or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

animation.mdchart-types.mdcore-plotting.mddata-streaming.mddata-updates.mdexport-utilities.mdindex.mdinteractive-components.mdlayout-system.mdtrace-management.md

data-streaming.mddocs/

0

# Data Streaming

1

2

Functions for efficiently appending or prepending data to existing traces, ideal for real-time data visualization and streaming applications.

3

4

## Capabilities

5

6

### extendTraces

7

8

Appends new data to the end of existing trace arrays. Perfect for real-time data feeds and growing datasets.

9

10

```javascript { .api }

11

/**

12

* Extends existing trace data arrays by appending new values

13

* @param graphDiv - DOM element ID (string) or element reference

14

* @param update - Object with arrays of new data to append

15

* @param indices - Array of trace indices to extend

16

* @param maxPoints - Maximum number of points to keep per trace (optional windowing)

17

* @returns Promise that resolves to the graph div element

18

*/

19

function extendTraces(

20

graphDiv: string | HTMLElement,

21

update: {[key: string]: any[][]},

22

indices: number | number[],

23

maxPoints?: number | number[]

24

): Promise<HTMLElement>;

25

```

26

27

**Usage Examples:**

28

29

```javascript

30

import Plotly from 'plotly.js-dist';

31

32

// Basic data extension - add single point

33

await Plotly.extendTraces('chart', {

34

x: [[new Date()]], // New x value for first trace

35

y: [[Math.random()]] // New y value for first trace

36

}, [0]);

37

38

// Extend multiple traces with multiple points

39

await Plotly.extendTraces('chart', {

40

x: [[1, 2, 3], [4, 5, 6]], // 3 points for trace 0, 3 points for trace 1

41

y: [[10, 11, 12], [20, 21, 22]] // Corresponding y values

42

}, [0, 1]);

43

44

// Real-time data streaming with windowing

45

await Plotly.extendTraces('chart', {

46

x: [[Date.now()]],

47

y: [[sensorReading]]

48

}, [0], 100); // Keep only last 100 points

49

50

// Different window sizes per trace

51

await Plotly.extendTraces('chart', {

52

x: [[time], [time]],

53

y: [[value1], [value2]]

54

}, [0, 1], [50, 200]); // Trace 0: 50 points, Trace 1: 200 points

55

56

// Streaming with timestamps

57

const timestamp = new Date().toISOString();

58

await Plotly.extendTraces('chart', {

59

x: [[timestamp]],

60

y: [[temperature]],

61

text: [[`Temp: ${temperature}°C`]]

62

}, [0]);

63

```

64

65

### prependTraces

66

67

Adds new data to the beginning of existing trace arrays. Useful for reverse chronological data or when new data should appear at the start.

68

69

```javascript { .api }

70

/**

71

* Extends existing trace data arrays by prepending new values

72

* @param graphDiv - DOM element ID (string) or element reference

73

* @param update - Object with arrays of new data to prepend

74

* @param indices - Array of trace indices to extend

75

* @param maxPoints - Maximum number of points to keep per trace (optional windowing)

76

* @returns Promise that resolves to the graph div element

77

*/

78

function prependTraces(

79

graphDiv: string | HTMLElement,

80

update: {[key: string]: any[][]},

81

indices: number | number[],

82

maxPoints?: number | number[]

83

): Promise<HTMLElement>;

84

```

85

86

**Usage Examples:**

87

88

```javascript

89

// Prepend single data point

90

await Plotly.prependTraces('chart', {

91

x: [[0]],

92

y: [[initialValue]]

93

}, [0]);

94

95

// Prepend multiple points to multiple traces

96

await Plotly.prependTraces('chart', {

97

x: [[-3, -2, -1], [-6, -5, -4]],

98

y: [[1, 2, 3], [4, 5, 6]]

99

}, [0, 1]);

100

101

// Prepend with windowing (remove from end)

102

await Plotly.prependTraces('chart', {

103

x: [[earlierTime]],

104

y: [[earlierValue]]

105

}, [0], 100); // Keep only first 100 points

106

107

// Historical data loading (newest first)

108

const historicalData = await fetchHistoricalData();

109

await Plotly.prependTraces('chart', {

110

x: [historicalData.timestamps],

111

y: [historicalData.values]

112

}, [0], 1000);

113

```

114

115

## Real-Time Streaming Patterns

116

117

### Continuous Data Stream

118

119

