Skip to content

Commit

Permalink
feat: integrate line chart with build query and update typings (#73)
Browse files Browse the repository at this point in the history
* feat: integrate line chart with buildQuery

* fix: typings

* fix: minor

* feat: derive groupbys

* fix: tooltip for single series
  • Loading branch information
kristw authored and zhaoyongjie committed Nov 26, 2021
1 parent 0eafb6c commit 23c4aa3
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,40 @@ export default [
formData: {
viz_type: LINE_PLUGIN_TYPE,
datasource: '3__table',
url_params: {},
granularity_sqla: 'ds',
time_grain_sqla: 'P1D',
time_range: '100 years ago : now',
metrics: ['sum__num'],
adhoc_filters: [],
groupby: [],
limit: 25,
row_limit: 50000,
encoding: {
x: {
field: '__timestamp',
type: 'temporal',
format: '%Y',
scale: {
type: 'time',
},
axis: {
title: 'Time',
},
},
y: {
field: 'sum__num',
type: 'quantitative',
scale: {
type: 'linear',
},
axis: {
title: 'Number of Babies',
},
},
color: {
field: 'gender',
type: 'nominal',
legend: true,
},
},
},
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ export interface Series {
}

export interface SeriesValue {
x: Outputs['x'];
y: Outputs['y'];
x: number | Date;
y: number;
data: PlainObject;
parent: Series;
}
Expand Down Expand Up @@ -90,21 +90,28 @@ class LineChart extends PureComponent<Props> {

const allSeries = values(groups).map(seriesData => {
const firstDatum = seriesData[0];

const key = fieldNames.map(f => firstDatum[f]).join(',');
const series: Series = {
key: fieldNames.map(f => firstDatum[f]).join(','),
color: channels.color.encode(firstDatum),
key: key.length === 0 ? channels.y.getTitle() : key,
color: channels.color.encode(firstDatum, '#222'),
fill: channels.fill.encode(firstDatum, false),
strokeDasharray: channels.strokeDasharray.encode(firstDatum),
strokeDasharray: channels.strokeDasharray.encode(firstDatum, ''),
values: [],
};

series.values = seriesData.map(v => ({
x: channels.x.get(v),
y: channels.y.get(v),
data: v,
parent: series,
}));
series.values = seriesData
.map(v => ({
x: channels.x.get<number | Date>(v),
y: channels.y.get<number>(v),
data: v,
parent: series,
}))
.sort((a: SeriesValue, b: SeriesValue) => {
const aTime = a.x instanceof Date ? a.x.getTime() : a.x;
const bTime = b.x instanceof Date ? b.x.getTime() : b.x;

return aTime - bTime;
});

return series;
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { buildQueryContext } from '@superset-ui/chart';
import ChartFormData from './ChartFormData';
import Encoder from './Encoder';

export default function buildQuery(formData: ChartFormData) {
const queryContext = buildQueryContext(formData);
const { encoding } = formData;
const encoder = new Encoder({ encoding });

// Enforce time-series mode
queryContext.queries.forEach(query => {
const q = query;
q.groupby = encoder.getGroupBys();
// Enforce time-series mode
q.is_timeseries = true;
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import { Value } from 'vega-lite/build/src/channeldef';
import AbstractEncoder from '../encodeable/AbstractEncoder';
import { Dataset } from '../encodeable/types/Data';
import { ObjectWithKeysFromAndValueType } from '../encodeable/types/Base';
import { ChannelType, EncodingFromChannelsAndOutputs } from '../encodeable/types/Channel';
import {
ChannelType,
EncodingFromChannelsAndOutputs,
ChannelInput,
} from '../encodeable/types/Channel';
import { BaseOptions } from '../encodeable/types/Specification';

type Props<Encoder> = {
Expand Down Expand Up @@ -50,7 +54,7 @@ export default class ChartLegend<
const domain = Array.from(new Set(data.map(channelEncoder.get)));
const scale = scaleOrdinal({
domain,
range: domain.map((key: string) => channelEncoder.encodeValue(key)),
range: domain.map((key: ChannelInput) => channelEncoder.encodeValue(key)),
});

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Value } from 'vega-lite/build/src/channeldef';
import { extractFormatFromChannelDef } from './parsers/extractFormat';
import extractScale, { ScaleAgent } from './parsers/extractScale';
import extractGetter from './parsers/extractGetter';
import { ChannelOptions, ChannelType } from './types/Channel';
import { ChannelOptions, ChannelType, ChannelInput } from './types/Channel';
import { PlainObject } from './types/Data';
import {
ChannelDef,
Expand All @@ -24,9 +24,9 @@ export default class ChannelEncoder<Def extends ChannelDef<Output>, Output exten
readonly definition: Def;
readonly options: ChannelOptions;

protected readonly getValue: (datum: PlainObject) => Value | undefined;
readonly encodeValue: (value: any) => Output | null | undefined;
readonly formatValue: (value: any) => string;
protected readonly getValue: (datum: PlainObject) => ChannelInput;
readonly encodeValue: (value: ChannelInput) => Output | null | undefined;
readonly formatValue: (value: ChannelInput | { toString(): string }) => string;
readonly scale?: ScaleAgent<Output>;
readonly axis?: AxisAgent<Def, Output>;

Expand Down Expand Up @@ -66,10 +66,14 @@ export default class ChannelEncoder<Def extends ChannelDef<Output>, Output exten
this.get = this.get.bind(this);
}

encode(datum: PlainObject): Output | null | undefined;
// eslint-disable-next-line no-dupe-class-members
encode(datum: PlainObject, otherwise: Output): Output;
// eslint-disable-next-line no-dupe-class-members
encode(datum: PlainObject, otherwise?: Output) {
const value = this.get(datum);
if (value === null || value === undefined) {
return value;
return otherwise;
}

const output = this.encodeValue(value);
Expand All @@ -83,10 +87,12 @@ export default class ChannelEncoder<Def extends ChannelDef<Output>, Output exten
return this.formatValue(this.get(datum));
}

get(datum: PlainObject, otherwise?: any) {
get<T extends ChannelInput>(datum: PlainObject, otherwise?: T) {
const value = this.getValue(datum);

return otherwise !== undefined && (value === null || value === undefined) ? otherwise : value;
return otherwise !== undefined && (value === null || value === undefined)
? otherwise
: (value as T);
}

getTitle() {
Expand All @@ -110,12 +116,13 @@ export default class ChannelEncoder<Def extends ChannelDef<Output>, Output exten

isGroupBy() {
if (isTypedFieldDef(this.definition)) {
const { type: dataType } = this.definition;

return (
this.type === 'XBand' ||
this.type === 'YBand' ||
this.type === 'Category' ||
this.type === 'Text' ||
(this.type === 'Color' && this.definition.type === 'nominal')
(this.type === 'Color' && (dataType === 'nominal' || dataType === 'ordinal')) ||
(this.isXY() && (dataType === 'nominal' || dataType === 'ordinal'))
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { Value } from 'vega-lite/build/src/channeldef';
import { XFieldDef, YFieldDef, ChannelDef, MarkPropChannelDef, TextChannelDef } from './ChannelDef';
import { ObjectWithKeysFromAndValueType } from './Base';

export type ChannelInput = number | string | boolean | null | Date | undefined;

// eslint-disable-next-line import/prefer-default-export
export interface ChannelOptions {
namespace?: string;
Expand Down

0 comments on commit 23c4aa3

Please sign in to comment.