or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

client-server.mdcolors-transforms.mdcommand-line.mddocument-management.mdembedding-integration.mdevents-interactivity.mdindex.mdio-operations.mdlayouts.mdmodels-data-sources.mdplotting-interface.mdserver-applications.mdwidgets.md

events-interactivity.mddocs/

0

# Events and Interactivity

1

2

Event system for building interactive applications and handling user interactions. Provides 30+ event types for mouse interactions, keyboard input, plot events, and custom events. Essential for creating responsive visualizations and interactive dashboards.

3

4

## Capabilities

5

6

### Base Event Classes

7

8

Core event classes that form the foundation of Bokeh's event system.

9

10

```python { .api }

11

class Event:

12

"""

13

Base class for all Bokeh events.

14

15

All events inherit from this class and provide common properties.

16

"""

17

model: Model # The model that generated the event

18

event_name: str # Name of the event type

19

20

class DocumentEvent(Event):

21

"""

22

Document-level events.

23

24

Events that occur at the document level, affecting the entire application.

25

"""

26

document: Document # The document where the event occurred

27

28

class ModelEvent(Event):

29

"""

30

Model-level events.

31

32

Events that occur on specific model objects.

33

"""

34

35

class PlotEvent(Event):

36

"""

37

Plot-specific events.

38

39

Events that occur within plot areas.

40

"""

41

42

class PointEvent(PlotEvent):

43

"""

44

Events with coordinate information.

45

46

Events that have associated x/y coordinates in data space.

47

"""

48

x: float # X coordinate in data space

49

y: float # Y coordinate in data space

50

sx: int # X coordinate in screen space (pixels)

51

sy: int # Y coordinate in screen space (pixels)

52

```

53

54

### Mouse Events

55

56

Events triggered by mouse interactions within plots.

57

58

```python { .api }

59

class Tap(PointEvent):

60

"""Single mouse click/tap event."""

61

62

class DoubleTap(PointEvent):

63

"""Double mouse click/tap event."""

64

65

class Press(PointEvent):

66

"""Mouse button press event."""

67

68

class PressUp(PointEvent):

69

"""Mouse button release event."""

70

71

class MouseEnter(PointEvent):

72

"""Mouse cursor enters plot area."""

73

74

class MouseLeave(PointEvent):

75

"""Mouse cursor leaves plot area."""

76

77

class MouseMove(PointEvent):

78

"""Mouse cursor movement within plot."""

79

80

class MouseWheel(PointEvent):

81

"""Mouse wheel scroll event."""

82

delta: float # Scroll delta value

83

```

84

85

### Pan and Zoom Events

86

87

Events related to plot navigation and viewport changes.

88

89

```python { .api }

90

class Pan(PointEvent):

91

"""Pan/drag event during movement."""

92

direction: int # Pan direction

93

94

class PanStart(PointEvent):

95

"""Pan/drag start event."""

96

97

class PanEnd(PointEvent):

98

"""Pan/drag end event."""

99

100

class Pinch(PointEvent):

101

"""Pinch/zoom gesture event."""

102

scale: float # Zoom scale factor

103

104

class PinchStart(PointEvent):

105

"""Pinch/zoom gesture start event."""

106

107

class PinchEnd(PointEvent):

108

"""Pinch/zoom gesture end event."""

109

110

class MouseWheel(PointEvent):

111

"""Mouse wheel zoom event."""

112

delta: float # Wheel delta value

113

```

114

115

### Selection Events

116

117

Events related to data selection and highlighting.

118

119

```python { .api }

120

class SelectionGeometry(PlotEvent):

121

"""Selection geometry change event."""

122

geometry: Dict[str, Any] # Selection geometry specification

123

final: bool # Whether selection is finalized

124

125

class Reset(PlotEvent):

126

"""Plot reset event (clear selections, reset view)."""

127

128

class RangesUpdate(PlotEvent):

129

"""Plot ranges update event."""

130

x0: float # New x-range start

131

x1: float # New x-range end

132

y0: float # New y-range start

133

y1: float # New y-range end

134

```