```javascript

120

class RealTimeChart {

121

constructor(chartId, maxPoints = 100) {

122

this.chartId = chartId;

123

this.maxPoints = maxPoints;

124

this.isStreaming = false;

125

}

126

127

async startStreaming(dataSource, interval = 1000) {

128

this.isStreaming = true;

129

130

while (this.isStreaming) {

131

try {

132

const newData = await dataSource.getNext();

133

await Plotly.extendTraces(this.chartId, {

134

x: [[new Date()]],

135

y: [[newData.value]]

136

}, [0], this.maxPoints);

137

138

await new Promise(resolve => setTimeout(resolve, interval));

139

} catch (error) {

140

console.error('Streaming error:', error);

141

this.stopStreaming();

142

}

143

}

144

}

145

146

stopStreaming() {

147

this.isStreaming = false;

148

}

149

}

150

151

// Usage

152

const chart = new RealTimeChart('live-chart', 200);

153

await chart.startStreaming(sensorDataSource, 500);

154

```

155

156

### Multi-Series Streaming

157

158

```javascript

159

// Stream data for multiple sensors

160

async function streamMultipleSensors(sensorData) {

161

const xData = [];

162

const yData = [];

163

const now = new Date();

164

165

sensorData.forEach(sensor => {

166

xData.push([now]);

167

yData.push([sensor.reading]);

168

});

169

170

await Plotly.extendTraces('multi-sensor-chart', {

171

x: xData,

172

y: yData

173

}, Array.from({length: sensorData.length}, (_, i) => i), 300);

174

}

175

176

// Stream every second

177

setInterval(async () => {

178

const readings = await Promise.all([

179

sensor1.read(),

180

sensor2.read(),

181

sensor3.read()

182

]);

183

await streamMultipleSensors(readings);

184

}, 1000);

185

```

186

187

### Batch Data Extension

188

189

```javascript

190

// Collect data in batches for better performance

191

class BatchStreamer {

192

constructor(chartId, batchSize = 10, maxPoints = 1000) {

193

this.chartId = chartId;

194

this.batchSize = batchSize;

195

this.maxPoints = maxPoints;

196

this.buffer = {x: [], y: []};

197

}

198

199

addDataPoint(x, y) {

200

this.buffer.x.push(x);

201

this.buffer.y.push(y);

202

203

if (this.buffer.x.length >= this.batchSize) {

204

this.flush();

205

}

206

}

207

208

async flush() {

209

if (this.buffer.x.length > 0) {

210

await Plotly.extendTraces(this.chartId, {

211

x: [this.buffer.x],

212

y: [this.buffer.y]

213

}, [0], this.maxPoints);

214

215

this.buffer = {x: [], y: []};

216

}

217

}

218

}

219

```

220

221

### Time-Based Windowing

222

223

```javascript

224

// Maintain a fixed time window (e.g., last 5 minutes)

225

class TimeWindowChart {

226

constructor(chartId, windowMs = 300000) { // 5 minutes

227

this.chartId = chartId;

228

this.windowMs = windowMs;

229

}

230

231

async addDataPoint(value) {

232

const now = Date.now();

233

234

// Add new point

235

await Plotly.extendTraces(this.chartId, {

236

x: [[now]],

237

y: [[value]]

238

}, [0]);

239

240

// Remove old points outside window

241

const chartDiv = document.getElementById(this.chartId);

242

const trace = chartDiv.data[0];

243

const cutoffTime = now - this.windowMs;

244

245

const validIndices = trace.x.findIndex(x => x >= cutoffTime);

246

if (validIndices > 0) {

247

await Plotly.restyle(this.chartId, {

248

x: [trace.x.slice(validIndices)],

249

y: [trace.y.slice(validIndices)]

250

}, [0]);

251

}

252

}

253

}

254

```

255

256

## Advanced Streaming Features

257

258

### Conditional Data Extension

259

260

```javascript

261

// Only extend if data meets certain criteria

262

async function conditionalExtend(chartId, newData, threshold = 0) {

263

const filteredData = newData.filter(point => point.value > threshold);

264

265

if (filteredData.length > 0) {

266

await Plotly.extendTraces(chartId, {

267

x: [filteredData.map(p => p.timestamp)],

268

y: [filteredData.map(p => p.value)]

269

}, [0]);

270

}

271

}

272

```

273

274

### Data Rate Limiting

275

276

