Skip to content

Commit a8c83fc

Browse files
committed
wip working on performance fix
1 parent 757726f commit a8c83fc

File tree

12 files changed

+264
-570
lines changed

12 files changed

+264
-570
lines changed

local_server.bat

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,5 @@
66
:: set http_proxy=http://127.0.0.1:7890
77
:: set https_proxy=http://127.0.0.1:7890
88

9-
set FLASK_APP=py-src/data_formulator/app.py
109
set FLASK_RUN_PORT=5000
11-
set FLASK_RUN_HOST=0.0.0.0
12-
flask run
10+
python -m py-src.data_formulator.app --port %FLASK_RUN_PORT% --dev

py-src/data_formulator/app.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,9 @@ def run_app():
274274
url = "http://localhost:{0}".format(args.port)
275275
threading.Timer(2, lambda: webbrowser.open(url, new=2)).start()
276276

277-
app.run(host='0.0.0.0', port=args.port, threaded=True)
277+
# Enable debug mode and auto-reload in development mode
278+
debug_mode = args.dev
279+
app.run(host='0.0.0.0', port=args.port, threaded=True, debug=debug_mode, use_reloader=debug_mode)
278280

279281
if __name__ == '__main__':
280282
#app.run(debug=True, host='127.0.0.1', port=5000)

src/app/dfSlice.tsx

Lines changed: 30 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4-
import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit'
4+
import { createAsyncThunk, createSlice, PayloadAction, createSelector } from '@reduxjs/toolkit'
55
import { Channel, Chart, ChartTemplate, EncodingItem, EncodingMap, FieldItem, Trigger } from '../components/ComponentType'
66
import { enableMapSet } from 'immer';
77
import { DictTable } from "../components/ComponentType";
@@ -16,14 +16,15 @@ import { handleSSEMessage } from './SSEActions';
1616

1717
enableMapSet();
1818

