Plotly.cpp 0.1.0
A C++ plotting library for expressive, interactive, real-time & streaming data visualization
Loading...
Searching...
No Matches
Architecture Overview

System Architecture

Plotly.cpp implements a client-server architecture that bridges C++ applications with web-based visualization capabilities through Plotly.js. The system enables real-time, bidirectional communication between C++ code and a JavaScript frontend running in a web browser.

Core Architecture Components

The architecture consists of three main layers:

  1. C++ Backend Layer - The core library providing the plotly::Figure API
  2. Communication Layer - WebSocket and HTTP servers enabling real-time data exchange
  3. JavaScript Frontend Layer - Browser-based visualization using Plotly.js
dot_inline_dotgraph_1.png

Communication Protocol

JSON-RPC 2.0 Over WebSocket

The system uses JSON-RPC 2.0 as the primary communication protocol, transmitted over WebSocket connections. This provides:

  • Structured messaging with request/response semantics
  • Bidirectional communication (C++ ↔ JavaScript)
  • Error handling with standardized error codes
  • Real-time updates with low latency

C++ to JavaScript Communication Flow

msc_inline_mscgraph_1

JavaScript to C++ Communication Flow

msc_inline_mscgraph_2

HTTP Server for Static Assets

An HTTP server serves the JavaScript frontend:

  • Single-page application with bundled Plotly.js
  • WebSocket endpoint discovery via /ws_port endpoint
  • Static file serving for HTML, CSS, and JavaScript assets
  • Automatic port allocation to avoid conflicts

Implementation Details

C++ Backend Components

plotly::Figure

It is implemented in plotly::Figure class in src/plotly.cpp. The main user-facing API that encapsulates:

  • PIMPL idiom for ABI stability
  • WebSocket server management
  • HTTP server management
  • Browser process control
  • JSON-RPC client functionality

Key implementation files:

WebSocket Server

It is implemented in plotly::detail::WebsocketServer class in src/detail/websockets_server.cpp. Built on websocketpp library with the following implementation:

Threading Architecture:

  • Service Thread: Runs the Boost.Asio event loop (_server.run()) handling WebSocket I/O operations
  • Callback Executor Thread: Processes incoming messages and dispatches to registered callbacks (inherited from WebsocketEndpointImpl)

Connection Management:

  • Multiple Client Support: Maintains active connections using std::set<connection_hdl> with WebSocket connection handles
  • Dynamic Client Tracking: Connections automatically added/removed via websocketpp handlers (set_open_handler/set_close_handler)
  • Client Lifecycle Synchronization: Provides waitConnection() and waitUntilNoClient() for coordinating with client connection states

Network Configuration:

  • Dynamic Port Allocation: Uses promise/future pattern to communicate the actual bound port after server initialization
  • TCP Optimization: Disables Nagle algorithm for low-latency JSON-RPC communication
  • Flexible Address Binding: Supports both specific address binding and wildcard binding
  • Socket Reuse: Enables address reuse to prevent binding conflicts on restart

Message Broadcasting:

  • All-Client Broadcasting: send() method delivers messages to all connected clients simultaneously
  • Resilient Delivery: Individual client send failures don't prevent delivery to other clients
  • Text Frame Protocol: Uses WebSocket text frames for JSON-RPC message transmission

HTTP Server

It is implemented in plotly::detail::HttpServer class in src/detail/http_server.cpp. Built on httplib library with the following implementation:

Dual Construction Modes:

  • Directory Serving Mode: Uses set_mount_point("/", directory) to serve static files from filesystem
  • Content Serving Mode: Registers a single GET handler for "/" to serve HTML content directly from memory

Port Management:

  • Dynamic Port Binding: Uses bind_to_any_port("0.0.0.0") to automatically allocate available ports
  • Port Discovery: Returns allocated port via getPort() for external components to connect
  • All-Interface Binding: Listens on "0.0.0.0" to accept connections from any network interface

WebSocket Integration:

  • Port Discovery Endpoint: /ws_port endpoint returns JSON with WebSocket server port for client connection
  • Page Load Confirmation: /loaded endpoint allows frontend to signal successful initialization
  • Connection Management: Uses setWebsocketPortRequestHandler() to configure WebSocket port response

Threading Model:

  • Background Operation: Server runs in dedicated thread (_serverThread) using listen_after_bind()
  • Startup Synchronization: Busy-waits using is_running() check to confirm server initialization
  • HTTP Keep-Alive: Configured with set_keep_alive_max_count(1) to limit persistent connections

JSON-RPC Server

It is implemented in plotly::detail::JsonRpc class in src/detail/json_rpc.cpp. Built as a complete JSON-RPC 2.0 implementation with the following architecture:

Protocol Compliance:

  • JSON-RPC 2.0 Standard: Full compliance with specification including request/response/notification formats
  • Standard Error Codes: Implements predefined error codes (PARSE_ERROR, INVALID_REQUEST, METHOD_NOT_FOUND, etc.)
  • Message Validation: Validates required fields (jsonrpc, method) and handles malformed requests

Method Dispatch System:

  • Handler Registration: Stores method handlers in std::unordered_map<std::string, std::function<json(json)>>
  • Notification Handlers: Separate handler map for notifications (no response required)
  • Request Processing: Parses incoming messages, validates format, and routes to appropriate handlers
  • Exception Handling: Catches handler exceptions and converts to JSON-RPC error responses

Asynchronous Call Management:

  • Future-Based API: call() method returns std::future<nlohmann::json> for asynchronous result handling
  • Request ID Correlation: Auto-incrementing request IDs to match responses with requests
  • Unique Callback Names: Uses UUID-generated callback names to handle concurrent requests
  • Call Cancellation: Provides cancellation function to abort pending requests

WebSocket Integration:

  • Endpoint Abstraction: Takes WebsocketEndpointInterface for transport layer independence
  • Callback Management: Tracks registered WebSocket callbacks for proper cleanup
  • Message Routing: Routes all incoming WebSocket messages through JSON-RPC protocol handler

Response Generation:

  • Success Responses: Automatically formats results into JSON-RPC response objects
  • Error Responses: Generates compliant error responses with code, message, and optional data
  • Notification Handling: Processes notifications without generating responses

Key Design Patterns

API Mirroring

Every Plotly.js method has a corresponding C++ method with identical semantics:

dot_inline_dotgraph_2.png

Event-Driven Architecture

Bidirectional events enable interactivity:

msc_inline_mscgraph_3

Browser Integration

Automatic browser management simplifies deployment:

  • Process spawning with configurable Chrome/Chromium paths
  • Headless mode support for server environments
  • Download directory configuration via Chrome DevTools Protocol
  • Shutdown with proper process cleanup