buckaroo-js-core 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierrc +16 -0
- package/CHANGELOG.md +23 -0
- package/LICENSE +15 -0
- package/README.md +66 -0
- package/buckaroo_js/baked_data/colorMap.d.ts +3 -0
- package/buckaroo_js/baked_data/colorMap.d.ts.map +1 -0
- package/buckaroo_js/baked_data/colorMap.js +520 -0
- package/buckaroo_js/baked_data/colorMap.js.map +1 -0
- package/buckaroo_js/baked_data/staticData.d.ts +124 -0
- package/buckaroo_js/baked_data/staticData.d.ts.map +1 -0
- package/buckaroo_js/baked_data/staticData.js +459 -0
- package/buckaroo_js/baked_data/staticData.js.map +1 -0
- package/buckaroo_js/components/ColumnsEditor.d.ts +19 -0
- package/buckaroo_js/components/ColumnsEditor.d.ts.map +1 -0
- package/buckaroo_js/components/ColumnsEditor.js +68 -0
- package/buckaroo_js/components/ColumnsEditor.js.map +1 -0
- package/buckaroo_js/components/CommandUtils.d.ts +22 -0
- package/buckaroo_js/components/CommandUtils.d.ts.map +1 -0
- package/buckaroo_js/components/CommandUtils.js +17 -0
- package/buckaroo_js/components/CommandUtils.js.map +1 -0
- package/buckaroo_js/components/DCFCell.d.ts +28 -0
- package/buckaroo_js/components/DCFCell.d.ts.map +1 -0
- package/buckaroo_js/components/DCFCell.js +120 -0
- package/buckaroo_js/components/DCFCell.js.map +1 -0
- package/buckaroo_js/components/DFViewerParts/DFViewer.d.ts +29 -0
- package/buckaroo_js/components/DFViewerParts/DFViewer.d.ts.map +1 -0
- package/buckaroo_js/components/DFViewerParts/DFViewer.js +163 -0
- package/buckaroo_js/components/DFViewerParts/DFViewer.js.map +1 -0
- package/buckaroo_js/components/DFViewerParts/DFWhole.d.ts +111 -0
- package/buckaroo_js/components/DFViewerParts/DFWhole.d.ts.map +1 -0
- package/buckaroo_js/components/DFViewerParts/DFWhole.js +17 -0
- package/buckaroo_js/components/DFViewerParts/DFWhole.js.map +1 -0
- package/buckaroo_js/components/DFViewerParts/Displayer.d.ts +19 -0
- package/buckaroo_js/components/DFViewerParts/Displayer.d.ts.map +1 -0
- package/buckaroo_js/components/DFViewerParts/Displayer.js +221 -0
- package/buckaroo_js/components/DFViewerParts/Displayer.js.map +1 -0
- package/buckaroo_js/components/DFViewerParts/HistogramCell.d.ts +20 -0
- package/buckaroo_js/components/DFViewerParts/HistogramCell.d.ts.map +1 -0
- package/buckaroo_js/components/DFViewerParts/HistogramCell.js +184 -0
- package/buckaroo_js/components/DFViewerParts/HistogramCell.js.map +1 -0
- package/buckaroo_js/components/DFViewerParts/SeriesSummaryTooltip.d.ts +5 -0
- package/buckaroo_js/components/DFViewerParts/SeriesSummaryTooltip.d.ts.map +1 -0
- package/buckaroo_js/components/DFViewerParts/SeriesSummaryTooltip.js +18 -0
- package/buckaroo_js/components/DFViewerParts/SeriesSummaryTooltip.js.map +1 -0
- package/buckaroo_js/components/DFViewerParts/gridUtils.d.ts +24 -0
- package/buckaroo_js/components/DFViewerParts/gridUtils.d.ts.map +1 -0
- package/buckaroo_js/components/DFViewerParts/gridUtils.js +230 -0
- package/buckaroo_js/components/DFViewerParts/gridUtils.js.map +1 -0
- package/buckaroo_js/components/DependentTabs.d.ts +33 -0
- package/buckaroo_js/components/DependentTabs.d.ts.map +1 -0
- package/buckaroo_js/components/DependentTabs.js +108 -0
- package/buckaroo_js/components/DependentTabs.js.map +1 -0
- package/buckaroo_js/components/OperationDetail.d.ts +16 -0
- package/buckaroo_js/components/OperationDetail.d.ts.map +1 -0
- package/buckaroo_js/components/OperationDetail.js +144 -0
- package/buckaroo_js/components/OperationDetail.js.map +1 -0
- package/buckaroo_js/components/OperationUtils.d.ts +17 -0
- package/buckaroo_js/components/OperationUtils.d.ts.map +1 -0
- package/buckaroo_js/components/OperationUtils.js +14 -0
- package/buckaroo_js/components/OperationUtils.js.map +1 -0
- package/buckaroo_js/components/Operations.d.ts +24 -0
- package/buckaroo_js/components/Operations.d.ts.map +1 -0
- package/buckaroo_js/components/Operations.js +209 -0
- package/buckaroo_js/components/Operations.js.map +1 -0
- package/buckaroo_js/components/StatusBar.d.ts +12 -0
- package/buckaroo_js/components/StatusBar.d.ts.map +1 -0
- package/buckaroo_js/components/StatusBar.js +155 -0
- package/buckaroo_js/components/StatusBar.js.map +1 -0
- package/buckaroo_js/components/WidgetTypes.d.ts +25 -0
- package/buckaroo_js/components/WidgetTypes.d.ts.map +1 -0
- package/buckaroo_js/components/WidgetTypes.js +3 -0
- package/buckaroo_js/components/WidgetTypes.js.map +1 -0
- package/buckaroo_js/components/bakedOperationDefaults.d.ts +5 -0
- package/buckaroo_js/components/bakedOperationDefaults.d.ts.map +1 -0
- package/buckaroo_js/components/bakedOperationDefaults.js +15 -0
- package/buckaroo_js/components/bakedOperationDefaults.js.map +1 -0
- package/buckaroo_js/components/utils.d.ts +294 -0
- package/buckaroo_js/components/utils.d.ts.map +1 -0
- package/buckaroo_js/components/utils.js +143 -0
- package/buckaroo_js/components/utils.js.map +1 -0
- package/buckaroo_js/extension.d.ts +2 -0
- package/buckaroo_js/extension.d.ts.map +1 -0
- package/buckaroo_js/extension.js +20 -0
- package/buckaroo_js/extension.js.map +1 -0
- package/buckaroo_js/index.d.ts +25 -0
- package/buckaroo_js/index.d.ts.map +1 -0
- package/buckaroo_js/index.js +46 -0
- package/buckaroo_js/index.js.map +1 -0
- package/buckaroo_js/vendor/RechartExtra.d.ts +38 -0
- package/buckaroo_js/vendor/RechartExtra.d.ts.map +1 -0
- package/buckaroo_js/vendor/RechartExtra.js +17 -0
- package/buckaroo_js/vendor/RechartExtra.js.map +1 -0
- package/buckaroo_js/vendor/RechartTooltip.d.ts +82 -0
- package/buckaroo_js/vendor/RechartTooltip.d.ts.map +1 -0
- package/buckaroo_js/vendor/RechartTooltip.js +232 -0
- package/buckaroo_js/vendor/RechartTooltip.js.map +1 -0
- package/codecov.yml +16 -0
- package/eslint.config.mjs +88 -0
- package/examples/App.tsx +160 -0
- package/examples/CodeBlock.tsx +27 -0
- package/examples/CodePenButton.tsx +77 -0
- package/examples/ReadmeBlock.tsx +11 -0
- package/examples/app.css +29 -0
- package/examples/ex/ColumnsEditorEx.tsx +5 -0
- package/examples/ex/CommandViewerEx.tsx +20 -0
- package/examples/ex/DFViewerEx.tsx +3 -0
- package/examples/ex/DFViewerEx_large.tsx +266 -0
- package/examples/ex/DFViewerEx_real_summary.tsx +20 -0
- package/examples/ex/DFViewerEx_short_data.tsx +22 -0
- package/examples/ex/DFViewerEx_string_index.tsx +1012 -0
- package/examples/ex/HistogramEx.tsx +67 -0
- package/examples/ex/StatusBarEx.tsx +46 -0
- package/examples/ex/WidgetDCFCellEx.tsx +6 -0
- package/examples/example.css +20 -0
- package/examples/index-iframe.hnottml +24 -0
- package/examples/index-react18.tsx +8 -0
- package/examples/index.html +20 -0
- package/examples/jsx-loader.ts +16 -0
- package/examples/tsconfig.json +31 -0
- package/index.d.ts +2 -0
- package/index.d.ts.map +1 -0
- package/index.js +7 -0
- package/index.js.map +1 -0
- package/jest.config.js +24 -0
- package/package.json +117 -0
- package/screen-animation.gif +0 -0
- package/src/buckaroo_js/baked_data/colorMap.ts +523 -0
- package/src/buckaroo_js/baked_data/staticData.ts +503 -0
- package/src/buckaroo_js/components/ColumnsEditor.tsx +66 -0
- package/src/buckaroo_js/components/CommandUtils.ts +40 -0
- package/src/buckaroo_js/components/DCFCell.tsx +175 -0
- package/src/buckaroo_js/components/DFViewerParts/DFViewer.tsx +215 -0
- package/src/buckaroo_js/components/DFViewerParts/DFWhole.ts +190 -0
- package/src/buckaroo_js/components/DFViewerParts/Displayer.ts +215 -0
- package/src/buckaroo_js/components/DFViewerParts/HistogramCell.tsx +251 -0
- package/src/buckaroo_js/components/DFViewerParts/SeriesSummaryTooltip.tsx +20 -0
- package/src/buckaroo_js/components/DFViewerParts/gridUtils.ts +290 -0
- package/src/buckaroo_js/components/DependentTabs.tsx +134 -0
- package/src/buckaroo_js/components/OperationDetail.tsx +203 -0
- package/src/buckaroo_js/components/OperationUtils.ts +33 -0
- package/src/buckaroo_js/components/Operations.tsx +243 -0
- package/src/buckaroo_js/components/StatusBar.tsx +190 -0
- package/src/buckaroo_js/components/WidgetTypes.tsx +42 -0
- package/src/buckaroo_js/components/bakedOperationDefaults.ts +14 -0
- package/src/buckaroo_js/components/utils.ts +60 -0
- package/src/buckaroo_js/extension.ts +15 -0
- package/src/buckaroo_js/index.ts +34 -0
- package/src/buckaroo_js/style/dcf-npm.css +244 -0
- package/src/buckaroo_js/style/icons/arrow-down-short-dark.svg +4 -0
- package/src/buckaroo_js/style/icons/arrow-down-short.svg +4 -0
- package/src/buckaroo_js/style/icons/arrow-up-short-dark.svg +4 -0
- package/src/buckaroo_js/style/icons/arrow-up-short.svg +4 -0
- package/src/buckaroo_js/style/icons/filter-dark.svg +3 -0
- package/src/buckaroo_js/style/icons/filter.svg +3 -0
- package/src/buckaroo_js/vendor/RechartExtra.ts +60 -0
- package/src/buckaroo_js/vendor/RechartTooltip.tsx +357 -0
- package/src/index.tsx +3 -0
- package/tsconfig.json +41 -0
- package/webpack.config.ts +97 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CellClassParams,
|
|
3
|
+
CellRendererSelectorResult,
|
|
4
|
+
ColDef,
|
|
5
|
+
ICellRendererParams
|
|
6
|
+
} from 'ag-grid-community';
|
|
7
|
+
import {BLUE_TO_YELLOW, DIVERGING_RED_WHITE_BLUE} from '../../baked_data/colorMap';
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
DFWhole,
|
|
11
|
+
DisplayerArgs,
|
|
12
|
+
cellRendererDisplayers,
|
|
13
|
+
ColumnConfig,
|
|
14
|
+
ColorMappingConfig,
|
|
15
|
+
ColorMapRules,
|
|
16
|
+
TooltipConfig,
|
|
17
|
+
ColorWhenNotNullRules,
|
|
18
|
+
DFViewerConfig
|
|
19
|
+
} from './DFWhole';
|
|
20
|
+
import _, {zipObject} from 'lodash';
|
|
21
|
+
import {getTextCellRenderer} from './HistogramCell';
|
|
22
|
+
|
|
23
|
+
import {DFData, SDFMeasure, SDFT} from './DFWhole';
|
|
24
|
+
|
|
25
|
+
import {CellRendererArgs, FormatterArgs, PinnedRowConfig} from './DFWhole';
|
|
26
|
+
import {getBakedDFViewer} from './SeriesSummaryTooltip';
|
|
27
|
+
import {getFormatterFromArgs, getCellRenderer, objFormatter, getFormatter} from './Displayer';
|
|
28
|
+
|
|
29
|
+
// for now colDef stuff with less than 3 implementantions should stay in this file
|
|
30
|
+
// as implementations grow large or with many implmentations, they should move to separate files
|
|
31
|
+
// like displayer
|
|
32
|
+
|
|
33
|
+
export function addToColDef(dispArgs: DisplayerArgs, summary_stats_column: SDFMeasure) {
|
|
34
|
+
const formatter = getFormatterFromArgs(dispArgs);
|
|
35
|
+
if (formatter !== undefined) {
|
|
36
|
+
const colDefExtras: ColDef = {valueFormatter: formatter};
|
|
37
|
+
return colDefExtras;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (_.includes(cellRendererDisplayers, dispArgs.displayer)) {
|
|
41
|
+
const crArgs: CellRendererArgs = dispArgs as CellRendererArgs;
|
|
42
|
+
return {
|
|
43
|
+
cellRenderer: getCellRenderer(crArgs)
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function getHistoIndex(val: number, histogram_edges: number[]): number {
|
|
50
|
+
/*
|
|
51
|
+
np.histogram([1, 2, 3, 4, 10, 20, 30, 40, 300, 300, 400, 500], bins=5)
|
|
52
|
+
( [ 8, 0, 2, 1, 1],
|
|
53
|
+
[ 1. , 100.8, 200.6, 300.4, 400.2, 500. ])
|
|
54
|
+
The bottom matters for us, those are the endge
|
|
55
|
+
|
|
56
|
+
this means that 8 values are between 1 and 100.8 and 2 values are between 200.6 and 300.4
|
|
57
|
+
*/
|
|
58
|
+
if (histogram_edges.length === 0) {
|
|
59
|
+
return 0;
|
|
60
|
+
}
|
|
61
|
+
for (let i = 0; i < histogram_edges.length; i++) {
|
|
62
|
+
if (val <= histogram_edges[i]) {
|
|
63
|
+
return i;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return histogram_edges.length;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function colorMap(cmr: ColorMapRules, histogram_edges: number[]) {
|
|
70
|
+
// https://colorcet.com/gallery.html#isoluminant
|
|
71
|
+
// https://github.com/holoviz/colorcet/tree/main/assets/CET
|
|
72
|
+
// https://github.com/bokeh/bokeh/blob/ed285b11ab196e72336b47bf12f44e1bef5abed3/src/bokeh/models/mappers.py#L304
|
|
73
|
+
const maps: Record<string, string[]> = {
|
|
74
|
+
BLUE_TO_YELLOW: BLUE_TO_YELLOW,
|
|
75
|
+
DIVERGING_RED_WHITE_BLUE: DIVERGING_RED_WHITE_BLUE
|
|
76
|
+
};
|
|
77
|
+
const cmap = maps[cmr.map_name];
|
|
78
|
+
|
|
79
|
+
function numberToColor(val: number) {
|
|
80
|
+
const histoIndex = getHistoIndex(val, histogram_edges);
|
|
81
|
+
const scaledIndex = Math.round((histoIndex / histogram_edges.length) * cmap.length);
|
|
82
|
+
return cmap[scaledIndex];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function cellStyle(params: CellClassParams) {
|
|
86
|
+
const val = cmr.val_column ? params.data[cmr.val_column] : params.value;
|
|
87
|
+
const color = numberToColor(val);
|
|
88
|
+
return {
|
|
89
|
+
backgroundColor: color
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const retProps = {
|
|
94
|
+
cellStyle: cellStyle
|
|
95
|
+
};
|
|
96
|
+
return retProps;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function colorNotNull(cmr: ColorWhenNotNullRules) {
|
|
100
|
+
function cellStyle(params: CellClassParams) {
|
|
101
|
+
if (params.data === undefined) {
|
|
102
|
+
return {backgroundColor: 'inherit'};
|
|
103
|
+
}
|
|
104
|
+
const val = params.data[cmr.exist_column];
|
|
105
|
+
const valPresent = val && val !== null;
|
|
106
|
+
const isPinned = params.node.rowPinned;
|
|
107
|
+
const color = valPresent && !isPinned ? cmr.conditional_color : 'inherit';
|
|
108
|
+
return {
|
|
109
|
+
backgroundColor: color
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const retProps = {
|
|
114
|
+
cellStyle: cellStyle
|
|
115
|
+
};
|
|
116
|
+
return retProps;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function getStyler(cmr: ColorMappingConfig, col_name: string, histogram_stats: SDFT) {
|
|
120
|
+
switch (cmr.color_rule) {
|
|
121
|
+
case 'color_map': {
|
|
122
|
+
//block necessary because you cant define varaibles in case blocks
|
|
123
|
+
const statsCol = cmr.val_column || col_name;
|
|
124
|
+
const summary_stats_cell = histogram_stats[statsCol];
|
|
125
|
+
|
|
126
|
+
if (summary_stats_cell && summary_stats_cell.histogram_bins !== undefined) {
|
|
127
|
+
return colorMap(cmr, summary_stats_cell.histogram_bins);
|
|
128
|
+
} else {
|
|
129
|
+
console.log('histogram bins not found for color_map');
|
|
130
|
+
return {};
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
case 'color_not_null':
|
|
134
|
+
return colorNotNull(cmr);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function extractPinnedRows(sdf: DFData, prc: PinnedRowConfig[]) {
|
|
139
|
+
return _.map(_.map(prc, 'primary_key_val'), (x) => _.find(sdf, {index: x}));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function getTooltip(ttc: TooltipConfig, single_series_summary_df: DFWhole): Partial<ColDef> {
|
|
143
|
+
switch (ttc.tooltip_type) {
|
|
144
|
+
case 'simple':
|
|
145
|
+
return {tooltipField: ttc.val_column};
|
|
146
|
+
|
|
147
|
+
case 'summary_series':
|
|
148
|
+
return {
|
|
149
|
+
tooltipComponent: getBakedDFViewer(single_series_summary_df),
|
|
150
|
+
tooltipField: 'index',
|
|
151
|
+
tooltipComponentParams: {}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function extractSingleSeriesSummary(
|
|
157
|
+
full_summary_stats_df: DFData,
|
|
158
|
+
col_name: string
|
|
159
|
+
): DFWhole {
|
|
160
|
+
return {
|
|
161
|
+
dfviewer_config: {
|
|
162
|
+
column_config: [
|
|
163
|
+
{col_name: 'index', displayer_args: {displayer: 'obj'}},
|
|
164
|
+
{col_name: col_name, displayer_args: {displayer: 'obj'}}
|
|
165
|
+
],
|
|
166
|
+
pinned_rows: []
|
|
167
|
+
},
|
|
168
|
+
data: _.filter(
|
|
169
|
+
_.map(full_summary_stats_df, (row) => _.pick(row, ['index', col_name])),
|
|
170
|
+
{index: 'dtype'}
|
|
171
|
+
)
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export function dfToAgrid(
|
|
176
|
+
tdf: DFData,
|
|
177
|
+
dfviewer_config: DFViewerConfig,
|
|
178
|
+
full_summary_stats_df: DFData
|
|
179
|
+
): [ColDef[], unknown[]] {
|
|
180
|
+
//more convienient df format for some formatters
|
|
181
|
+
const hdf = extractSDFT(full_summary_stats_df || []);
|
|
182
|
+
|
|
183
|
+
const retColumns: ColDef[] = dfviewer_config.column_config.map((f: ColumnConfig) => {
|
|
184
|
+
const single_series_summary_df = extractSingleSeriesSummary(
|
|
185
|
+
full_summary_stats_df,
|
|
186
|
+
f.col_name
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
const color_map_config = f.color_map_config
|
|
190
|
+
? getStyler(f.color_map_config, f.col_name, hdf)
|
|
191
|
+
: {};
|
|
192
|
+
|
|
193
|
+
const tooltip_config = f.tooltip_config
|
|
194
|
+
? getTooltip(f.tooltip_config, single_series_summary_df)
|
|
195
|
+
: {};
|
|
196
|
+
const colDef: ColDef = {
|
|
197
|
+
field: f.col_name,
|
|
198
|
+
headerName: f.col_name,
|
|
199
|
+
cellDataType: false,
|
|
200
|
+
cellStyle: {}, // necessary for colormapped columns to have a default
|
|
201
|
+
...addToColDef(f.displayer_args, hdf[f.col_name]),
|
|
202
|
+
...color_map_config,
|
|
203
|
+
...tooltip_config,
|
|
204
|
+
...f.ag_grid_specs
|
|
205
|
+
};
|
|
206
|
+
return colDef;
|
|
207
|
+
});
|
|
208
|
+
return [retColumns, tdf];
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// this is very similar to the colDef parts of dfToAgrid
|
|
212
|
+
export function getCellRendererSelector(pinned_rows: PinnedRowConfig[]) {
|
|
213
|
+
const anyRenderer: CellRendererSelectorResult = {
|
|
214
|
+
component: getTextCellRenderer(objFormatter)
|
|
215
|
+
};
|
|
216
|
+
return (params: ICellRendererParams<any, any, any>): CellRendererSelectorResult | undefined => {
|
|
217
|
+
if (params.node.rowPinned) {
|
|
218
|
+
const pk = _.get(params.node.data, 'index');
|
|
219
|
+
if (pk === undefined) {
|
|
220
|
+
return anyRenderer; // default renderer
|
|
221
|
+
}
|
|
222
|
+
const maybePrc: PinnedRowConfig | undefined = _.find(pinned_rows, {
|
|
223
|
+
primary_key_val: pk
|
|
224
|
+
});
|
|
225
|
+
if (maybePrc === undefined) {
|
|
226
|
+
return anyRenderer;
|
|
227
|
+
}
|
|
228
|
+
const prc: PinnedRowConfig = maybePrc;
|
|
229
|
+
console.log('params', params);
|
|
230
|
+
const currentCol = params.column?.getColId();
|
|
231
|
+
if (
|
|
232
|
+
(prc.default_renderer_columns === undefined && currentCol === 'index') ||
|
|
233
|
+
_.includes(prc.default_renderer_columns, currentCol)
|
|
234
|
+
) {
|
|
235
|
+
return anyRenderer;
|
|
236
|
+
}
|
|
237
|
+
const possibCellRenderer = getCellRenderer(prc.displayer_args as CellRendererArgs);
|
|
238
|
+
|
|
239
|
+
if (possibCellRenderer === undefined) {
|
|
240
|
+
const formattedRenderer: CellRendererSelectorResult = {
|
|
241
|
+
component: getTextCellRenderer(
|
|
242
|
+
getFormatter(prc.displayer_args as FormatterArgs)
|
|
243
|
+
)
|
|
244
|
+
};
|
|
245
|
+
return formattedRenderer;
|
|
246
|
+
}
|
|
247
|
+
return {component: possibCellRenderer};
|
|
248
|
+
} else {
|
|
249
|
+
return undefined; // rows that are not pinned don't use a row level cell renderer
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export function extractSDFT(summaryStatsDf: DFData): SDFT {
|
|
255
|
+
const maybeHistogramBins = _.find(summaryStatsDf, {index: 'histogram_bins'}) || {};
|
|
256
|
+
const maybeHistogramLogBins = _.find(summaryStatsDf, {index: 'histogram_log_bins'}) || {};
|
|
257
|
+
const allColumns: string[] = _.without(
|
|
258
|
+
_.union(_.keys(maybeHistogramBins), _.keys(maybeHistogramLogBins)),
|
|
259
|
+
'index'
|
|
260
|
+
);
|
|
261
|
+
const vals: SDFMeasure[] = _.map(allColumns, (colName) => {
|
|
262
|
+
return {
|
|
263
|
+
histogram_bins: _.get(maybeHistogramBins, colName, []) as number[],
|
|
264
|
+
histogram_log_bins: _.get(maybeHistogramLogBins, colName, []) as number[]
|
|
265
|
+
};
|
|
266
|
+
});
|
|
267
|
+
return zipObject(allColumns, vals) as SDFT;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/*
|
|
271
|
+
I would love for extractSDF to be more elegant like the following function. I just can't quite get it to work
|
|
272
|
+
time to move on
|
|
273
|
+
|
|
274
|
+
export function extractSDFT2(summaryStatsDf:DFData) : SDFT {
|
|
275
|
+
const rows = ['histogram_bins', 'histogram_log_bins']
|
|
276
|
+
|
|
277
|
+
const extracted = _.map(rows, (pk) => {
|
|
278
|
+
return _.find(summaryStatsDf, {'index': pk}) || {}
|
|
279
|
+
})
|
|
280
|
+
const dupKeys: string[][] = _.map(extracted, _.keys);
|
|
281
|
+
const allColumns: string[] = _.without(_.union(...dupKeys), 'index');
|
|
282
|
+
const vals:SDFMeasure[] = _.map(allColumns, (colName) => {
|
|
283
|
+
const pairs = _.map(_.zip(rows, extracted), (rname, row) => {
|
|
284
|
+
return [rname, (_.get(row, colName, []) as number[])];
|
|
285
|
+
})
|
|
286
|
+
return _.fromPairs(pairs) as SDFMeasure;
|
|
287
|
+
});
|
|
288
|
+
return zipObject(allColumns, vals) as SDFT;
|
|
289
|
+
}
|
|
290
|
+
*/
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import React, {useState, CSSProperties, Dispatch, SetStateAction} from 'react';
|
|
2
|
+
import {DFWhole, EmptyDf} from './DFViewerParts/DFWhole';
|
|
3
|
+
import _ from 'lodash';
|
|
4
|
+
import {Operation} from './OperationUtils';
|
|
5
|
+
|
|
6
|
+
export function OperationDisplayer({
|
|
7
|
+
filledOperations,
|
|
8
|
+
style
|
|
9
|
+
}: {
|
|
10
|
+
filledOperations: Operation[];
|
|
11
|
+
style: CSSProperties;
|
|
12
|
+
}): React.JSX.Element {
|
|
13
|
+
const baseStyle: CSSProperties = {margin: '0', textAlign: 'left'};
|
|
14
|
+
const localStyle: CSSProperties = {...baseStyle, ...style};
|
|
15
|
+
return (
|
|
16
|
+
<div className='command-displayer' style={{width: '100%'}}>
|
|
17
|
+
<pre style={localStyle}>{JSON.stringify(filledOperations)}</pre>
|
|
18
|
+
</div>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function PythonDisplayer({
|
|
23
|
+
style,
|
|
24
|
+
generatedPyCode
|
|
25
|
+
}: {
|
|
26
|
+
style: CSSProperties;
|
|
27
|
+
generatedPyCode: string;
|
|
28
|
+
}) {
|
|
29
|
+
const baseStyle: CSSProperties = {margin: '0', textAlign: 'left'};
|
|
30
|
+
const localStyle: CSSProperties = {...baseStyle, ...style};
|
|
31
|
+
return (
|
|
32
|
+
<div className='python-displayer' style={{width: '100%'}}>
|
|
33
|
+
<pre style={localStyle}>{generatedPyCode}</pre>
|
|
34
|
+
</div>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function TransformViewer({
|
|
39
|
+
style,
|
|
40
|
+
transformedDf
|
|
41
|
+
}: {
|
|
42
|
+
style: CSSProperties;
|
|
43
|
+
transformedDf: DFWhole;
|
|
44
|
+
}) {
|
|
45
|
+
return <div className='transform-viewer'>"transformed view"</div>;
|
|
46
|
+
}
|
|
47
|
+
export type OperationResult = {
|
|
48
|
+
transformed_df: DFWhole;
|
|
49
|
+
generated_py_code: string;
|
|
50
|
+
transform_error?: string;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export type OrRequesterT = (ops: Operation[]) => void;
|
|
54
|
+
export type getOperationResultSetterT = (
|
|
55
|
+
setter: Dispatch<SetStateAction<OperationResult>>
|
|
56
|
+
) => OrRequesterT;
|
|
57
|
+
|
|
58
|
+
export const baseOperationResults: OperationResult = {
|
|
59
|
+
transformed_df: EmptyDf,
|
|
60
|
+
generated_py_code: 'default py code'
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export function TabComponent({
|
|
64
|
+
currentTab,
|
|
65
|
+
_setTab,
|
|
66
|
+
tabName
|
|
67
|
+
}: {
|
|
68
|
+
currentTab: any;
|
|
69
|
+
_setTab: any;
|
|
70
|
+
tabName: any;
|
|
71
|
+
}): JSX.Element {
|
|
72
|
+
return (
|
|
73
|
+
<li
|
|
74
|
+
onClick={() => {
|
|
75
|
+
_setTab(tabName);
|
|
76
|
+
}}
|
|
77
|
+
className={currentTab === tabName ? 'active' : ''}
|
|
78
|
+
>
|
|
79
|
+
{tabName}
|
|
80
|
+
</li>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function DependentTabs({
|
|
85
|
+
filledOperations,
|
|
86
|
+
operationResult
|
|
87
|
+
}: {
|
|
88
|
+
filledOperations: Operation[];
|
|
89
|
+
operationResult: OperationResult;
|
|
90
|
+
}) {
|
|
91
|
+
const [tab, _setTab] = useState('DataFrame');
|
|
92
|
+
const style: CSSProperties = {height: '45vh'};
|
|
93
|
+
return (
|
|
94
|
+
<div className='dependent-tabs' style={{width: '100%'}}>
|
|
95
|
+
<ul className='tabs'>
|
|
96
|
+
<TabComponent currentTab={tab} _setTab={_setTab} tabName={'DataFrame'} />
|
|
97
|
+
<TabComponent currentTab={tab} _setTab={_setTab} tabName={'Python'} />
|
|
98
|
+
<TabComponent currentTab={tab} _setTab={_setTab} tabName={'Operations'} />
|
|
99
|
+
</ul>
|
|
100
|
+
<div className='output-area'>
|
|
101
|
+
{operationResult.transform_error ? (
|
|
102
|
+
<div>
|
|
103
|
+
<h2> error </h2>
|
|
104
|
+
<PythonDisplayer
|
|
105
|
+
style={style}
|
|
106
|
+
generatedPyCode={operationResult.transform_error}
|
|
107
|
+
/>
|
|
108
|
+
</div>
|
|
109
|
+
) : (
|
|
110
|
+
<span></span>
|
|
111
|
+
)}
|
|
112
|
+
{
|
|
113
|
+
{
|
|
114
|
+
Operations: (
|
|
115
|
+
<OperationDisplayer style={style} filledOperations={filledOperations} />
|
|
116
|
+
),
|
|
117
|
+
Python: (
|
|
118
|
+
<PythonDisplayer
|
|
119
|
+
style={style}
|
|
120
|
+
generatedPyCode={operationResult.generated_py_code}
|
|
121
|
+
/>
|
|
122
|
+
),
|
|
123
|
+
DataFrame: (
|
|
124
|
+
<TransformViewer
|
|
125
|
+
style={style}
|
|
126
|
+
transformedDf={operationResult.transformed_df}
|
|
127
|
+
/>
|
|
128
|
+
)
|
|
129
|
+
}[tab]
|
|
130
|
+
}
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
);
|
|
134
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import {Operation, SettableArg, OperationEventFunc} from './OperationUtils';
|
|
3
|
+
import {ActualArg, CommandArgSpec} from './CommandUtils';
|
|
4
|
+
import {objWithoutNull, replaceAtIdx, replaceAtKey} from './utils';
|
|
5
|
+
import React from 'react';
|
|
6
|
+
|
|
7
|
+
export const OperationDetail = ({
|
|
8
|
+
command,
|
|
9
|
+
setCommand,
|
|
10
|
+
columns,
|
|
11
|
+
commandPatterns
|
|
12
|
+
}: {
|
|
13
|
+
command: Operation;
|
|
14
|
+
setCommand: OperationEventFunc;
|
|
15
|
+
columns: string[];
|
|
16
|
+
commandPatterns: CommandArgSpec;
|
|
17
|
+
}) => {
|
|
18
|
+
if (command === undefined) {
|
|
19
|
+
return <span></span>;
|
|
20
|
+
}
|
|
21
|
+
const commandName = command[0]['symbol'];
|
|
22
|
+
const pattern = commandPatterns[commandName];
|
|
23
|
+
|
|
24
|
+
if (!_.isArray(pattern)) {
|
|
25
|
+
//we shouldn't get here
|
|
26
|
+
return <h2>unknown command {commandName}</h2>;
|
|
27
|
+
} else if (_.isEqual(pattern, [null])) {
|
|
28
|
+
return <div className='operation-detail'></div>;
|
|
29
|
+
} else {
|
|
30
|
+
const fullPattern = pattern as ActualArg[];
|
|
31
|
+
return (
|
|
32
|
+
<div className='operation-detail'>
|
|
33
|
+
<ArgGetters
|
|
34
|
+
command={command}
|
|
35
|
+
fullPattern={fullPattern}
|
|
36
|
+
setCommand={setCommand}
|
|
37
|
+
columns={columns}
|
|
38
|
+
/>
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
return <h2></h2>;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const ArgGetters = ({
|
|
46
|
+
command,
|
|
47
|
+
fullPattern,
|
|
48
|
+
setCommand,
|
|
49
|
+
columns
|
|
50
|
+
}: {
|
|
51
|
+
command: Operation;
|
|
52
|
+
fullPattern: ActualArg[];
|
|
53
|
+
setCommand: OperationEventFunc;
|
|
54
|
+
columns: string[];
|
|
55
|
+
}) => {
|
|
56
|
+
/* reads the argspec and sets up the proper getters/setters */
|
|
57
|
+
const makeArgGetter = (pattern: ActualArg) => {
|
|
58
|
+
const idx = pattern[0];
|
|
59
|
+
const val = command[idx] as SettableArg;
|
|
60
|
+
const valSetter = (newVal: unknown) => {
|
|
61
|
+
const newCommand = replaceAtIdx(command, idx, newVal);
|
|
62
|
+
//console.log('newCommand', newCommand);
|
|
63
|
+
setCommand(newCommand as Operation);
|
|
64
|
+
};
|
|
65
|
+
return (
|
|
66
|
+
<div key={idx}>
|
|
67
|
+
<ArgGetter
|
|
68
|
+
argProps={pattern}
|
|
69
|
+
renderKey={idx}
|
|
70
|
+
val={val}
|
|
71
|
+
setter={valSetter}
|
|
72
|
+
columns={columns}
|
|
73
|
+
/>
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
};
|
|
77
|
+
return <div className='arg-getters'>{fullPattern.map(makeArgGetter)}</div>;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const ArgGetter = ({
|
|
81
|
+
argProps,
|
|
82
|
+
val,
|
|
83
|
+
setter,
|
|
84
|
+
columns,
|
|
85
|
+
renderKey
|
|
86
|
+
}: {
|
|
87
|
+
argProps: ActualArg;
|
|
88
|
+
val: SettableArg;
|
|
89
|
+
setter: (arg: SettableArg) => void;
|
|
90
|
+
columns: string[];
|
|
91
|
+
renderKey: number;
|
|
92
|
+
}) => {
|
|
93
|
+
const [_argPos, label, argType, lastArg] = argProps;
|
|
94
|
+
|
|
95
|
+
const defaultShim = (event: {target: {value: SettableArg}}) => setter(event.target.value);
|
|
96
|
+
if (argType === 'enum' && _.isArray(lastArg)) {
|
|
97
|
+
return (
|
|
98
|
+
<fieldset key={renderKey}>
|
|
99
|
+
<label> {label} </label>
|
|
100
|
+
<select defaultValue={val as string} onChange={defaultShim}>
|
|
101
|
+
{lastArg.map((optionVal) => (
|
|
102
|
+
<option key={optionVal} value={optionVal}>
|
|
103
|
+
{optionVal}
|
|
104
|
+
</option>
|
|
105
|
+
))}
|
|
106
|
+
</select>
|
|
107
|
+
</fieldset>
|
|
108
|
+
);
|
|
109
|
+
} else if (argType === 'type') {
|
|
110
|
+
if (lastArg === 'integer') {
|
|
111
|
+
const valSetterShim = (event: {target: {value: string}}) =>
|
|
112
|
+
setter(parseInt(event.target.value));
|
|
113
|
+
return (
|
|
114
|
+
<fieldset key={renderKey}>
|
|
115
|
+
<label> {label} </label>
|
|
116
|
+
<input
|
|
117
|
+
type='number'
|
|
118
|
+
defaultValue={val as number}
|
|
119
|
+
step='1'
|
|
120
|
+
onChange={valSetterShim}
|
|
121
|
+
/>
|
|
122
|
+
</fieldset>
|
|
123
|
+
);
|
|
124
|
+
} else if (lastArg === 'float') {
|
|
125
|
+
const valSetterShim = (event: {target: {value: string}}) =>
|
|
126
|
+
setter(parseFloat(event.target.value));
|
|
127
|
+
return (
|
|
128
|
+
<fieldset key={renderKey}>
|
|
129
|
+
<label> {label} </label>
|
|
130
|
+
<input
|
|
131
|
+
type='number'
|
|
132
|
+
step='0.01'
|
|
133
|
+
defaultValue={val as number}
|
|
134
|
+
onChange={valSetterShim}
|
|
135
|
+
/>
|
|
136
|
+
</fieldset>
|
|
137
|
+
);
|
|
138
|
+
} else if (lastArg === 'string') {
|
|
139
|
+
const valSetterShim = (event: {target: {value: string}}) => setter(event.target.value);
|
|
140
|
+
return (
|
|
141
|
+
<fieldset key={renderKey}>
|
|
142
|
+
<label> {label} </label>
|
|
143
|
+
<input type='text' defaultValue={val as string} onChange={valSetterShim} />
|
|
144
|
+
</fieldset>
|
|
145
|
+
);
|
|
146
|
+
} else {
|
|
147
|
+
return (
|
|
148
|
+
<fieldset key={renderKey}>
|
|
149
|
+
<label> {label} </label>
|
|
150
|
+
<input value='dont know' />
|
|
151
|
+
</fieldset>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
} else if (argType === 'colEnum') {
|
|
155
|
+
const widgetRow = columns.map((colName: string) => {
|
|
156
|
+
const colSetter = (event: {target: {value: any}}) => {
|
|
157
|
+
const newColVal = event.target.value;
|
|
158
|
+
if (_.isString(newColVal)) {
|
|
159
|
+
const updatedColDict = replaceAtKey(
|
|
160
|
+
val as Record<string, string>,
|
|
161
|
+
colName,
|
|
162
|
+
newColVal as string
|
|
163
|
+
); // as Record<string, string>
|
|
164
|
+
setter(objWithoutNull(updatedColDict, ['null']));
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
const colVal = _.get(val, colName, 'null');
|
|
168
|
+
if (!_.isArray(lastArg)) {
|
|
169
|
+
return <h3> arg error</h3>;
|
|
170
|
+
}
|
|
171
|
+
return (
|
|
172
|
+
<td key={renderKey + colName}>
|
|
173
|
+
<select defaultValue={colVal} onChange={colSetter}>
|
|
174
|
+
{lastArg.map((optionVal) => (
|
|
175
|
+
<option key={optionVal} value={optionVal}>
|
|
176
|
+
{optionVal}
|
|
177
|
+
</option>
|
|
178
|
+
))}
|
|
179
|
+
</select>
|
|
180
|
+
</td>
|
|
181
|
+
);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
return (
|
|
185
|
+
<div className='col-enum' key={renderKey}>
|
|
186
|
+
<table>
|
|
187
|
+
<thead>
|
|
188
|
+
<tr>
|
|
189
|
+
{columns.map((colName) => (
|
|
190
|
+
<th key={colName}>{colName}</th>
|
|
191
|
+
))}
|
|
192
|
+
</tr>
|
|
193
|
+
</thead>
|
|
194
|
+
<tbody>
|
|
195
|
+
<tr>{widgetRow}</tr>
|
|
196
|
+
</tbody>
|
|
197
|
+
</table>
|
|
198
|
+
</div>
|
|
199
|
+
);
|
|
200
|
+
} else {
|
|
201
|
+
return <h3> unknown argtype </h3>;
|
|
202
|
+
}
|
|
203
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/*
|
|
2
|
+
used for manipulating the JSON Flavored lisp of operations and commands
|
|
3
|
+
*/
|
|
4
|
+
import _ from 'lodash';
|
|
5
|
+
import {SymbolT, ColEnumArgs, SymbolDf, symDf} from './CommandUtils';
|
|
6
|
+
|
|
7
|
+
export const sym = (symbolName: string) => {
|
|
8
|
+
return {symbol: symbolName};
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type Atom = number | string | SymbolT | ColEnumArgs;
|
|
12
|
+
export type SettableArg = number | string | ColEnumArgs;
|
|
13
|
+
|
|
14
|
+
export type OperationSingleColumn = [SymbolT, SymbolDf, string];
|
|
15
|
+
export type OperationSingleArg = [SymbolT, SymbolDf, string, Atom];
|
|
16
|
+
export type OperationTwoArg = [SymbolT, SymbolDf, string, Atom, Atom];
|
|
17
|
+
export type Operation = OperationSingleColumn | OperationSingleArg | OperationTwoArg;
|
|
18
|
+
|
|
19
|
+
export type SetOperationFunc = (newCommand: Operation) => void;
|
|
20
|
+
export type SetOperationsFunc = (newCommands: Operation[]) => void;
|
|
21
|
+
|
|
22
|
+
export type OperationDefaultArgs = Record<string, Operation>;
|
|
23
|
+
|
|
24
|
+
//const ArgNames = ['Idx', 'label', 'specName', 'extraSpecArgs'];
|
|
25
|
+
export const bakedOperations: Operation[] = [
|
|
26
|
+
[sym('dropcol'), symDf, 'col1'],
|
|
27
|
+
[sym('fillna'), symDf, 'col2', 5],
|
|
28
|
+
[sym('resample'), symDf, 'month', 'monthly', {}]
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
//this will become OperationEventFunc
|
|
32
|
+
export type OperationEventFunc = (newCommand: Operation) => void;
|
|
33
|
+
export type NoArgEventFunc = () => void;
|