Fix deck.gl form data (#6953)

* Fix deck.gl viz

* Fix more form data

* Fix a few more places

* Fix unit tests
This commit is contained in:
Beto Dealmeida
2019-02-27 10:19:52 -08:00
committed by GitHub
parent 8f2ce75665
commit e0feec9117
14 changed files with 91 additions and 91 deletions

View File

@@ -30,7 +30,7 @@ describe('getBreakPoints', () => {
});
it('returns sorted break points', () => {
const fd = { break_points: ['0', '10', '100', '50', '1000'] };
const fd = { breakPoints: ['0', '10', '100', '50', '1000'] };
const result = getBreakPoints(fd, [], metricAccessor);
const expected = ['0', '10', '50', '100', '1000'];
expect(result).toEqual(expected);
@@ -45,7 +45,7 @@ describe('getBreakPoints', () => {
});
it('formats number with proper precision', () => {
const fd = { metric: 'count', num_buckets: 2 };
const fd = { metric: 'count', numBuckets: 2 };
const features = [0, 1 / 3, 2 / 3, 1].map(count => ({ count }));
const result = getBreakPoints(fd, features, metricAccessor);
const expected = ['0.0', '0.5', '1.0'];
@@ -53,7 +53,7 @@ describe('getBreakPoints', () => {
});
it('works with a zero range', () => {
const fd = { metric: 'count', num_buckets: 1 };
const fd = { metric: 'count', numBuckets: 1 };
const features = [1, 1, 1].map(count => ({ count }));
const result = getBreakPoints(fd, features, metricAccessor);
const expected = ['1', '1'];
@@ -69,7 +69,7 @@ describe('getBreakPointColorScaler', () => {
it('returns linear color scaler if there are no break points', () => {
const fd = {
metric: 'count',
linear_color_scheme: ['#000000', '#ffffff'],
linearColorScheme: ['#000000', '#ffffff'],
opacity: 100,
};
const features = [10, 20, 30].map(count => ({ count }));
@@ -82,8 +82,8 @@ describe('getBreakPointColorScaler', () => {
it('returns bucketing scaler if there are break points', () => {
const fd = {
metric: 'count',
linear_color_scheme: ['#000000', '#ffffff'],
break_points: ['0', '1', '10'],
linearColorScheme: ['#000000', '#ffffff'],
breakPoints: ['0', '1', '10'],
opacity: 100,
};
const features = [];
@@ -97,8 +97,8 @@ describe('getBreakPointColorScaler', () => {
it('mask values outside the break points', () => {
const fd = {
metric: 'count',
linear_color_scheme: ['#000000', '#ffffff'],
break_points: ['0', '1', '10'],
linearColorScheme: ['#000000', '#ffffff'],
breakPoints: ['0', '1', '10'],
opacity: 100,
};
const features = [];
@@ -116,8 +116,8 @@ describe('getBuckets', () => {
it('computes buckets for break points', () => {
const fd = {
metric: 'count',
linear_color_scheme: ['#000000', '#ffffff'],
break_points: ['0', '1', '10'],
linearColorScheme: ['#000000', '#ffffff'],
breakPoints: ['0', '1', '10'],
opacity: 100,
};
const features = [];

View File

@@ -31,9 +31,9 @@ import { fitViewport } from './layers/common';
const { getScale } = CategoricalColorNamespace;
function getCategories(fd, data) {
const c = fd.color_picker || { r: 0, g: 0, b: 0, a: 1 };
const c = fd.colorPicker || { r: 0, g: 0, b: 0, a: 1 };
const fixedColor = [c.r, c.g, c.b, 255 * c.a];
const colorFn = getScale(fd.color_scheme);
const colorFn = getScale(fd.colorScheme);
const categories = {};
data.forEach((d) => {
if (d.cat_color != null && !categories.hasOwnProperty(d.cat_color)) {
@@ -108,7 +108,7 @@ export default class CategoricalDeckGLContainer extends React.PureComponent {
// the granularity has to be read from the payload form_data, not the
// props formData which comes from the instantaneous controls state
const granularity = (
props.payload.form_data.time_grain_sqla ||
props.payload.form_data.timeGrainSqla ||
props.payload.form_data.granularity ||
'P1D'
);
@@ -154,8 +154,8 @@ export default class CategoricalDeckGLContainer extends React.PureComponent {
features = this.addColor(features, fd);
// Apply user defined data mutator if defined
if (fd.js_data_mutator) {
const jsFnMutator = sandboxedEval(fd.js_data_mutator);
if (fd.jsDataMutator) {
const jsFnMutator = sandboxedEval(fd.jsDataMutator);
features = jsFnMutator(features);
}
@@ -180,8 +180,8 @@ export default class CategoricalDeckGLContainer extends React.PureComponent {
return [getLayer(fd, filteredPayload, onAddFilter, setTooltip)];
}
addColor(data, fd) {
const c = fd.color_picker || { r: 0, g: 0, b: 0, a: 1 };
const colorFn = getScale(fd.color_scheme);
const c = fd.colorPicker || { r: 0, g: 0, b: 0, a: 1 };
const colorFn = getScale(fd.colorScheme);
return data.map((d) => {
let color;
if (fd.dimension) {
@@ -229,14 +229,14 @@ export default class CategoricalDeckGLContainer extends React.PureComponent {
viewport={this.state.viewport}
onViewportChange={this.onViewportChange}
mapboxApiAccessToken={this.props.mapboxApiKey}
mapStyle={this.props.formData.mapbox_style}
mapStyle={this.props.formData.mapboxStyle}
setControlValue={this.props.setControlValue}
>
<Legend
categories={this.state.categories}
toggleCategory={this.toggleCategory}
showSingleCategory={this.showSingleCategory}
position={this.props.formData.legend_position}
position={this.props.formData.legendPosition}
/>
</AnimatableDeckGLContainer>
</div>

View File

@@ -56,7 +56,7 @@ class DeckMulti extends React.PureComponent {
const filters = [
...(subslice.form_data.filters || []),
...(formData.filters || []),
...(formData.extra_filters || []),
...(formData.extraFilters || []),
];
const subsliceCopy = {
...subslice,
@@ -70,7 +70,7 @@ class DeckMulti extends React.PureComponent {
endpoint: getExploreLongUrl(subsliceCopy.form_data, 'json'),
})
.then(({ json }) => {
const layer = layerGenerators[subsliceCopy.form_data.viz_type](
const layer = layerGenerators[subsliceCopy.form_data.vizType](
subsliceCopy.form_data,
json,
);
@@ -96,7 +96,7 @@ class DeckMulti extends React.PureComponent {
mapboxApiAccessToken={payload.data.mapboxApiKey}
viewport={viewport}
layers={layers}
mapStyle={formData.mapbox_style}
mapStyle={formData.mapboxStyle}
setControlValue={setControlValue}
/>
);

View File

@@ -90,7 +90,7 @@ export function createDeckGLComponent(getLayer, getPoints) {
mapboxApiAccessToken={payload.data.mapboxApiKey}
viewport={viewport}
layers={[layer]}
mapStyle={formData.mapbox_style}
mapStyle={formData.mapboxStyle}
setControlValue={setControlValue}
onViewportChange={this.onViewportChange}
/>);

View File

@@ -31,14 +31,14 @@ function getPoints(data) {
export function getLayer(fd, payload, onAddFilter, setTooltip) {
const data = payload.data.features;
const sc = fd.color_picker;
const tc = fd.target_color_picker;
const sc = fd.colorPicker;
const tc = fd.targetColorPicker;
return new ArcLayer({
id: `path-layer-${fd.slice_id}`,
id: `path-layer-${fd.sliceId}`,
data,
getSourceColor: d => d.sourceColor || d.color || [sc.r, sc.g, sc.b, 255 * sc.a],
getTargetColor: d => d.targetColor || d.color || [tc.r, tc.g, tc.b, 255 * tc.a],
strokeWidth: (fd.stroke_width) ? fd.stroke_width : 3,
strokeWidth: (fd.strokeWidth) ? fd.strokeWidth : 3,
...commonLayerProps(fd, setTooltip),
});
}

View File

@@ -77,8 +77,8 @@ const recurseGeoJson = (node, propOverrides, extraProps) => {
export function getLayer(formData, payload, onAddFilter, setTooltip) {
const fd = formData;
const fc = fd.fill_color_picker;
const sc = fd.stroke_color_picker;
const fc = fd.fillColorPicker;
const sc = fd.strokeColorPicker;
const fillColor = [fc.r, fc.g, fc.b, 255 * fc.a];
const strokeColor = [sc.r, sc.g, sc.b, 255 * sc.a];
const propOverrides = {};
@@ -93,19 +93,19 @@ export function getLayer(formData, payload, onAddFilter, setTooltip) {
recurseGeoJson(payload.data, propOverrides);
let jsFnMutator;
if (fd.js_data_mutator) {
if (fd.jsDataMutator) {
// Applying user defined data mutator if defined
jsFnMutator = sandboxedEval(fd.js_data_mutator);
jsFnMutator = sandboxedEval(fd.jsDataMutator);
features = jsFnMutator(features);
}
return new GeoJsonLayer({
id: `geojson-layer-${fd.slice_id}`,
id: `geojson-layer-${fd.sliceId}`,
filled: fd.filled,
data: features,
stroked: fd.stroked,
extruded: fd.extruded,
pointRadiusScale: fd.point_radius_scale,
pointRadiusScale: fd.pointRadiusScale,
...commonLayerProps(fd, setTooltip),
});
}
@@ -145,7 +145,7 @@ function deckGeoJson(props) {
mapboxApiAccessToken={payload.data.mapboxApiKey}
viewport={viewport}
layers={[layer]}
mapStyle={formData.mapbox_style}
mapStyle={formData.mapboxStyle}
setControlValue={setControlValue}
/>
);

View File

@@ -24,24 +24,24 @@ import { createDeckGLComponent } from '../../factory';
export function getLayer(formData, payload, onAddFilter, setTooltip) {
const fd = formData;
const c = fd.color_picker;
const c = fd.colorPicker;
let data = payload.data.features.map(d => ({
...d,
color: [c.r, c.g, c.b, 255 * c.a],
}));
if (fd.js_data_mutator) {
if (fd.jsDataMutator) {
// Applying user defined data mutator if defined
const jsFnMutator = sandboxedEval(fd.js_data_mutator);
const jsFnMutator = sandboxedEval(fd.jsDataMutator);
data = jsFnMutator(data);
}
const aggFunc = getAggFunc(fd.js_agg_function, p => p.weight);
const aggFunc = getAggFunc(fd.jsAggFunction, p => p.weight);
return new GridLayer({
id: `grid-layer-${fd.slice_id}`,
id: `grid-layer-${fd.sliceId}`,
data,
pickable: true,
cellSize: fd.grid_size,
cellSize: fd.gridSize,
minColor: [0, 0, 0, 0],
extruded: fd.extruded,
maxColor: [c.r, c.g, c.b, 255 * c.a],

View File

@@ -24,23 +24,23 @@ import { createDeckGLComponent } from '../../factory';
export function getLayer(formData, payload, onAddFilter, setTooltip) {
const fd = formData;
const c = fd.color_picker;
const c = fd.colorPicker;
let data = payload.data.features.map(d => ({
...d,
color: [c.r, c.g, c.b, 255 * c.a],
}));
if (fd.js_data_mutator) {
if (fd.jsDataMutator) {
// Applying user defined data mutator if defined
const jsFnMutator = sandboxedEval(fd.js_data_mutator);
const jsFnMutator = sandboxedEval(fd.jsDataMutator);
data = jsFnMutator(data);
}
const aggFunc = getAggFunc(fd.js_agg_function, p => p.weight);
const aggFunc = getAggFunc(fd.jsAggFunction, p => p.weight);
return new HexagonLayer({
id: `hex-layer-${fd.slice_id}`,
id: `hex-layer-${fd.sliceId}`,
data,
pickable: true,
radius: fd.grid_size,
radius: fd.gridSize,
minColor: [0, 0, 0, 0],
extruded: fd.extruded,
maxColor: [c.r, c.g, c.b, 255 * c.a],

View File

@@ -23,22 +23,22 @@ import { createDeckGLComponent } from '../../factory';
export function getLayer(formData, payload, onAddFilter, setTooltip) {
const fd = formData;
const c = fd.color_picker;
const c = fd.colorPicker;
const fixedColor = [c.r, c.g, c.b, 255 * c.a];
let data = payload.data.features.map(feature => ({
...feature,
path: feature.path,
width: fd.line_width,
width: fd.lineWidth,
color: fixedColor,
}));
if (fd.js_data_mutator) {
const jsFnMutator = sandboxedEval(fd.js_data_mutator);
if (fd.jsDataMutator) {
const jsFnMutator = sandboxedEval(fd.jsDataMutator);
data = jsFnMutator(data);
}
return new PathLayer({
id: `path-layer-${fd.slice_id}`,
id: `path-layer-${fd.sliceId}`,
data,
rounded: true,
widthScale: 1,

View File

@@ -50,8 +50,8 @@ function getElevation(d, colorScaler) {
export function getLayer(formData, payload, setTooltip, selected, onSelect, filters) {
const fd = formData;
const fc = fd.fill_color_picker;
const sc = fd.stroke_color_picker;
const fc = fd.fillColorPicker;
const sc = fd.strokeColorPicker;
let data = [...payload.data.features];
if (filters != null) {
@@ -60,9 +60,9 @@ export function getLayer(formData, payload, setTooltip, selected, onSelect, filt
});
}
if (fd.js_data_mutator) {
if (fd.jsDataMutator) {
// Applying user defined data mutator if defined
const jsFnMutator = sandboxedEval(fd.js_data_mutator);
const jsFnMutator = sandboxedEval(fd.jsDataMutator);
data = jsFnMutator(data);
}
@@ -76,13 +76,13 @@ export function getLayer(formData, payload, setTooltip, selected, onSelect, filt
// when polygons are selected, reduce the opacity of non-selected polygons
const colorScaler = (d) => {
const baseColor = baseColorScaler(d);
if (selected.length > 0 && selected.indexOf(d[fd.line_column]) === -1) {
if (selected.length > 0 && selected.indexOf(d[fd.lineColumn]) === -1) {
baseColor[3] /= 2;
}
return baseColor;
};
return new PolygonLayer({
id: `path-layer-${fd.slice_id}`,
id: `path-layer-${fd.sliceId}`,
data,
pickable: true,
filled: fd.filled,
@@ -90,7 +90,7 @@ export function getLayer(formData, payload, setTooltip, selected, onSelect, filt
getPolygon: d => d.polygon,
getFillColor: colorScaler,
getLineColor: [sc.r, sc.g, sc.b, 255 * sc.a],
getLineWidth: fd.line_width,
getLineWidth: fd.lineWidth,
extruded: fd.extruded,
getElevation: d => getElevation(d, colorScaler),
elevationScale: fd.multiplier,
@@ -138,7 +138,7 @@ class DeckGLPolygon extends React.Component {
// the granularity has to be read from the payload form_data, not the
// props formData which comes from the instantaneous controls state
const granularity = (
props.payload.form_data.time_grain_sqla ||
props.payload.form_data.timeGrainSqla ||
props.payload.form_data.granularity ||
'P1D'
);
@@ -177,7 +177,7 @@ class DeckGLPolygon extends React.Component {
const selected = [...this.state.selected];
if (doubleClick) {
selected.splice(0, selected.length, polygon);
} else if (formData.toggle_polygons) {
} else if (formData.togglePolygons) {
const i = selected.indexOf(polygon);
if (i === -1) {
selected.push(polygon);
@@ -189,8 +189,8 @@ class DeckGLPolygon extends React.Component {
}
this.setState({ selected, lastClick: now });
if (formData.table_filter) {
onAddFilter(formData.line_column, selected, false, true);
if (formData.tableFilter) {
onAddFilter(formData.lineColumn, selected, false, true);
}
}
onValuesChange(values) {
@@ -249,14 +249,14 @@ class DeckGLPolygon extends React.Component {
viewport={viewport}
onViewportChange={this.onViewportChange}
mapboxApiAccessToken={payload.data.mapboxApiKey}
mapStyle={formData.mapbox_style}
mapStyle={formData.mapboxStyle}
setControlValue={setControlValue}
aggregation
>
{formData.metric !== null &&
<Legend
categories={buckets}
position={formData.legend_position}
position={formData.legendPosition}
/>}
</AnimatableDeckGLContainer>
</div>

View File

@@ -27,24 +27,24 @@ function getPoints(data) {
export function getLayer(fd, payload, onAddFilter, setTooltip) {
const dataWithRadius = payload.data.features.map((d) => {
let radius = unitToRadius(fd.point_unit, d.radius) || 10;
let radius = unitToRadius(fd.pointUnit, d.radius) || 10;
if (fd.multiplier) {
radius *= fd.multiplier;
}
if (d.color) {
return { ...d, radius };
}
const c = fd.color_picker || { r: 0, g: 0, b: 0, a: 1 };
const c = fd.colorPicker || { r: 0, g: 0, b: 0, a: 1 };
const color = [c.r, c.g, c.b, c.a * 255];
return { ...d, radius, color };
});
return new ScatterplotLayer({
id: `scatter-layer-${fd.slice_id}`,
id: `scatter-layer-${fd.sliceId}`,
data: dataWithRadius,
fp64: true,
radiusMinPixels: fd.min_radius || null,
radiusMaxPixels: fd.max_radius || null,
radiusMinPixels: fd.minRadius || null,
radiusMaxPixels: fd.maxRadius || null,
outline: false,
...commonLayerProps(fd, setTooltip),
});

View File

@@ -32,15 +32,15 @@ function getPoints(data) {
export function getLayer(formData, payload, onAddFilter, setTooltip, filters) {
const fd = formData;
const c = fd.color_picker;
const c = fd.colorPicker;
let data = payload.data.features.map(d => ({
...d,
color: [c.r, c.g, c.b, 255 * c.a],
}));
if (fd.js_data_mutator) {
if (fd.jsDataMutator) {
// Applying user defined data mutator if defined
const jsFnMutator = sandboxedEval(fd.js_data_mutator);
const jsFnMutator = sandboxedEval(fd.jsDataMutator);
data = jsFnMutator(data);
}
@@ -53,10 +53,10 @@ export function getLayer(formData, payload, onAddFilter, setTooltip, filters) {
// Passing a layer creator function instead of a layer since the
// layer needs to be regenerated at each render
return new ScreenGridLayer({
id: `screengrid-layer-${fd.slice_id}`,
id: `screengrid-layer-${fd.sliceId}`,
data,
pickable: true,
cellSizePixels: fd.grid_size,
cellSizePixels: fd.gridSize,
minColor: [c.r, c.g, c.b, 0],
maxColor: [c.r, c.g, c.b, 255 * c.a],
outline: false,
@@ -102,7 +102,7 @@ class DeckGLScreenGrid extends React.PureComponent {
// the granularity has to be read from the payload form_data, not the
// props formData which comes from the instantaneous controls state
const granularity = (
props.payload.form_data.time_grain_sqla ||
props.payload.form_data.timeGrainSqla ||
props.payload.form_data.granularity ||
'P1D'
);
@@ -176,7 +176,7 @@ class DeckGLScreenGrid extends React.PureComponent {
viewport={this.state.viewport}
onViewportChange={this.onViewportChange}
mapboxApiAccessToken={payload.data.mapboxApiKey}
mapStyle={formData.mapbox_style}
mapStyle={formData.mapboxStyle}
setControlValue={setControlValue}
aggregation
/>

View File

@@ -54,13 +54,13 @@ export function commonLayerProps(formData, setTooltip, onSelect) {
const fd = formData;
let onHover;
let tooltipContentGenerator;
if (fd.js_tooltip) {
tooltipContentGenerator = sandboxedEval(fd.js_tooltip);
} else if (fd.line_column && fd.metric && ['geohash', 'zipcode'].indexOf(fd.line_type) >= 0) {
if (fd.jsTooltip) {
tooltipContentGenerator = sandboxedEval(fd.jsTooltip);
} else if (fd.lineColumn && fd.metric && ['geohash', 'zipcode'].indexOf(fd.lineType) >= 0) {
const metricLabel = fd.metric.label || fd.metric;
tooltipContentGenerator = o => (
<div>
<div>{fd.line_column}: <strong>{o.object[fd.line_column]}</strong></div>
<div>{fd.lineColumn}: <strong>{o.object[fd.lineColumn]}</strong></div>
{fd.metric &&
<div>{metricLabel}: <strong>{o.object[metricLabel]}</strong></div>}
</div>);
@@ -79,13 +79,13 @@ export function commonLayerProps(formData, setTooltip, onSelect) {
};
}
let onClick;
if (fd.js_onclick_href) {
if (fd.jsOnclickHref) {
onClick = (o) => {
const href = sandboxedEval(fd.js_onclick_href)(o);
const href = sandboxedEval(fd.jsOnclickHref)(o);
window.open(href);
};
} else if (fd.table_filter && onSelect !== undefined) {
onClick = o => onSelect(o.object[fd.line_column]);
} else if (fd.tableFilter && onSelect !== undefined) {
onClick = o => onSelect(o.object[fd.lineColumn]);
}
return {
onClick,

View File

@@ -24,8 +24,8 @@ import { hexToRGB } from '../../modules/colors';
const DEFAULT_NUM_BUCKETS = 10;
export function getBreakPoints({
break_points: formDataBreakPoints,
num_buckets: formDataNumBuckets,
breakPoints: formDataBreakPoints,
numBuckets: formDataNumBuckets,
}, features, accessor) {
if (!features) {
return [];
@@ -46,15 +46,15 @@ export function getBreakPoints({
}
export function getBreakPointColorScaler({
break_points: formDataBreakPoints,
num_buckets: formDataNumBuckets,
linear_color_scheme: linearColorScheme,
breakPoints: formDataBreakPoints,
numBuckets: formDataNumBuckets,
linearColorScheme,
opacity,
}, features, accessor) {
const breakPoints = formDataBreakPoints || formDataNumBuckets
? getBreakPoints({
break_points: formDataBreakPoints,
num_buckets: formDataNumBuckets,
breakPoints: formDataBreakPoints,
numBuckets: formDataNumBuckets,
}, features, accessor)
: null;
const colorScheme = Array.isArray(linearColorScheme)