A C++ plotting library for expressive, interactive, real-time & streaming data visualization
Plotly.cpp brings the power of Plotly.js to C++. Most Plotly.js functions have direct C++ equivalents, making it a familiar plotting library for C++ developers.
Warning
This library is currently under active development
We welcome feedback, bug reports, and contributions to help stabilize the library!
- β¨ Key Features
- π Plotly.js Compatibility
- π Installation & Quick Start
- π Simple Examples
- π¨ Advanced Gallery
- ποΈ Architecture Overview
- π Complete API Reference
- ποΈ Development & Contributing
- π License
- π Star History
-
π Plotly.js API Mapping - Translation of most Plotly.js methods
-
π¨ Advanced Visualizations - Rich variety of plot types. See gallery for more examples.
-
β‘ Real-Time Updates - Stream data with smooth animations and live updates
-
π Bidirectional Events - Handle user interactions from C++
If you know Plotly.js, you already know Plotly.cpp. The library provides C++ equivalents for Plotly.js functions:
| Plotly.js (JavaScript) | Plotly.cpp (C++) | Purpose |
|---|---|---|
| Plotly.newPlot() | plotly::Figure::newPlot() |
Create new plot |
| Plotly.update() | plotly::Figure::update() |
Update data & layout |
| Plotly.restyle() | plotly::Figure::restyle() |
Update styling |
| Plotly.relayout() | plotly::Figure::relayout() |
Update layout only |
| Plotly.extendTraces() | plotly::Figure::extendTraces() |
Stream data |
| Plotly.addTraces() | plotly::Figure::addTraces() |
Add new traces |
| Plotly.deleteTraces() | plotly::Figure::deleteTraces() |
Remove traces |
| Plotly.downloadImage() | plotly::Figure::downloadImage() |
Save image file |
Similar data structures, same parameters, and similar behavior with C++ syntax.
- Ubuntu Linux (tested platform)
- Chrome/Chromium browser
- C++17 or higher
wget https://github.com/yhisaki/plotly.cpp/releases/download/v0.1.0/libplotly-cpp-0.1.0-Linux.deb
sudo apt install ./libplotly-cpp-0.1.0-Linux.debAdd to your CMake project using FetchContent:
include(FetchContent)
FetchContent_Declare(
plotly-cpp
GIT_REPOSITORY https://github.com/yhisaki/plotly.cpp.git
GIT_TAG v0.1.0
)
FetchContent_MakeAvailable(plotly-cpp)After installation, add the following to your CMakeLists.txt:
find_package(plotly-cpp REQUIRED)
target_link_libraries(your_target plotly-cpp::plotly-cpp)Plotly.cpp requires the following dependencies:
- nlohmann/json - JSON serialization/deserialization. You can install it by
sudo apt install nlohmann-json3-dev.
You can find more details in documentation.
#include "plotly/plotly.hpp"
#include <vector>
int main() {
plotly::Figure fig;
fig.openBrowser(); // Open browser explicitly
std::vector<double> x = {1, 2, 3, 4, 5};
std::vector<double> y = {1, 4, 2, 8, 5};
plotly::Object trace = {
{"x", x}, {"y", y}, {"type", "scatter"},
{"mode", "lines+markers"}
};
fig.newPlot(plotly::Array{trace});
fig.waitClose();
return 0;
}π Complete example
JavaScript equivalent:
Plotly.newPlot("myDiv", [
{
x: [1, 2, 3, 4, 5],
y: [1, 4, 2, 8, 5],
type: "scatter",
mode: "lines+markers",
},
]);#include "plotly/plotly.hpp"
#include <chrono>
#include <cmath>
#include <thread>
int main() {
plotly::Figure fig;
fig.openBrowser();
// Create initial empty trace
plotly::Object trace = {
{"x", std::vector<double>{}}, {"y", std::vector<double>{}},
{"type", "scatter"}, {"mode", "lines"}
};
std::vector<plotly::Object> data = {trace};
fig.newPlot(data);
// Stream sine wave data in real-time
for (double t = 0; t < 100 && fig.isOpen(); t += 0.1) {
fig.extendTraces({{"x", {std::vector<double>{t}}},
{"y", {std::vector<double>{std::sin(t)}}}}, {0}, 100);
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
return 0;
}π Complete example
JavaScript equivalent:
function streamData() {
const newX = [currentTime];
const newY = [Math.sin(currentTime)];
Plotly.extendTraces("myDiv", { x: [newX], y: [newY] }, [0], 100);
}#include "plotly/plotly.hpp"
#include <cmath>
int main() {
plotly::Figure fig;
fig.openBrowser();
// Generate 3D surface data
int size = 50;
std::vector<std::vector<double>> z(size, std::vector<double>(size));
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
double x = (i - size / 2.0) * 0.2;
double y = (j - size / 2.0) * 0.2;
z[i][j] = std::sin(std::sqrt(x * x + y * y));
}
}
plotly::Object trace = {
{"z", z}, {"type", "surface"}, {"colorscale", "Viridis"}
};
fig.newPlot(plotly::Array{trace});
fig.waitClose();
return 0;
}π Complete example
JavaScript equivalent:
const z = []; // 2D array of surface data
// Generate 3D surface data...
Plotly.newPlot("myDiv", [
{
z: z,
type: "surface",
colorscale: "Viridis",
},
]);#include "plotly/plotly.hpp"
#include <cmath>
#include <numbers>
#include <vector>
int main() {
plotly::Figure fig;
fig.openBrowser();
int n = 5000;
std::vector<double> x(n), y(n), z(n), w(n, 2.0);
for (int i = 0; i < n; ++i) {
x[i] = i * i;
y[i] = std::sin(2 * std::numbers::pi * i / 360.0);
z[i] = std::log(i + 1); // +1 to avoid log(0)
}
// Multiple traces with different styles
plotly::Object trace1 = {{"x", x}, {"y", y}, {"type", "scatter"},
{"mode", "lines"}, {"name", "sin(2Οi/360)"}};
plotly::Object trace2 = {{"x", x}, {"y", w}, {"type", "scatter"}, {"mode", "lines"},
{"line", {{"color", "red"}, {"dash", "dash"}}},
{"name", "constant line (y=2)"}};
plotly::Object trace3 = {{"x", x}, {"y", z}, {"type", "scatter"},
{"mode", "lines"}, {"name", "log(x)"}};
plotly::Object layout = {
{"title", {{"text", "Sample figure"}}},
{"xaxis", {{"range", {0, 1000000}}}}, // xlim equivalent
{"showlegend", true},
{"width", 1200}, {"height", 780}
};
fig.newPlot({trace1, trace2, trace3}, layout);
fig.waitClose();
return 0;
}π Complete example
JavaScript equivalent:
const trace1 = {
x: x,
y: y,
type: "scatter",
mode: "lines",
name: "sin(2Οi/360)",
};
const trace2 = {
x: x,
y: w,
type: "scatter",
mode: "lines",
line: { color: "red", dash: "dash" },
name: "constant line (y=2)",
};
const trace3 = {
x: x,
y: z,
type: "scatter",
mode: "lines",
name: "log(x)",
};
const layout = {
title: { text: "Sample figure" },
xaxis: { range: [0, 1000000] },
showlegend: true,
width: 1200,
height: 780,
};
Plotly.newPlot("myDiv", [trace1, trace2, trace3], layout);
Plotly.downloadImage("myDiv", { format: "png", filename: "basic" });#include "plotly/plotly.hpp"
#include <vector>
#include <cmath>
int main() {
plotly::Figure fig;
std::vector<plotly::Object> traces;
// Create traces for each subplot...
plotly::Object layout = {
{"title", {{"text", "2x2 Subplot Grid"}}},
{"grid", {{"rows", 2}, {"columns", 2}, {"pattern", "independent"}}},
{"showlegend", false}};
fig.newPlot(traces, layout);
fig.waitClose();
return 0;
}π Complete example
#include "plotly/plotly.hpp"
#include <vector>
int main() {
plotly::Figure fig;
fig.openBrowser();
// Create plot
std::vector<double> x = {1, 2, 3, 4, 5};
std::vector<double> y = {1, 4, 2, 8, 5};
plotly::Object trace = {{"x", x}, {"y", y}, {"type", "scatter"}, {"mode", "markers"}};
fig.newPlot(plotly::Array{trace});
// Register event handlers
fig.on("plotly_click", [](const plotly::Object &event) {
// Do something when a point is clicked
});
fig.on("plotly_hover", [](const plotly::Object &event) {
// Do something when a point is hovered
});
fig.waitClose();
return 0;
}π Complete example
More complex examples and use cases are available in the gallery.
You can find more details in Architecture Overview.
1. C++ Backend (plotly::Figure)
- WebSocket Server: Real-time bidirectional communication using libwebsockets
- HTTP Server: Serves the web frontend assets (HTML, CSS, JavaScript)
- JSON-RPC Protocol: Structured message passing for plot commands and events
- Browser Integration: Automatically launches Chrome/Chromium with appropriate configuration
2. Web Frontend (JavaScript)
- Plotly.js Runtime: The actual plotting engine that renders visualizations
- WebSocket Client: Connects to C++ backend for command/event exchange
- JSON-RPC Handler: Maps incoming C++ calls to Plotly.js API functions
- Event Bridge: Forwards user interactions (clicks, hovers) back to C++
- Startup: The
plotly::Figureconstructor starts an HTTP server (with an automatically selected port) and a WebSocket server. The browser is opened separately via theopenBrowser()method. - Sending Plot Commands: C++ function calls such as
fig.newPlot(data)are converted into JSON-RPC messages and returnboolindicating success/failure. - Rendering: The frontend receives these messages and invokes the corresponding Plotly.js functions.
- Event Handling: If C++ callbacks are registered with
fig.on(), the frontend sends event data back to C++ via WebSocket whenever such events occur.
fig.newPlot({{"x", {1,2,3}}, {"y", {4,5,6}}, {"type", "scatter"}});Becomes JSON-RPC message:
{
"jsonrpc": "2.0",
"method": "Plotly.newPlot",
"params": {
"data": [{ "x": [1, 2, 3], "y": [4, 5, 6], "type": "scatter" }]
},
"id": 0
}Frontend sends back the following JSON-RPC message when the plot is completed:
{
"jsonrpc": "2.0",
"result": { "success": true },
"id": 0
}| Class | Description |
|---|---|
plotly::Figure |
Main plotting interface (replaces HTML div element) |
plotly::Object |
JSON-compatible data container (same as JavaScript objects) |
| C++ Method | JavaScript Equivalent | Purpose |
|---|---|---|
newPlot(data, layout, config) |
Plotly.newPlot(div, data, layout, config) |
Create new plot |
update(traceUpdate, layoutUpdate) |
Plotly.update(div, traceUpdate, layoutUpdate) |
Update data & layout |
relayout(layout) |
Plotly.relayout(div, layout) |
Update layout only |
restyle(aobj, traces) |
Plotly.restyle(div, aobj, traces) |
Update trace styling |
extendTraces(update, indices, maxPoints) |
Plotly.extendTraces(div, update, indices, maxPoints) |
Stream new data |
react(data, layout, config) |
Plotly.react(div, data, layout, config) |
Efficient update |
| C++ Method | JavaScript Equivalent | Purpose |
|---|---|---|
addTraces(traces, indices) |
Plotly.addTraces(div, traces, indices) |
Add new traces |
deleteTraces(indices) |
Plotly.deleteTraces(div, indices) |
Remove traces |
moveTraces(currentIndices, newIndices) |
Plotly.moveTraces(div, currentIndices, newIndices) |
Reorder traces |
prependTraces(update, indices) |
Plotly.prependTraces(div, update, indices) |
Prepend data |
addFrames(frames) |
Plotly.addFrames(div, frames) |
Add animation frames |
animate(frames, opts) |
Plotly.animate(div, frames, opts) |
Trigger animations |
| C++ Method | JavaScript Equivalent | Purpose |
|---|---|---|
downloadImage(opts) |
Plotly.downloadImage(div, opts) |
Save image file |
setDownloadDirectory(path, port) |
N/A (C++-specific) | Set browser download folder |
isOpen() |
N/A (C++-specific) | Check connection status |
waitClose() |
N/A (C++-specific) | Block until closed |
Documentation Reference: Use Plotly.js documentation directly - most examples translate directly to C++.
git clone https://github.com/yhisaki/plotly.cpp.git
cd plotly.cpp
# Build everything
make release # or make debug for debug build
# Build with Thread Sanitizer
make tsan
# Build with Address Sanitizer
make asan# Set up development environment
pip install pre-commit
pre-commit install
# Format code (with clang-format)
make format
# Run clang-tidy
make tidy
# Build and create coverage report
make coverageThis project is licensed under the MIT License - see the LICENSE file for details.