19-
export const generateFreshChart = (tableRef: string, chartType?: string) : Chart => {
19+
export const generateFreshChart = (tableRef: string, chartType?: string, source: "user" | "trigger" = "user") : Chart => {
2020
let realChartType = chartType || "?"
2121
return {
2222
id: `chart-${Date.now()- Math.floor(Math.random() * 10000)}`,
2323
chartType: realChartType,
2424
encodingMap: Object.assign({}, ...getChartChannels(realChartType).map((channel) => ({ [channel]: { channel: channel, bin: false } }))),
2525
tableRef: tableRef,
26-
saved: false
26+
saved: false,
27+
source: source,
2728
}
2829
}
2930

@@ -69,7 +70,6 @@ export interface DataFormulatorState {
6970

7071
focusedTableId: string | undefined;
7172
focusedChartId: string | undefined;
72-
activeThreadChartId: string | undefined; // specifying which chartThread is actively viewed
7373

7474
chartSynthesisInProgress: string[];
7575

@@ -111,7 +111,6 @@ const initialState: DataFormulatorState = {
111111

112112
focusedTableId: undefined,
113113
focusedChartId: undefined,
114-
activeThreadChartId: undefined,
115114

116115
chartSynthesisInProgress: [],
117116

@@ -128,27 +127,20 @@ const initialState: DataFormulatorState = {
128127
}
129128

130129
let getUnrefedDerivedTableIds = (state: DataFormulatorState) => {
131-
132130
// find tables directly referred by charts
133-
let chartRefedTables = state.charts.map(chart => getDataTable(chart, state.tables, state.charts, state.conceptShelfItems));
134-
135-
// find tables referred via triggers
136-
let triggerRefedTableIds = chartRefedTables.filter(t => t.derive != undefined).map(t => t.derive?.trigger as Trigger);
131+
let allCharts = dfSelectors.getAllCharts(state);
132+
let chartRefedTables = allCharts.map(chart => getDataTable(chart, state.tables, allCharts, state.conceptShelfItems)).map(t => t.id);
137133

138-
let allRefedTableIds = [...chartRefedTables.map(t => t.id), ...triggerRefedTableIds];
139-
140-
return state.tables.filter(table => table.derive && !allRefedTableIds.includes(table.id)).map(t => t.id);
134+
return state.tables.filter(table => table.derive && !chartRefedTables.includes(table.id)).map(t => t.id);
141135
}
142136

143137
let deleteChartsRoutine = (state: DataFormulatorState, chartIds: string[]) => {
144138
let charts = state.charts.filter(c => !chartIds.includes(c.id));
145139
let focusedChartId = state.focusedChartId;
146-
let activeThreadChartId = state.activeThreadChartId;
147140

148141
if (focusedChartId && chartIds.includes(focusedChartId)) {
149-
let leafCharts = charts.filter(c => c.intermediate == undefined);
142+
let leafCharts = charts;
150143
focusedChartId = leafCharts.length > 0 ? leafCharts[0].id : undefined;
151-
activeThreadChartId = focusedChartId;
152144

153145
state.focusedTableId = charts.find(c => c.id == focusedChartId)?.tableRef;
154146
}
@@ -157,14 +149,10 @@ let deleteChartsRoutine = (state: DataFormulatorState, chartIds: string[]) => {
157149
// update focusedChart and activeThreadChart
158150
state.charts = charts;
159151
state.focusedChartId = focusedChartId;
160-
state.activeThreadChartId = activeThreadChartId;
161152

162153
let unrefedDerivedTableIds = getUnrefedDerivedTableIds(state);
163154
let tableIdsToDelete = state.tables.filter(t => !t.anchored && unrefedDerivedTableIds.includes(t.id)).map(t => t.id);
164-
165155
state.tables = state.tables.filter(t => !tableIdsToDelete.includes(t.id));
166-
// remove intermediate charts that lead to this table
167-
state.charts = state.charts.filter(c => !(c.intermediate && tableIdsToDelete.includes(c.intermediate.resultTableId)));
168156
}
169157

170158
export const fetchFieldSemanticType = createAsyncThunk(
@@ -289,7 +277,6 @@ export const dataFormulatorSlice = createSlice({
289277

290278
state.focusedTableId = undefined;
291279
state.focusedChartId = undefined;
292-
state.activeThreadChartId = undefined;
293280

294281
state.chartSynthesisInProgress = [];
295282

@@ -318,7 +305,6 @@ export const dataFormulatorSlice = createSlice({
318305

319306
state.focusedTableId = savedState.focusedTableId || undefined;
320307
state.focusedChartId = savedState.focusedChartId || undefined;
321-
state.activeThreadChartId = savedState.activeThreadChartId || undefined;
322308

323309
state.chartSynthesisInProgress = [];
324310

@@ -360,7 +346,6 @@ export const dataFormulatorSlice = createSlice({
360346

361347
state.focusedTableId = table.id;
362348
state.focusedChartId = undefined;
363-
state.activeThreadChartId = undefined;
364349
},
365350
deleteTable: (state, action: PayloadAction<string>) => {
366351
let tableId = action.payload;
@@ -372,9 +357,6 @@ export const dataFormulatorSlice = createSlice({
372357
// delete charts that refer to this table and intermediate charts that produce this table
373358
let chartIdsToDelete = state.charts.filter(c => c.tableRef == tableId).map(c => c.id);
374359
deleteChartsRoutine(state, chartIdsToDelete);
375-
376-
// separate this, so that we only delete on tier of table a time
377-
state.charts = state.charts.filter(c => !(c.intermediate && c.intermediate.resultTableId == tableId));
378360
},
379361
updateTableAnchored: (state, action: PayloadAction<{tableId: string, anchored: boolean}>) => {
380362
let tableId = action.payload.tableId;
@@ -456,15 +438,15 @@ export const dataFormulatorSlice = createSlice({
456438
createNewChart: (state, action: PayloadAction<{chartType?: string, tableId?: string}>) => {
457439
let chartType = action.payload.chartType;
458440
let tableId = action.payload.tableId || state.tables[0].id;
459-
let freshChart = generateFreshChart(tableId, chartType) as Chart;
441+
let freshChart = generateFreshChart(tableId, chartType, "user") as Chart;
460442
state.charts = [ freshChart , ...state.charts];
461443
state.focusedTableId = tableId;
462444
state.focusedChartId = freshChart.id;
463-
state.activeThreadChartId = freshChart.id;
464445
},
465-
addChart: (state, action: PayloadAction<Chart>) => {
446+
addAndFocusChart: (state, action: PayloadAction<Chart>) => {
466447
let chart = action.payload;
467-
state.charts = [chart, ...state.charts]
448+
state.charts = [chart, ...state.charts];
449+
state.focusedChartId = chart.id;
468450
},
469451
duplicateChart: (state, action: PayloadAction<string>) => {
470452
let chartId = action.payload;
@@ -516,7 +498,8 @@ export const dataFormulatorSlice = createSlice({
516498
let chartId = action.payload.chartId;
517499
let chart = state.charts.find(c => c.id == chartId) as Chart;
518500
let table = action.payload.table;
519-
let currentTableRef = getDataTable(chart, state.tables, state.charts, state.conceptShelfItems).id;
501+
let allCharts = dfSelectors.getAllCharts(state);
502+
let currentTableRef = getDataTable(chart, state.tables, allCharts, state.conceptShelfItems).id;
520503
state.charts = state.charts.map(c => {
521504
if (c.id == chartId) {
522505
return { ...c, tableRef: table.id }
@@ -525,7 +508,7 @@ export const dataFormulatorSlice = createSlice({
525508
}
526509
})
527510

528-
if (!state.charts.some(c => c.id != chartId && getDataTable(c, state.tables, state.charts, state.conceptShelfItems).id == currentTableRef)) {
511+
if (!state.charts.some(c => c.id != chartId && getDataTable(c, state.tables, allCharts, state.conceptShelfItems).id == currentTableRef)) {
529512
state.tables = [...state.tables.filter(t => t.id != currentTableRef), table];
530513
} else {
531514
state.tables = [...state.tables, table];
@@ -680,8 +663,8 @@ export const dataFormulatorSlice = createSlice({
680663
},
681664
clearUnReferencedTables: (state) => {
682665
// remove all tables that are not referred
683-
let charts = state.charts;
684-
let referredTableId = charts.map(chart => getDataTable(chart, state.tables, state.charts, state.conceptShelfItems).id);
666+
let allCharts = dfSelectors.getAllCharts(state);
667+
let referredTableId = allCharts.map(chart => getDataTable(chart, state.tables, allCharts, state.conceptShelfItems).id);
685668
state.tables = state.tables.filter(t => !(t.derive && !referredTableId.some(tableId => tableId == t.id)));
686669
},
687670
clearUnReferencedCustomConcepts: (state) => {
@@ -716,26 +699,6 @@ export const dataFormulatorSlice = createSlice({
716699
let chartId = action.payload;
717700
state.focusedChartId = chartId;
718701
state.visViewMode = "carousel";
719-
720-
let chart = state.charts.find(c => c.id == chartId)
721-
722-
// update activeThread based on focused chart
723-
if (chart?.intermediate == undefined) {
724-
state.activeThreadChartId = chartId;
725-
} else {
726-
let currentActiveThreadChart = state.charts.find(c => c.id == state.activeThreadChartId);
727-
let activeThreadChartTable = state.tables.find(t => t.id == currentActiveThreadChart?.tableRef);
728-
729-
if (activeThreadChartTable) {
730-
let triggers = getTriggers(activeThreadChartTable, state.tables);
731-
if (triggers.map(tg => tg.tableId).includes(chart?.intermediate?.resultTableId)) {
732-
let nextChart = state.charts.find(c => c.intermediate == undefined && c.tableRef == chart?.intermediate?.resultTableId);
733-
if (nextChart) {
734-
state.activeThreadChartId = nextChart.id;
735-
}
736-
}
737-
}
738-
}
739702
},
740703
setVisViewMode: (state, action: PayloadAction<"carousel" | "gallery">) => {
741704
state.visViewMode = action.payload;
@@ -844,7 +807,19 @@ export const dfSelectors = {
844807
let focusedTable = tables.find(t => t.id == focusedTableId);
845808
let sourceTables = focusedTable?.derive?.source || [focusedTable?.id];
846809
return sourceTables;
847-
}
810+
},
811+
812+
// Memoized chart selector that combines both sources
813+
getAllCharts: createSelector(
814+
[(state: DataFormulatorState) => state.charts,
815+
(state: DataFormulatorState) => state.tables],
816+
(userCharts, tables) => {
817+
const triggerCharts = tables
818+
.filter(t => t.derive?.trigger?.chart)
819+
.map(t => t.derive?.trigger?.chart) as Chart[];
820+
return [...userCharts, ...triggerCharts];
821+
}
822+
),
848823
}
849824

850825
// derived field: extra all field items from the table

src/app/utils.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -525,8 +525,8 @@ export let getTriggers = (leafTable: DictTable, tables: DictTable[]) => {
525525
// recursively find triggers that ends in leafTable (if the leaf table is anchored, we will find till the previous table is anchored)
526526
let triggers : Trigger[] = [];
527527
let t = leafTable;
528+
528529
while(true) {
529-
530530
// this is when we find an original table
531531
if (t.derive == undefined) {
532532
break;
@@ -541,11 +541,12 @@ export let getTriggers = (leafTable: DictTable, tables: DictTable[]) => {
541541
triggers = [trigger, ...triggers];
542542
let parentTable = tables.find(x => x.id == trigger.tableId);
543543
if (parentTable) {
544-
t = parentTable
544+
t = parentTable;
545545
} else {
546-
break
546+
break;
547547
}
548548
}
549+
549550
return triggers;
550551
}
551552

src/components/ComponentType.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,8 @@ export interface Trigger {
4949

5050
sourceTableIds: string[], // which tables are used in the trigger
5151

52-
chartRef?: string, // what's the intented chart from the user when running formulation
52+
chart?: Chart, // what's the intented chart from the user when running formulation
5353
instruction: string
54-
5554
resultTableId: string,
5655
}
5756

@@ -106,7 +105,7 @@ export type Chart = {
106105
encodingMap: EncodingMap,
107106
tableRef: string,
108107
saved: boolean,
109-
intermediate?: Trigger // whether this chart is only an intermediate chart (e.g., only used as a spec for transforming tables)
108+
source: "user" | "trigger",
110109
}
111110

112111
export let duplicateChart = (chart: Chart) : Chart => {
@@ -116,7 +115,7 @@ export let duplicateChart = (chart: Chart) : Chart => {
116115
encodingMap: JSON.parse(JSON.stringify(chart.encodingMap)) as EncodingMap,
117116
tableRef: chart.tableRef,
118117
saved: false,
119-
intermediate: undefined
118+
source: chart.source,
120119
}
121120
}
122121

src/views/ConceptCard.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ export const ConceptCard: FC<ConceptCardProps> = function ConceptCard({ field })
263263
color="primary" aria-label="Delete" component="span"
264264
disabled={
265265
conceptShelfItems.filter(f => f.source == "derived" && f.transform?.parentIDs.includes(field.id)).length > 0
266-
|| focusedTableId != field.tableRef
266+
267267
}
268268
onClick={() => { handleDeleteConcept(field.id); }}>
269269
<DeleteIcon fontSize="inherit" />

0 commit comments

Comments
 (0)