135

136

### UI Component Events

137

138

Events from interactive UI components like buttons and widgets.

139

140

```python { .api }

141

class ButtonClick(ModelEvent):

142

"""Button click event."""

143

144

class MenuItemClick(ModelEvent):

145

"""Menu item selection event."""

146

item: str # Selected menu item value

147

148

class ValueSubmit(ModelEvent):

149

"""Value submission event (from input widgets)."""

150

value: Any # Submitted value

151

152

class LegendItemClick(ModelEvent):

153

"""Legend item click event."""

154

item: str # Legend item identifier

155

```

156

157

### Plot-Specific Events

158

159

Events related to plot rendering and lifecycle.

160

161

```python { .api }

162

class LODStart(PlotEvent):

163

"""Level-of-detail rendering start event."""

164

165

class LODEnd(PlotEvent):

166

"""Level-of-detail rendering end event."""

167

168

class AxisClick(PlotEvent):

169

"""Axis label or tick click event."""

170

axis: Axis # The clicked axis object

171

```

172

173

### Connection and Lifecycle Events

174

175

Events related to client-server connection and document lifecycle.

176

177

```python { .api }

178

class DocumentReady(DocumentEvent):

179

"""Document fully loaded and ready event."""

180

181

class ConnectionLost(DocumentEvent):

182

"""Server connection lost event."""

183

184

class ClientReconnected(DocumentEvent):

185

"""Client reconnected to server event."""

186

```

187

188

### Touch and Gesture Events

189

190

Events for touch-based interactions on mobile devices.

191

192

```python { .api }

193

class Rotate(PointEvent):

194

"""Rotation gesture event."""

195

rotation: float # Rotation angle in radians

196

197

class RotateStart(PointEvent):

198

"""Rotation gesture start event."""

199

200

class RotateEnd(PointEvent):

201

"""Rotation gesture end event."""

202

```

203

204

### Event Handling

205

206

Methods for registering event callbacks and handling events.

207

208

```python { .api }

209

# Event callback registration (available on all models)

210

def on_event(self, event_type, *callbacks):

211

"""

212

Register callbacks for specific event types.

213

214

Parameters:

215

- event_type: Event class or event name string

216

- callbacks: Callback functions to register

217

218

Each callback receives the event object as its argument.

219

"""

220

221

# Example callback signature

222

def event_callback(event: Event) -> None:

223

"""

224

Event callback function.

225

226

Parameters:

227

- event: The event object containing event data

228

"""

229

230

# JavaScript callbacks for client-side handling

231

class CustomJS:

232

"""JavaScript callback for client-side event handling."""

233

def __init__(self, args=None, code=""):

234

"""

235

Parameters:

236

- args: Dictionary of Python objects available in JavaScript

237

- code: JavaScript code string to execute

238

"""

239

240

args: Dict[str, Any] # Python objects available as JavaScript variables

241

code: str # JavaScript code to execute

242

```

243

244

## Usage Examples

245

246

### Basic Event Handling

247

248

```python

249

from bokeh.plotting import figure, show, curdoc

250

from bokeh.events import Tap

251

from bokeh.models import ColumnDataSource

252

import numpy as np

253

254

# Create data and plot

255

x = np.random.random(100)

256

y = np.random.random(100)

257

source = ColumnDataSource(data=dict(x=x, y=y))

258

259

p = figure(width=400, height=400, tools="tap", title="Click on points")

260

p.circle('x', 'y', source=source, size=10, alpha=0.6)

261

262

def tap_handler(event):

263

"""Handle tap events."""

264

print(f"Tapped at: ({event.x:.2f}, {event.y:.2f})")

265

266

# Register event handler

267

p.on_event(Tap, tap_handler)

268

269

# For server applications

270

curdoc().add_root(p)

271

272

# For standalone scripts

273

# show(p)

274

```

275

276

### Selection Event Handling

277

278

