diff --git a/superset/assets/src/visualizations/BigNumber/BigNumber.jsx b/superset/assets/src/visualizations/BigNumber/BigNumber.jsx index ff78a56e7..2ea19c2d0 100644 --- a/superset/assets/src/visualizations/BigNumber/BigNumber.jsx +++ b/superset/assets/src/visualizations/BigNumber/BigNumber.jsx @@ -1,8 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; - +import shortid from 'shortid'; import { XYChart, AreaSeries, CrossHair, LinearGradient } from '@data-ui/xy-chart'; - import { brandColor } from '../../modules/colors'; import { formatDateVerbose } from '../../modules/dates'; import { computeMaxFontSize } from '../../modules/visUtils'; @@ -51,30 +50,33 @@ const propTypes = { bigNumber: PropTypes.number.isRequired, formatBigNumber: PropTypes.func, subheader: PropTypes.string, - showTrendline: PropTypes.bool, + showTrendLine: PropTypes.bool, startYAxisAtZero: PropTypes.bool, - trendlineData: PropTypes.array, + trendLineData: PropTypes.array, mainColor: PropTypes.string, - gradientId: PropTypes.string, renderTooltip: PropTypes.func, }; const defaultProps = { className: '', formatBigNumber: identity, subheader: '', - showTrendline: false, + showTrendLine: false, startYAxisAtZero: true, - trendlineData: null, + trendLineData: null, mainColor: brandColor, - gradientId: '', renderTooltip: renderTooltipFactory(identity), }; class BigNumberVis extends React.Component { + constructor(props) { + super(props); + this.gradientId = shortid.generate(); + } + getClassName() { - const { className, showTrendline } = this.props; + const { className, showTrendLine } = this.props; const names = `big_number ${className}`; - if (showTrendline) { + if (showTrendLine) { return names; } return `${names} no_trendline`; @@ -148,11 +150,10 @@ class BigNumberVis extends React.Component { renderTrendline(maxHeight) { const { width, - trendlineData, + trendLineData, mainColor, subheader, renderTooltip, - gradientId, startYAxisAtZero, } = this.props; return ( @@ -170,13 +171,13 @@ class BigNumberVis extends React.Component { snapTooltipToDataX > a[TIME_COLUMN] - b[TIME_COLUMN]); - bigNumber = sortedData[sortedData.length - 1][metricName]; - if (compareLag > 0) { - const compareIndex = sortedData.length - (compareLag + 1); - if (compareIndex >= 0) { - const compareValue = sortedData[compareIndex][metricName]; - percentChange = compareValue === 0 - ? 0 : (bigNumber - compareValue) / Math.abs(compareValue); - const formatPercentChange = d3.format('+.1%'); - formattedSubheader = `${formatPercentChange(percentChange)} ${compareSuffix}`; - } - } - trendlineData = showTrendline - ? sortedData.map(point => ({ x: point[TIME_COLUMN], y: point[metricName] })) - : null; - } else { - bigNumber = data[0][metricName]; - trendlineData = null; - } - - let className = ''; - if (percentChange > 0) { - className = 'positive'; - } else if (percentChange < 0) { - className = 'negative'; - } - - return { - bigNumber, - trendlineData, - className, - subheader: formattedSubheader, - showTrendline, - }; -} - -function adaptor(slice, payload) { - const { formData, containerId } = slice; - - const transformedData = transform(payload.data, formData); - const startYAxisAtZero = formData.start_y_axis_at_zero; - const formatValue = d3FormatPreset(formData.y_axis_format); - let userColor; - if (formData.color_picker) { - const { r, g, b } = formData.color_picker; - userColor = color.rgb(r, g, b).hex(); - } - - ReactDOM.render( - , - document.getElementById(containerId), - ); -} - -export default adaptor; +export default createAdaptor(Component, transformProps); diff --git a/superset/assets/src/visualizations/BigNumber/index.js b/superset/assets/src/visualizations/BigNumber/index.js deleted file mode 100644 index 3aaef63c3..000000000 --- a/superset/assets/src/visualizations/BigNumber/index.js +++ /dev/null @@ -1,5 +0,0 @@ -import adaptor from './adaptor'; -import BigNumber from './BigNumber'; - -export { BigNumber }; -export default adaptor; diff --git a/superset/assets/src/visualizations/BigNumber/transformProps.js b/superset/assets/src/visualizations/BigNumber/transformProps.js new file mode 100644 index 000000000..7b06874a0 --- /dev/null +++ b/superset/assets/src/visualizations/BigNumber/transformProps.js @@ -0,0 +1,78 @@ +import * as color from 'd3-color'; +import d3 from 'd3'; +import { d3FormatPreset } from '../../modules/utils'; +import { renderTooltipFactory } from './BigNumber'; + +const TIME_COLUMN = '__timestamp'; + +export default function transformProps(basicChartInput) { + const { formData, payload } = basicChartInput; + const { + colorPicker, + compareLag: compareLagInput, + compareSuffix = '', + metric, + showTrendLine, + startYAxisAtZero, + subheader = '', + vizType, + yAxisFormat, + } = formData; + const { data } = payload; + + let mainColor; + if (colorPicker) { + const { r, g, b } = colorPicker; + mainColor = color.rgb(r, g, b).hex(); + } + + let bigNumber; + let trendLineData; + const metricName = metric.label || metric; + const compareLag = +compareLagInput || 0; + const supportTrendLine = vizType === 'big_number'; + const supportAndShowTrendLine = supportTrendLine && showTrendLine; + let percentChange = 0; + let formattedSubheader = subheader; + if (supportTrendLine) { + const sortedData = [...data].sort((a, b) => a[TIME_COLUMN] - b[TIME_COLUMN]); + bigNumber = sortedData[sortedData.length - 1][metricName]; + if (compareLag > 0) { + const compareIndex = sortedData.length - (compareLag + 1); + if (compareIndex >= 0) { + const compareValue = sortedData[compareIndex][metricName]; + percentChange = compareValue === 0 + ? 0 : (bigNumber - compareValue) / Math.abs(compareValue); + const formatPercentChange = d3.format('+.1%'); + formattedSubheader = `${formatPercentChange(percentChange)} ${compareSuffix}`; + } + } + trendLineData = supportAndShowTrendLine + ? sortedData.map(point => ({ x: point[TIME_COLUMN], y: point[metricName] })) + : null; + } else { + bigNumber = data[0][metricName]; + trendLineData = null; + } + + let className = ''; + if (percentChange > 0) { + className = 'positive'; + } else if (percentChange < 0) { + className = 'negative'; + } + + const formatValue = d3FormatPreset(yAxisFormat); + + return { + bigNumber, + className, + formatBigNumber: formatValue, + mainColor, + renderTooltip: renderTooltipFactory(formatValue), + showTrendLine: supportAndShowTrendLine, + startYAxisAtZero, + subheader: formattedSubheader, + trendLineData, + }; +} diff --git a/superset/assets/src/visualizations/EventFlow.jsx b/superset/assets/src/visualizations/EventFlow.jsx deleted file mode 100644 index e4b9685c6..000000000 --- a/superset/assets/src/visualizations/EventFlow.jsx +++ /dev/null @@ -1,62 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import { - App, - withParentSize, - cleanEvents, - TS, - EVENT_NAME, - ENTITY_ID, -} from '@data-ui/event-flow'; -import { t } from '../locales'; - -/* - * This function takes the slice object and json payload as input and renders a - * responsive component using the json data. - */ -function renderEventFlow(slice, json) { - const container = document.querySelector(slice.selector); - const hasData = json.data && json.data.length > 0; - - // the slice container overflows ~80px in explorer, so we have to correct for this - const isExplorer = (/explore/).test(window.location.pathname); - - const ResponsiveVis = withParentSize(({ - parentWidth, - parentHeight, - ...rest - }) => ( - - )); - - // render the component if we have data, otherwise render a no-data message - let Component; - if (hasData) { - const userKey = json.form_data.entity; - const eventNameKey = json.form_data.all_columns_x; - - // map from the Superset form fields to 's expected data keys - const accessorFunctions = { - [TS]: datum => new Date(datum.__timestamp), // eslint-disable-line no-underscore-dangle - [EVENT_NAME]: datum => datum[eventNameKey], - [ENTITY_ID]: datum => String(datum[userKey]), - }; - - const dirtyData = json.data; - const cleanData = cleanEvents(dirtyData, accessorFunctions); - const minEventCount = slice.formData.min_leaf_node_event_count; - - Component = ; - } else { - Component =
{t('Sorry, there appears to be no data')}
; - } - - ReactDOM.render(Component, container); -} - -module.exports = renderEventFlow; diff --git a/superset/assets/src/visualizations/EventFlow/EventFlow.jsx b/superset/assets/src/visualizations/EventFlow/EventFlow.jsx new file mode 100644 index 000000000..7359bda95 --- /dev/null +++ b/superset/assets/src/visualizations/EventFlow/EventFlow.jsx @@ -0,0 +1,52 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { App, withParentSize } from '@data-ui/event-flow'; +import { t } from '../../locales'; + +const propTypes = { + className: PropTypes.string, + data: PropTypes.array, + initialMinEventCount: PropTypes.number, +}; +const defaultProps = { + className: '', + data: null, +}; + +function isExplorer() { + return (/explore/).test(window.location.pathname); +} + +// The slice container overflows ~80px in explorer, +// so we have to correct for this. +const ResponsiveVis = withParentSize(({ + parentWidth, + parentHeight, + ...rest +}) => ( + +)); + +function CustomEventFlow(props) { + const { data, initialMinEventCount } = props; + if (data) { + return ( + + ); + } + return ( +
{t('Sorry, there appears to be no data')}
+ ); +} + +CustomEventFlow.propTypes = propTypes; +CustomEventFlow.defaultProps = defaultProps; + +export default CustomEventFlow; diff --git a/superset/assets/src/visualizations/EventFlow/adaptor.jsx b/superset/assets/src/visualizations/EventFlow/adaptor.jsx new file mode 100644 index 000000000..63f319b88 --- /dev/null +++ b/superset/assets/src/visualizations/EventFlow/adaptor.jsx @@ -0,0 +1,5 @@ +import createAdaptor from '../../utils/createAdaptor'; +import Component from './EventFlow'; +import transformProps from './transformProps'; + +export default createAdaptor(Component, transformProps); diff --git a/superset/assets/src/visualizations/EventFlow/transformProps.js b/superset/assets/src/visualizations/EventFlow/transformProps.js new file mode 100644 index 000000000..b5176936a --- /dev/null +++ b/superset/assets/src/visualizations/EventFlow/transformProps.js @@ -0,0 +1,36 @@ +import { + cleanEvents, + TS, + EVENT_NAME, + ENTITY_ID, +} from '@data-ui/event-flow'; + +export default function transformProps(basicChartInput) { + const { formData, payload } = basicChartInput; + const { + allColumnsX, + entity, + minLeafNodeEventCount, + } = formData; + const { data } = payload; + + const hasData = data && data.length > 0; + if (hasData) { + const userKey = entity; + const eventNameKey = allColumnsX; + + // map from the Superset form fields to 's expected data keys + const accessorFunctions = { + [TS]: datum => new Date(datum.__timestamp), // eslint-disable-line no-underscore-dangle + [EVENT_NAME]: datum => datum[eventNameKey], + [ENTITY_ID]: datum => String(datum[userKey]), + }; + + const cleanData = cleanEvents(data, accessorFunctions); + return { + data: cleanData, + initialMinEventCount: minLeafNodeEventCount, + }; + } + return { data: null }; +} diff --git a/superset/assets/src/visualizations/MapBox/MapBox.jsx b/superset/assets/src/visualizations/MapBox/MapBox.jsx index f2381588e..6dd2eb253 100644 --- a/superset/assets/src/visualizations/MapBox/MapBox.jsx +++ b/superset/assets/src/visualizations/MapBox/MapBox.jsx @@ -1,16 +1,14 @@ import React from 'react'; import PropTypes from 'prop-types'; -import ReactDOM from 'react-dom'; import MapGL from 'react-map-gl'; import Immutable from 'immutable'; -import supercluster from 'supercluster'; import ViewportMercator from 'viewport-mercator-project'; import ScatterPlotGlowOverlay from './ScatterPlotGlowOverlay'; import './MapBox.css'; const NOOP = () => {}; -const DEFAULT_POINT_RADIUS = 60; -const DEFAULT_MAX_ZOOM = 16; +export const DEFAULT_MAX_ZOOM = 16; +export const DEFAULT_POINT_RADIUS = 60; const propTypes = { width: PropTypes.number, @@ -124,86 +122,4 @@ class MapBox extends React.Component { MapBox.propTypes = propTypes; MapBox.defaultProps = defaultProps; -function mapbox(slice, payload, setControlValue) { - const { formData, selector } = slice; - const { - hasCustomMetric, - geoJSON, - bounds, - mapboxApiKey, - } = payload.data; - const { - clustering_radius: clusteringRadius, - global_opacity: globalOpacity, - mapbox_color: color, - mapbox_style: mapStyle, - pandas_aggfunc: aggregatorName, - point_radius: pointRadius, - point_radius_unit: pointRadiusUnit, - render_while_dragging: renderWhileDragging, - } = formData; - - // Validate mapbox color - const rgb = /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/ - .exec(color); - if (rgb === null) { - slice.error('Color field must be of form \'rgb(%d, %d, %d)\''); - return; - } - - const opts = { - radius: clusteringRadius, - maxZoom: DEFAULT_MAX_ZOOM, - }; - if (hasCustomMetric) { - opts.initial = () => ({ - sum: 0, - squaredSum: 0, - min: Infinity, - max: -Infinity, - }); - opts.map = prop => ({ - sum: prop.metric, - squaredSum: Math.pow(prop.metric, 2), - min: prop.metric, - max: prop.metric, - }); - opts.reduce = (accu, prop) => { - // Temporarily disable param-reassignment linting to work with supercluster's api - /* eslint-disable no-param-reassign */ - accu.sum += prop.sum; - accu.squaredSum += prop.squaredSum; - accu.min = Math.min(accu.min, prop.min); - accu.max = Math.max(accu.max, prop.max); - /* eslint-enable no-param-reassign */ - }; - } - const clusterer = supercluster(opts); - clusterer.load(geoJSON.features); - - ReactDOM.render( - { - setControlValue('viewport_longitude', longitude); - setControlValue('viewport_latitude', latitude); - setControlValue('viewport_zoom', zoom); - }} - pointRadius={pointRadius === 'Auto' ? DEFAULT_POINT_RADIUS : pointRadius} - pointRadiusUnit={pointRadiusUnit} - renderWhileDragging={renderWhileDragging} - rgb={rgb} - bounds={bounds} - />, - document.querySelector(selector), - ); -} - -export default mapbox; +export default MapBox; diff --git a/superset/assets/src/visualizations/MapBox/adaptor.jsx b/superset/assets/src/visualizations/MapBox/adaptor.jsx new file mode 100644 index 000000000..cbe369fe1 --- /dev/null +++ b/superset/assets/src/visualizations/MapBox/adaptor.jsx @@ -0,0 +1,5 @@ +import createAdaptor from '../../utils/createAdaptor'; +import Component from './MapBox'; +import transformProps from './transformProps'; + +export default createAdaptor(Component, transformProps); diff --git a/superset/assets/src/visualizations/MapBox/transformProps.js b/superset/assets/src/visualizations/MapBox/transformProps.js new file mode 100644 index 000000000..4180eef86 --- /dev/null +++ b/superset/assets/src/visualizations/MapBox/transformProps.js @@ -0,0 +1,79 @@ +import supercluster from 'supercluster'; +import { DEFAULT_POINT_RADIUS, DEFAULT_MAX_ZOOM } from './MapBox'; + +export default function transformProps(basicChartInput) { + const { formData, onError, payload, setControlValue } = basicChartInput; + const { + bounds, + geoJSON, + hasCustomMetric, + mapboxApiKey, + } = payload.data; + const { + clusteringRadius, + globalOpacity, + mapboxColor, + mapboxStyle, + pandasAggfunc, + pointRadius, + pointRadiusUnit, + renderWhileDragging, + } = formData; + + // Validate mapbox color + const rgb = /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/ + .exec(mapboxColor); + if (rgb === null) { + onError('Color field must be of form \'rgb(%d, %d, %d)\''); + return {}; + } + + const opts = { + radius: clusteringRadius, + maxZoom: DEFAULT_MAX_ZOOM, + }; + if (hasCustomMetric) { + opts.initial = () => ({ + sum: 0, + squaredSum: 0, + min: Infinity, + max: -Infinity, + }); + opts.map = prop => ({ + sum: prop.metric, + squaredSum: Math.pow(prop.metric, 2), + min: prop.metric, + max: prop.metric, + }); + opts.reduce = (accu, prop) => { + // Temporarily disable param-reassignment linting to work with supercluster's api + /* eslint-disable no-param-reassign */ + accu.sum += prop.sum; + accu.squaredSum += prop.squaredSum; + accu.min = Math.min(accu.min, prop.min); + accu.max = Math.max(accu.max, prop.max); + /* eslint-enable no-param-reassign */ + }; + } + const clusterer = supercluster(opts); + clusterer.load(geoJSON.features); + + return { + aggregatorName: pandasAggfunc, + bounds, + clusterer, + globalOpacity, + hasCustomMetric, + mapboxApiKey, + mapStyle: mapboxStyle, + onViewportChange({ latitude, longitude, zoom }) { + setControlValue('viewport_longitude', longitude); + setControlValue('viewport_latitude', latitude); + setControlValue('viewport_zoom', zoom); + }, + pointRadius: pointRadius === 'Auto' ? DEFAULT_POINT_RADIUS : pointRadius, + pointRadiusUnit, + renderWhileDragging, + rgb, + }; +} diff --git a/superset/assets/src/visualizations/TimeTable/TimeTable.jsx b/superset/assets/src/visualizations/TimeTable/TimeTable.jsx index 8ce9a7d7a..c414a7cbb 100644 --- a/superset/assets/src/visualizations/TimeTable/TimeTable.jsx +++ b/superset/assets/src/visualizations/TimeTable/TimeTable.jsx @@ -1,4 +1,3 @@ -import ReactDOM from 'react-dom'; import React from 'react'; import PropTypes from 'prop-types'; import d3 from 'd3'; @@ -270,58 +269,4 @@ class TimeTable extends React.PureComponent { TimeTable.propTypes = propTypes; TimeTable.defaultProps = defaultProps; -function adaptor(slice, payload) { - const { containerId, formData, datasource } = slice; - const { - column_collection: columnConfigs, - groupby, - metrics, - url, - } = formData; - const { records, columns } = payload.data; - const isGroupBy = groupby.length > 0; - - // When there is a "group by", - // each row in the table is a database column - // Otherwise, - // each row in the table is a metric - let rows; - if (isGroupBy) { - rows = columns.map(column => (typeof column === 'object') - ? column - : { label: column }); - } else { - const metricMap = datasource.metrics - .reduce((acc, current) => { - const map = acc; - map[current.metric_name] = current; - return map; - }, {}); - - rows = metrics.map(metric => (typeof metric === 'object') - ? metric - : metricMap[metric]); - } - - // TODO: Better parse this from controls instead of mutative value here. - columnConfigs.forEach((column) => { - const c = column; - if (c.timeLag !== undefined && c.timeLag !== null && c.timeLag !== '') { - c.timeLag = parseInt(c.timeLag, 10); - } - }); - - ReactDOM.render( - , - document.getElementById(containerId), - ); -} - -export default adaptor; +export default TimeTable; diff --git a/superset/assets/src/visualizations/TimeTable/adaptor.jsx b/superset/assets/src/visualizations/TimeTable/adaptor.jsx new file mode 100644 index 000000000..34daa9023 --- /dev/null +++ b/superset/assets/src/visualizations/TimeTable/adaptor.jsx @@ -0,0 +1,5 @@ +import createAdaptor from '../../utils/createAdaptor'; +import Component from './TimeTable'; +import transformProps from './transformProps'; + +export default createAdaptor(Component, transformProps); diff --git a/superset/assets/src/visualizations/TimeTable/transformProps.js b/superset/assets/src/visualizations/TimeTable/transformProps.js new file mode 100644 index 000000000..11a1a1abf --- /dev/null +++ b/superset/assets/src/visualizations/TimeTable/transformProps.js @@ -0,0 +1,49 @@ +export default function transformProps(basicChartInput) { + const { datasource, formData, payload } = basicChartInput; + const { + columnCollection, + groupby, + metrics, + url, + } = formData; + const { records, columns } = payload.data; + const isGroupBy = groupby.length > 0; + + // When there is a "group by", + // each row in the table is a database column + // Otherwise, + // each row in the table is a metric + let rows; + if (isGroupBy) { + rows = columns.map(column => (typeof column === 'object') + ? column + : { label: column }); + } else { + const metricMap = datasource.metrics + .reduce((acc, current) => { + const map = acc; + map[current.metric_name] = current; + return map; + }, {}); + + rows = metrics.map(metric => (typeof metric === 'object') + ? metric + : metricMap[metric]); + } + + // TODO: Better parse this from controls instead of mutative value here. + columnCollection.forEach((column) => { + const c = column; + if (c.timeLag !== undefined && c.timeLag !== null && c.timeLag !== '') { + c.timeLag = parseInt(c.timeLag, 10); + } + }); + + return { + data: records, + columnConfigs: columnCollection, + rows, + rowType: isGroupBy ? 'column' : 'metric', + url, + }; +} diff --git a/superset/assets/src/visualizations/index.js b/superset/assets/src/visualizations/index.js index 5d9b3b4d9..5ed2ce8ce 100644 --- a/superset/assets/src/visualizations/index.js +++ b/superset/assets/src/visualizations/index.js @@ -65,9 +65,9 @@ const vizMap = { [VIZ_TYPES.area]: loadNvd3, [VIZ_TYPES.bar]: loadNvd3, [VIZ_TYPES.big_number]: () => - loadVis(import(/* webpackChunkName: 'big_number' */ './BigNumber/index.js')), + loadVis(import(/* webpackChunkName: 'big_number' */ './BigNumber/adaptor.jsx')), [VIZ_TYPES.big_number_total]: () => - loadVis(import(/* webpackChunkName: "big_number" */ './BigNumber/index.js')), + loadVis(import(/* webpackChunkName: "big_number" */ './BigNumber/adaptor.jsx')), [VIZ_TYPES.box_plot]: loadNvd3, [VIZ_TYPES.bubble]: loadNvd3, [VIZ_TYPES.bullet]: loadNvd3, @@ -89,7 +89,7 @@ const vizMap = { [VIZ_TYPES.line_multi]: () => loadVis(import(/* webpackChunkName: "line_multi" */ './nvd3/LineMulti.js')), [VIZ_TYPES.time_pivot]: loadNvd3, - [VIZ_TYPES.mapbox]: () => loadVis(import(/* webpackChunkName: "mapbox" */ './MapBox/MapBox.jsx')), + [VIZ_TYPES.mapbox]: () => loadVis(import(/* webpackChunkName: "mapbox" */ './MapBox/adaptor.jsx')), [VIZ_TYPES.markup]: () => loadVis(import(/* webpackChunkName: "markup" */ './markup.js')), [VIZ_TYPES.para]: () => loadVis(import(/* webpackChunkName: "parallel_coordinates" */ './ParallelCoordinates/adaptor.jsx')), @@ -101,7 +101,7 @@ const vizMap = { [VIZ_TYPES.sunburst]: () => loadVis(import(/* webpackChunkName: "sunburst" */ './Sunburst/adaptor.jsx')), [VIZ_TYPES.table]: () => loadVis(import(/* webpackChunkName: "table" */ './Table/adaptor.jsx')), [VIZ_TYPES.time_table]: () => - loadVis(import(/* webpackChunkName: "time_table" */ './TimeTable/TimeTable.jsx')), + loadVis(import(/* webpackChunkName: "time_table" */ './TimeTable/adaptor.jsx')), [VIZ_TYPES.treemap]: () => loadVis(import(/* webpackChunkName: "treemap" */ './Treemap/adaptor.jsx')), [VIZ_TYPES.country_map]: () => loadVis(import(/* webpackChunkName: "country_map" */ './CountryMap/adaptor.jsx')), @@ -111,7 +111,7 @@ const vizMap = { loadVis(import(/* webpackChunkName: "world_map" */ './WorldMap/adaptor.jsx')), [VIZ_TYPES.dual_line]: loadNvd3, [VIZ_TYPES.event_flow]: () => - loadVis(import(/* webpackChunkName: "EventFlow" */ './EventFlow.jsx')), + loadVis(import(/* webpackChunkName: "EventFlow" */ './EventFlow/adaptor.jsx')), [VIZ_TYPES.paired_ttest]: () => loadVis(import(/* webpackChunkName: "paired_ttest" */ './PairedTTest/adaptor.jsx')), [VIZ_TYPES.partition]: () =>