Skip to content

Commit 9024d2f

Browse files
committed
violinchart support for only showing left side
1 parent 9dfeb66 commit 9024d2f

File tree

2 files changed

+97
-69
lines changed

2 files changed

+97
-69
lines changed

src/components/DistributionReport.tsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ export const DistributionReport = (
129129
const charts = columnNames.map((column, index) => {
130130
const dataType = dataTypes[column];
131131
return columnNames.map((column2, index2) => {
132-
if (column === column2 || index >= index2) {
132+
if (column === column2 || index <= index2) {
133133
return null;
134134
}
135135
const dataType2 = dataTypes[column2];
@@ -200,6 +200,20 @@ export const DistributionReport = (
200200
/>
201201
</div>
202202
);
203+
} else if (
204+
dataType === 'float' &&
205+
dataType2 === 'category'
206+
) {
207+
return (
208+
<ViolinChart
209+
key={column + column2}
210+
categoricalColumn={column2}
211+
numericColumn={column}
212+
realData={realData}
213+
syntheticData={syntheticData}
214+
comparison={false}
215+
/>
216+
);
203217
}
204218
});
205219
});
@@ -237,6 +251,7 @@ export const DistributionReport = (
237251
numericColumn={column}
238252
realData={realData}
239253
syntheticData={syntheticData}
254+
comparison={true}
240255
/>
241256
);
242257
}

src/components/graphs/ViolinChart.tsx

Lines changed: 81 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ interface ViolinChartProps {
77
numericColumn: string;
88
realData: Array<{ [key: string]: any }>;
99
syntheticData: Array<{ [key: string]: any }>;
10+
comparison: boolean;
1011
}
1112

