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

server-applications.mddocs/

0

# Server and Applications

1

2

Framework for building interactive web applications with Python callbacks, real-time data updates, and complex application logic. The Bokeh server enables creation of full-featured data applications that respond to user interactions entirely in Python without requiring JavaScript programming.

3

4

## Capabilities

5

6

### Application Framework

7

8

Core classes for creating Bokeh server applications.

9

10

```python { .api }

11

class Application:

12

"""

13

Bokeh application factory for creating documents.

14

15

An Application object is a factory for Document instances. It

16

defines the structure and behavior of server applications.

17

"""

18

def __init__(self, *handlers, **kwargs):

19

"""

20

Parameters:

21

- handlers: FunctionHandler, DirectoryHandler, or ScriptHandler objects

22

- **kwargs: Additional application configuration

23

"""

24

25

# Application lifecycle methods

26

def create_document(self):

27

"""Create a new document instance for a session."""

28

29

def process_request(self, request):

30

"""Process incoming HTTP request."""

31

32

def on_server_loaded(self, server_context):

33

"""Called when application is loaded on server."""

34

35

def on_server_unloaded(self, server_context):

36

"""Called when application is unloaded from server."""

37

38

def on_session_created(self, session_context):

39

"""Called when new session is created."""

40

41

def on_session_destroyed(self, session_context):

42

"""Called when session is destroyed."""

43

44

# Application handlers

45

class Handler:

46

"""Base class for application handlers."""

47

48

class FunctionHandler(Handler):

49

"""Handler that uses a function to create document content."""

50

def __init__(self, func):

51

"""

52

Parameters:

53

- func: Function that takes a Document and modifies it

54

"""

55

56

class ScriptHandler(Handler):

57

"""Handler that loads Python script as application."""

58

def __init__(self, filename):

59

"""

60

Parameters:

61

- filename: Path to Python script file

62

"""

63

64

class DirectoryHandler(Handler):

65

"""Handler that loads application from directory structure."""

66

def __init__(self, path):

67

"""

68

Parameters:

69

- path: Path to application directory

70

"""

71

```

72

73

### Document Management

74

75

Functions and classes for managing the current document context in server applications.

76

77

```python { .api }

78

def curdoc():

79

"""

80

Get current document.

81

82

In server applications, returns the Document instance for the

83

current session. In standalone scripts, creates a new Document.

84

85

Returns:

86

Document: Current document instance

87

"""

88

89

class Document:

90

"""

91

Container for all Bokeh models in an application.

92

93

The Document holds all models and manages their relationships,

94

callbacks, and lifecycle in server applications.

95

"""

96

def __init__(self, **kwargs): ...

97

98

# Model management

99

def add_root(self, model):

100

"""Add a model as a root of the document."""

101

102

def remove_root(self, model):

103

"""Remove a root model from the document."""

104

105

@property

106

def roots(self):

107

"""List of root models in the document."""

108

109

# Callback management

110

def add_periodic_callback(self, callback, period_milliseconds):

111

"""

112

Add a callback to be executed periodically.

113

114

Parameters:

115

- callback: Function to call periodically

116

- period_milliseconds: Callback interval in milliseconds

117

118

Returns:

119

PeriodicCallback: Callback object for management

120

"""

121

122

def add_timeout_callback(self, callback, timeout_milliseconds):

123

"""

124

Add a callback to be executed once after a timeout.

125

126

Parameters:

127

- callback: Function to call after timeout

128

- timeout_milliseconds: Timeout in milliseconds

129

130

Returns:

131

TimeoutCallback: Callback object for management

132

"""

133

134

def add_next_tick_callback(self, callback):

135

"""Add a callback to be executed on the next tick."""

136

137

def remove_periodic_callback(self, callback):

138

"""Remove a periodic callback."""

139

140

def remove_timeout_callback(self, callback):

141

"""Remove a timeout callback."""

142

143

def remove_next_tick_callback(self, callback):

144

"""Remove a next-tick callback."""

145

146

# Property change callbacks

147

def on_change(self, *callbacks):

148

"""Register callbacks for document changes."""

149

150

# Session management

151

@property

152

def session_context(self):

153

"""Current session context."""

154

155

# Serialization

156

def to_json_string(self, include_defaults=True):

157

"""Serialize document to JSON string."""

158

159

def to_json(self, include_defaults=True):

160

"""Serialize document to JSON object."""

161

162

# Title and metadata

163

title: str # Document title

164

template: str # HTML template name

165

template_variables: Dict[str, Any] # Template variables

166

167

class without_document_lock:

168

"""

169

Context manager for operations outside document lock.

170

171

Some operations (like network requests) should be performed

172

outside the document lock to avoid blocking the server.

173

"""

174

def __enter__(self): ...

175

def __exit__(self, exc_type, exc_val, exc_tb): ...

176

```

