Skip to content

Commit 09e5fd6

Browse files
committed
feat: Add plot node and update related components
- Introduced a new plot node with corresponding compute and visual definitions. - Updated the node registration files to include the new plot node in both worker and main node registrations. - Created example flow files for scatterplot and linear regression to demonstrate the new plot functionality. - Enhanced the compute logic to support additional parameters in node computations. - Modified JSON transformation utilities to handle new input types and improve data handling. - Adjusted the raw JSON node to accept number types for input, ensuring compatibility with expressions. - Updated variable payload input utilities to include original input in the payload for better context during execution. - Enhanced map node to allow multiple connections from output.
1 parent 148c93f commit 09e5fd6

File tree

14 files changed

+1165
-36
lines changed

14 files changed

+1165
-36
lines changed

apps/vps-web/src/app/custom-nodes-v2/pie-chart-visual.tsx

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,24 @@ export class PieChartVisual extends NodeVisual<NodeInfo> {
4040
// eslint-disable-next-line @typescript-eslint/no-unused-vars
4141
_nodeInfo: NodeInfo
4242
) => {
43-
this.lastData = Array.isArray(data) ? data.map((d: InputDataTuple | Record<string, unknown>) => {
44-
// Handle both array-like and object-like structures
45-
if (Array.isArray(d)) {
46-
return {
47-
name: String(d[0]),
48-
value: Number(d[1]),
49-
};
50-
} else if (d && typeof d === 'object') {
51-
// Handle object format with name/value keys
52-
const name = d.name !== undefined ? String(d.name) : 'Unknown';
53-
const value = d.value !== undefined ? Number(d.value) : 0;
54-
return { name, value };
55-
}
56-
return { name: 'Unknown', value: 0 };
57-
}) : undefined;
58-
43+
this.lastData = Array.isArray(data)
44+
? data.map((d: InputDataTuple | Record<string, unknown>) => {
45+
// Handle both array-like and object-like structures
46+
if (Array.isArray(d)) {
47+
return {
48+
name: String(d[0]),
49+
value: Number(d[1]),
50+
};
51+
} else if (d && typeof d === 'object') {
52+
// Handle object format with name/value keys
53+
const name = d.name !== undefined ? String(d.name) : 'Unknown';
54+
const value = d.value !== undefined ? Number(d.value) : 0;
55+
return { name, value };
56+
}
57+
return { name: 'Unknown', value: 0 };
58+
})
59+
: undefined;
60+
5961
console.log('pieChartVisual', data);
6062
// Clear the parent node before rendering... should this be handled by the framework?
6163

@@ -77,24 +79,27 @@ export class PieChartVisual extends NodeVisual<NodeInfo> {
7779
{ name: 'I', value: 900 },
7880
{ name: 'J', value: 1000 },
7981
];
80-
82+
8183
pieData.columns = ['name', 'value'];
82-
84+
8385
// Create the color scale.
8486
const color = d3
8587
.scaleOrdinal<string>()
86-
.domain(pieData.map(d => d.name))
88+
.domain(pieData.map((d) => d.name))
8789
.range(
8890
d3
89-
.quantize((t) => d3.interpolateSpectral(t * 0.8 + 0.1), pieData.length)
91+
.quantize(
92+
(t) => d3.interpolateSpectral(t * 0.8 + 0.1),
93+
pieData.length
94+
)
9095
.reverse()
9196
);
9297

9398
// Create the pie layout and arc generator.
9499
const pie = d3
95100
.pie<PieDataItem>()
96101
.sort(null)
97-
.value(d => d.value);
102+
.value((d) => d.value);
98103

99104
const arc = d3
100105
.arc<d3.PieArcDatum<PieDataItem>>()
@@ -128,10 +133,10 @@ export class PieChartVisual extends NodeVisual<NodeInfo> {
128133
.selectAll<SVGPathElement, d3.PieArcDatum<PieDataItem>>('path')
129134
.data(arcs)
130135
.join('path')
131-
.attr('fill', d => color(d.data.name))
136+
.attr('fill', (d) => color(d.data.name))
132137
.attr('d', arc)
133138
.append('title')
134-
.text(d => `${d.data.name}: ${d.data.value.toLocaleString('en-US')}`);
139+
.text((d) => `${d.data.name}: ${d.data.value.toLocaleString('en-US')}`);
135140

136141
// Create labels
137142
svg
@@ -140,27 +145,27 @@ export class PieChartVisual extends NodeVisual<NodeInfo> {
140145
.selectAll<SVGTextElement, d3.PieArcDatum<PieDataItem>>('text')
141146
.data(arcs)
142147
.join('text')
143-
.attr('transform', d => `translate(${arcLabel.centroid(d)})`)
148+
.attr('transform', (d) => `translate(${arcLabel.centroid(d)})`)
144149
.call((text) =>
145150
text
146151
.append('tspan')
147152
.attr('y', '-0.4em')
148153
.attr('font-weight', 'bold')
149-
.text(d => d.data.name)
154+
.text((d) => d.data.name)
150155
)
151156
.call((text) =>
152157
text
153-
.filter(d => d.endAngle - d.startAngle > 0.25)
158+
.filter((d) => d.endAngle - d.startAngle > 0.25)
154159
.append('tspan')
155160
.attr('x', 0)
156161
.attr('y', '0.7em')
157162
.attr('fill-opacity', 0.7)
158-
.text(d => d.data.value.toLocaleString('en-US'))
163+
.text((d) => d.data.value.toLocaleString('en-US'))
159164
);
160165

161166
parentNode.appendChild(svg.node() as Node);
162167
};
163-
168+
164169
renderPie();
165170

166171
this.resizeObserver = new ResizeObserver((entries) => {
@@ -178,7 +183,7 @@ export class PieChartVisual extends NodeVisual<NodeInfo> {
178183
this.resizeObserver.observe(parentNode); // Start observing the container
179184
}
180185
};
181-
186+
182187
isResizing = false;
183188
resizeObserver: ResizeObserver | undefined = undefined;
184189

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { NodeCompute } from '@devhelpr/visual-programming-system';
2+
import { NodeInfo } from '@devhelpr/web-flow-executor';
3+
4+
// depending if "ai-canvas" is used.. the below is called from a worker or main thread
5+
6+
export const plotCompute: NodeCompute<NodeInfo> = {
7+
initializeCompute: () => {
8+
// Initialization logic if needed
9+
},
10+
compute: async (data: unknown, _1, _2, _3, _4, _5, connection) => {
11+
const plotData = data as { type: string; data: unknown };
12+
if (plotData.type !== 'plot' && plotData.type !== 'line') {
13+
return Promise.resolve({
14+
output: undefined,
15+
result: undefined,
16+
});
17+
}
18+
19+
console.log('plotCompute', plotData);
20+
21+
const dataToPlot = {
22+
type: plotData.type,
23+
data: plotData.data,
24+
id: connection?.id ?? '',
25+
};
26+
return Promise.resolve({
27+
output: dataToPlot,
28+
result: dataToPlot,
29+
});
30+
},
31+
};
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { NodeDefinition } from '@devhelpr/visual-programming-system';
2+
3+
export const plotDefinition: NodeDefinition = {
4+
nodeTypeName: 'plot',
5+
description:
6+
'A plot component that visualizes data in a graphical format, such as a line chart, bar chart, or scatter plot.',
7+
};

0 commit comments

Comments
 (0)