```javascript

277

// Limit update frequency to prevent overwhelming the UI

278

class RateLimitedStream {

279

constructor(chartId, minInterval = 100) {

280

this.chartId = chartId;

281

this.minInterval = minInterval;

282

this.lastUpdate = 0;

283

this.pendingData = [];

284

}

285

286

async addData(x, y) {

287

this.pendingData.push({x, y});

288

289

const now = Date.now();

290

if (now - this.lastUpdate >= this.minInterval) {

291

await this.flushPending();

292

this.lastUpdate = now;

293

}

294

}

295

296

async flushPending() {

297

if (this.pendingData.length > 0) {

298

const xData = this.pendingData.map(d => d.x);

299

const yData = this.pendingData.map(d => d.y);

300

301

await Plotly.extendTraces(this.chartId, {

302

x: [xData],

303

y: [yData]

304

}, [0]);

305

306

this.pendingData = [];

307

}

308

}

309

}

310

```

311

312

## Performance Optimization

313

314

### Efficient Data Structures

315

316

```javascript

317

// Use typed arrays for better performance with large datasets

318

const bufferSize = 1000;

319

const xBuffer = new Float64Array(bufferSize);

320

const yBuffer = new Float32Array(bufferSize);

321

let bufferIndex = 0;

322

323

function addPoint(x, y) {

324

xBuffer[bufferIndex] = x;

325

yBuffer[bufferIndex] = y;

326

bufferIndex = (bufferIndex + 1) % bufferSize;

327

328

// Update plot every N points

329

if (bufferIndex % 10 === 0) {

330

const recentX = Array.from(xBuffer.slice(Math.max(0, bufferIndex - 10), bufferIndex));

331

const recentY = Array.from(yBuffer.slice(Math.max(0, bufferIndex - 10), bufferIndex));

332

333

Plotly.extendTraces('chart', {x: [recentX], y: [recentY]}, [0], 1000);

334

}

335

}

336

```

337

338

### WebGL for High-Frequency Data

339

340

```javascript

341

// Use scattergl for high-frequency streaming

342

const initialData = [{

343

x: [],

344

y: [],

345

type: 'scattergl', // WebGL-accelerated rendering

346

mode: 'lines',

347

name: 'High Frequency Data'

348

}];

349

350

await Plotly.newPlot('high-freq-chart', initialData);

351

352

// Stream data at high frequency

353

setInterval(async () => {

354

await Plotly.extendTraces('high-freq-chart', {

355

x: [[Date.now()]],

356

y: [[Math.sin(Date.now() / 1000)]]

357

}, [0], 10000); // Keep 10,000 points

358

}, 16); // ~60 FPS

359

```

360

361

## Event Handling

362

363

```javascript { .api }

364

interface StreamingEvents {

365

'plotly_afterplot': () => void;

366

'plotly_autosize': () => void;

367

'plotly_beforeplot': () => void;

368

}

369

```

370

371

**Usage Examples:**

372

373

```javascript

374

const chartDiv = document.getElementById('streaming-chart');

375

376

// Detect when streaming updates complete

377

chartDiv.on('plotly_afterplot', () => {

378

console.log('Streaming update rendered');

379

});

380

381

// Handle plot resizing during streaming

382

chartDiv.on('plotly_autosize', () => {

383

console.log('Plot resized during streaming');

384

});

385

```

386

387

## Error Handling

388

389

```javascript

390

// Handle streaming errors gracefully

391

async function safeExtendTraces(chartId, update, indices, maxPoints) {

392

try {

393

await Plotly.extendTraces(chartId, update, indices, maxPoints);

394

} catch (error) {

395

console.error('Failed to extend traces:', error);

396

397

// Fallback: clear and restart

398

if (error.message.includes('data')) {

399

console.warn('Clearing chart data and restarting');

400

await Plotly.react(chartId, [{x: [], y: [], type: 'scatter'}]);

401

}

402

}

403

}

404

```

405

406

## Types

407

408

```javascript { .api }

409

// Data update structure for streaming

410

interface StreamUpdate {

411

x?: any[][];

412

y?: any[][];

413

z?: any[][];

414

text?: string[][];

415

marker?: {

416

color?: any[][];

417

size?: number[][];

418

};

419

[key: string]: any[][];

420

}

421

422

// Windowing configuration

423

type MaxPoints = number | number[];

424

425

// Streaming configuration options

426

interface StreamingConfig {

427

maxPoints?: MaxPoints;

428

updateInterval?: number;

429

batchSize?: number;

430

enableWebGL?: boolean;

431

timeWindow?: number;

432

}

433

```