177

178

### Client Session Management

179

180

Classes for connecting to and managing Bokeh server sessions from client code.

181

182

```python { .api }

183

class ClientSession:

184

"""

185

Client session for connecting to Bokeh server.

186

187

Manages the connection between a client and a server application,

188

handling authentication, document synchronization, and callbacks.

189

"""

190

def __init__(self, session_id=None, websocket_url=None, io_loop=None, **kwargs):

191

"""

192

Parameters:

193

- session_id: Unique session identifier

194

- websocket_url: WebSocket URL for server connection

195

- io_loop: Tornado IOLoop instance

196

"""

197

198

# Connection management

199

def connect(self):

200

"""Connect to the server."""

201

202

def close(self, why="closed"):

203

"""Close the connection."""

204

205

@property

206

def connected(self):

207

"""Whether session is connected to server."""

208

209

# Document access

210

@property

211

def document(self):

212

"""Document associated with this session."""

213

214

# Callback management

215

def on_change(self, *callbacks):

216

"""Register callbacks for session changes."""

217

218

# Request handling

219

def request_server_info(self):

220

"""Request server information."""

221

222

def force_roundtrip(self):

223

"""Force a round-trip to synchronize with server."""

224

225

def pull_session(session_id=None, url=None, io_loop=None, **kwargs):

226

"""

227

Pull session from server.

228

229

Creates a ClientSession connected to an existing server session.

230

231

Parameters:

232

- session_id: Session ID to connect to (None for new session)

233

- url: Server URL

234

- io_loop: Tornado IOLoop instance

235

236

Returns:

237

ClientSession: Connected client session

238

"""

239

240

def push_session(document, session_id=None, url=None, io_loop=None, **kwargs):

241

"""

242

Push session to server.

243

244

Creates a new server session with the given document.

245

246

Parameters:

247

- document: Document to push to server

248

- session_id: Session ID (None for auto-generated)

249

- url: Server URL

250

- io_loop: Tornado IOLoop instance

251

252

Returns:

253

ClientSession: Client session for the pushed document

254

"""

255

256

def show_session(session_id=None, server_url=None, session_url=None,

257

browser=None, new=None, **kwargs):

258

"""

259

Display session in browser.

260

261

Parameters:

262

- session_id: Session ID to display

263

- server_url: Base server URL

264

- session_url: Full session URL

265

- browser: Browser name/path

266

- new: Browser window behavior ('tab', 'window', None)

267

"""

268

269

DEFAULT_SESSION_ID: str # Default session identifier constant

270

```

271

272

### Server Infrastructure

273

274

Classes for running and configuring the Bokeh server.

275

276

```python { .api }

277

class Server:

278

"""

279

Bokeh server for hosting applications.

280

281

The Server class provides the web server infrastructure for

282

hosting Bokeh applications with WebSocket communication.

283

"""

284

def __init__(self, applications, port=5006, address=None, **kwargs):

285

"""

286

Parameters:

287

- applications: Dict mapping URL paths to Application objects

288

- port: Server port number

289

- address: Server bind address

290

"""

291

292

def start(self):

293

"""Start the server."""

294

295

def stop(self):

296

"""Stop the server."""

297

298

def run_until_shutdown(self):

299

"""Run server until shutdown signal."""

300

301

@property

302

def port(self):

303

"""Server port number."""

304

305

@property

306

def address(self):

307

"""Server bind address."""

308

309

# Server lifecycle callbacks

310

class SessionContext:

311

"""Context for server session lifecycle callbacks."""

312

session_id: str

313

server_context: 'ServerContext'

314

destroyed: bool

315

316

class ServerContext:

317

"""Context for server application lifecycle callbacks."""

318

application_context: 'ApplicationContext'

319

sessions: Dict[str, SessionContext]

320

```

321

322

### Callback Types

323

324

Classes for different types of server callbacks.

325

326

