Merge pull request #368 from apache-superset/kristw--migrate-pivot

feat: migrate 4 chart plugins
This commit is contained in:
Krist Wongsuphasawat 2020-04-16 12:34:30 -07:00 committed by Yongjie Zhao
parent f2cf0a2a7f
commit 89c2203704
48 changed files with 5423 additions and 1 deletions

View File

@ -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",

View File

@ -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,
}}
/>
);

View File

@ -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,
},
],
},
],
};

View File

@ -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,
}}
/>
);

View File

@ -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,
},
];

View File

@ -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',
}}
/>
);

View File

@ -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: [],
},
],
},
],
},
];

View File

@ -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',
}}
/>
);

View File

@ -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: {...},
}}
/>
```

View File

@ -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"
}
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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,
});
}
}

View File

@ -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),
};
}

View File

@ -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: {...},
}}
/>
```

View File

@ -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"
}
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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,
});
}
}

View File

@ -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,
};
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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: {...},
}}
/>
```

View File

@ -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"
}
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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,
});
}
}

View File

@ -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,
};
}

View File

@ -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: {...},
}}
/>
```

View File

@ -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"
}
}

View File

@ -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;

View File

@ -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);

View File

@ -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,
});
}
}

View File

@ -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,
};
}

View File

@ -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);
}

View File

@ -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"