1213
const formatTick = (value: number) => {
@@ -26,6 +27,7 @@ const ViolinChart = ({
2627
numericColumn,
2728
realData,
2829
syntheticData,
30+
comparison,
2931
}: ViolinChartProps) => {
3032
const svgRef = useRef<SVGSVGElement>(null);
3133
const containerRef = useRef<HTMLDivElement>(null);
@@ -37,10 +39,12 @@ const ViolinChart = ({
3739

3840
// Get unique categories
3941
const categories = Array.from(
40-
new Set([
41-
...realData.map(d => d[categoricalColumn]),
42-
...syntheticData.map(d => d[categoricalColumn]),
43-
])
42+
comparison
43+
? new Set([
44+
...realData.map(d => d[categoricalColumn]),
45+
...syntheticData.map(d => d[categoricalColumn]),
46+
])
47+
: new Set([...realData.map(d => d[categoricalColumn])])
4448
);
4549

4650
// Process data for violin plots
@@ -73,7 +77,10 @@ const ViolinChart = ({
7377
// Reserve space for legend (120px width + 20px padding)
7478
const legendWidth = 140;
7579
const plotWidth =
76-
containerWidth - margin.left - margin.right - legendWidth;
80+
containerWidth -
81+
margin.left -
82+
margin.right -
83+
(comparison ? legendWidth : 0);
7784

7885
// Create scales
7986
const xScale = d3
@@ -86,16 +93,18 @@ const ViolinChart = ({
8693
const bandwidth = Math.min(xScale.bandwidth() / 2, 50);
8794

8895
// Calculate min and max with padding
89-
const minValue =
90-
d3.min([
91-
...realData.map(d => +d[numericColumn]),
92-
...syntheticData.map(d => +d[numericColumn]),
93-
]) || 0;
94-
const maxValue =
95-
d3.max([
96-
...realData.map(d => +d[numericColumn]),
97-
...syntheticData.map(d => +d[numericColumn]),
98-
]) || 0;
96+
const minValue = comparison
97+
? d3.min([
98+
...realData.map(d => +d[numericColumn]),
99+
...syntheticData.map(d => +d[numericColumn]),
100+
]) || 0
101+
: d3.min([...realData.map(d => +d[numericColumn])]) || 0;
102+
const maxValue = comparison
103+
? d3.max([
104+
...realData.map(d => +d[numericColumn]),
105+
...syntheticData.map(d => +d[numericColumn]),
106+
]) || 0
107+
: d3.max([...realData.map(d => +d[numericColumn])]) || 0;
99108

100109
// Add padding and ensure domain includes zero
101110
const range = Math.abs(maxValue - minValue);
@@ -279,20 +288,22 @@ const ViolinChart = ({
279288
.attr('d', path)
280289
.attr('transform', `translate(${centerPos}, 0)`)
281290
.style('fill', 'steelblue')
291+
.style('stroke', 'darkblue')
282292
.style('opacity', 0.5);
283293

284294
drawQuartileLines(real, 'left', 'steelblue');
285295
}
286296
}
287297

288298
// Draw synthetic data violin (right side)
289-
if (synthetic.length > 0) {
299+
if (comparison && synthetic.length > 0) {
290300
const path = createViolin(synthetic, 'right');
291301
if (path) {
292302
svg.append('path')
293303
.attr('d', path)
294304
.attr('transform', `translate(${centerPos}, 0)`)
295305
.style('fill', 'orange')
306+
.style('stroke', '#ff6200')
296307
.style('opacity', 0.5);
297308

298309
drawQuartileLines(synthetic, 'right', 'orange');
@@ -322,59 +333,61 @@ const ViolinChart = ({
322333
.attr('font-size', '12px')
323334
.text(numericColumn);
324335

325-
// Add legend at fixed position relative to plot area
326-
const legend = svg
327-
.append('g')
328-
.attr('class', 'legend')
329-
.attr('transform', `translate(${plotWidth + 20}, 30)`);
330-
331-
// No need to adjust SVG width since we reserved space for legend
336+
if (comparison) {
337+
// Add legend at fixed position relative to plot area
338+
const legend = svg
339+
.append('g')
340+
.attr('class', 'legend')
341+
.attr('transform', `translate(${plotWidth + 20}, 30)`);
342+
343+
// No need to adjust SVG width since we reserved space for legend
344+
345+
// Add background rectangle for legend
346+
legend
347+
.append('rect')
348+
.attr('x', -10)
349+
.attr('y', -10)
350+
.attr('width', 110)
351+
.attr('height', 55)
352+
.attr('rx', 5)
353+
.style('fill', 'white')
354+
.style('opacity', 0.7)
355+
.style('stroke', '#e2e8f0')
356+
.style('stroke-width', 1);
332357

333-
// Add background rectangle for legend
334-
legend
335-
.append('rect')
336-
.attr('x', -10)
337-
.attr('y', -10)
338-
.attr('width', 110)
339-
.attr('height', 55)
340-
.attr('rx', 5)
341-
.style('fill', 'white')
342-
.style('opacity', 0.7)
343-
.style('stroke', '#e2e8f0')
344-
.style('stroke-width', 1);
345-
346-
// Add legend items
347-
legend
348-
.append('rect')
349-
.attr('x', 0)
350-
.attr('y', 0)
351-
.attr('width', 15)
352-
.attr('height', 15)
353-
.style('fill', 'steelblue')
354-
.style('opacity', 0.5);
355-
356-
legend
357-
.append('text')
358-
.attr('x', 20)
359-
.attr('y', 12)
360-
.style('font-size', '12px')
361-
.text(t('distribution.realData'));
362-
363-
legend
364-
.append('rect')
365-
.attr('x', 0)
366-
.attr('y', 20)
367-
.attr('width', 15)
368-
.attr('height', 15)
369-
.style('fill', 'orange')
370-
.style('opacity', 0.5);
371-
372-
legend
373-
.append('text')
374-
.attr('x', 20)
375-
.attr('y', 32)
376-
.style('font-size', '12px')
377-
.text(t('distribution.syntheticData'));
358+
// Add legend items
359+
legend
360+
.append('rect')
361+
.attr('x', 0)
362+
.attr('y', 0)
363+
.attr('width', 15)
364+
.attr('height', 15)
365+
.style('fill', 'steelblue')
366+
.style('opacity', 0.5);
367+
368+
legend
369+
.append('text')
370+
.attr('x', 20)
371+
.attr('y', 12)
372+
.style('font-size', '12px')
373+
.text(t('distribution.realData'));
374+
375+
legend
376+
.append('rect')
377+
.attr('x', 0)
378+
.attr('y', 20)
379+
.attr('width', 15)
380+
.attr('height', 15)
381+
.style('fill', 'orange')
382+
.style('opacity', 0.5);
383+
384+
legend
385+
.append('text')
386+
.attr('x', 20)
387+
.attr('y', 32)
388+
.style('font-size', '12px')
389+
.text(t('distribution.syntheticData'));
390+
}
378391
}, [
379392
containerWidth,
380393
categoricalColumn,

0 commit comments

Comments
 (0)