```python { .api }

327

class PeriodicCallback:

328

"""Periodic callback that executes at regular intervals."""

329

def __init__(self, callback, period, io_loop=None):

330

"""

331

Parameters:

332

- callback: Function to execute

333

- period: Period in milliseconds

334

- io_loop: Tornado IOLoop instance

335

"""

336

337

def start(self):

338

"""Start the periodic callback."""

339

340

def stop(self):

341

"""Stop the periodic callback."""

342

343

@property

344

def is_running(self):

345

"""Whether callback is currently running."""

346

347

class TimeoutCallback:

348

"""One-time callback that executes after a timeout."""

349

def __init__(self, callback, timeout, io_loop=None):

350

"""

351

Parameters:

352

- callback: Function to execute

353

- timeout: Timeout in milliseconds

354

- io_loop: Tornado IOLoop instance

355

"""

356

357

class NextTickCallback:

358

"""Callback that executes on the next event loop tick."""

359

def __init__(self, callback, io_loop=None):

360

"""

361

Parameters:

362

- callback: Function to execute

363

- io_loop: Tornado IOLoop instance

364

"""

365

```

366

367

## Usage Examples

368

369

### Basic Server Application

370

371

```python

372

# save as: myapp.py

373

from bokeh.plotting import figure, curdoc

374

from bokeh.models import ColumnDataSource, Button, Column

375

from bokeh.events import ButtonClick

376

import numpy as np

377

378

# Create data source

379

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

380

381

# Create plot

382

p = figure(width=400, height=400, title="Server Application")

383

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

384

385

# Create button

386

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

387

388

def update():

389

"""Update plot with random data."""

390

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

391

new_data = dict(

392

x=list(range(n)),

393

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

394

)

395

source.data = new_data

396

397

# Handle button clicks

398

button.on_event(ButtonClick, lambda event: update())

399

400

# Create layout

401

layout = Column(button, p)

402

403

# Add to current document

404

curdoc().add_root(layout)

405

curdoc().title = "My Bokeh App"

406

407

# Run with: bokeh serve myapp.py

408

```

409

410

### Periodic Updates

411

412

```python

413

# Real-time data application

414

from bokeh.plotting import figure, curdoc

415

from bokeh.models import ColumnDataSource

416

import numpy as np

417

from datetime import datetime

418

import random

419

420

# Create streaming data source

421

source = ColumnDataSource(data=dict(time=[], value=[]))

422

423

# Create plot

424

p = figure(width=600, height=400, title="Real-Time Data Stream",

425

x_axis_type='datetime')

426

p.line('time', 'value', source=source, line_width=2)

427

428

def update_data():

429

"""Add new data point."""

430

new_time = datetime.now()

431

new_value = random.random() * 100

432

433

# Stream new data (keep last 100 points)

434

source.stream(dict(time=[new_time], value=[new_value]), rollover=100)

435

436

# Add periodic callback for updates every 500ms

437

curdoc().add_periodic_callback(update_data, 500)

438

curdoc().add_root(p)

439

curdoc().title = "Real-Time Dashboard"

440

```

441

442

### Interactive Dashboard with Widgets

443

444

```python

445

from bokeh.plotting import figure, curdoc

446

from bokeh.models import ColumnDataSource, Slider, Select, Column, Row

447

from bokeh.layouts import column, row

448

import numpy as np

449

450

# Data source

451

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

452

453

# Create plot

454

p = figure(width=500, height=400, title="Interactive Dashboard")

455

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

456

457

# Widgets

458

freq_slider = Slider(start=0.1, end=5.0, value=1.0, step=0.1,

459

title="Frequency")

460

func_select = Select(title="Function", value="sin",

461

options=["sin", "cos", "tan"])

462

amplitude_slider = Slider(start=0.1, end=5.0, value=1.0, step=0.1,

463

title="Amplitude")

464

465

def update_plot():

466

"""Update plot based on widget values."""

467

freq = freq_slider.value

468

func_name = func_select.value

469

amplitude = amplitude_slider.value

470

471

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

472

473

if func_name == "sin":

474

y = amplitude * np.sin(freq * x)

475

elif func_name == "cos":

476

y = amplitude * np.cos(freq * x)

477

else: # tan

478

y = amplitude * np.tan(freq * x)

479

y = np.clip(y, -10, 10) # Limit tan values

480

481

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

482

483

# Widget callbacks

484

def on_change(attr, old, new):

485

update_plot()

486

487

freq_slider.on_change('value', on_change)

488

func_select.on_change('value', on_change)

489

amplitude_slider.on_change('value', on_change)

490

491

# Initial plot

492

update_plot()

493

494

# Layout

495

controls = column(freq_slider, func_select, amplitude_slider)

496

layout = row(controls, p)

497

498

curdoc().add_root(layout)

499

curdoc().title = "Interactive Function Plotter"

500

```

501

502

### Multi-Session Application

503

504

