Merge pull request #368 from apache-superset/kristw--migrate-pivot
feat: migrate 4 chart plugins
@ -45,6 +45,10 @@
|
||||
"@superset-ui/legacy-plugin-chart-horizon": "^0.11.15",
|
||||
"@superset-ui/legacy-plugin-chart-iframe": "^0.11.15",
|
||||
"@superset-ui/legacy-plugin-chart-markup": "^0.11.15",
|
||||
"@superset-ui/legacy-plugin-chart-paired-t-test": "^0.11.15",
|
||||
"@superset-ui/legacy-plugin-chart-parallel-coordinates": "^0.11.15",
|
||||
"@superset-ui/legacy-plugin-chart-partition": "^0.11.15",
|
||||
"@superset-ui/legacy-plugin-chart-pivot-table": "^0.11.15",
|
||||
"@superset-ui/legacy-plugin-chart-sankey": "^0.11.15",
|
||||
"@superset-ui/legacy-plugin-chart-sunburst": "^0.11.15",
|
||||
"@superset-ui/legacy-plugin-chart-table": "0.12.18",
|
||||
|
@ -0,0 +1,27 @@
|
||||
/* eslint-disable no-magic-numbers */
|
||||
import React from 'react';
|
||||
import { SuperChart } from '@superset-ui/chart';
|
||||
import PairedTTestChartPlugin from '@superset-ui/legacy-plugin-chart-paired-t-test';
|
||||
import data from './data';
|
||||
|
||||
new PairedTTestChartPlugin().configure({ key: 'paired-t-test' }).register();
|
||||
|
||||
export default {
|
||||
title: 'Legacy Chart Plugins|legacy-plugin-chart-paired-t-test',
|
||||
};
|
||||
|
||||
export const basic = () => (
|
||||
<SuperChart
|
||||
chartType="paired-t-test"
|
||||
width={400}
|
||||
height={400}
|
||||
queryData={{ data }}
|
||||
formData={{
|
||||
groupby: ['name'],
|
||||
liftvaluePrecision: 4,
|
||||
metrics: ['sum__num'],
|
||||
pvaluePrecision: 6,
|
||||
significanceLevel: 0.05,
|
||||
}}
|
||||
/>
|
||||
);
|
@ -0,0 +1,683 @@
|
||||
/* eslint-disable sort-keys */
|
||||
export default {
|
||||
sum__num: [
|
||||
{
|
||||
group: ['Christopher'],
|
||||
values: [
|
||||
{
|
||||
x: -157766400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: -126230400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: -94694400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: -63158400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: -31536000000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 0.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 31536000000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 63072000000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 94694400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 126230400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 157766400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 189302400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 220924800000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 252460800000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 283996800000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 315532800000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 347155200000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 378691200000.0,
|
||||
y: 59055.0,
|
||||
},
|
||||
{
|
||||
x: 410227200000.0,
|
||||
y: 59188.0,
|
||||
},
|
||||
{
|
||||
x: 441763200000.0,
|
||||
y: 59859.0,
|
||||
},
|
||||
{
|
||||
x: 473385600000.0,
|
||||
y: 59516.0,
|
||||
},
|
||||
{
|
||||
x: 504921600000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 536457600000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 567993600000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 599616000000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 631152000000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 662688000000.0,
|
||||
y: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
group: ['David'],
|
||||
values: [
|
||||
{
|
||||
x: -157766400000.0,
|
||||
y: 67646.0,
|
||||
},
|
||||
{
|
||||
x: -126230400000.0,
|
||||
y: 66207.0,
|
||||
},
|
||||
{
|
||||
x: -94694400000.0,
|
||||
y: 66581.0,
|
||||
},
|
||||
{
|
||||
x: -63158400000.0,
|
||||
y: 63531.0,
|
||||
},
|
||||
{
|
||||
x: -31536000000.0,
|
||||
y: 63502.0,
|
||||
},
|
||||
{
|
||||
x: 0.0,
|
||||
y: 61570.0,
|
||||
},
|
||||
{
|
||||
x: 31536000000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 63072000000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 94694400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 126230400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 157766400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 189302400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 220924800000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 252460800000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 283996800000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 315532800000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 347155200000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 378691200000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 410227200000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 441763200000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 473385600000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 504921600000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 536457600000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 567993600000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 599616000000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 631152000000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 662688000000.0,
|
||||
y: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
group: ['James'],
|
||||
values: [
|
||||
{
|
||||
x: -157766400000.0,
|
||||
y: 67506.0,
|
||||
},
|
||||
{
|
||||
x: -126230400000.0,
|
||||
y: 65036.0,
|
||||
},
|
||||
{
|
||||
x: -94694400000.0,
|
||||
y: 61554.0,
|
||||
},
|
||||
{
|
||||
x: -63158400000.0,
|
||||
y: 60584.0,
|
||||
},
|
||||
{
|
||||
x: -31536000000.0,
|
||||
y: 59824.0,
|
||||
},
|
||||
{
|
||||
x: 0.0,
|
||||
y: 61597.0,
|
||||
},
|
||||
{
|
||||
x: 31536000000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 63072000000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 94694400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 126230400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 157766400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 189302400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 220924800000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 252460800000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 283996800000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 315532800000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 347155200000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 378691200000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 410227200000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 441763200000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 473385600000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 504921600000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 536457600000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 567993600000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 599616000000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 631152000000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 662688000000.0,
|
||||
y: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
group: ['John'],
|
||||
values: [
|
||||
{
|
||||
x: -157766400000.0,
|
||||
y: 71390.0,
|
||||
},
|
||||
{
|
||||
x: -126230400000.0,
|
||||
y: 64858.0,
|
||||
},
|
||||
{
|
||||
x: -94694400000.0,
|
||||
y: 61480.0,
|
||||
},
|
||||
{
|
||||
x: -63158400000.0,
|
||||
y: 60754.0,
|
||||
},
|
||||
{
|
||||
x: -31536000000.0,
|
||||
y: 58644.0,
|
||||
},
|
||||
{
|
||||
x: 0.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 31536000000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 63072000000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 94694400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 126230400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 157766400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 189302400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 220924800000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 252460800000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 283996800000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 315532800000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 347155200000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 378691200000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 410227200000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 441763200000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 473385600000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 504921600000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 536457600000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 567993600000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 599616000000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 631152000000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 662688000000.0,
|
||||
y: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
group: ['Michael'],
|
||||
values: [
|
||||
{
|
||||
x: -157766400000.0,
|
||||
y: 80812.0,
|
||||
},
|
||||
{
|
||||
x: -126230400000.0,
|
||||
y: 79709.0,
|
||||
},
|
||||
{
|
||||
x: -94694400000.0,
|
||||
y: 82204.0,
|
||||
},
|
||||
{
|
||||
x: -63158400000.0,
|
||||
y: 81785.0,
|
||||
},
|
||||
{
|
||||
x: -31536000000.0,
|
||||
y: 84893.0,
|
||||
},
|
||||
{
|
||||
x: 0.0,
|
||||
y: 85015.0,
|
||||
},
|
||||
{
|
||||
x: 31536000000.0,
|
||||
y: 77321.0,
|
||||
},
|
||||
{
|
||||
x: 63072000000.0,
|
||||
y: 71197.0,
|
||||
},
|
||||
{
|
||||
x: 94694400000.0,
|
||||
y: 67598.0,
|
||||
},
|
||||
{
|
||||
x: 126230400000.0,
|
||||
y: 67304.0,
|
||||
},
|
||||
{
|
||||
x: 157766400000.0,
|
||||
y: 68149.0,
|
||||
},
|
||||
{
|
||||
x: 189302400000.0,
|
||||
y: 66686.0,
|
||||
},
|
||||
{
|
||||
x: 220924800000.0,
|
||||
y: 67344.0,
|
||||
},
|
||||
{
|
||||
x: 252460800000.0,
|
||||
y: 66875.0,
|
||||
},
|
||||
{
|
||||
x: 283996800000.0,
|
||||
y: 67473.0,
|
||||
},
|
||||
{
|
||||
x: 315532800000.0,
|
||||
y: 68375.0,
|
||||
},
|
||||
{
|
||||
x: 347155200000.0,
|
||||
y: 68467.0,
|
||||
},
|
||||
{
|
||||
x: 378691200000.0,
|
||||
y: 67904.0,
|
||||
},
|
||||
{
|
||||
x: 410227200000.0,
|
||||
y: 67708.0,
|
||||
},
|
||||
{
|
||||
x: 441763200000.0,
|
||||
y: 67457.0,
|
||||
},
|
||||
{
|
||||
x: 473385600000.0,
|
||||
y: 64667.0,
|
||||
},
|
||||
{
|
||||
x: 504921600000.0,
|
||||
y: 63959.0,
|
||||
},
|
||||
{
|
||||
x: 536457600000.0,
|
||||
y: 63442.0,
|
||||
},
|
||||
{
|
||||
x: 567993600000.0,
|
||||
y: 63924.0,
|
||||
},
|
||||
{
|
||||
x: 599616000000.0,
|
||||
y: 65233.0,
|
||||
},
|
||||
{
|
||||
x: 631152000000.0,
|
||||
y: 65138.0,
|
||||
},
|
||||
{
|
||||
x: 662688000000.0,
|
||||
y: 60646.0,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
group: ['Robert'],
|
||||
values: [
|
||||
{
|
||||
x: -157766400000.0,
|
||||
y: 62973.0,
|
||||
},
|
||||
{
|
||||
x: -126230400000.0,
|
||||
y: 59162.0,
|
||||
},
|
||||
{
|
||||
x: -94694400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: -63158400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: -31536000000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 0.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 31536000000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 63072000000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 94694400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 126230400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 157766400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 189302400000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 220924800000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 252460800000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 283996800000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 315532800000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 347155200000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 378691200000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 410227200000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 441763200000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 473385600000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 504921600000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 536457600000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 567993600000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 599616000000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 631152000000.0,
|
||||
y: null,
|
||||
},
|
||||
{
|
||||
x: 662688000000.0,
|
||||
y: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
@ -0,0 +1,27 @@
|
||||
import React from 'react';
|
||||
import { SuperChart } from '@superset-ui/chart';
|
||||
import ParallelCoordinatesChartPlugin from '@superset-ui/legacy-plugin-chart-parallel-coordinates';
|
||||
import data from './data';
|
||||
|
||||
new ParallelCoordinatesChartPlugin().configure({ key: 'parallel-coordinates' }).register();
|
||||
|
||||
export default {
|
||||
title: 'Legacy Chart Plugins|legacy-plugin-chart-parallel-coordinates',
|
||||
};
|
||||
|
||||
export const basic = () => (
|
||||
<SuperChart
|
||||
chartType="parallel-coordinates"
|
||||
width={400}
|
||||
height={400}
|
||||
queryData={{ data }}
|
||||
formData={{
|
||||
includeSeries: false,
|
||||
linearColorScheme: 'schemeRdYlBu',
|
||||
metrics: ['sum__SP_POP_TOTL', 'sum__SP_RUR_TOTL_ZS', 'sum__SH_DYN_AIDS'],
|
||||
secondaryMetric: 'sum__SP_POP_TOTL',
|
||||
series: 'country_name',
|
||||
showDatatable: false,
|
||||
}}
|
||||
/>
|
||||
);
|
@ -0,0 +1,62 @@
|
||||
export default [
|
||||
{
|
||||
country_name: 'China',
|
||||
sum__SP_POP_TOTL: 1344130000.0,
|
||||
sum__SP_RUR_TOTL_ZS: 49.427,
|
||||
sum__SH_DYN_AIDS: 0.0,
|
||||
},
|
||||
{
|
||||
country_name: 'India',
|
||||
sum__SP_POP_TOTL: 1247446011.0,
|
||||
sum__SP_RUR_TOTL_ZS: 68.724,
|
||||
sum__SH_DYN_AIDS: 0.0,
|
||||
},
|
||||
{
|
||||
country_name: 'United States',
|
||||
sum__SP_POP_TOTL: 311721632.0,
|
||||
sum__SP_RUR_TOTL_ZS: 19.06,
|
||||
sum__SH_DYN_AIDS: 0.0,
|
||||
},
|
||||
{
|
||||
country_name: 'Indonesia',
|
||||
sum__SP_POP_TOTL: 244808254.0,
|
||||
sum__SP_RUR_TOTL_ZS: 49.288,
|
||||
sum__SH_DYN_AIDS: 540000.0,
|
||||
},
|
||||
{
|
||||
country_name: 'Brazil',
|
||||
sum__SP_POP_TOTL: 200517584.0,
|
||||
sum__SP_RUR_TOTL_ZS: 15.377,
|
||||
sum__SH_DYN_AIDS: 0.0,
|
||||
},
|
||||
{
|
||||
country_name: 'Pakistan',
|
||||
sum__SP_POP_TOTL: 173669648.0,
|
||||
sum__SP_RUR_TOTL_ZS: 62.993,
|
||||
sum__SH_DYN_AIDS: 52000.0,
|
||||
},
|
||||
{
|
||||
country_name: 'Nigeria',
|
||||
sum__SP_POP_TOTL: 163770669.0,
|
||||
sum__SP_RUR_TOTL_ZS: 55.638,
|
||||
sum__SH_DYN_AIDS: 3000000.0,
|
||||
},
|
||||
{
|
||||
country_name: 'Bangladesh',
|
||||
sum__SP_POP_TOTL: 153405612.0,
|
||||
sum__SP_RUR_TOTL_ZS: 68.775,
|
||||
sum__SH_DYN_AIDS: 7800.0,
|
||||
},
|
||||
{
|
||||
country_name: 'Russian Federation',
|
||||
sum__SP_POP_TOTL: 142960868.0,
|
||||
sum__SP_RUR_TOTL_ZS: 26.268,
|
||||
sum__SH_DYN_AIDS: 0.0,
|
||||
},
|
||||
{
|
||||
country_name: 'Japan',
|
||||
sum__SP_POP_TOTL: 127817277.0,
|
||||
sum__SP_RUR_TOTL_ZS: 8.752,
|
||||
sum__SH_DYN_AIDS: 0.0,
|
||||
},
|
||||
];
|
@ -0,0 +1,34 @@
|
||||
import React from 'react';
|
||||
import { SuperChart } from '@superset-ui/chart';
|
||||
import PartitionChartPlugin from '@superset-ui/legacy-plugin-chart-partition';
|
||||
import data from './data';
|
||||
import dummyDatasource from '../../../shared/dummyDatasource';
|
||||
|
||||
new PartitionChartPlugin().configure({ key: 'partition' }).register();
|
||||
|
||||
export default {
|
||||
title: 'Legacy Chart Plugins|legacy-plugin-chart-partition',
|
||||
};
|
||||
|
||||
export const basic = () => (
|
||||
<SuperChart
|
||||
chartType="partition"
|
||||
width={400}
|
||||
height={400}
|
||||
datasource={dummyDatasource}
|
||||
queryData={{ data }}
|
||||
formData={{
|
||||
colorScheme: 'd3Category10',
|
||||
dateTimeFormat: '%Y-%m-%d',
|
||||
equalDateSize: true,
|
||||
groupby: ['region', 'country_code'],
|
||||
logScale: false,
|
||||
metrics: ['sum__SP_POP_TOTL'],
|
||||
numberFormat: '.3s',
|
||||
partitionLimit: '5',
|
||||
partitionThreshold: '0.05',
|
||||
richTooltip: true,
|
||||
timeSeriesOption: 'not-time',
|
||||
}}
|
||||
/>
|
||||
);
|
@ -0,0 +1,94 @@
|
||||
export default [
|
||||
{
|
||||
name: 'World',
|
||||
val: 165709793794.0,
|
||||
children: [
|
||||
{
|
||||
name: 'East Asia & Pacific',
|
||||
val: 74157936990.0,
|
||||
children: [
|
||||
{
|
||||
name: 'CHN',
|
||||
val: 58345455000.0,
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
name: 'IDN',
|
||||
val: 9357861231.0,
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
name: 'JPN',
|
||||
val: 6454620759.0,
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Europe & Central Asia',
|
||||
val: 7667188460.0,
|
||||
children: [
|
||||
{
|
||||
name: 'RUS',
|
||||
val: 7667188460.0,
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Latin America & Caribbean',
|
||||
val: 7752058955.0,
|
||||
children: [
|
||||
{
|
||||
name: 'BRA',
|
||||
val: 7752058955.0,
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'North America',
|
||||
val: 13604468357.0,
|
||||
children: [
|
||||
{
|
||||
name: 'USA',
|
||||
val: 13604468357.0,
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'South Asia',
|
||||
val: 57268340539.0,
|
||||
children: [
|
||||
{
|
||||
name: 'BGD',
|
||||
val: 5549261462.0,
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
name: 'IND',
|
||||
val: 46023037597.0,
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
name: 'PAK',
|
||||
val: 5696041480.0,
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Sub-Saharan Africa',
|
||||
val: 5259800493.0,
|
||||
children: [
|
||||
{
|
||||
name: 'NGA',
|
||||
val: 5259800493.0,
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
@ -0,0 +1,64 @@
|
||||
/* eslint-disable no-magic-numbers */
|
||||
import React from 'react';
|
||||
import { SuperChart } from '@superset-ui/chart';
|
||||
import PivotTableChartPlugin from '@superset-ui/legacy-plugin-chart-pivot-table';
|
||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
|
||||
new PivotTableChartPlugin().configure({ key: 'pivot-table' }).register();
|
||||
|
||||
export default {
|
||||
title: 'Legacy Chart Plugins|legacy-plugin-chart-pivot-table',
|
||||
};
|
||||
|
||||
const datasource = {
|
||||
columnFormats: {},
|
||||
verboseMap: {
|
||||
sum__num: 'sum__num',
|
||||
},
|
||||
};
|
||||
|
||||
export const basic = () => (
|
||||
<SuperChart
|
||||
chartType="pivot-table"
|
||||
width={400}
|
||||
height={400}
|
||||
datasource={datasource}
|
||||
queryData={{
|
||||
data: {
|
||||
columns: [
|
||||
['sum__num', 'other'],
|
||||
['sum__num', 'All'],
|
||||
],
|
||||
html:
|
||||
'<table border="1" class="dataframe dataframe table table-striped table-bordered table-condensed table-hover">\n <thead>\n <tr>\n <th></th>\n <th colspan="2" halign="left">sum__num</th>\n </tr>\n <tr>\n <th>state</th>\n <th>other</th>\n <th>All</th>\n </tr>\n <tr>\n <th>name</th>\n <th></th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <th>Christopher</th>\n <td>803607</td>\n <td>803607</td>\n </tr>\n <tr>\n <th>David</th>\n <td>673992</td>\n <td>673992</td>\n </tr>\n <tr>\n <th>James</th>\n <td>749686</td>\n <td>749686</td>\n </tr>\n <tr>\n <th>Jennifer</th>\n <td>587540</td>\n <td>587540</td>\n </tr>\n <tr>\n <th>John</th>\n <td>638450</td>\n <td>638450</td>\n </tr>\n <tr>\n <th>Joshua</th>\n <td>548044</td>\n <td>548044</td>\n </tr>\n <tr>\n <th>Matthew</th>\n <td>608212</td>\n <td>608212</td>\n </tr>\n <tr>\n <th>Michael</th>\n <td>1047996</td>\n <td>1047996</td>\n </tr>\n <tr>\n <th>Robert</th>\n <td>575592</td>\n <td>575592</td>\n </tr>\n <tr>\n <th>William</th>\n <td>574464</td>\n <td>574464</td>\n </tr>\n <tr>\n <th>All</th>\n <td>6807583</td>\n <td>6807583</td>\n </tr>\n </tbody>\n</table>',
|
||||
},
|
||||
}}
|
||||
formData={{
|
||||
groupby: ['name'],
|
||||
numberFormat: '.3s',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
export const withNull = () => (
|
||||
<SuperChart
|
||||
chartType="pivot-table"
|
||||
width={400}
|
||||
height={400}
|
||||
datasource={datasource}
|
||||
queryData={{
|
||||
data: {
|
||||
columns: [
|
||||
['sum__num', 'other'],
|
||||
['sum__num', 'All'],
|
||||
],
|
||||
html:
|
||||
'<table border="1" class="dataframe dataframe table table-striped table-bordered table-condensed table-hover">\n <thead>\n <tr>\n <th></th>\n <th colspan="2" halign="left">sum__num</th>\n </tr>\n <tr>\n <th>state</th>\n <th>other</th>\n <th>All</th>\n </tr>\n <tr>\n <th>name</th>\n <th></th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <th>Christopher</th>\n <td>null</td>\n <td>803607</td>\n </tr>\n <tr>\n <th>David</th>\n <td>null</td>\n <td>673992</td>\n </tr>\n <tr>\n <th>James</th>\n <td>749686</td>\n <td>null</td>\n </tr>\n <tr>\n <th>Jennifer</th>\n <td>587540</td>\n <td>null</td>\n </tr>\n <tr>\n <th>John</th>\n <td>638450</td>\n <td>638450</td>\n </tr>\n <tr>\n <th>Joshua</th>\n <td>null</td>\n <td>548044</td>\n </tr>\n <tr>\n <th>Matthew</th>\n <td>608212</td>\n <td>608212</td>\n </tr>\n <tr>\n <th>Michael</th>\n <td>1047996</td>\n <td>1047996</td>\n </tr>\n <tr>\n <th>Robert</th>\n <td>575592</td>\n <td>575592</td>\n </tr>\n <tr>\n <th>William</th>\n <td>574464</td>\n <td>574464</td>\n </tr>\n <tr>\n <th>All</th>\n <td>6807583</td>\n <td>6807583</td>\n </tr>\n </tbody>\n</table>',
|
||||
},
|
||||
}}
|
||||
formData={{
|
||||
groupby: ['name'],
|
||||
numberFormat: '.3s',
|
||||
}}
|
||||
/>
|
||||
);
|
@ -0,0 +1,32 @@
|
||||
## @superset-ui/legacy-plugin-chart-paired-t-test
|
||||
|
||||
[![Version](https://img.shields.io/npm/v/@superset-ui/legacy-plugin-chart-paired-t-test.svg?style=flat-square)](https://img.shields.io/npm/v/@superset-ui/legacy-plugin-chart-paired-t-test.svg?style=flat-square)
|
||||
[![David (path)](https://img.shields.io/david/apache-superset/superset-ui-plugins.svg?path=packages%2Fsuperset-ui-legacy-plugin-chart-paired-t-test&style=flat-square)](https://david-dm.org/apache-superset/superset-ui-plugins?path=packages/superset-ui-legacy-plugin-chart-paired-t-test)
|
||||
|
||||
This plugin provides Paired T Test for Superset.
|
||||
|
||||
### Usage
|
||||
|
||||
Configure `key`, which can be any `string`, and register the plugin. This `key` will be used to lookup this chart throughout the app.
|
||||
|
||||
```js
|
||||
import PairedTTestChartPlugin from '@superset-ui/legacy-plugin-chart-paired-t-test';
|
||||
|
||||
new PairedTTestChartPlugin()
|
||||
.configure({ key: 'paired-t-test' })
|
||||
.register();
|
||||
```
|
||||
|
||||
Then use it via `SuperChart`. See [storybook](https://apache-superset.github.io/superset-ui-plugins/?selectedKind=plugin-chart-paired-t-test) for more details.
|
||||
|
||||
```js
|
||||
<SuperChart
|
||||
chartType="paired-t-test"
|
||||
width={600}
|
||||
height={600}
|
||||
formData={...}
|
||||
queryData={{
|
||||
data: {...},
|
||||
}}
|
||||
/>
|
||||
```
|
@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "@superset-ui/legacy-plugin-chart-paired-t-test",
|
||||
"version": "0.11.15",
|
||||
"description": "Superset Legacy Chart - Paired T Test",
|
||||
"sideEffects": [
|
||||
"*.css"
|
||||
],
|
||||
"main": "lib/index.js",
|
||||
"module": "esm/index.js",
|
||||
"files": [
|
||||
"esm",
|
||||
"lib"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/apache-superset/superset-ui-plugins.git"
|
||||
},
|
||||
"keywords": [
|
||||
"superset"
|
||||
],
|
||||
"author": "Superset",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/apache-superset/superset-ui-plugins/issues"
|
||||
},
|
||||
"homepage": "https://github.com/apache-superset/superset-ui-plugins#readme",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"dependencies": {
|
||||
"distributions": "^1.0.0",
|
||||
"prop-types": "^15.6.2",
|
||||
"reactable-arc": "0.15.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@superset-ui/chart": "^0.12.0",
|
||||
"@superset-ui/translation": "^0.12.0",
|
||||
"react": "^15 || ^16"
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
.superset-legacy-chart-paired_ttest .scrollbar-container {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.paired-ttest-table .scrollbar-content {
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.paired-ttest-table table {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.paired-ttest-table h1 {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.reactable-data tr,
|
||||
.reactable-header-sortable {
|
||||
-webkit-transition: ease-in-out 0.1s;
|
||||
transition: ease-in-out 0.1s;
|
||||
}
|
||||
|
||||
.reactable-data tr:hover {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
||||
.reactable-data tr .false {
|
||||
color: #f44336;
|
||||
}
|
||||
|
||||
.reactable-data tr .true {
|
||||
color: #4caf50;
|
||||
}
|
||||
|
||||
.reactable-data tr .control {
|
||||
color: #2196f3;
|
||||
}
|
||||
|
||||
.reactable-data tr .invalid {
|
||||
color: #ff9800;
|
||||
}
|
||||
|
||||
.reactable-data .control td {
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
|
||||
.reactable-header-sortable:hover,
|
||||
.reactable-header-sortable:focus,
|
||||
.reactable-header-sort-asc,
|
||||
.reactable-header-sort-desc {
|
||||
background-color: #e0e0e0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.reactable-header-sort-asc:after {
|
||||
content: '\25bc';
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.reactable-header-sort-desc:after {
|
||||
content: '\25b2';
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
/* eslint-disable react/no-array-index-key */
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import TTestTable, { dataPropType } from './TTestTable';
|
||||
import './PairedTTest.css';
|
||||
|
||||
const propTypes = {
|
||||
alpha: PropTypes.number,
|
||||
className: PropTypes.string,
|
||||
data: PropTypes.objectOf(dataPropType).isRequired,
|
||||
groups: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
liftValPrec: PropTypes.number,
|
||||
metrics: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
pValPrec: PropTypes.number,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
alpha: 0.05,
|
||||
className: '',
|
||||
liftValPrec: 4,
|
||||
pValPrec: 6,
|
||||
};
|
||||
|
||||
class PairedTTest extends React.PureComponent {
|
||||
render() {
|
||||
const { className, metrics, groups, data, alpha, pValPrec, liftValPrec } = this.props;
|
||||
|
||||
return (
|
||||
<div className={`superset-legacy-chart-paired-t-test ${className}`}>
|
||||
<div className="paired-ttest-table scrollbar-container">
|
||||
<div className="scrollbar-content">
|
||||
{metrics.map((metric, i) => (
|
||||
<TTestTable
|
||||
key={i}
|
||||
metric={metric}
|
||||
groups={groups}
|
||||
data={data[metric]}
|
||||
alpha={alpha}
|
||||
pValPrec={Math.min(pValPrec, 32)}
|
||||
liftValPrec={Math.min(liftValPrec, 32)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
PairedTTest.propTypes = propTypes;
|
||||
PairedTTest.defaultProps = defaultProps;
|
||||
|
||||
export default PairedTTest;
|
@ -0,0 +1,290 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
/* eslint-disable no-plusplus, react/no-array-index-key, react/jsx-no-bind */
|
||||
import dist from 'distributions';
|
||||
import React from 'react';
|
||||
import { Table, Tr, Td, Thead, Th } from 'reactable-arc';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export const dataPropType = PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
group: PropTypes.arrayOf(PropTypes.string),
|
||||
values: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
x: PropTypes.number,
|
||||
y: PropTypes.number,
|
||||
}),
|
||||
),
|
||||
}),
|
||||
);
|
||||
|
||||
const propTypes = {
|
||||
alpha: PropTypes.number,
|
||||
data: dataPropType.isRequired,
|
||||
groups: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
liftValPrec: PropTypes.number,
|
||||
metric: PropTypes.string.isRequired,
|
||||
pValPrec: PropTypes.number,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
alpha: 0.05,
|
||||
liftValPrec: 4,
|
||||
pValPrec: 6,
|
||||
};
|
||||
|
||||
class TTestTable extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
control: 0,
|
||||
liftValues: [],
|
||||
pValues: [],
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { control } = this.state;
|
||||
this.computeTTest(control); // initially populate table
|
||||
}
|
||||
|
||||
getLiftStatus(row) {
|
||||
const { control, liftValues } = this.state;
|
||||
// Get a css class name for coloring
|
||||
if (row === control) {
|
||||
return 'control';
|
||||
}
|
||||
const liftVal = liftValues[row];
|
||||
if (Number.isNaN(liftVal) || !Number.isFinite(liftVal)) {
|
||||
return 'invalid'; // infinite or NaN values
|
||||
}
|
||||
|
||||
return liftVal >= 0 ? 'true' : 'false'; // green on true, red on false
|
||||
}
|
||||
|
||||
getPValueStatus(row) {
|
||||
const { control, pValues } = this.state;
|
||||
if (row === control) {
|
||||
return 'control';
|
||||
}
|
||||
const pVal = pValues[row];
|
||||
if (Number.isNaN(pVal) || !Number.isFinite(pVal)) {
|
||||
return 'invalid';
|
||||
}
|
||||
|
||||
return ''; // p-values won't normally be colored
|
||||
}
|
||||
|
||||
getSignificance(row) {
|
||||
const { control, pValues } = this.state;
|
||||
const { alpha } = this.props;
|
||||
// Color significant as green, else red
|
||||
if (row === control) {
|
||||
return 'control';
|
||||
}
|
||||
|
||||
// p-values significant below set threshold
|
||||
return pValues[row] <= alpha;
|
||||
}
|
||||
|
||||
computeLift(values, control) {
|
||||
const { liftValPrec } = this.props;
|
||||
// Compute the lift value between two time series
|
||||
let sumValues = 0;
|
||||
let sumControl = 0;
|
||||
values.forEach((value, i) => {
|
||||
sumValues += value.y;
|
||||
sumControl += control[i].y;
|
||||
});
|
||||
|
||||
return (((sumValues - sumControl) / sumControl) * 100).toFixed(liftValPrec);
|
||||
}
|
||||
|
||||
computePValue(values, control) {
|
||||
const { pValPrec } = this.props;
|
||||
// Compute the p-value from Student's t-test
|
||||
// between two time series
|
||||
let diffSum = 0;
|
||||
let diffSqSum = 0;
|
||||
let finiteCount = 0;
|
||||
values.forEach((value, i) => {
|
||||
const diff = control[i].y - value.y;
|
||||
/* eslint-disable-next-line */
|
||||
if (isFinite(diff)) {
|
||||
finiteCount++;
|
||||
diffSum += diff;
|
||||
diffSqSum += diff * diff;
|
||||
}
|
||||
});
|
||||
const tvalue = -Math.abs(
|
||||
diffSum * Math.sqrt((finiteCount - 1) / (finiteCount * diffSqSum - diffSum * diffSum)),
|
||||
);
|
||||
try {
|
||||
return (2 * new dist.Studentt(finiteCount - 1).cdf(tvalue)).toFixed(pValPrec); // two-sided test
|
||||
} catch (error) {
|
||||
return NaN;
|
||||
}
|
||||
}
|
||||
|
||||
computeTTest(control) {
|
||||
// Compute lift and p-values for each row
|
||||
// against the selected control
|
||||
const { data } = this.props;
|
||||
const pValues = [];
|
||||
const liftValues = [];
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
if (i === control) {
|
||||
pValues.push('control');
|
||||
liftValues.push('control');
|
||||
} else {
|
||||
pValues.push(this.computePValue(data[i].values, data[control].values));
|
||||
liftValues.push(this.computeLift(data[i].values, data[control].values));
|
||||
}
|
||||
}
|
||||
this.setState({ control, liftValues, pValues });
|
||||
}
|
||||
|
||||
render() {
|
||||
const { data, metric, groups } = this.props;
|
||||
const { control, liftValues, pValues } = this.state;
|
||||
// Render column header for each group
|
||||
const columns = groups.map((group, i) => (
|
||||
<Th key={i} column={group}>
|
||||
{group}
|
||||
</Th>
|
||||
));
|
||||
const numGroups = groups.length;
|
||||
// Columns for p-value, lift-value, and significance (true/false)
|
||||
columns.push(
|
||||
<Th key={numGroups + 1} column="pValue">
|
||||
p-value
|
||||
</Th>,
|
||||
);
|
||||
columns.push(
|
||||
<Th key={numGroups + 2} column="liftValue">
|
||||
Lift %
|
||||
</Th>,
|
||||
);
|
||||
columns.push(
|
||||
<Th key={numGroups + 3} column="significant">
|
||||
Significant
|
||||
</Th>,
|
||||
);
|
||||
const rows = data.map((entry, i) => {
|
||||
const values = groups.map((
|
||||
group,
|
||||
j, // group names
|
||||
) => <Td key={j} column={group} data={entry.group[j]} />);
|
||||
values.push(
|
||||
<Td
|
||||
key={numGroups + 1}
|
||||
className={this.getPValueStatus(i)}
|
||||
column="pValue"
|
||||
data={pValues[i]}
|
||||
/>,
|
||||
);
|
||||
values.push(
|
||||
<Td
|
||||
key={numGroups + 2}
|
||||
className={this.getLiftStatus(i)}
|
||||
column="liftValue"
|
||||
data={liftValues[i]}
|
||||
/>,
|
||||
);
|
||||
values.push(
|
||||
<Td
|
||||
key={numGroups + 3}
|
||||
className={this.getSignificance(i).toString()}
|
||||
column="significant"
|
||||
data={this.getSignificance(i)}
|
||||
/>,
|
||||
);
|
||||
|
||||
return (
|
||||
<Tr
|
||||
key={i}
|
||||
className={i === control ? 'control' : ''}
|
||||
onClick={this.computeTTest.bind(this, i)}
|
||||
>
|
||||
{values}
|
||||
</Tr>
|
||||
);
|
||||
});
|
||||
// When sorted ascending, 'control' will always be at top
|
||||
const sortConfig = groups.concat([
|
||||
{
|
||||
column: 'pValue',
|
||||
sortFunction: (a, b) => {
|
||||
if (a === 'control') {
|
||||
return -1;
|
||||
}
|
||||
if (b === 'control') {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return a > b ? 1 : -1; // p-values ascending
|
||||
},
|
||||
},
|
||||
{
|
||||
column: 'liftValue',
|
||||
sortFunction: (a, b) => {
|
||||
if (a === 'control') {
|
||||
return -1;
|
||||
}
|
||||
if (b === 'control') {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return parseFloat(a) > parseFloat(b) ? -1 : 1; // lift values descending
|
||||
},
|
||||
},
|
||||
{
|
||||
column: 'significant',
|
||||
sortFunction: (a, b) => {
|
||||
if (a === 'control') {
|
||||
return -1;
|
||||
}
|
||||
if (b === 'control') {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return a > b ? -1 : 1; // significant values first
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h3>{metric}</h3>
|
||||
<Table className="table" id={`table_${metric}`} sortable={sortConfig}>
|
||||
<Thead>{columns}</Thead>
|
||||
{rows}
|
||||
</Table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TTestTable.propTypes = propTypes;
|
||||
TTestTable.defaultProps = defaultProps;
|
||||
|
||||
export default TTestTable;
|
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 230 KiB |
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { t } from '@superset-ui/translation';
|
||||
import { ChartMetadata, ChartPlugin } from '@superset-ui/chart';
|
||||
import transformProps from './transformProps';
|
||||
import thumbnail from './images/thumbnail.png';
|
||||
|
||||
const metadata = new ChartMetadata({
|
||||
description: '',
|
||||
name: t('Paired t-test Table'),
|
||||
thumbnail,
|
||||
useLegacyApi: true,
|
||||
});
|
||||
|
||||
export default class PairedTTestChartPlugin extends ChartPlugin {
|
||||
constructor() {
|
||||
super({
|
||||
loadChart: () => import('./PairedTTest'),
|
||||
metadata,
|
||||
transformProps,
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
export default function transformProps(chartProps) {
|
||||
const { formData, queryData } = chartProps;
|
||||
const { groupby, liftvaluePrecision, metrics, pvaluePrecision, significanceLevel } = formData;
|
||||
|
||||
return {
|
||||
alpha: significanceLevel,
|
||||
data: queryData.data,
|
||||
groups: groupby,
|
||||
liftValPrec: parseInt(liftvaluePrecision, 10),
|
||||
metrics,
|
||||
pValPrec: parseInt(pvaluePrecision, 10),
|
||||
};
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
## @superset-ui/legacy-plugin-chart-parallel-coordinates
|
||||
|
||||
[![Version](https://img.shields.io/npm/v/@superset-ui/legacy-plugin-chart-parallel-coordinates.svg?style=flat-square)](https://img.shields.io/npm/v/@superset-ui/legacy-plugin-chart-parallel-coordinates.svg?style=flat-square)
|
||||
[![David (path)](https://img.shields.io/david/apache-superset/superset-ui-plugins.svg?path=packages%2Fsuperset-ui-legacy-plugin-chart-parallel-coordinates&style=flat-square)](https://david-dm.org/apache-superset/superset-ui-plugins?path=packages/superset-ui-legacy-plugin-chart-parallel-coordinates)
|
||||
|
||||
This plugin provides Parallel Coordinates for Superset.
|
||||
|
||||
### Usage
|
||||
|
||||
Configure `key`, which can be any `string`, and register the plugin. This `key` will be used to lookup this chart throughout the app.
|
||||
|
||||
```js
|
||||
import ParallelCoordinatesChartPlugin from '@superset-ui/legacy-plugin-chart-parallel-coordinates';
|
||||
|
||||
new ParallelCoordinatesChartPlugin()
|
||||
.configure({ key: 'parallel-coordinates' })
|
||||
.register();
|
||||
```
|
||||
|
||||
Then use it via `SuperChart`. See [storybook](https://apache-superset.github.io/superset-ui-plugins/?selectedKind=plugin-chart-parallel-coordinates) for more details.
|
||||
|
||||
```js
|
||||
<SuperChart
|
||||
chartType="parallel-coordinates"
|
||||
width={600}
|
||||
height={600}
|
||||
formData={...}
|
||||
queryData={{
|
||||
data: {...},
|
||||
}}
|
||||
/>
|
||||
```
|
@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "@superset-ui/legacy-plugin-chart-parallel-coordinates",
|
||||
"version": "0.11.15",
|
||||
"description": "Superset Legacy Chart - Parallel Coordinates",
|
||||
"sideEffects": [
|
||||
"*.css"
|
||||
],
|
||||
"main": "lib/index.js",
|
||||
"module": "esm/index.js",
|
||||
"files": [
|
||||
"esm",
|
||||
"lib"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/apache-superset/superset-ui-plugins.git"
|
||||
},
|
||||
"keywords": [
|
||||
"superset"
|
||||
],
|
||||
"author": "Superset",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/apache-superset/superset-ui-plugins/issues"
|
||||
},
|
||||
"homepage": "https://github.com/apache-superset/superset-ui-plugins#readme",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"dependencies": {
|
||||
"d3": "^3.5.17",
|
||||
"prop-types": "^15.6.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@superset-ui/chart": "^0.12.0",
|
||||
"@superset-ui/color": "^0.12.0",
|
||||
"@superset-ui/translation": "^0.12.0"
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
.superset-legacy-chart-parallel-coordinates div.grid {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.superset-legacy-chart-parallel-coordinates .grid div.row:hover {
|
||||
background-color: #ccc;
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
/* eslint-disable react/sort-prop-types */
|
||||
import d3 from 'd3';
|
||||
import PropTypes from 'prop-types';
|
||||
import { getSequentialSchemeRegistry } from '@superset-ui/color';
|
||||
|
||||
import parcoords from './vendor/parcoords/d3.parcoords';
|
||||
import divgrid from './vendor/parcoords/divgrid';
|
||||
import './vendor/parcoords/d3.parcoords.css';
|
||||
import './ParallelCoordinates.css';
|
||||
|
||||
const propTypes = {
|
||||
// Standard tabular data [{ fieldName1: value1, fieldName2: value2 }]
|
||||
data: PropTypes.arrayOf(PropTypes.object),
|
||||
width: PropTypes.number,
|
||||
height: PropTypes.number,
|
||||
colorMetric: PropTypes.string,
|
||||
includeSeries: PropTypes.bool,
|
||||
linearColorScheme: PropTypes.string,
|
||||
metrics: PropTypes.arrayOf(PropTypes.string),
|
||||
series: PropTypes.string,
|
||||
showDatatable: PropTypes.bool,
|
||||
};
|
||||
|
||||
function ParallelCoordinates(element, props) {
|
||||
const {
|
||||
data,
|
||||
width,
|
||||
height,
|
||||
colorMetric,
|
||||
includeSeries,
|
||||
linearColorScheme,
|
||||
metrics,
|
||||
series,
|
||||
showDatatable,
|
||||
} = props;
|
||||
|
||||
const cols = includeSeries ? [series].concat(metrics) : metrics;
|
||||
|
||||
const ttypes = {};
|
||||
ttypes[series] = 'string';
|
||||
metrics.forEach(v => {
|
||||
ttypes[v] = 'number';
|
||||
});
|
||||
|
||||
const colorScale = colorMetric
|
||||
? getSequentialSchemeRegistry()
|
||||
.get(linearColorScheme)
|
||||
.createLinearScale(d3.extent(data, d => d[colorMetric]))
|
||||
: () => 'grey';
|
||||
const color = d => colorScale(d[colorMetric]);
|
||||
const container = d3.select(element).classed('superset-legacy-chart-parallel-coordinates', true);
|
||||
container.selectAll('*').remove();
|
||||
const effHeight = showDatatable ? height / 2 : height;
|
||||
|
||||
const div = container.append('div').style('height', `${effHeight}px`).classed('parcoords', true);
|
||||
|
||||
const chart = parcoords()(div.node())
|
||||
.width(width)
|
||||
.color(color)
|
||||
.alpha(0.5)
|
||||
.composite('darken')
|
||||
.height(effHeight)
|
||||
.data(data)
|
||||
.dimensions(cols)
|
||||
.types(ttypes)
|
||||
.render()
|
||||
.createAxes()
|
||||
.shadows()
|
||||
.reorderable()
|
||||
.brushMode('1D-axes');
|
||||
|
||||
if (showDatatable) {
|
||||
// create data table, row hover highlighting
|
||||
const grid = divgrid();
|
||||
container
|
||||
.append('div')
|
||||
.style('height', `${effHeight}px`)
|
||||
.datum(data)
|
||||
.call(grid)
|
||||
.classed('parcoords grid', true)
|
||||
.selectAll('.row')
|
||||
.on({
|
||||
mouseover(d) {
|
||||
chart.highlight([d]);
|
||||
},
|
||||
mouseout: chart.unhighlight,
|
||||
});
|
||||
// update data table on brush event
|
||||
chart.on('brush', d => {
|
||||
d3.select('.grid')
|
||||
.datum(d)
|
||||
.call(grid)
|
||||
.selectAll('.row')
|
||||
.on({
|
||||
mouseover(dd) {
|
||||
chart.highlight([dd]);
|
||||
},
|
||||
mouseout: chart.unhighlight,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ParallelCoordinates.displayName = 'ParallelCoordinates';
|
||||
ParallelCoordinates.propTypes = propTypes;
|
||||
|
||||
export default ParallelCoordinates;
|
@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { reactify } from '@superset-ui/chart';
|
||||
import Component from './ParallelCoordinates';
|
||||
|
||||
export default reactify(Component);
|
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 460 KiB |
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { t } from '@superset-ui/translation';
|
||||
import { ChartMetadata, ChartPlugin } from '@superset-ui/chart';
|
||||
import transformProps from './transformProps';
|
||||
import thumbnail from './images/thumbnail.png';
|
||||
|
||||
const metadata = new ChartMetadata({
|
||||
credits: ['https://syntagmatic.github.io/parallel-coordinates'],
|
||||
description: '',
|
||||
name: t('Parallel Coordinates'),
|
||||
thumbnail,
|
||||
useLegacyApi: true,
|
||||
});
|
||||
|
||||
export default class ParallelCoordinatesChartPlugin extends ChartPlugin {
|
||||
constructor() {
|
||||
super({
|
||||
loadChart: () => import('./ReactParallelCoordinates.js'),
|
||||
metadata,
|
||||
transformProps,
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
export default function transformProps(chartProps) {
|
||||
const { width, height, formData, queryData } = chartProps;
|
||||
const {
|
||||
includeSeries,
|
||||
linearColorScheme,
|
||||
metrics,
|
||||
secondaryMetric,
|
||||
series,
|
||||
showDatatable,
|
||||
} = formData;
|
||||
|
||||
return {
|
||||
width,
|
||||
height,
|
||||
data: queryData.data,
|
||||
includeSeries,
|
||||
linearColorScheme,
|
||||
metrics: metrics.map(m => m.label || m),
|
||||
colorMetric: secondaryMetric && secondaryMetric.label ? secondaryMetric.label : secondaryMetric,
|
||||
series,
|
||||
showDatatable,
|
||||
};
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/* [LICENSE TBD] */
|
||||
.parcoords svg,
|
||||
.parcoords canvas {
|
||||
font-size: 12px;
|
||||
position: absolute;
|
||||
}
|
||||
.parcoords > canvas {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.parcoords text.label {
|
||||
font: 100%;
|
||||
font-size: 12px;
|
||||
cursor: drag;
|
||||
}
|
||||
|
||||
.parcoords rect.background {
|
||||
fill: transparent;
|
||||
}
|
||||
.parcoords rect.background:hover {
|
||||
fill: rgba(120, 120, 120, 0.2);
|
||||
}
|
||||
.parcoords .resize rect {
|
||||
fill: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.parcoords rect.extent {
|
||||
fill: rgba(255, 255, 255, 0.25);
|
||||
stroke: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
.parcoords .axis line,
|
||||
.parcoords .axis path {
|
||||
fill: none;
|
||||
stroke: #222;
|
||||
shape-rendering: crispEdges;
|
||||
}
|
||||
.parcoords canvas {
|
||||
opacity: 1;
|
||||
-moz-transition: opacity 0.3s;
|
||||
-webkit-transition: opacity 0.3s;
|
||||
-o-transition: opacity 0.3s;
|
||||
}
|
||||
.parcoords canvas.faded {
|
||||
opacity: 0.25;
|
||||
}
|
||||
.parcoords {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
/* data table styles */
|
||||
.parcoords .row,
|
||||
.parcoords .header {
|
||||
clear: left;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
height: 18px;
|
||||
margin: 0px;
|
||||
}
|
||||
.parcoords .row:nth-child(odd) {
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
.parcoords .header {
|
||||
font-weight: bold;
|
||||
}
|
||||
.parcoords .cell {
|
||||
float: left;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
width: 100px;
|
||||
height: 18px;
|
||||
}
|
||||
.parcoords .col-0 {
|
||||
width: 180px;
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/* [LICENSE TBD] */
|
||||
/* eslint-disable */
|
||||
// from http://bl.ocks.org/3687826
|
||||
export default function(config) {
|
||||
var columns = [];
|
||||
|
||||
var dg = function(selection) {
|
||||
if (columns.length == 0) columns = d3.keys(selection.data()[0][0]);
|
||||
|
||||
// header
|
||||
selection
|
||||
.selectAll('.header')
|
||||
.data([true])
|
||||
.enter()
|
||||
.append('div')
|
||||
.attr('class', 'header');
|
||||
|
||||
var header = selection
|
||||
.select('.header')
|
||||
.selectAll('.cell')
|
||||
.data(columns);
|
||||
|
||||
header
|
||||
.enter()
|
||||
.append('div')
|
||||
.attr('class', function(d, i) {
|
||||
return 'col-' + i;
|
||||
})
|
||||
.classed('cell', true);
|
||||
|
||||
selection.selectAll('.header .cell').text(function(d) {
|
||||
return d;
|
||||
});
|
||||
|
||||
header.exit().remove();
|
||||
|
||||
// rows
|
||||
var rows = selection.selectAll('.row').data(function(d) {
|
||||
return d;
|
||||
});
|
||||
|
||||
rows
|
||||
.enter()
|
||||
.append('div')
|
||||
.attr('class', 'row');
|
||||
|
||||
rows.exit().remove();
|
||||
|
||||
var cells = selection
|
||||
.selectAll('.row')
|
||||
.selectAll('.cell')
|
||||
.data(function(d) {
|
||||
return columns.map(function(col) {
|
||||
return d[col];
|
||||
});
|
||||
});
|
||||
|
||||
// cells
|
||||
cells
|
||||
.enter()
|
||||
.append('div')
|
||||
.attr('class', function(d, i) {
|
||||
return 'col-' + i;
|
||||
})
|
||||
.classed('cell', true);
|
||||
|
||||
cells.exit().remove();
|
||||
|
||||
selection.selectAll('.cell').text(function(d) {
|
||||
return d;
|
||||
});
|
||||
|
||||
return dg;
|
||||
};
|
||||
|
||||
dg.columns = function(_) {
|
||||
if (!arguments.length) return columns;
|
||||
columns = _;
|
||||
return this;
|
||||
};
|
||||
|
||||
return dg;
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
## @superset-ui/legacy-plugin-chart-partition
|
||||
|
||||
[![Version](https://img.shields.io/npm/v/@superset-ui/legacy-plugin-chart-partition.svg?style=flat-square)](https://img.shields.io/npm/v/@superset-ui/legacy-plugin-chart-partition.svg?style=flat-square)
|
||||
[![David (path)](https://img.shields.io/david/apache-superset/superset-ui-plugins.svg?path=packages%2Fsuperset-ui-legacy-plugin-chart-partition&style=flat-square)](https://david-dm.org/apache-superset/superset-ui-plugins?path=packages/superset-ui-legacy-plugin-chart-partition)
|
||||
|
||||
This plugin provides Partition for Superset.
|
||||
|
||||
### Usage
|
||||
|
||||
Configure `key`, which can be any `string`, and register the plugin. This `key` will be used to lookup this chart throughout the app.
|
||||
|
||||
```js
|
||||
import PartitionChartPlugin from '@superset-ui/legacy-plugin-chart-partition';
|
||||
|
||||
new PartitionChartPlugin()
|
||||
.configure({ key: 'partition' })
|
||||
.register();
|
||||
```
|
||||
|
||||
Then use it via `SuperChart`. See [storybook](https://apache-superset.github.io/superset-ui-plugins/?selectedKind=plugin-chart-partition) for more details.
|
||||
|
||||
```js
|
||||
<SuperChart
|
||||
chartType="partition"
|
||||
width={600}
|
||||
height={600}
|
||||
formData={...}
|
||||
queryData={{
|
||||
data: {...},
|
||||
}}
|
||||
/>
|
||||
```
|
@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "@superset-ui/legacy-plugin-chart-partition",
|
||||
"version": "0.11.15",
|
||||
"description": "Superset Legacy Chart - Partition",
|
||||
"sideEffects": [
|
||||
"*.css"
|
||||
],
|
||||
"main": "lib/index.js",
|
||||
"module": "esm/index.js",
|
||||
"files": [
|
||||
"esm",
|
||||
"lib"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/apache-superset/superset-ui-plugins.git"
|
||||
},
|
||||
"keywords": [
|
||||
"superset"
|
||||
],
|
||||
"author": "Superset",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/apache-superset/superset-ui-plugins/issues"
|
||||
},
|
||||
"homepage": "https://github.com/apache-superset/superset-ui-plugins#readme",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"dependencies": {
|
||||
"d3": "^3.5.17",
|
||||
"d3-hierarchy": "^1.1.8",
|
||||
"prop-types": "^15.6.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@superset-ui/chart": "^0.12.0",
|
||||
"@superset-ui/color": "^0.12.0",
|
||||
"@superset-ui/number-format": "^0.12.0",
|
||||
"@superset-ui/time-format": "^0.12.0",
|
||||
"@superset-ui/translation": "^0.12.0"
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
.superset-legacy-chart-partition {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.superset-legacy-chart-partition .chart {
|
||||
display: block;
|
||||
margin: auto;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.superset-legacy-chart-partition rect {
|
||||
stroke: #eee;
|
||||
fill: #aaa;
|
||||
fill-opacity: 0.8;
|
||||
transition: fill-opacity 180ms linear;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.superset-legacy-chart-partition rect:hover {
|
||||
fill-opacity: 1;
|
||||
}
|
||||
|
||||
.superset-legacy-chart-partition g text {
|
||||
font-weight: bold;
|
||||
fill: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
.superset-legacy-chart-partition g:hover text {
|
||||
fill: rgba(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
.superset-legacy-chart-partition .partition-tooltip {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
opacity: 0;
|
||||
padding: 5px;
|
||||
pointer-events: none;
|
||||
background-color: rgba(255, 255, 255, 0.75);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.partition-tooltip td {
|
||||
padding-left: 5px;
|
||||
font-size: 11px;
|
||||
}
|
@ -0,0 +1,389 @@
|
||||
/* eslint-disable react/sort-prop-types */
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
/* eslint no-param-reassign: [2, {"props": false}] */
|
||||
/* eslint-disable no-plusplus */
|
||||
import d3 from 'd3';
|
||||
import PropTypes from 'prop-types';
|
||||
import { hierarchy } from 'd3-hierarchy';
|
||||
import { CategoricalColorNamespace } from '@superset-ui/color';
|
||||
import { getNumberFormatter } from '@superset-ui/number-format';
|
||||
import { getTimeFormatter } from '@superset-ui/time-format';
|
||||
import './Partition.css';
|
||||
|
||||
// Compute dx, dy, x, y for each node and
|
||||
// return an array of nodes in breadth-first order
|
||||
function init(root) {
|
||||
const flat = [];
|
||||
const dy = 1 / (root.height + 1);
|
||||
let prev = null;
|
||||
root.each(n => {
|
||||
n.y = dy * n.depth;
|
||||
n.dy = dy;
|
||||
if (n.parent) {
|
||||
n.x = prev.depth === n.parent.depth ? 0 : prev.x + prev.dx;
|
||||
n.dx = (n.weight / n.parent.sum) * n.parent.dx;
|
||||
} else {
|
||||
n.x = 0;
|
||||
n.dx = 1;
|
||||
}
|
||||
prev = n;
|
||||
flat.push(n);
|
||||
});
|
||||
|
||||
return flat;
|
||||
}
|
||||
|
||||
// Declare PropTypes for recursive data structures
|
||||
// https://github.com/facebook/react/issues/5676
|
||||
/* eslint-disable-next-line no-undef */
|
||||
const lazyFunction = f => () => f().apply(this, arguments);
|
||||
const leafType = PropTypes.shape({
|
||||
name: PropTypes.string,
|
||||
val: PropTypes.number.isRequired,
|
||||
});
|
||||
const parentShape = {
|
||||
name: PropTypes.string,
|
||||
val: PropTypes.number.isRequired,
|
||||
children: PropTypes.arrayOf(
|
||||
PropTypes.oneOfType([PropTypes.shape(lazyFunction(() => parentShape)), leafType]),
|
||||
),
|
||||
};
|
||||
const nodeType = PropTypes.oneOfType([PropTypes.shape(parentShape), leafType]);
|
||||
|
||||
const propTypes = {
|
||||
data: PropTypes.arrayOf(nodeType), // array of rootNode
|
||||
width: PropTypes.number,
|
||||
height: PropTypes.number,
|
||||
colorScheme: PropTypes.string,
|
||||
dateTimeFormat: PropTypes.string,
|
||||
equalDateSize: PropTypes.bool,
|
||||
levels: PropTypes.arrayOf(PropTypes.string),
|
||||
metrics: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.object])),
|
||||
numberFormat: PropTypes.string,
|
||||
partitionLimit: PropTypes.number,
|
||||
partitionThreshold: PropTypes.number,
|
||||
timeSeriesOption: PropTypes.string,
|
||||
useLogScale: PropTypes.bool,
|
||||
useRichTooltip: PropTypes.bool,
|
||||
};
|
||||
|
||||
function getAncestors(d) {
|
||||
const ancestors = [d];
|
||||
let node = d;
|
||||
while (node.parent) {
|
||||
ancestors.push(node.parent);
|
||||
node = node.parent;
|
||||
}
|
||||
|
||||
return ancestors;
|
||||
}
|
||||
|
||||
// This vis is based on
|
||||
// http://mbostock.github.io/d3/talk/20111018/partition.html
|
||||
function Icicle(element, props) {
|
||||
const {
|
||||
width,
|
||||
height,
|
||||
data,
|
||||
colorScheme,
|
||||
dateTimeFormat,
|
||||
equalDateSize,
|
||||
levels,
|
||||
useLogScale = false,
|
||||
metrics = [],
|
||||
numberFormat,
|
||||
partitionLimit,
|
||||
partitionThreshold,
|
||||
useRichTooltip,
|
||||
timeSeriesOption = 'not_time',
|
||||
} = props;
|
||||
|
||||
const div = d3.select(element);
|
||||
div.classed('superset-legacy-chart-partition', true);
|
||||
|
||||
// Chart options
|
||||
const chartType = timeSeriesOption;
|
||||
const hasTime = ['adv_anal', 'time_series'].includes(chartType);
|
||||
const format = getNumberFormatter(numberFormat);
|
||||
const timeFormat = getTimeFormatter(dateTimeFormat);
|
||||
const colorFn = CategoricalColorNamespace.getScale(colorScheme);
|
||||
|
||||
div.selectAll('*').remove();
|
||||
const tooltip = div.append('div').classed('partition-tooltip', true);
|
||||
|
||||
function hasDateNode(n) {
|
||||
return metrics.includes(n.data.name) && hasTime;
|
||||
}
|
||||
|
||||
function getCategory(depth) {
|
||||
if (!depth) {
|
||||
return 'Metric';
|
||||
}
|
||||
if (hasTime && depth === 1) {
|
||||
return 'Date';
|
||||
}
|
||||
|
||||
return levels[depth - (hasTime ? 2 : 1)];
|
||||
}
|
||||
|
||||
function drawVis(i, dat) {
|
||||
const datum = dat[i];
|
||||
const w = width;
|
||||
const h = height / data.length;
|
||||
const x = d3.scale.linear().range([0, w]);
|
||||
const y = d3.scale.linear().range([0, h]);
|
||||
|
||||
const viz = div
|
||||
.append('div')
|
||||
.attr('class', 'chart')
|
||||
.style('width', `${w}px`)
|
||||
.style('height', `${h}px`)
|
||||
.append('svg:svg')
|
||||
.attr('width', w)
|
||||
.attr('height', h);
|
||||
|
||||
// Add padding between multiple visualizations
|
||||
if (i !== data.length - 1 && data.length > 1) {
|
||||
viz.style('padding-bottom', '3px');
|
||||
}
|
||||
if (i !== 0 && data.length > 1) {
|
||||
viz.style('padding-top', '3px');
|
||||
}
|
||||
|
||||
const root = hierarchy(datum);
|
||||
|
||||
// node.name is the metric/group name
|
||||
// node.disp is the display value
|
||||
// node.value determines sorting order
|
||||
// node.weight determines partition height
|
||||
// node.sum is the sum of children weights
|
||||
root.eachAfter(n => {
|
||||
n.disp = n.data.val;
|
||||
n.value = n.disp < 0 ? -n.disp : n.disp;
|
||||
n.weight = n.value;
|
||||
n.name = n.data.name;
|
||||
// If the parent is a metric and we still have
|
||||
// the time column, perform a date-time format
|
||||
if (n.parent && hasDateNode(n.parent)) {
|
||||
// Format timestamp values
|
||||
n.weight = equalDateSize ? 1 : n.value;
|
||||
n.value = n.name;
|
||||
n.name = timeFormat(n.name);
|
||||
}
|
||||
if (useLogScale) n.weight = Math.log(n.weight + 1);
|
||||
n.disp = n.disp && !Number.isNaN(n.disp) && Number.isFinite(n.disp) ? format(n.disp) : '';
|
||||
});
|
||||
// Perform sort by weight
|
||||
root.sort((a, b) => {
|
||||
const v = b.value - a.value;
|
||||
if (v === 0) {
|
||||
return b.name > a.name ? 1 : -1;
|
||||
}
|
||||
|
||||
return v;
|
||||
});
|
||||
|
||||
// Prune data based on partition limit and threshold
|
||||
// both are applied at the same time
|
||||
if (partitionThreshold && partitionThreshold >= 0) {
|
||||
// Compute weight sums as we go
|
||||
root.each(n => {
|
||||
n.sum = n.children ? n.children.reduce((a, v) => a + v.weight, 0) || 1 : 1;
|
||||
if (n.children) {
|
||||
// Dates are not ordered by weight
|
||||
if (hasDateNode(n)) {
|
||||
if (equalDateSize) {
|
||||
return;
|
||||
}
|
||||
const removeIndices = [];
|
||||
// Keep at least one child
|
||||
for (let j = 1; j < n.children.length; j++) {
|
||||
if (n.children[j].weight / n.sum < partitionThreshold) {
|
||||
removeIndices.push(j);
|
||||
}
|
||||
}
|
||||
for (let j = removeIndices.length - 1; j >= 0; j--) {
|
||||
n.children.splice(removeIndices[j], 1);
|
||||
}
|
||||
} else {
|
||||
// Find first child that falls below the threshold
|
||||
let j;
|
||||
for (j = 1; j < n.children.length; j++) {
|
||||
if (n.children[j].weight / n.sum < partitionThreshold) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
n.children = n.children.slice(0, j);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (partitionLimit && partitionLimit >= 0) {
|
||||
root.each(n => {
|
||||
if (n.children && n.children.length > partitionLimit) {
|
||||
if (!hasDateNode(n)) {
|
||||
n.children = n.children.slice(0, partitionLimit);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// Compute final weight sums
|
||||
root.eachAfter(n => {
|
||||
n.sum = n.children ? n.children.reduce((a, v) => a + v.weight, 0) || 1 : 1;
|
||||
});
|
||||
|
||||
function positionAndPopulate(tip, d) {
|
||||
let t = '<table>';
|
||||
if (useRichTooltip) {
|
||||
const nodes = getAncestors(d);
|
||||
nodes.reverse().forEach(n => {
|
||||
const atNode = n.depth === d.depth;
|
||||
t += '<tbody>';
|
||||
t +=
|
||||
'<tr>' +
|
||||
'<td>' +
|
||||
'<div ' +
|
||||
`style='border: 2px solid ${atNode ? 'black' : 'transparent'};` +
|
||||
`background-color: ${n.color};'` +
|
||||
'></div>' +
|
||||
'</td>' +
|
||||
`<td>${getCategory(n.depth)}</td>` +
|
||||
`<td>${n.name}</td>` +
|
||||
`<td>${n.disp}</td>` +
|
||||
'</tr>';
|
||||
});
|
||||
} else {
|
||||
t +=
|
||||
'<thead><tr><td colspan="3">' +
|
||||
`<strong>${getCategory(d.depth)}</strong>` +
|
||||
'</td></tr></thead><tbody>';
|
||||
t +=
|
||||
'<tr>' +
|
||||
'<td>' +
|
||||
`<div style='border: thin solid grey; background-color: ${d.color};'` +
|
||||
'></div>' +
|
||||
'</td>' +
|
||||
`<td>${d.name}</td>` +
|
||||
`<td>${d.disp}</td>` +
|
||||
'</tr>';
|
||||
}
|
||||
t += '</tbody></table>';
|
||||
const [tipX, tipY] = d3.mouse(element);
|
||||
tip
|
||||
.html(t)
|
||||
.style('left', `${tipX + 15}px`)
|
||||
.style('top', `${tipY}px`);
|
||||
}
|
||||
|
||||
const nodes = init(root);
|
||||
|
||||
let zoomX = w / root.dx;
|
||||
let zoomY = h / 1;
|
||||
|
||||
// Keep text centered in its division
|
||||
function transform(d) {
|
||||
return `translate(8,${(d.dx * zoomY) / 2})`;
|
||||
}
|
||||
|
||||
const g = viz
|
||||
.selectAll('g')
|
||||
.data(nodes)
|
||||
.enter()
|
||||
.append('svg:g')
|
||||
.attr('transform', d => `translate(${x(d.y)},${y(d.x)})`)
|
||||
.on('mouseover', d => {
|
||||
tooltip.interrupt().transition().duration(100).style('opacity', 0.9);
|
||||
positionAndPopulate(tooltip, d);
|
||||
})
|
||||
.on('mousemove', d => {
|
||||
positionAndPopulate(tooltip, d);
|
||||
})
|
||||
.on('mouseout', () => {
|
||||
tooltip.interrupt().transition().duration(250).style('opacity', 0);
|
||||
});
|
||||
|
||||
// When clicking a subdivision, the vis will zoom in to it
|
||||
function click(d) {
|
||||
if (!d.children) {
|
||||
if (d.parent) {
|
||||
// Clicking on the rightmost level should zoom in
|
||||
return click(d.parent);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
zoomX = (d.y ? w - 40 : w) / (1 - d.y);
|
||||
zoomY = h / d.dx;
|
||||
x.domain([d.y, 1]).range([d.y ? 40 : 0, w]);
|
||||
y.domain([d.x, d.x + d.dx]);
|
||||
|
||||
const t = g
|
||||
.transition()
|
||||
.duration(d3.event.altKey ? 7500 : 750)
|
||||
.attr('transform', nd => `translate(${x(nd.y)},${y(nd.x)})`);
|
||||
|
||||
t.select('rect')
|
||||
.attr('width', d.dy * zoomX)
|
||||
.attr('height', nd => nd.dx * zoomY);
|
||||
|
||||
t.select('text')
|
||||
.attr('transform', transform)
|
||||
.style('opacity', nd => (nd.dx * zoomY > 12 ? 1 : 0));
|
||||
|
||||
d3.event.stopPropagation();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
g.on('click', click);
|
||||
|
||||
g.append('svg:rect')
|
||||
.attr('width', root.dy * zoomX)
|
||||
.attr('height', d => d.dx * zoomY);
|
||||
|
||||
g.append('svg:text')
|
||||
.attr('transform', transform)
|
||||
.attr('dy', '0.35em')
|
||||
.style('opacity', d => (d.dx * zoomY > 12 ? 1 : 0))
|
||||
.text(d => {
|
||||
if (!d.disp) {
|
||||
return d.name;
|
||||
}
|
||||
|
||||
return `${d.name}: ${d.disp}`;
|
||||
});
|
||||
|
||||
// Apply color scheme
|
||||
g.selectAll('rect').style('fill', d => {
|
||||
d.color = colorFn(d.name);
|
||||
|
||||
return d.color;
|
||||
});
|
||||
}
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
drawVis(i, data);
|
||||
}
|
||||
}
|
||||
|
||||
Icicle.displayName = 'Icicle';
|
||||
Icicle.propTypes = propTypes;
|
||||
|
||||
export default Icicle;
|
@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { reactify } from '@superset-ui/chart';
|
||||
import Component from './Partition';
|
||||
|
||||
export default reactify(Component);
|
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 194 KiB |
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { t } from '@superset-ui/translation';
|
||||
import { ChartMetadata, ChartPlugin } from '@superset-ui/chart';
|
||||
import transformProps from './transformProps';
|
||||
import thumbnail from './images/thumbnail.png';
|
||||
|
||||
const metadata = new ChartMetadata({
|
||||
description: '',
|
||||
name: t('Partition Chart'),
|
||||
thumbnail,
|
||||
useLegacyApi: true,
|
||||
});
|
||||
|
||||
export default class PartitionChartPlugin extends ChartPlugin {
|
||||
constructor() {
|
||||
super({
|
||||
loadChart: () => import('./ReactPartition.js'),
|
||||
metadata,
|
||||
transformProps,
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
export default function transformProps(chartProps) {
|
||||
const { width, height, datasource, formData, queryData } = chartProps;
|
||||
const {
|
||||
colorScheme,
|
||||
dateTimeFormat,
|
||||
equalDateSize,
|
||||
groupby,
|
||||
logScale,
|
||||
metrics,
|
||||
numberFormat,
|
||||
partitionLimit,
|
||||
partitionThreshold,
|
||||
richTooltip,
|
||||
timeSeriesOption,
|
||||
} = formData;
|
||||
const { verboseMap } = datasource;
|
||||
|
||||
return {
|
||||
width,
|
||||
height,
|
||||
data: queryData.data,
|
||||
colorScheme,
|
||||
dateTimeFormat,
|
||||
equalDateSize,
|
||||
levels: groupby.map(g => verboseMap[g] || g),
|
||||
metrics,
|
||||
numberFormat,
|
||||
partitionLimit: partitionLimit && parseInt(partitionLimit, 10),
|
||||
partitionThreshold: partitionThreshold && parseInt(partitionThreshold, 10),
|
||||
timeSeriesOption,
|
||||
useLogScale: logScale,
|
||||
useRichTooltip: richTooltip,
|
||||
};
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
## @superset-ui/legacy-plugin-chart-pivot-table
|
||||
|
||||
[![Version](https://img.shields.io/npm/v/@superset-ui/legacy-plugin-chart-pivot-table.svg?style=flat-square)](https://img.shields.io/npm/v/@superset-ui/legacy-plugin-chart-pivot-table.svg?style=flat-square)
|
||||
[![David (path)](https://img.shields.io/david/apache-superset/superset-ui-plugins.svg?path=packages%2Fsuperset-ui-legacy-plugin-chart-pivot-table&style=flat-square)](https://david-dm.org/apache-superset/superset-ui-plugins?path=packages/superset-ui-legacy-plugin-chart-pivot-table)
|
||||
|
||||
This plugin provides Pivot Table for Superset.
|
||||
|
||||
### Usage
|
||||
|
||||
Configure `key`, which can be any `string`, and register the plugin. This `key` will be used to lookup this chart throughout the app.
|
||||
|
||||
```js
|
||||
import PivottableChartPlugin from '@superset-ui/legacy-plugin-chart-pivot-table';
|
||||
|
||||
new PivottableChartPlugin()
|
||||
.configure({ key: 'pivot-table' })
|
||||
.register();
|
||||
```
|
||||
|
||||
Then use it via `SuperChart`. See [storybook](https://apache-superset.github.io/superset-ui-plugins/?selectedKind=plugin-chart-pivot-table) for more details.
|
||||
|
||||
```js
|
||||
<SuperChart
|
||||
chartType="pivot-table"
|
||||
width={600}
|
||||
height={600}
|
||||
formData={...}
|
||||
queryData={{
|
||||
data: {...},
|
||||
}}
|
||||
/>
|
||||
```
|
@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "@superset-ui/legacy-plugin-chart-pivot-table",
|
||||
"version": "0.11.15",
|
||||
"description": "Superset Legacy Chart - Pivot Table",
|
||||
"sideEffects": [
|
||||
"*.css"
|
||||
],
|
||||
"main": "lib/index.js",
|
||||
"module": "esm/index.js",
|
||||
"files": [
|
||||
"esm",
|
||||
"lib"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/apache-superset/superset-ui-plugins.git"
|
||||
},
|
||||
"keywords": [
|
||||
"superset"
|
||||
],
|
||||
"author": "Superset",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/apache-superset/superset-ui-plugins/issues"
|
||||
},
|
||||
"homepage": "https://github.com/apache-superset/superset-ui-plugins#readme",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"dependencies": {
|
||||
"d3": "^3.5.17",
|
||||
"datatables.net-bs": "^1.10.15",
|
||||
"prop-types": "^15.6.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@superset-ui/chart": "^0.12.0",
|
||||
"@superset-ui/number-format": "^0.12.0",
|
||||
"@superset-ui/translation": "^0.12.0"
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
/* eslint-disable react/sort-prop-types */
|
||||
import dt from 'datatables.net-bs';
|
||||
import PropTypes from 'prop-types';
|
||||
import { formatNumber } from '@superset-ui/number-format';
|
||||
import fixTableHeight from './utils/fixTableHeight';
|
||||
import 'datatables.net-bs/css/dataTables.bootstrap.css';
|
||||
|
||||
if (window.$) {
|
||||
dt(window, window.$);
|
||||
}
|
||||
const $ = window.$ || dt.$;
|
||||
|
||||
const propTypes = {
|
||||
data: PropTypes.shape({
|
||||
// TODO: replace this with raw data in SIP-6
|
||||
html: PropTypes.string,
|
||||
columns: PropTypes.arrayOf(
|
||||
PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
|
||||
),
|
||||
}),
|
||||
height: PropTypes.number,
|
||||
columnFormats: PropTypes.objectOf(PropTypes.string),
|
||||
numberFormat: PropTypes.string,
|
||||
numGroups: PropTypes.number,
|
||||
verboseMap: PropTypes.objectOf(PropTypes.string),
|
||||
};
|
||||
|
||||
function PivotTable(element, props) {
|
||||
const { data, height, columnFormats, numberFormat, numGroups, verboseMap } = props;
|
||||
|
||||
const { html, columns } = data;
|
||||
const container = element;
|
||||
const $container = $(element);
|
||||
|
||||
// queryData data is a string of html with a single table element
|
||||
container.innerHTML = html;
|
||||
|
||||
const cols = Array.isArray(columns[0]) ? columns.map(col => col[0]) : columns;
|
||||
|
||||
// jQuery hack to set verbose names in headers
|
||||
// eslint-disable-next-line func-name-matching
|
||||
const replaceCell = function replace() {
|
||||
const s = $(this)[0].textContent;
|
||||
$(this)[0].textContent = verboseMap[s] || s;
|
||||
};
|
||||
$container.find('thead tr:first th').each(replaceCell);
|
||||
$container.find('thead tr th:first-child').each(replaceCell);
|
||||
|
||||
// jQuery hack to format number
|
||||
$container.find('tbody tr').each(function eachRow() {
|
||||
$(this)
|
||||
.find('td')
|
||||
.each(function each(i) {
|
||||
const metric = cols[i];
|
||||
const format = columnFormats[metric] || numberFormat || '.3s';
|
||||
const tdText = $(this)[0].textContent;
|
||||
if (!Number.isNaN(tdText) && tdText !== '' && tdText.trim().toLowerCase() !== 'null') {
|
||||
$(this)[0].textContent = formatNumber(format, tdText);
|
||||
$(this).attr('data-sort', tdText);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (numGroups === 1) {
|
||||
// When there is only 1 group by column,
|
||||
// we use the DataTable plugin to make the header fixed.
|
||||
// The plugin takes care of the scrolling so we don't need
|
||||
// overflow: 'auto' on the table.
|
||||
container.style.overflow = 'hidden';
|
||||
const table = $container.find('table').DataTable({
|
||||
paging: false,
|
||||
searching: false,
|
||||
bInfo: false,
|
||||
scrollY: `${height}px`,
|
||||
scrollCollapse: true,
|
||||
scrollX: true,
|
||||
});
|
||||
table.column('-1').order('desc').draw();
|
||||
fixTableHeight($container.find('.dataTables_wrapper'), height);
|
||||
} else {
|
||||
// When there is more than 1 group by column we just render the table, without using
|
||||
// the DataTable plugin, so we need to handle the scrolling ourselves.
|
||||
// In this case the header is not fixed.
|
||||
container.style.overflow = 'auto';
|
||||
container.style.height = `${height + 10}px`;
|
||||
}
|
||||
}
|
||||
|
||||
PivotTable.displayName = 'PivotTable';
|
||||
PivotTable.propTypes = propTypes;
|
||||
|
||||
export default PivotTable;
|
@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { reactify } from '@superset-ui/chart';
|
||||
import Component from './PivotTable';
|
||||
|
||||
export default reactify(Component);
|
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 270 KiB |
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { t } from '@superset-ui/translation';
|
||||
import { ChartMetadata, ChartPlugin } from '@superset-ui/chart';
|
||||
import transformProps from './transformProps';
|
||||
import thumbnail from './images/thumbnail.png';
|
||||
|
||||
const metadata = new ChartMetadata({
|
||||
description: '',
|
||||
name: t('Pivot Table'),
|
||||
thumbnail,
|
||||
useLegacyApi: true,
|
||||
});
|
||||
|
||||
export default class PivotTableChartPlugin extends ChartPlugin {
|
||||
constructor() {
|
||||
super({
|
||||
loadChart: () => import('./ReactPivotTable.js'),
|
||||
metadata,
|
||||
transformProps,
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
export default function transformProps(chartProps) {
|
||||
const { height, datasource, formData, queryData } = chartProps;
|
||||
const { groupby, numberFormat } = formData;
|
||||
const { columnFormats, verboseMap } = datasource;
|
||||
|
||||
return {
|
||||
height,
|
||||
data: queryData.data,
|
||||
columnFormats,
|
||||
numGroups: groupby.length,
|
||||
numberFormat,
|
||||
verboseMap,
|
||||
};
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Fix the height of the table body of a DataTable with scrollY set
|
||||
*/
|
||||
export default function fixTableHeight($tableDom, height) {
|
||||
const headHeight = $tableDom.find('.dataTables_scrollHead').height();
|
||||
const filterHeight = $tableDom.find('.dataTables_filter').height() || 0;
|
||||
const pageLengthHeight = $tableDom.find('.dataTables_length').height() || 0;
|
||||
const paginationHeight = $tableDom.find('.dataTables_paginate').height() || 0;
|
||||
const controlsHeight = pageLengthHeight > filterHeight ? pageLengthHeight : filterHeight;
|
||||
$tableDom
|
||||
.find('.dataTables_scrollBody')
|
||||
.css('max-height', height - headHeight - controlsHeight - paginationHeight);
|
||||
}
|
@ -6900,7 +6900,7 @@ data-urls@^1.1.0:
|
||||
whatwg-mimetype "^2.2.0"
|
||||
whatwg-url "^7.0.0"
|
||||
|
||||
datatables.net-bs@^1.10.20:
|
||||
datatables.net-bs@^1.10.15, datatables.net-bs@^1.10.20:
|
||||
version "1.10.20"
|
||||
resolved "https://registry.yarnpkg.com/datatables.net-bs/-/datatables.net-bs-1.10.20.tgz#4a54a65527013aa8bb98eb7fa27d6231f7dc1bee"
|
||||
integrity sha512-NsMoOOYZ6NlteOpzhltw21lXsNdhjIMbIOxnqmcrb62ntl8eL9pYzk2AeiDXBlIKY4e550ZrExCq3CYKQ9myEg==
|
||||
@ -7180,6 +7180,13 @@ discontinuous-range@1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/discontinuous-range/-/discontinuous-range-1.0.0.tgz#e38331f0844bba49b9a9cb71c771585aab1bc65a"
|
||||
integrity sha1-44Mx8IRLukm5qctxx3FYWqsbxlo=
|
||||
|
||||
distributions@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/distributions/-/distributions-1.1.0.tgz#012973634ef6dd595a525ab1b397d217131c0ea5"
|
||||
integrity sha512-mufW9T1kRlzLVAaekUhgdfcMgX2r/zYQmJx3sGdUAwe0/JSQWey0XgqiDtfUUqYcr/QWHCnBd2M/v45tS/+YAQ==
|
||||
dependencies:
|
||||
mathfn "^1.0.0"
|
||||
|
||||
doctrine@1.5.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa"
|
||||
@ -11557,6 +11564,11 @@ math-expression-evaluator@^1.2.14:
|
||||
resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.22.tgz#c14dcb3d8b4d150e5dcea9c68c8dad80309b0d5e"
|
||||
integrity sha512-L0j0tFVZBQQLeEjmWOvDLoRciIY8gQGWahvkztXUal8jH8R5Rlqo9GCvgqvXcy9LQhEWdQCVvzqAbxgYNt4blQ==
|
||||
|
||||
mathfn@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/mathfn/-/mathfn-1.1.0.tgz#5b88048479508cd693a8131125f621d8b75b8352"
|
||||
integrity sha512-glxPY9PZqaoGUySN1QOVnKfnWH4Az2PnHEYMRVWUnR1RZpWTLNzdCm7RxEiEJ0SJ7G95ruF6Q2/1s/LuQnhXyg==
|
||||
|
||||
md5.js@^1.3.4:
|
||||
version "1.3.5"
|
||||
resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
|
||||
@ -13844,6 +13856,11 @@ react@^16.6.0, react@^16.8.3, react@^16.9.0:
|
||||
object-assign "^4.1.1"
|
||||
prop-types "^15.6.2"
|
||||
|
||||
reactable-arc@0.15.0:
|
||||
version "0.15.0"
|
||||
resolved "https://registry.yarnpkg.com/reactable-arc/-/reactable-arc-0.15.0.tgz#b9e145f58c787227bced894cd9c1611b37c20f3c"
|
||||
integrity sha512-XH1mryI/xvbYb3lCVOU3rx/KRacDE0PDa45KazL/PPTM0AgPZ/awVmCAxRi179BpjbStk7cgCyFjI2oYJ28E8A==
|
||||
|
||||
reactcss@^1.2.0:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/reactcss/-/reactcss-1.2.3.tgz#c00013875e557b1cf0dfd9a368a1c3dab3b548dd"
|
||||
|