Skip to content

Commit 51e63cf

Browse files
authored
Add legend to zoomed in plots (#1794)
* add legend to zoomed in plot * add legend for zoomed in checkpoint plots * refactor removal of legend suppression up to top level function * commit broken storybook for now * create zoomed in plot component and do not mutate props
1 parent cbed227 commit 51e63cf

File tree

5 files changed

+131
-92
lines changed

5 files changed

+131
-92
lines changed

webview/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
"@tippyjs/react": "^4.2.6",
2626
"@vscode/webview-ui-toolkit": "^1.0.0",
2727
"classnames": "^2.2.6",
28+
"lodash.clonedeep": "^4.5.0",
29+
"lodash.merge": "^4.6.2",
2830
"react": "^17.0.1",
2931
"react-dom": "^17.0.1",
3032
"react-table": "^7.7.0",

webview/src/plots/components/Plots.tsx

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import { PlotSize, Section } from 'dvc/src/plots/webview/contract'
22
import { MessageFromWebviewType } from 'dvc/src/webview/contract'
33
import React, { useEffect, useRef, useState, useCallback } from 'react'
4-
import VegaLite, { VegaLiteProps } from 'react-vega/lib/VegaLite'
5-
import { Config } from 'vega-lite'
6-
import styles from './styles.module.scss'
4+
import { VegaLiteProps } from 'react-vega/lib/VegaLite'
75
import { PlotsSizeProvider } from './PlotsSizeContext'
86
import { AddPlots, Welcome } from './GetStarted'
7+
import { ZoomedInPlot } from './ZoomedInPlot'
98
import { CheckpointPlotsWrapper } from './checkpointPlots/CheckpointPlotsWrapper'
109
import { TemplatePlotsWrapper } from './templatePlots/TemplatePlotsWrapper'
1110
import { ComparisonTableWrapper } from './comparisonTable/ComparisonTableWrapper'
@@ -16,7 +15,6 @@ import { Modal } from '../../shared/components/modal/Modal'
1615
import { WebviewWrapper } from '../../shared/components/webviewWrapper/WebviewWrapper'
1716
import { DragDropProvider } from '../../shared/components/dragDrop/DragDropContext'
1817
import { sendMessage } from '../../shared/vscode'
19-
import { getThemeValue, ThemeProperty } from '../../util/styles'
2018
import { GetStarted } from '../../shared/components/getStarted/GetStarted'
2119

2220
interface PlotsProps {
@@ -153,21 +151,7 @@ const PlotsContent = ({ state }: PlotsProps) => {
153151

154152
{zoomedInPlot && (
155153
<Modal onClose={handleModalClose}>
156-
<div className={styles.zoomedInPlot} data-testid="zoomed-in-plot">
157-
<VegaLite
158-
{...zoomedInPlot}
159-
config={{
160-
...(zoomedInPlot.config as Config),
161-
background: getThemeValue(ThemeProperty.MENU_BACKGROUND)
162-
}}
163-
actions={{
164-
compiled: false,
165-
editor: false,
166-
export: true,
167-
source: false
168-
}}
169-
/>
170-
</div>
154+
<ZoomedInPlot props={zoomedInPlot} />
171155
</Modal>
172156
)}
173157
</>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import React from 'react'
2+
import VegaLite, { VegaLiteProps } from 'react-vega/lib/VegaLite'
3+
import { Config } from 'vega-lite'
4+
import merge from 'lodash.merge'
5+
import cloneDeep from 'lodash.clonedeep'
6+
import styles from './styles.module.scss'
7+
import { getThemeValue, ThemeProperty } from '../../util/styles'
8+
9+
export type ZoomedInPlotProps = {
10+
props: VegaLiteProps
11+
}
12+
13+
export const ZoomedInPlot: React.FC<ZoomedInPlotProps> = ({
14+
props
15+
}: ZoomedInPlotProps) => (
16+
<div className={styles.zoomedInPlot} data-testid="zoomed-in-plot">
17+
<VegaLite
18+
{...merge(
19+
{ ...cloneDeep(props) },
20+
{
21+
spec: { encoding: { color: { legend: { disable: false } } } }
22+
}
23+
)}
24+
config={{
25+
...(props.config as Config),
26+
background: getThemeValue(ThemeProperty.MENU_BACKGROUND)
27+
}}
28+
actions={{
29+
compiled: false,
30+
editor: false,
31+
export: true,
32+
source: false
33+
}}
34+
/>
35+
</div>
36+
)

webview/src/plots/components/checkpointPlots/util.ts

Lines changed: 77 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -4,86 +4,90 @@ import { ColorScale } from 'dvc/src/plots/webview/contract'
44
export const createSpec = (
55
title: string,
66
scale?: ColorScale
7-
): VisualizationSpec => ({
8-
$schema: 'https://vega.github.io/schema/vega-lite/v5.json',
9-
data: { name: 'values' },
10-
encoding: {
11-
x: {
12-
axis: { format: '0d', tickMinStep: 1 },
13-
field: 'iteration',
14-
title: 'iteration',
15-
type: 'quantitative'
7+
): VisualizationSpec =>
8+
({
9+
$schema: 'https://vega.github.io/schema/vega-lite/v5.json',
10+
data: { name: 'values' },
11+
encoding: {
12+
color: {
13+
field: 'group',
14+
legend: { disable: true },
15+
scale,
16+
title: 'rev',
17+
type: 'nominal'
18+
},
19+
x: {
20+
axis: { format: '0d', tickMinStep: 1 },
21+
field: 'iteration',
22+
title: 'iteration',
23+
type: 'quantitative'
24+
},
25+
y: {
26+
field: 'y',
27+
scale: { zero: false },
28+
title,
29+
type: 'quantitative'
30+
}
1631
},
17-
y: {
18-
field: 'y',
19-
scale: { zero: false },
20-
title,
21-
type: 'quantitative'
22-
}
23-
},
24-
height: 'container',
25-
layer: [
26-
{
27-
encoding: {
28-
color: { field: 'group', legend: null, scale, type: 'nominal' }
32+
height: 'container',
33+
layer: [
34+
{
35+
layer: [
36+
{ mark: { type: 'line' } },
37+
{
38+
mark: { type: 'point' },
39+
transform: [
40+
{
41+
filter: { empty: false, param: 'hover' }
42+
}
43+
]
44+
}
45+
]
2946
},
30-
31-
layer: [
32-
{ mark: { type: 'line' } },
33-
{
34-
mark: { type: 'point' },
35-
transform: [
47+
{
48+
encoding: {
49+
opacity: { value: 0 },
50+
tooltip: [
51+
{ field: 'group', title: 'name' },
3652
{
37-
filter: { empty: false, param: 'hover' }
53+
field: 'y',
54+
title: title.slice(Math.max(0, title.indexOf(':') + 1)),
55+
type: 'quantitative'
3856
}
3957
]
40-
}
41-
]
42-
},
43-
{
44-
encoding: {
45-
opacity: { value: 0 },
46-
tooltip: [
47-
{ field: 'group', title: 'name' },
58+
},
59+
mark: { type: 'rule' },
60+
params: [
4861
{
49-
field: 'y',
50-
title: title.slice(Math.max(0, title.indexOf(':') + 1)),
51-
type: 'quantitative'
62+
name: 'hover',
63+
select: {
64+
clear: 'mouseout',
65+
fields: ['iteration', 'y'],
66+
nearest: true,
67+
on: 'mouseover',
68+
type: 'point'
69+
}
5270
}
5371
]
5472
},
55-
mark: { type: 'rule' },
56-
params: [
57-
{
58-
name: 'hover',
59-
select: {
60-
clear: 'mouseout',
61-
fields: ['iteration', 'y'],
62-
nearest: true,
63-
on: 'mouseover',
64-
type: 'point'
73+
{
74+
encoding: {
75+
color: { field: 'group', scale },
76+
x: { aggregate: 'max', field: 'iteration', type: 'quantitative' },
77+
y: {
78+
aggregate: { argmax: 'iteration' },
79+
field: 'y',
80+
type: 'quantitative'
6581
}
66-
}
67-
]
68-
},
69-
{
70-
encoding: {
71-
color: { field: 'group', scale },
72-
x: { aggregate: 'max', field: 'iteration', type: 'quantitative' },
73-
y: {
74-
aggregate: { argmax: 'iteration' },
75-
field: 'y',
76-
type: 'quantitative'
77-
}
78-
},
79-
mark: { stroke: null, type: 'circle' }
80-
}
81-
],
82-
transform: [
83-
{
84-
as: 'y',
85-
calculate: "format(datum['y'],'.5f')"
86-
}
87-
],
88-
width: 'container'
89-
})
82+
},
83+
mark: { stroke: null, type: 'circle' }
84+
}
85+
],
86+
transform: [
87+
{
88+
as: 'y',
89+
calculate: "format(datum['y'],'.5f')"
90+
}
91+
],
92+
width: 'container'
93+
} as VisualizationSpec)

webview/src/stories/Plots.stories.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,3 +185,16 @@ MultiviewZoomedInPlot.play = async ({ canvasElement }) => {
185185

186186
fireEvent.click(plotButton)
187187
}
188+
189+
export const CheckpointZoomedInPlot = Template.bind({})
190+
CheckpointZoomedInPlot.parameters = {
191+
chromatic: { delay: 500 }
192+
}
193+
CheckpointZoomedInPlot.play = async ({ canvasElement }) => {
194+
const canvas = within(canvasElement)
195+
const plot = await canvas.findByText('summary.json:val_accuracy')
196+
197+
plot.scrollIntoView()
198+
199+
fireEvent.click(plot)
200+
}

0 commit comments

Comments
 (0)