```python

505

from bokeh.plotting import figure, curdoc

506

from bokeh.models import ColumnDataSource, Div, Column

507

import numpy as np

508

import uuid

509

510

# Generate unique session data

511

session_id = str(uuid.uuid4())[:8]

512

session_data = np.random.random(50) * 100

513

514

# Create data source with session-specific data

515

source = ColumnDataSource(data=dict(

516

x=list(range(len(session_data))),

517

y=session_data

518

))

519

520

# Create plot

521

p = figure(width=500, height=300, title=f"Session {session_id}")

522

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

523

p.circle('x', 'y', source=source, size=8, alpha=0.7)

524

525

# Session info

526

info = Div(text=f"""

527

<h3>Session Information</h3>

528

<p><b>Session ID:</b> {session_id}</p>

529

<p><b>Data Points:</b> {len(session_data)}</p>

530

<p><b>Data Range:</b> {min(session_data):.2f} - {max(session_data):.2f}</p>

531

""")

532

533

layout = Column(info, p)

534

curdoc().add_root(layout)

535

curdoc().title = f"Multi-Session App - {session_id}"

536

537

# Optional: Add periodic callback to update data

538

def update_session_data():

539

"""Update session-specific data."""

540

global session_data

541

# Add some noise to existing data

542

session_data = session_data + np.random.normal(0, 1, len(session_data))

543

source.data = dict(x=list(range(len(session_data))), y=session_data)

544

545

curdoc().add_periodic_callback(update_session_data, 2000) # Update every 2 seconds

546

```

547

548

### Client Connection Example

549

550

```python

551

# Client script to connect to server application

552

from bokeh.client import pull_session, push_session, show_session

553

from bokeh.plotting import figure

554

from bokeh.io import curdoc

555

import numpy as np

556

557

# Method 1: Pull existing session

558

session = pull_session(url="http://localhost:5006/myapp")

559

print(f"Connected to session: {session.session_id}")

560

561

# Access the document

562

doc = session.document

563

print(f"Document has {len(doc.roots)} root models")

564

565

# Method 2: Push new document to server

566

new_doc = curdoc()

567

568

# Create content for new document

569

p = figure(width=400, height=400)

570

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

571

p.line(x, np.sin(x))

572

new_doc.add_root(p)

573

574

# Push to server

575

push_session = push_session(new_doc, url="http://localhost:5006/")

576

print(f"Pushed document to session: {push_session.session_id}")

577

578

# Method 3: Show session in browser

579

show_session(session_id=push_session.session_id,

580

server_url="http://localhost:5006")

581

```

582

583

### Application Factory Pattern

584

585

```python

586

# application.py - Reusable application factory

587

from bokeh.application import Application

588

from bokeh.application.handlers import FunctionHandler

589

from bokeh.plotting import figure, curdoc

590

from bokeh.models import ColumnDataSource, Slider, Column

591

import numpy as np

592

593

def create_app(config=None):

594

"""

595

Factory function to create Bokeh application.

596

597

Parameters:

598

- config: Dictionary of configuration options

599

"""

600

config = config or {}

601

602

def modify_doc(doc):

603

"""Function to set up the document."""

604

# Create plot based on config

605

width = config.get('width', 500)

606

height = config.get('height', 400)

607

title = config.get('title', 'Default App')

608

609

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

610

611

p = figure(width=width, height=height, title=title)

612

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

613

614

# Add interactivity

615

slider = Slider(start=0.1, end=5.0, value=1.0, step=0.1,

616

title="Parameter")

617

618

def update(attr, old, new):

619

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

620

y = np.sin(new * x)

621

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

622

623

slider.on_change('value', update)

624

update(None, None, 1.0) # Initial update

625

626

layout = Column(slider, p)

627

doc.add_root(layout)

628

doc.title = title

629

630

return Application(FunctionHandler(modify_doc))

631

632

# Usage:

633

# app1 = create_app({'title': 'Sin Wave', 'width': 600})

634

# app2 = create_app({'title': 'Different Config', 'height': 500})

635

#

636

# # Run with multiple apps:

637

# # bokeh serve --show application.py:app1 application.py:app2

638

```

639

640

### Command Line Server Usage

641

642

```bash

643

# Basic server commands

644

645

# Serve single application

646

bokeh serve myapp.py

647

648

# Serve on specific port

649

bokeh serve myapp.py --port 8080

650

651

# Serve multiple applications

652

bokeh serve app1.py app2.py --show

653

654

# Serve with auto-reload during development

655

bokeh serve myapp.py --dev

656

657

# Serve from directory

658

bokeh serve myapp/ --show

659

660

# Serve with custom URL prefix

661

bokeh serve myapp.py --prefix /custom/path

662

663

# Allow external connections

664

bokeh serve myapp.py --allow-websocket-origin=*

665

666

# Serve with authentication

667

bokeh serve myapp.py --oauth-provider=github

668

```