```python

279

from bokeh.plotting import figure, curdoc

280

from bokeh.events import SelectionGeometry

281

from bokeh.models import ColumnDataSource

282

import numpy as np

283

284

# Create data

285

n = 300

286

x = np.random.random(n)

287

y = np.random.random(n)

288

colors = np.random.choice(['red', 'green', 'blue'], n)

289

290

source = ColumnDataSource(data=dict(x=x, y=y, colors=colors))

291

292

p = figure(width=500, height=500, tools="box_select,lasso_select,reset",

293

title="Select points to see coordinates")

294

p.circle('x', 'y', source=source, color='colors', size=8, alpha=0.6)

295

296

def selection_handler(event):

297

"""Handle selection events."""

298

indices = source.selected.indices

299

print(f"Selected {len(indices)} points")

300

if indices:

301

selected_x = [source.data['x'][i] for i in indices]

302

selected_y = [source.data['y'][i] for i in indices]

303

print(f"X range: {min(selected_x):.2f} - {max(selected_x):.2f}")

304

print(f"Y range: {min(selected_y):.2f} - {max(selected_y):.2f}")

305

306

p.on_event(SelectionGeometry, selection_handler)

307

308

curdoc().add_root(p)

309

```

310

311

### Mouse Movement Tracking

312

313

```python

314

from bokeh.plotting import figure, curdoc

315

from bokeh.events import MouseMove

316

from bokeh.models import Div, Column

317

import numpy as np

318

319

# Create plot

320

x = np.linspace(0, 4*np.pi, 100)

321

y = np.sin(x)

322

323

p = figure(width=500, height=300, title="Mouse Movement Tracker")

324

p.line(x, y, line_width=2)

325

326

# Create info display

327

info = Div(text="<p>Move mouse over plot</p>", width=500)

328

329

def mouse_handler(event):

330

"""Handle mouse movement."""

331

info.text = f"""

332

<p><b>Mouse Position:</b></p>

333

<p>Data coordinates: ({event.x:.3f}, {event.y:.3f})</p>

334

<p>Screen coordinates: ({event.sx}, {event.sy})</p>

335

"""

336

337

p.on_event(MouseMove, mouse_handler)

338

339

layout = Column(p, info)

340

curdoc().add_root(layout)

341

```

342

343

### Button Click Events

344

345

```python

346

from bokeh.plotting import figure, curdoc

347

from bokeh.models import Button, ColumnDataSource, Column

348

from bokeh.events import ButtonClick

349

import numpy as np

350

351

# Create plot with dynamic data

352

source = ColumnDataSource(data=dict(x=[1, 2, 3], y=[1, 4, 2]))

353

354

p = figure(width=400, height=300, title="Dynamic Data")

355

line = p.line('x', 'y', source=source, line_width=3)

356

357

# Create control buttons

358

update_button = Button(label="Update Data", button_type="success")

359

reset_button = Button(label="Reset Data", button_type="primary")

360

361

def update_data():

362

"""Generate new random data."""

363

n = np.random.randint(5, 15)

364

new_data = dict(

365

x=sorted(np.random.random(n) * 10),

366

y=np.random.random(n) * 10

367

)

368

source.data = new_data

369

370

def reset_data():

371

"""Reset to original data."""

372

source.data = dict(x=[1, 2, 3], y=[1, 4, 2])

373

374

# Handle button clicks

375

def button_handler(event):

376

if event.model == update_button:

377

update_data()

378

elif event.model == reset_button:

379

reset_data()

380

381

update_button.on_event(ButtonClick, button_handler)

382

reset_button.on_event(ButtonClick, button_handler)

383

384

layout = Column(p, update_button, reset_button)

385

curdoc().add_root(layout)

386

```

387

388

### JavaScript Callbacks for Client-Side Events

389

390

