Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: Optimize memory for plot tooltips #1876

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 57 additions & 22 deletions ts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ export type Packed<T> = T | S
export interface Data {
list(): (Rec | null)[]
dict(): Dict<Rec>
getTupByIdx(i: U): Rec | null
}

interface OpsD {
Expand Down Expand Up @@ -399,6 +400,14 @@ export function unpack<T>(data: any): T {
: data
}

export function unpackByIdx<T>(data: any, idx: U): T {
marek-mihok marked this conversation as resolved.
Show resolved Hide resolved
return (typeof data === 'string')
? decodeString(data, idx)
marek-mihok marked this conversation as resolved.
Show resolved Hide resolved
: (isData(data))
? (data as Data).getTupByIdx(idx)
marek-mihok marked this conversation as resolved.
Show resolved Hide resolved
: data
}
marek-mihok marked this conversation as resolved.
Show resolved Hide resolved

const
errorCodes: Dict<WaveErrorCode> = {
not_found: WaveErrorCode.PageNotFound,
Expand All @@ -407,13 +416,31 @@ const
const i = d.indexOf(':')
return (i > 0) ? [d.substring(0, i), d.substring(i + 1)] : ['', d]
},
decodeString = (data: S): any => {
rowToRowObj = (item: any, fields: any) => {
const rec: Rec = {}
for (let j = 0; j < fields.length; j++) {
const f = fields[j], v = item[j]
rec[f] = v
}
return rec
},
colToRowObj = (columns: any, fields: any, idx: U) => {
const rec: Rec = {}
for (let j = 0; j < fields.length; j++) {
const f = fields[j], v = columns[j][idx]
rec[f] = v
}
return rec
},
decodeString = (data: S, idx?: U): any => {
marek-mihok marked this conversation as resolved.
Show resolved Hide resolved
if (data === '') return data
const [t, d] = decodeType(data)
switch (t) {
case 'data':
try {
return JSON.parse(d)
const parsedData = JSON.parse(d)
if (idx !== undefined && parsedData?.[idx]) return parsedData[idx]
marek-mihok marked this conversation as resolved.
Show resolved Hide resolved
return parsedData
} catch (e) {
console.error(e)
}
Expand All @@ -423,17 +450,12 @@ const
const [fields, rows] = JSON.parse(d)
if (!Array.isArray(fields)) return data
if (!Array.isArray(rows)) return data
const w = fields.length // width
if (idx !== undefined) return rowToRowObj(rows[idx], fields)
const recs: Rec[] = []
for (const r of rows) {
if (!Array.isArray(r)) continue
if (r.length !== w) continue
const rec: Rec = {}
for (let j = 0; j < w; j++) {
const f = fields[j], v = r[j]
rec[f] = v
}
recs.push(rec)
if (r.length !== fields.length) continue
recs.push(rowToRowObj(r, fields))
}
return recs
} catch (e) {
Expand All @@ -445,18 +467,13 @@ const
const [fields, columns] = JSON.parse(d)
if (!Array.isArray(fields)) return data
if (!Array.isArray(columns)) return data
const w = fields.length // width
if (columns.length !== w) return data
if (columns.length !== fields.length) return data
if (columns.length === 0) return data
if (idx !== undefined) return colToRowObj(columns, fields, idx)
const n = columns[0].length
const recs = new Array<Rec>(n)
const recs: Rec[] = []
for (let i = 0; i < n; i++) {
const rec: Rec = {}
for (let j = 0; j < w; j++) {
const f = fields[j], v = columns[j][i]
rec[f] = v
}
recs[i] = rec
recs.push(colToRowObj(columns, fields, i))
}
return recs
} catch (e) {
Expand Down Expand Up @@ -566,13 +583,20 @@ const
}
return null
},
getTupByIdx = (i: U): Rec | null => {
if (i >= 0 && i < n) {
const tup = tups[i]
if (tup) return t.make(tup)
}
return null
},
list = (): (Rec | null)[] => {
const xs: (Rec | null)[] = []
for (const tup of tups) xs.push(tup ? t.make(tup) : null)
return xs
},
dict = (): Dict<Rec> => ({})
return { __buf__: true, n, put, set, seti, get, geti, list, dict }
return { __buf__: true, n, put, set, seti, get, geti, getTupByIdx, list, dict }
},
newCycBuf = (t: Typ, tups: (Tup | null)[], i: U): CycBuf => {
const
Expand All @@ -590,6 +614,13 @@ const
get = (_k: S): Cur | null => {
return b.geti(i)
},
getTupByIdx = (i: U): Rec | null => {
if (i >= 0 && i < n) {
const tup = tups[i]
if (tup) return t.make(tup)
}
return null
},
list = (): Rec[] => {
const xs: Rec[] = []
for (let j = i, k = 0; k < n; j++, k++) {
Expand All @@ -600,7 +631,7 @@ const
return xs
},
dict = (): Dict<Rec> => ({})
return { __buf__: true, put, set, get, list, dict }
return { __buf__: true, put, set, get, getTupByIdx, list, dict }
},
newMapBuf = (t: Typ, tups: Dict<Tup>): MapBuf => {
const
Expand All @@ -624,6 +655,10 @@ const
const tup = tups[k]
return tup ? newCur(t, tup) : null
},
getTupByIdx = (i: U): Rec | null => {
const k = keysOf(tups)[i]
marek-mihok marked this conversation as resolved.
Show resolved Hide resolved
return t.make(tups[k])
},
list = (): Rec[] => {
const keys = keysOf(tups)
keys.sort()
Expand All @@ -636,7 +671,7 @@ const
for (const k in tups) d[k] = t.make(tups[k])
return d
}
return { __buf__: true, put, set, get, list, dict }
return { __buf__: true, put, set, get, getTupByIdx, list, dict }
},
newTups = (n: U) => {
const xs = new Array<Tup | null>(n)
Expand Down
1 change: 1 addition & 0 deletions ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"scripts": {
"build": "tsc",
"build-dev": "tsc --project dev.tsconfig.json",
"build-dev-watch": "tsc --project dev.tsconfig.json --watch",
marek-mihok marked this conversation as resolved.
Show resolved Hide resolved
"minify": "terser dist/index.js -c -m -o dist/index.min.js",
"prepublishOnly": "npm run build && npm run minify",
"test": "echo \"Error: no test specified\" && exit 1"
Expand Down
17 changes: 8 additions & 9 deletions ui/src/plot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import { Chart } from '@antv/g2'
import { AdjustOption, AnnotationPosition, ArcOption, AxisOption, ChartCfg, CoordinateActions, CoordinateOption, DataMarkerOption, DataRegionOption, GeometryOption, LineOption, RegionOption, ScaleOption, TextOption, TooltipItem } from '@antv/g2/lib/interface'
import { B, Dict, Disposable, F, Model, on, parseI, parseU, Rec, S, unpack, V } from 'h2o-wave'
import { B, Dict, Disposable, F, Model, on, parseI, parseU, Rec, S, unpack, unpackByIdx, V } from 'h2o-wave'
import React from 'react'
import ReactDOM from 'react-dom'
import { stylesheet } from 'typestyle'
Expand Down Expand Up @@ -1040,11 +1040,12 @@ export interface Visualization {
const tooltipContainer = document.createElement('div')
tooltipContainer.className = 'g2-tooltip'

const PlotTooltip = ({ items, originalItems }: { items: TooltipItem[], originalItems: any[] }) =>
const PlotTooltip = ({ items, originalData }: { items: TooltipItem[], originalData: Rec }) =>
<>
{items.map(({ data, mappingData, color }: TooltipItem) =>
Object.keys(originalItems[data.idx]).map((itemKey, idx) => {
const item = originalItems[data.idx][itemKey]
{items.map(({ data, mappingData, color }: TooltipItem) => {
const originalItems = unpackByIdx<any>(originalData, data.idx)
return Object.keys(originalItems).map((itemKey, idx) => {
const item = originalItems[itemKey]
marek-mihok marked this conversation as resolved.
Show resolved Hide resolved
return <li key={idx} className="g2-tooltip-list-item" data-index={idx} style={{ display: 'flex', alignItems: 'center', marginBottom: 4 }}>
<span style={{ backgroundColor: mappingData?.color || color }} className="g2-tooltip-marker" />
<span style={{ display: 'inline-flex', flex: 1, justifyContent: 'space-between' }}>
Expand All @@ -1054,6 +1055,7 @@ const PlotTooltip = ({ items, originalItems }: { items: TooltipItem[], originalI
</li>
}
)
}
)}
</>

Expand All @@ -1066,7 +1068,6 @@ export const
currentChart = React.useRef<Chart | null>(null),
currentPlot = React.useRef<Plot | null>(null),
themeWatchRef = React.useRef<Disposable | null>(null),
originalDataRef = React.useRef<any[]>([]),
checkDimensionsPostInit = (w: F, h: F) => { // Safari fix
const el = container.current
if (!el) return
Expand All @@ -1091,7 +1092,6 @@ export const
data = refactorData(raw_data, plot.marks),
{ Chart } = await import('@antv/g2'),
chart = plot.marks ? new Chart(makeChart(el, space, plot.marks, model.interactions || [])) : null
originalDataRef.current = unpack<any[]>(model.data)
currentPlot.current = plot
if (chart) {
chart.tooltip({
Expand All @@ -1105,7 +1105,7 @@ export const
},
},
customContent: (_title, items) => {
ReactDOM.render(<PlotTooltip items={items} originalItems={originalDataRef.current} />, tooltipContainer)
ReactDOM.render(<PlotTooltip items={items} originalData={model.data} />, tooltipContainer)
return tooltipContainer
}
})
Expand Down Expand Up @@ -1155,7 +1155,6 @@ export const
const
raw_data = unpack<any[]>(model.data),
data = refactorData(raw_data, currentPlot.current.marks)
originalDataRef.current = unpack<any[]>(model.data)
currentChart.current.changeData(data)
}, [currentChart, currentPlot, model])

Expand Down
4 changes: 4 additions & 0 deletions ui/vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { defineConfig } from 'vite'
import legacy from '@vitejs/plugin-legacy'
import eslintPlugin from 'vite-plugin-eslint'
import react from '@vitejs/plugin-react'
import path from 'path'
marek-mihok marked this conversation as resolved.
Show resolved Hide resolved

// https://vitejs.dev/config/
export default defineConfig({
Expand All @@ -31,6 +32,9 @@ export default defineConfig({
assetsDir: 'wave-static',
chunkSizeWarningLimit: 900
},
optimizeDeps: {
link: ['h2o-wave']
},
server: {
port: 3000,
proxy: {
Expand Down