0
# Trace Management
1
2
Functions for adding, removing, and reordering traces in existing plots. These functions allow dynamic manipulation of plot data series without recreating the entire plot.
3
4
## Capabilities
5
6
### addTraces
7
8
Adds new traces to an existing plot at specified positions.
9
10
```javascript { .api }
11
/**
12
* Adds new traces to an existing plot
13
* @param graphDiv - DOM element ID (string) or element reference
14
* @param traces - Single trace object or array of trace objects to add
15
* @param newIndices - Position(s) to insert traces (optional, defaults to end)
16
* @returns Promise that resolves to the graph div element
17
*/
18
function addTraces(
19
graphDiv: string | HTMLElement,
20
traces: Partial<PlotlyTrace> | Partial<PlotlyTrace>[],
21
newIndices?: number | number[]
22
): Promise<HTMLElement>;
23
```
24
25
**Usage Examples:**
26
27
```javascript
28
import Plotly from 'plotly.js-dist';
29
30
// Add a single trace to the end
31
const newTrace = {
32
x: [1, 2, 3, 4],
33
y: [5, 6, 7, 8],
34
type: 'scatter',
35
name: 'New Series'
36
};
37
await Plotly.addTraces('chart', newTrace);
38
39
// Add multiple traces
40
const newTraces = [
41
{
42
x: [1, 2, 3],
43
y: [10, 11, 12],
44
type: 'bar',
45
name: 'Bar Series'
46
},
47
{
48
x: [1, 2, 3],
49
y: [2, 4, 6],
50
type: 'scatter',
51
mode: 'lines',
52
name: 'Line Series'
53
}
54
];
55
await Plotly.addTraces('chart', newTraces);
56
57
// Add trace at specific position (index 1)
58
await Plotly.addTraces('chart', newTrace, 1);
59
60
// Add multiple traces at specific positions
61
await Plotly.addTraces('chart', newTraces, [0, 2]);
62
63
// Add trace with complex configuration
64
const complexTrace = {
65
x: [1, 2, 3, 4, 5],
66
y: [10, 15, 13, 17, 20],
67
type: 'scatter',
68
mode: 'lines+markers',
69
name: 'Complex Series',
70
line: {
71
color: 'rgb(255, 127, 14)',
72
width: 3
73
},
74
marker: {
75
color: 'rgba(255, 127, 14, 0.8)',
76
size: 8,
77
symbol: 'circle'
78
},
79
hovertemplate: 'X: %{x}<br>Y: %{y}<extra></extra>'
80
};
81
await Plotly.addTraces('chart', complexTrace);
82
```
83
84
### deleteTraces
85
86
Removes traces from an existing plot by their indices.
87
88
```javascript { .api }
89
/**
90
* Removes traces from an existing plot
91
* @param graphDiv - DOM element ID (string) or element reference
92
* @param indices - Single trace index or array of trace indices to remove
93
* @returns Promise that resolves to the graph div element
94
*/
95
function deleteTraces(
96
graphDiv: string | HTMLElement,
97
indices: number | number[]
98
): Promise<HTMLElement>;
99
```
100
101
**Usage Examples:**
102
103
```javascript
104
// Remove single trace by index
105
await Plotly.deleteTraces('chart', 0); // Remove first trace
106
107
// Remove multiple traces
108
await Plotly.deleteTraces('chart', [0, 2, 4]); // Remove traces at indices 0, 2, and 4
109
110
// Remove last trace
111
const currentTraces = document.getElementById('chart').data.length;
112
await Plotly.deleteTraces('chart', currentTraces - 1);
113
114
// Remove all traces except the first one
115
const totalTraces = document.getElementById('chart').data.length;
116
const indicesToRemove = Array.from({length: totalTraces - 1}, (_, i) => i + 1);
117
await Plotly.deleteTraces('chart', indicesToRemove);
118
119
// Conditional removal based on trace properties
120
const chartDiv = document.getElementById('chart');
121
const tracesToRemove = [];
122
chartDiv.data.forEach((trace, index) => {
123
if (trace.name && trace.name.includes('temporary')) {
124
tracesToRemove.push(index);
125
}
126
});
127
if (tracesToRemove.length > 0) {
128
await Plotly.deleteTraces('chart', tracesToRemove);
129
}
130
```
131
132
### moveTraces
133
134
Reorders traces in an existing plot by moving them to new positions.
135
136
```javascript { .api }
137
/**
138
* Reorders traces in an existing plot
139
* @param graphDiv - DOM element ID (string) or element reference
140
* @param currentIndices - Current position(s) of traces to move
141
* @param newIndices - New position(s) for the traces (optional, defaults to end)
142
* @returns Promise that resolves to the graph div element
143
*/
144
function moveTraces(
145
graphDiv: string | HTMLElement,
146
currentIndices: number | number[],
147
newIndices?: number | number[]
148
): Promise<HTMLElement>;
149
```
150
151
**Usage Examples:**
152
153
```javascript
154
// Move single trace to end
155
await Plotly.moveTraces('chart', 0); // Move first trace to end
156
157
// Move trace to specific position
158
await Plotly.moveTraces('chart', 2, 0); // Move trace from index 2 to index 0
159
160
// Move multiple traces
161
await Plotly.moveTraces('chart', [0, 1], [2, 3]); // Move traces 0,1 to positions 2,3
162
163
// Swap two traces
164
await Plotly.moveTraces('chart', [0, 1], [1, 0]);
165
166
// Move trace to second position
167
await Plotly.moveTraces('chart', 3, 1); // Move trace from index 3 to index 1
168
169
// Reorder multiple traces to end
170
await Plotly.moveTraces('chart', [1, 3, 5]); // Move traces 1, 3, 5 to end
171
```
172
173
## Advanced Trace Management Patterns
174
175
### Dynamic Trace Creation
176
177
```javascript
178
// Create traces based on data categories
179
const categories = ['A', 'B', 'C'];
180
const colors = ['red', 'blue', 'green'];
181
182
const traces = categories.map((category, index) => ({
183
x: data.filter(d => d.category === category).map(d => d.x),
184
y: data.filter(d => d.category === category).map(d => d.y),
185
type: 'scatter',
186
mode: 'markers',
187
name: `Category ${category}`,
188
marker: { color: colors[index] }
189
}));
190
191
await Plotly.addTraces('chart', traces);
192
```
193
194
### Trace Lifecycle Management
195
196
```javascript
197
class TraceManager {
198
constructor(chartId) {
199
this.chartId = chartId;
200
this.traceIds = new Map(); // Map custom IDs to plot indices
201
}
202
203
async addTrace(customId, traceData) {
204
await Plotly.addTraces(this.chartId, traceData);
205
const chartDiv = document.getElementById(this.chartId);
206
const newIndex = chartDiv.data.length - 1;
207
this.traceIds.set(customId, newIndex);
208
}
209
210
async removeTrace(customId) {
211
const index = this.traceIds.get(customId);
212
if (index !== undefined) {
213
await Plotly.deleteTraces(this.chartId, index);
214
this.traceIds.delete(customId);
215
// Update remaining indices
216
this.traceIds.forEach((value, key) => {
217
if (value > index) {
218
this.traceIds.set(key, value - 1);
219
}
220
});
221
}
222
}
223
224
async updateTrace(customId, updates) {
225
const index = this.traceIds.get(customId);
226
if (index !== undefined) {
227
await Plotly.restyle(this.chartId, updates, index);
228
}
229
}
230
}
231
```
232
233
### Conditional Trace Display
234
235
```javascript
236
// Toggle traces based on user selection
237
async function toggleTracesByCategory(category, visible) {
238
const chartDiv = document.getElementById('chart');
239
const indicesToUpdate = [];
240
241
chartDiv.data.forEach((trace, index) => {
242
if (trace.name && trace.name.includes(category)) {
243
indicesToUpdate.push(index);
244
}
245
});
246
247
const visibility = visible ? true : 'legendonly';
248
await Plotly.restyle('chart', {'visible': visibility}, indicesToUpdate);
249
}
250
251
// Show only top N traces by some metric
252
async function showTopTraces(n, sortBy = 'max') {
253
const chartDiv = document.getElementById('chart');
254
const traceMetrics = chartDiv.data.map((trace, index) => ({
255
index,
256
metric: sortBy === 'max' ? Math.max(...trace.y) : trace.y.reduce((a, b) => a + b, 0)
257
}));
258
259
traceMetrics.sort((a, b) => b.metric - a.metric);
260
const topIndices = traceMetrics.slice(0, n).map(t => t.index);
261
const hiddenIndices = traceMetrics.slice(n).map(t => t.index);
262
263
if (hiddenIndices.length > 0) {
264
await Plotly.restyle('chart', {'visible': 'legendonly'}, hiddenIndices);
265
}
266
if (topIndices.length > 0) {
267
await Plotly.restyle('chart', {'visible': true}, topIndices);
268
}
269
}
270
```
271
272
## Event Handling
273
274
Trace management functions emit specific events:
275
276
```javascript { .api }
277
interface TraceEvents {
278
'plotly_traceadded': (eventData: { traceIndices: number[] }) => void;
279
'plotly_tracedeleted': (eventData: { traceIndices: number[] }) => void;
280
'plotly_tracesmoved': (eventData: {
281
previousIndices: number[];
282
currentIndices: number[];
283
}) => void;
284
}
285
```
286
287
**Usage Examples:**
288
289
```javascript
290
const chartDiv = document.getElementById('my-chart');
291
292
chartDiv.on('plotly_traceadded', (eventData) => {
293
console.log('Traces added at indices:', eventData.traceIndices);
294
});
295
296
chartDiv.on('plotly_tracedeleted', (eventData) => {
297
console.log('Traces deleted from indices:', eventData.traceIndices);
298
});
299
300
chartDiv.on('plotly_tracesmoved', (eventData) => {
301
console.log('Traces moved:', {
302
from: eventData.previousIndices,
303
to: eventData.currentIndices
304
});
305
});
306
```
307
308
## Error Handling
309
310
```javascript
311
// Handle invalid trace indices
312
try {
313
await Plotly.deleteTraces('chart', [0, 1, 2]);
314
} catch (error) {
315
if (error.message.includes('index')) {
316
console.error('Invalid trace index specified');
317
}
318
}
319
320
// Validate trace data before adding
321
function validateTrace(trace) {
322
if (!trace.type) {
323
throw new Error('Trace must have a type');
324
}
325
if (trace.type === 'scatter' && (!trace.x || !trace.y)) {
326
throw new Error('Scatter traces must have x and y data');
327
}
328
return true;
329
}
330
331
try {
332
validateTrace(newTrace);
333
await Plotly.addTraces('chart', newTrace);
334
} catch (error) {
335
console.error('Invalid trace data:', error.message);
336
}
337
```
338
339
## Performance Considerations
340
341
- Adding many traces individually is slower than adding them in batch
342
- Use `moveTraces()` instead of delete + add for reordering
343
- Consider using `visible: 'legendonly'` instead of deleting traces if they might be needed again
344
- For frequently changing trace sets, consider using `react()` with a complete data array
345
346
## Types
347
348
```javascript { .api }
349
interface PlotlyTrace {
350
type: string;
351
name?: string;
352
visible?: boolean | 'legendonly';
353
showlegend?: boolean;
354
x?: any[];
355
y?: any[];
356
z?: any[];
357
mode?: string;
358
marker?: MarkerConfig;
359
line?: LineConfig;
360
fill?: string;
361
fillcolor?: string;
362
opacity?: number;
363
hovertemplate?: string;
364
customdata?: any[];
365
meta?: any;
366
uid?: string;
367
[key: string]: any;
368
}
369
370
interface MarkerConfig {
371
color?: string | string[];
372
size?: number | number[];
373
symbol?: string | string[];
374
opacity?: number | number[];
375
line?: {
376
color?: string | string[];
377
width?: number | number[];
378
};
379
}
380
381
interface LineConfig {
382
color?: string;
383
width?: number;
384
dash?: string;
385
shape?: string;
386
smoothing?: number;
387
}
388
```