Compare commits

...

16 Commits

Author SHA1 Message Date
Maxime Beauchemin
915466fdfc 0.29.0rc5 2018-12-01 12:39:20 -08:00
Grace Guo
e48def35d6 [logging] Add render failure error into log (#6422)
(cherry picked from commit 2489876bc9)
2018-11-30 13:32:05 -08:00
Krist Wongsuphasawat
6b0f42c81c [bugfix] Display raw value in addition to ERROR (#6417)
* Display raw value in addition to ERROR

* update unit test

(cherry picked from commit 3c6e882d28)
2018-11-30 13:32:01 -08:00
Grace Guo
4e8411c7f1 [fix] view results in sql lab (#6405)
(cherry picked from commit e469086d61)
2018-11-30 13:31:57 -08:00
Maxime Beauchemin
3c6f34cabd [bugfix] deck.gl grid&hex don't respond to zoom&drag (#6363)
* [bugfix] deck.gl grid&hex don't respond to zoom&drag

Following recent changes, Hex & Grid component wouldn't respond to
viewport interactions. This fixes the issue.

This PR also greatly improve rendering performance by only recomputing
the deck.gl layers when needed, as opposed to every time the viewport
changes, which is very inneficient.

Note that most other deck.gl layers seem to be systematically
recomputing layers, we'll have to fix this in another PR.

* Addressing comments

(cherry picked from commit 8177fa17fa)
2018-11-30 13:31:53 -08:00
Maxime Beauchemin
b9c8b0a112 Fix adhoc metrics in Polygon (#6399)
* Fix adhoc metrics in Polygon

* Addressing comments

(cherry picked from commit 4c94447635)
2018-11-30 13:31:45 -08:00
Jeffrey Wang
9c88fefdeb Set default limit on creation of new qe and on run (#6400)
(cherry picked from commit 8c4f723a61)
2018-11-30 13:31:40 -08:00
Grace Guo
6581a827ee [fix] JS error after delete row level tab (#6393)
(cherry picked from commit ec1316a5a8)
2018-11-30 13:31:33 -08:00
Maxime Beauchemin
7d28a84cce [bugfix] prevent d3-format from raising (#6386)
Since https://github.com/apache/incubator-superset/pull/6287 and
effectively moving to a new version of d3, d3-format and d3-time-format
raises when receiving invalid input strings.

This code wraps the potential issues inside `try` blocks that will
effectively return an `ERROR` string as output to the formatting
function.

(cherry picked from commit 4690563d40)
2018-11-30 13:31:24 -08:00
Krist Wongsuphasawat
ba8f3c784c do not convert value to lowercase when looking up color (#6384)
(cherry picked from commit cb556688ec)
2018-11-30 13:31:20 -08:00
Conglei
b23505e5c7 Fixed the cache issue for BigNumber (#6375)
* fixed the cache issue for bignumber

* fixed

(cherry picked from commit 8e2d28dd6e)
2018-11-30 13:31:16 -08:00
Maxime Beauchemin
82a6708d10 0.29.0rc4 2018-11-12 10:54:56 -08:00
Maxime Beauchemin
88ab67b69a Merge branch 'master' into 0.29 2018-11-12 10:54:43 -08:00
Maxime Beauchemin
c08f4eaee1 0.29.0rc3 2018-11-10 12:39:44 -08:00
Maxime Beauchemin
1d74f308ee Merge branch 'master' into 0.29 2018-11-10 12:39:02 -08:00
Maxime Beauchemin
60cb608839 0.29.0rc2 2018-11-08 09:39:24 -08:00
18 changed files with 196 additions and 128 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "superset",
"version": "0.999.0dev",
"version": "0.29.0rc5",
"description": "Superset is a data exploration platform designed to be visual, intuitive, and interactive.",
"license": "Apache-2.0",
"directories": {
@@ -79,7 +79,7 @@
"d3-tip": "^0.9.1",
"datamaps": "^0.5.8",
"datatables.net-bs": "^1.10.15",
"deck.gl": "^5.3.4",
"deck.gl": "^5.3.5",
"distributions": "^1.0.0",
"dnd-core": "^2.6.0",
"dompurify": "^1.0.3",

View File

@@ -29,6 +29,7 @@ describe('utils', () => {
expect(d3format('.3s', 1234)).toBe('1.23k');
expect(d3format('.3s', 1237)).toBe('1.24k');
expect(d3format('', 1237)).toBe('1.24k');
expect(d3format('.2efd2.ef.2.e', 1237)).toBe('1237 (Invalid format: .2efd2.ef.2.e)');
});
});
@@ -45,8 +46,9 @@ describe('utils', () => {
it('is a function', () => {
expect(typeof d3TimeFormatPreset).toBe('function');
});
it('returns a working time formatter', () => {
it('returns a working formatter', () => {
expect(d3FormatPreset('smart_date')(0)).toBe('1970');
expect(d3FormatPreset('%%GIBBERISH')(0)).toBe('0 (Invalid format: %%GIBBERISH)');
});
});

View File

@@ -4,6 +4,8 @@ import {
getBuckets,
} from '../../../../src/visualizations/deckgl/utils';
const metricAccessor = d => d.count;
describe('getBreakPoints', () => {
it('is a function', () => {
expect(typeof getBreakPoints).toBe('function');
@@ -11,7 +13,7 @@ describe('getBreakPoints', () => {
it('returns sorted break points', () => {
const fd = { break_points: ['0', '10', '100', '50', '1000'] };
const result = getBreakPoints(fd, []);
const result = getBreakPoints(fd, [], metricAccessor);
const expected = ['0', '10', '50', '100', '1000'];
expect(result).toEqual(expected);
});
@@ -19,7 +21,7 @@ describe('getBreakPoints', () => {
it('returns evenly distributed break points when no break points are specified', () => {
const fd = { metric: 'count' };
const features = [0, 1, 2, 10].map(count => ({ count }));
const result = getBreakPoints(fd, features);
const result = getBreakPoints(fd, features, metricAccessor);
const expected = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10'];
expect(result).toEqual(expected);
});
@@ -27,7 +29,7 @@ describe('getBreakPoints', () => {
it('formats number with proper precision', () => {
const fd = { metric: 'count', num_buckets: 2 };
const features = [0, 1 / 3, 2 / 3, 1].map(count => ({ count }));
const result = getBreakPoints(fd, features);
const result = getBreakPoints(fd, features, metricAccessor);
const expected = ['0.0', '0.5', '1.0'];
expect(result).toEqual(expected);
});
@@ -35,7 +37,7 @@ describe('getBreakPoints', () => {
it('works with a zero range', () => {
const fd = { metric: 'count', num_buckets: 1 };
const features = [1, 1, 1].map(count => ({ count }));
const result = getBreakPoints(fd, features);
const result = getBreakPoints(fd, features, metricAccessor);
const expected = ['1', '1'];
expect(result).toEqual(expected);
});
@@ -53,7 +55,7 @@ describe('getBreakPointColorScaler', () => {
opacity: 100,
};
const features = [10, 20, 30].map(count => ({ count }));
const scaler = getBreakPointColorScaler(fd, features);
const scaler = getBreakPointColorScaler(fd, features, metricAccessor);
expect(scaler({ count: 10 })).toEqual([0, 0, 0, 255]);
expect(scaler({ count: 15 })).toEqual([64, 64, 64, 255]);
expect(scaler({ count: 30 })).toEqual([255, 255, 255, 255]);
@@ -67,7 +69,7 @@ describe('getBreakPointColorScaler', () => {
opacity: 100,
};
const features = [];
const scaler = getBreakPointColorScaler(fd, features);
const scaler = getBreakPointColorScaler(fd, features, metricAccessor);
expect(scaler({ count: 0 })).toEqual([0, 0, 0, 255]);
expect(scaler({ count: 0.5 })).toEqual([0, 0, 0, 255]);
expect(scaler({ count: 1 })).toEqual([255, 255, 255, 255]);
@@ -82,7 +84,7 @@ describe('getBreakPointColorScaler', () => {
opacity: 100,
};
const features = [];
const scaler = getBreakPointColorScaler(fd, features);
const scaler = getBreakPointColorScaler(fd, features, metricAccessor);
expect(scaler({ count: -1 })).toEqual([0, 0, 0, 0]);
expect(scaler({ count: 11 })).toEqual([255, 255, 255, 0]);
});
@@ -101,7 +103,7 @@ describe('getBuckets', () => {
opacity: 100,
};
const features = [];
const result = getBuckets(fd, features);
const result = getBuckets(fd, features, metricAccessor);
const expected = {
'0 - 1': { color: [0, 0, 0, 255], enabled: true },
'1 - 10': { color: [255, 255, 255, 255], enabled: true },

View File

@@ -28,6 +28,7 @@ const defaultProps = {
csv: true,
actions: {},
cache: false,
database: {},
};
const SEARCH_HEIGHT = 46;

View File

@@ -149,7 +149,7 @@ class SqlEditor extends React.PureComponent {
schema: qe.schema,
tempTableName: ctas ? this.state.ctas : '',
templateParams: qe.templateParams,
queryLimit: qe.queryLimit,
queryLimit: qe.queryLimit || this.props.defaultQueryLimit,
runAsync,
ctas,
};

View File

@@ -138,6 +138,7 @@ class TabbedSqlEditors extends React.PureComponent {
sql: `${t(
'-- Note: Unless you save your query, these tabs will NOT persist if you clear your cookies or change browsers.',
)}\n\nSELECT ...`,
queryLimit: this.props.defaultQueryLimit,
};
this.props.actions.addQueryEditor(qe);
}

View File

@@ -95,6 +95,14 @@ class Chart extends React.PureComponent {
const { actions, chartId } = this.props;
console.warn(error); // eslint-disable-line
actions.chartRenderingFailed(error.toString(), chartId, info ? info.componentStack : null);
Logger.append(LOG_ACTIONS_RENDER_CHART, {
slice_id: chartId,
has_err: true,
error_details: error.toString(),
start_offset: this.renderStartTime,
duration: Logger.getTimestamp() - this.renderStartTime,
});
}
prepareChartProps() {
@@ -126,8 +134,7 @@ class Chart extends React.PureComponent {
renderTooltip() {
const { tooltip } = this.state;
if (tooltip) {
if (tooltip && tooltip.content) {
return (
<Tooltip
className="chart-tooltip"
@@ -173,32 +180,31 @@ class Chart extends React.PureComponent {
this.renderStartTime = Logger.getTimestamp();
return (
<div
className={`chart-container ${isLoading ? 'is-loading' : ''}`}
style={containerStyles}
>
{this.renderTooltip()}
<ErrorBoundary onError={this.handleRenderFailure} showMessage={false}>
<div
className={`chart-container ${isLoading ? 'is-loading' : ''}`}
style={containerStyles}
>
{this.renderTooltip()}
{['loading', 'success'].indexOf(chartStatus) >= 0 && <Loading size={50} />}
{['loading', 'success'].indexOf(chartStatus) >= 0 && <Loading size={50} />}
{chartAlert && (
<StackTraceMessage
message={chartAlert}
link={queryResponse ? queryResponse.link : null}
stackTrace={chartStackTrace}
/>
)}
{chartAlert && (
<StackTraceMessage
message={chartAlert}
link={queryResponse ? queryResponse.link : null}
stackTrace={chartStackTrace}
/>
)}
{!isLoading && !chartAlert && isFaded && (
<RefreshChartOverlay
width={width}
height={height}
onQuery={onQuery}
onDismiss={onDismissRefreshOverlay}
/>
)}
<ErrorBoundary onError={this.handleRenderFailure} showMessage={false}>
{!isLoading && !chartAlert && isFaded && (
<RefreshChartOverlay
width={width}
height={height}
onQuery={onQuery}
onDismiss={onDismissRefreshOverlay}
/>
)}
<SuperChart
className={`slice_container ${snakeCase(vizType)} ${isFaded ? ' faded' : ''}`}
chartType={vizType}
@@ -207,8 +213,8 @@ class Chart extends React.PureComponent {
onRenderFailure={this.handleRenderFailure}
skipRendering={skipChartRendering}
/>
</ErrorBoundary>
</div>
</div>
</ErrorBoundary>
);
}
}

View File

@@ -39,15 +39,17 @@ function mapStateToProps(
// rows and columns need more data about their child dimensions
// doing this allows us to not pass the entire component lookup to all Components
const componentType = component.type;
if (componentType === ROW_TYPE || componentType === COLUMN_TYPE) {
const { occupiedWidth, minimumWidth } = getDetailedComponentWidth({
id,
components: dashboardLayout,
});
if (component) {
const componentType = component.type;
if (componentType === ROW_TYPE || componentType === COLUMN_TYPE) {
const { occupiedWidth, minimumWidth } = getDetailedComponentWidth({
id,
components: dashboardLayout,
});
if (componentType === ROW_TYPE) props.occupiedColumnCount = occupiedWidth;
if (componentType === COLUMN_TYPE) props.minColumnWidth = minimumWidth;
if (componentType === ROW_TYPE) props.occupiedColumnCount = occupiedWidth;
if (componentType === COLUMN_TYPE) props.minColumnWidth = minimumWidth;
}
}
return props;
@@ -68,7 +70,7 @@ function mapDispatchToProps(dispatch) {
class DashboardComponent extends React.PureComponent {
render() {
const { component } = this.props;
const Component = ComponentLookup[component.type];
const Component = component ? ComponentLookup[component.type] : null;
return Component ? <Component {...this.props} /> : null;
}
}

View File

@@ -22,7 +22,13 @@ export function d3FormatPreset(format) {
return formatDate;
}
if (format) {
return d3Format(format);
try {
return d3Format(format);
} catch (e) {
// eslint-disable-next-line no-console
console.warn(e);
return value => `${value} (Invalid format: ${format})`;
}
}
return defaultNumberFormatter;
}
@@ -45,12 +51,18 @@ export function d3format(format, number) {
format = format || '.3s';
// Formats a number and memoizes formatters to be reused
if (!(format in formatters)) {
formatters[format] = d3Format(format);
try {
formatters[format] = d3Format(format);
} catch (e) {
// eslint-disable-next-line no-console
console.warn(e);
return `${number} (Invalid format: ${format})`;
}
}
try {
return formatters[format](number);
} catch (e) {
return 'ERR';
return `${number} (Invalid format: ${format})`;
}
}

View File

@@ -3,8 +3,9 @@ import PropTypes from 'prop-types';
import MapGL from 'react-map-gl';
import DeckGL from 'deck.gl';
import 'mapbox-gl/dist/mapbox-gl.css';
import { isEqual } from 'lodash';
const TICK = 1000; // milliseconds
const TICK = 2000; // milliseconds
const propTypes = {
viewport: PropTypes.object.isRequired,
@@ -23,12 +24,13 @@ const defaultProps = {
export default class DeckGLContainer extends React.Component {
constructor(props) {
super(props);
this.tick = this.tick.bind(this);
this.onViewportChange = this.onViewportChange.bind(this);
// This has to be placed after this.tick is bound to this
this.state = {
previousViewport: props.viewport,
timer: setInterval(this.tick, TICK),
};
this.tick = this.tick.bind(this);
this.onViewportChange = this.onViewportChange.bind(this);
}
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.viewport !== prevState.viewport) {
@@ -53,7 +55,9 @@ export default class DeckGLContainer extends React.Component {
}
tick() {
// Limiting updating viewport controls through Redux at most 1*sec
if (this.state && this.state.previousViewport !== this.props.viewport) {
// Deep compare is needed as shallow equality doesn't work here, viewport object
// changes id at every change
if (this.state && !isEqual(this.state.previousViewport, this.props.viewport)) {
const setCV = this.props.setControlValue;
const vp = this.props.viewport;
if (setCV) {

View File

@@ -1,5 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { isEqual } from 'lodash';
import DeckGLContainer from './DeckGLContainer';
import CategoricalDeckGLContainer from './CategoricalDeckGLContainer';
import { fitViewport } from './layers/common';
@@ -18,36 +20,66 @@ const defaultProps = {
};
export function createDeckGLComponent(getLayer, getPoints) {
function Component(props) {
const {
formData,
payload,
setControlValue,
onAddFilter,
setTooltip,
viewport: originalViewport,
} = props;
const viewport = formData.autozoom
? fitViewport(originalViewport, getPoints(payload.data.features))
: originalViewport;
const layer = getLayer(formData, payload, onAddFilter, setTooltip);
return (
<DeckGLContainer
mapboxApiAccessToken={payload.data.mapboxApiKey}
viewport={viewport}
layers={[layer]}
mapStyle={formData.mapbox_style}
setControlValue={setControlValue}
/>
);
// Higher order component
class Component extends React.PureComponent {
constructor(props) {
super(props);
const originalViewport = props.viewport;
const viewport = props.formData.autozoom
? fitViewport(originalViewport, getPoints(props.payload.data.features))
: originalViewport;
this.state = {
viewport,
layer: this.computeLayer(props),
};
this.onViewportChange = this.onViewportChange.bind(this);
}
componentWillReceiveProps(nextProps) {
// Only recompute the layer if anything BUT the viewport has changed
const nextFdNoVP = { ...nextProps.formData, viewport: null };
const currFdNoVP = { ...this.props.formData, viewport: null };
if (
!isEqual(nextFdNoVP, currFdNoVP) ||
nextProps.payload !== this.props.payload
) {
this.setState({ layer: this.computeLayer(nextProps) });
}
}
onViewportChange(viewport) {
this.setState({ viewport });
}
computeLayer(props) {
const {
formData,
payload,
onAddFilter,
setTooltip,
} = props;
return getLayer(formData, payload, onAddFilter, setTooltip);
}
render() {
const {
formData,
payload,
setControlValue,
} = this.props;
const {
layer,
viewport,
} = this.state;
return (
<DeckGLContainer
mapboxApiAccessToken={payload.data.mapboxApiKey}
viewport={viewport}
layers={[layer]}
mapStyle={formData.mapbox_style}
setControlValue={setControlValue}
onViewportChange={this.onViewportChange}
/>);
}
}
Component.propTypes = propTypes;
Component.defaultProps = defaultProps;
return Component;
}

View File

@@ -48,10 +48,12 @@ export function getLayer(formData, payload, setTooltip, selected, onSelect, filt
data = jsFnMutator(data);
}
const metricLabel = fd.metric ? fd.metric.label || fd.metric : null;
const accessor = d => d[metricLabel];
// base color for the polygons
const baseColorScaler = fd.metric === null
? () => [fc.r, fc.g, fc.b, 255 * fc.a]
: getBreakPointColorScaler(fd, data);
: getBreakPointColorScaler(fd, data, accessor);
// when polygons are selected, reduce the opacity of non-selected polygons
const colorScaler = (d) => {
@@ -61,7 +63,6 @@ export function getLayer(formData, payload, setTooltip, selected, onSelect, filt
}
return baseColor;
};
return new PolygonLayer({
id: `path-layer-${fd.slice_id}`,
data,
@@ -211,7 +212,12 @@ class DeckGLPolygon extends React.Component {
render() {
const { payload, formData, setControlValue } = this.props;
const { start, end, getStep, values, disabled, viewport } = this.state;
const buckets = getBuckets(formData, payload.data.features);
const fd = formData;
const metricLabel = fd.metric ? fd.metric.label || fd.metric : null;
const accessor = d => d[metricLabel];
const buckets = getBuckets(formData, payload.data.features, accessor);
return (
<div style={{ position: 'relative' }}>
<AnimatableDeckGLContainer

View File

@@ -38,12 +38,13 @@ export function commonLayerProps(formData, setTooltip, onSelect) {
let tooltipContentGenerator;
if (fd.js_tooltip) {
tooltipContentGenerator = sandboxedEval(fd.js_tooltip);
} else if (fd.line_column && fd.line_type === 'geohash') {
} else if (fd.line_column && fd.metric && ['geohash', 'zipcode'].indexOf(fd.line_type) >= 0) {
const metricLabel = fd.metric.label || fd.metric;
tooltipContentGenerator = o => (
<div>
<div>{fd.line_column}: <strong>{o.object[fd.line_column]}</strong></div>
{fd.metric &&
<div>{fd.metric}: <strong>{o.object[fd.metric]}</strong></div>}
<div>{metricLabel}: <strong>{o.object[metricLabel]}</strong></div>}
</div>);
}
if (tooltipContentGenerator) {

View File

@@ -3,20 +3,19 @@ import { scaleThreshold } from 'd3-scale';
import { getSequentialSchemeRegistry, SequentialScheme } from '@superset-ui/color';
import { hexToRGB } from '../../modules/colors';
const DEFAULT_NUM_BUCKETS = 10;
export function getBreakPoints({
break_points: formDataBreakPoints,
num_buckets: formDataNumBuckets,
metric,
}, features) {
}, features, accessor) {
if (!features) {
return [];
}
if (formDataBreakPoints === undefined || formDataBreakPoints.length === 0) {
// compute evenly distributed break points based on number of buckets
const numBuckets = formDataNumBuckets
? parseInt(formDataNumBuckets, 10)
: 10;
const [minValue, maxValue] = extent(features, d => d[metric]);
const numBuckets = formDataNumBuckets ? parseInt(formDataNumBuckets, 10) : DEFAULT_NUM_BUCKETS;
const [minValue, maxValue] = extent(features, accessor);
const delta = (maxValue - minValue) / numBuckets;
const precision = delta === 0
? 0
@@ -32,15 +31,13 @@ export function getBreakPointColorScaler({
break_points: formDataBreakPoints,
num_buckets: formDataNumBuckets,
linear_color_scheme: linearColorScheme,
metric,
opacity,
}, features) {
}, features, accessor) {
const breakPoints = formDataBreakPoints || formDataNumBuckets
? getBreakPoints({
break_points: formDataBreakPoints,
num_buckets: formDataNumBuckets,
metric,
}, features)
}, features, accessor)
: null;
const colorScheme = Array.isArray(linearColorScheme)
? new SequentialScheme({
@@ -69,13 +66,14 @@ export function getBreakPointColorScaler({
maskPoint = value => value > breakPoints[n] || value < breakPoints[0];
} else {
// interpolate colors linearly
scaler = colorScheme.createLinearScale(extent(features, d => d[metric]));
scaler = colorScheme.createLinearScale(extent(features, accessor));
maskPoint = () => false;
}
return (d) => {
const c = hexToRGB(scaler(d[metric]));
if (maskPoint(d[metric])) {
const v = accessor(d);
const c = hexToRGB(scaler(v));
if (maskPoint(v)) {
c[3] = 0;
} else {
c[3] = (opacity / 100.0) * 255;
@@ -84,15 +82,15 @@ export function getBreakPointColorScaler({
};
}
export function getBuckets(fd, features) {
const breakPoints = getBreakPoints(fd, features, true);
const colorScaler = getBreakPointColorScaler(fd, features);
export function getBuckets(fd, features, accessor) {
const breakPoints = getBreakPoints(fd, features, accessor);
const colorScaler = getBreakPointColorScaler(fd, features, accessor);
const buckets = {};
breakPoints.slice(1).forEach((value, i) => {
const range = breakPoints[i] + ' - ' + breakPoints[i + 1];
const mid = 0.5 * (parseInt(breakPoints[i], 10) + parseInt(breakPoints[i + 1], 10));
buckets[range] = {
color: colorScaler({ [fd.metric]: mid }),
color: colorScaler({ [fd.metric.label || fd.metric]: mid }),
enabled: true,
};
});

View File

@@ -456,11 +456,13 @@ function nvd3Vis(element, props) {
chart.xScale(d3.scale.log());
}
let xAxisFormatter = d3FormatPreset(xAxisFormat);
let xAxisFormatter;
if (isTimeSeries) {
xAxisFormatter = d3TimeFormatPreset(xAxisFormat);
// In tooltips, always use the verbose time format
chart.interactiveLayer.tooltip.headerFormatter(formatDateVerbose);
} else {
xAxisFormatter = d3FormatPreset(xAxisFormat);
}
if (chart.x2Axis && chart.x2Axis.tickFormat) {
chart.x2Axis.tickFormat(xAxisFormatter);

View File

@@ -10,7 +10,6 @@ const TIME_SHIFT_PATTERN = /\d+ \w+ offset/;
export function cleanColorInput(value) {
// for superset series that should have the same color
return String(value).trim()
.toLowerCase()
.split(', ')
.filter(k => !TIME_SHIFT_PATTERN.test(k))
.join(', ');

View File

@@ -307,30 +307,30 @@
d3-array "^1.2.0"
prop-types "^15.5.10"
"@deck.gl/core@^5.3.3":
version "5.3.3"
resolved "https://registry.yarnpkg.com/@deck.gl/core/-/core-5.3.3.tgz#a13c07e5fa3e22297fd450d6da8ab9aac334b1f0"
"@deck.gl/core@^5.3.5":
version "5.3.5"
resolved "https://registry.yarnpkg.com/@deck.gl/core/-/core-5.3.5.tgz#24e6b3164a36b89b05cd020c2f7bcb5d08e3c266"
dependencies:
luma.gl "^5.3.0"
luma.gl "^5.3.1"
math.gl "^1.2.1"
mjolnir.js "^1.0.0"
probe.gl "^1.0.0"
seer "^0.2.4"
viewport-mercator-project "^5.1.0"
"@deck.gl/layers@^5.3.4":
version "5.3.4"
resolved "https://registry.yarnpkg.com/@deck.gl/layers/-/layers-5.3.4.tgz#ab3de1bf8bb68d67772642acbb4e0f87f4f11300"
"@deck.gl/layers@^5.3.5":
version "5.3.5"
resolved "https://registry.yarnpkg.com/@deck.gl/layers/-/layers-5.3.5.tgz#79c19be42961b909772e9dcd4eef5416d226d58e"
dependencies:
"@deck.gl/core" "^5.3.3"
"@deck.gl/core" "^5.3.5"
d3-hexbin "^0.2.1"
earcut "^2.0.6"
"@deck.gl/react@^5.3.3":
version "5.3.3"
resolved "https://registry.yarnpkg.com/@deck.gl/react/-/react-5.3.3.tgz#e7352934f6742d3ce672a394cbff312aab5ccaa0"
"@deck.gl/react@^5.3.5":
version "5.3.5"
resolved "https://registry.yarnpkg.com/@deck.gl/react/-/react-5.3.5.tgz#caace72d4afc6531103fbb87292400de7c6f292a"
dependencies:
"@deck.gl/core" "^5.3.3"
"@deck.gl/core" "^5.3.5"
prop-types "^15.6.0"
"@mapbox/geojson-area@0.2.2":
@@ -3679,13 +3679,13 @@ decimal.js@9.0.1:
version "9.0.1"
resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-9.0.1.tgz#1cc8b228177da7ab6498c1cc06eb130a290e6e1e"
deck.gl@^5.3.4:
version "5.3.4"
resolved "https://registry.yarnpkg.com/deck.gl/-/deck.gl-5.3.4.tgz#35e5a7087ef0d8ca7811d06a721ea289edbe7c24"
deck.gl@^5.3.5:
version "5.3.5"
resolved "https://registry.yarnpkg.com/deck.gl/-/deck.gl-5.3.5.tgz#a30b8a6ee6caba1133167de461edc15ee3bb0f8b"
dependencies:
"@deck.gl/core" "^5.3.3"
"@deck.gl/layers" "^5.3.4"
"@deck.gl/react" "^5.3.3"
"@deck.gl/core" "^5.3.5"
"@deck.gl/layers" "^5.3.5"
"@deck.gl/react" "^5.3.5"
decode-uri-component@^0.2.0:
version "0.2.0"
@@ -7241,9 +7241,9 @@ lru-cache@^4.0.1, lru-cache@^4.1.1, lru-cache@^4.1.3:
pseudomap "^1.0.2"
yallist "^2.1.2"
luma.gl@^5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/luma.gl/-/luma.gl-5.3.0.tgz#a93b2f34489d8230eb6d8c871335800d9b83ee67"
luma.gl@^5.3.1:
version "5.3.1"
resolved "https://registry.yarnpkg.com/luma.gl/-/luma.gl-5.3.1.tgz#d380d554fe4c9de0b883e5d75f58d2a2142cfa05"
dependencies:
math.gl "^1.1.0"
probe.gl "^1.0.0"

View File

@@ -489,7 +489,7 @@ class BaseViz(object):
return df.to_csv(index=include_index, **config.get('CSV_EXPORT'))
def get_data(self, df):
return self.get_df().to_dict(orient='records')
return df.to_dict(orient='records')
@property
def json_data(self):