```python

391

from bokeh.plotting import figure, show

392

from bokeh.models import CustomJS, ColumnDataSource, Slider, Column

393

from bokeh.events import MouseMove

394

import numpy as np

395

396

# Create data

397

x = np.linspace(0, 4*np.pi, 100)

398

y = np.sin(x)

399

source = ColumnDataSource(data=dict(x=x, y=y))

400

401

# Create plot

402

p = figure(width=500, height=300, title="Client-Side Interaction")

403

line = p.line('x', 'y', source=source, line_width=2)

404

405

# JavaScript callback for mouse events

406

mouse_callback = CustomJS(args=dict(p=p), code="""

407

// This runs in the browser without server communication

408

console.log('Mouse at:', cb_obj.x, cb_obj.y);

409

410

// Update plot title with coordinates

411

p.title.text = 'Mouse at: (' + cb_obj.x.toFixed(2) + ', ' + cb_obj.y.toFixed(2) + ')';

412

""")

413

414

p.js_on_event('mousemove', mouse_callback)

415

416

# Slider with JavaScript callback

417

slider = Slider(start=0, end=2, value=1, step=0.1, title="Frequency")

418

419

slider_callback = CustomJS(args=dict(source=source), code="""

420

const data = source.data;

421

const f = cb_obj.value;

422

const x = data['x'];

423

const y = data['y'];

424

425

for (let i = 0; i < x.length; i++) {

426

y[i] = Math.sin(f * x[i]);

427

}

428

429

source.change.emit();

430

""")

431

432

slider.js_on_change('value', slider_callback)

433

434

layout = Column(p, slider)

435

show(layout)

436

```

437

438

### Range Update Events

439

440

```python

441

from bokeh.plotting import figure, curdoc

442

from bokeh.events import RangesUpdate

443

from bokeh.models import Div, Column

444

import numpy as np

445

446

# Create plot with pan/zoom tools

447

x = np.random.random(1000)

448

y = np.random.random(1000)

449

450

p = figure(width=500, height=400, tools="pan,wheel_zoom,box_zoom,reset",

451

title="Pan and zoom to see range updates")

452

p.circle(x, y, size=5, alpha=0.5)

453

454

# Info display

455

info = Div(text="<p>Pan or zoom to see range updates</p>", width=500)

456

457

def range_handler(event):

458

"""Handle range update events."""

459

info.text = f"""

460

<p><b>Current View Ranges:</b></p>

461

<p>X: {event.x0:.3f} to {event.x1:.3f}</p>

462

<p>Y: {event.y0:.3f} to {event.y1:.3f}</p>

463

<p>Area: {(event.x1-event.x0)*(event.y1-event.y0):.6f}</p>

464

"""

465

466

p.on_event(RangesUpdate, range_handler)

467

468

layout = Column(p, info)

469

curdoc().add_root(layout)

470

```

471

472

### Multi-Event Handler

473

474

```python

475

from bokeh.plotting import figure, curdoc

476

from bokeh.events import Tap, DoubleTap, Pan, MouseWheel

477

from bokeh.models import Div, Column

478

import numpy as np

479

480

# Create interactive plot

481

x = np.random.random(200)

482

y = np.random.random(200)

483

484

p = figure(width=500, height=400, tools="pan,tap",

485

title="Multi-Event Demo")

486

circles = p.circle(x, y, size=8, alpha=0.6, color='blue')

487

488

# Event log

489

log = Div(text="<p>Event log:</p>", width=500, height=200)

490

491

def event_logger(event):

492

"""Log different types of events."""

493

event_type = type(event).__name__

494

495

if hasattr(event, 'x') and hasattr(event, 'y'):

496

message = f"{event_type} at ({event.x:.2f}, {event.y:.2f})"

497

else:

498

message = f"{event_type} event"

499

500

# Add to log (keep last 10 entries)

501

lines = log.text.split('<br>')

502

if len(lines) > 10:

503

lines = lines[-9:] # Keep last 9 + new one = 10

504

505

lines.append(message)

506

log.text = '<br>'.join(lines)

507

508

# Register multiple event types

509

p.on_event(Tap, event_logger)

510

p.on_event(DoubleTap, event_logger)

511

p.on_event(Pan, event_logger)

512

p.on_event(MouseWheel, event_logger)

513

514

layout = Column(p, log)

515

curdoc().add_root(layout)

516

```