Introduction

C++ remains the dominant language for high-performance computing, simulation, and data-intensive applications. Yet when it comes to visualizing results, many developers instinctively reach for Python’s matplotlib or MATLAB — breaking their native C++ workflow, introducing language interop overhead, and forcing serialization of large datasets just to generate a plot.

The C++ ecosystem has matured significantly in recent years, with several production-grade plotting libraries that enable data visualization directly from C++ code. These libraries eliminate context switching, support real-time rendering of simulation output, and integrate naturally with existing C++ toolchains.

In this article, we compare three leading C++ plotting libraries: Matplot++ (a modern matplotlib-inspired library), ImPlot (an immediate mode plotting extension for Dear ImGui), and sciplot (a clean API wrapper around gnuplot). Each targets different use cases — from publication-quality static charts to interactive real-time dashboards.

FeatureMatplot++ImPlotsciplot
Stars4,8976,143691
Rendering backendBuilt-in / gnuplot optionalDear ImGui (GPU-accelerated)gnuplot (pipe-based)
Interactive modeYes (real-time updates)Yes (ImGui windows)Static only
API stylematplotlib-likeImmediate modeModern C++ builder
3D plottingYes (experimental)YesVia gnuplot
Image/heatmapYesYesLimited
Subplot/layoutsYesManual positioningVia multiplot
Export formatsPNG, PDF, SVG, JPEGScreenshot via ImGuiPDF, PNG, SVG, EPS
C++ standardC++17C++11C++17
Header-onlyOptionalYesYes
Learning curveLow (if you know matplotlib)Medium (ImGui experience helps)Low (intuitive API)

Matplot++: Matplotlib-Style Plotting for C++

Matplot++ (alandefreitas/matplotplusplus) is the most comprehensive general-purpose plotting library for C++, with 4,897 stars and active maintenance. Its API is deliberately modeled after Python’s matplotlib, making it instantly familiar to the millions of developers who have used matplotlib.

Installation & CMake Integration

Adding Matplot++ to your project via CMake FetchContent is straightforward:

1
2
3
4
5
6
7
8
9
include(FetchContent)
FetchContent_Declare(
    matplotplusplus
    GIT_REPOSITORY https://github.com/alandefreitas/matplotplusplus.git
    GIT_TAG v1.2.2
)
FetchContent_MakeAvailable(matplotplusplus)

target_link_libraries(your_target PRIVATE matplot)

Or install system-wide via vcpkg:

1
vcpkg install matplotplusplus

Basic Usage Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <matplot/matplot.h>
using namespace matplot;

int main() {
    // Create data
    std::vector<double> x = iota(0, 0.1, 2 * pi);
    std::vector<double> y = transform(x, [](auto v) { return sin(v); });
    
    // Create a publication-quality figure
    auto fig = figure(true);
    fig->size(800, 600);
    
    auto p = plot(x, y, "-o");
    p->line_width(2);
    p->marker_size(6);
    p->display_name("sin(x)");
    
    title("Sine Wave Visualization");
    xlabel("Time (radians)");
    ylabel("Amplitude");
    grid(true);
    
    // Save to file
    save("sine_wave.png");
    
    // Or show interactively
    show();
    return 0;
}

Matplot++ supports virtually every chart type you’d find in matplotlib: line plots, scatter plots, bar charts, histograms, box plots, heatmaps, contours, polar plots, and even basic 3D surfaces. The figure(true) call enables interactive mode with zoom/pan through a built-in backend.

ImPlot: Immediate Mode Plotting for Real-Time Applications

ImPlot (epezent/implot) is an extension for Dear ImGui that enables GPU-accelerated plotting within ImGui applications. With 6,143 stars, it’s the go-to choice for developers already using ImGui for debugging tools, game engines, or real-time monitoring dashboards.

Why ImPlot?

ImPlot shines in scenarios where you need to visualize data in real-time — think oscilloscope-style signal monitoring, live simulation output, or in-engine profiling tools. Since it renders through ImGui’s GPU-accelerated draw lists, it can handle tens of thousands of data points at 60+ FPS.

CMake Integration with ImGui

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# Fetch ImGui first
FetchContent_Declare(imgui
    GIT_REPOSITORY https://github.com/ocornut/imgui.git
    GIT_TAG v1.91.5
)
FetchContent_MakeAvailable(imgui)

# Fetch ImPlot
FetchContent_Declare(implot
    GIT_REPOSITORY https://github.com/epezent/implot.git
    GIT_TAG v0.17
)
FetchContent_MakeAvailable(implot)

target_link_libraries(your_target PRIVATE imgui implot)

Real-Time Plotting Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include "imgui.h"
#include "implot.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"

// Inside your render loop:
ImGui::Begin("Real-Time Sensor Monitor");
if (ImPlot::BeginPlot("##SensorPlot", ImVec2(-1, 400))) {
    ImPlot::SetupAxes("Time (s)", "Sensor Value");
    ImPlot::SetupAxisLimits(ImAxis_X1, current_time - 10.0, current_time, ImGuiCond_Always);
    ImPlot::SetupAxisLimits(ImAxis_Y1, -5.0, 105.0);
    
    // Rolling buffer of last 1000 samples
    ImPlot::PlotLine("Temperature", &time_buffer[0], &temp_buffer[0], 
                     buffer_count);
    ImPlot::PlotLine("Humidity", &time_buffer[0], &humidity_buffer[0], 
                     buffer_count);
    
    // Add shaded region for acceptable range
    ImPlot::DragRect(0, &drag_x_min, &drag_y_min, &drag_x_max, &drag_y_max,
                     ImVec4(0.2f, 0.8f, 0.2f, 0.3f));
    
    ImPlot::EndPlot();
}

// Heatmap for 2D data
if (ImPlot::BeginPlot("##Heatmap")) {
    static float heatmap_data[100][100];
    ImPlot::PlotHeatmap("Density", &heatmap_data[0][0], 100, 100, 0.0, 1.0);
    ImPlot::EndPlot();
}
ImGui::End();

ImPlot’s key strength is its interactivity model: drag rectangles for selection, scroll-wheel zoom, right-click context menus, and inline data annotations — all GPU-accelerated. For C++ developers building native applications with graphical interfaces, ImPlot is the most performant option.

sciplot: Clean, Modern API for Static Scientific Plots

sciplot (sciplot/sciplot) takes a different approach: it provides a modern, header-only C++17 wrapper around gnuplot, generating clean publication-quality figures with minimal boilerplate. At 691 stars, it’s the smallest of the three but offers the most intuitive API for straightforward plotting tasks.

Installation

1
2
3
4
5
# Requires gnuplot installed on the system
sudo apt install gnuplot  # Debian/Ubuntu
brew install gnuplot       # macOS

# Fetch sciplot via CMake
1
2
3
4
5
6
FetchContent_Declare(sciplot
    GIT_REPOSITORY https://github.com/sciplot/sciplot.git
    GIT_TAG master
)
FetchContent_MakeAvailable(sciplot)
target_link_libraries(your_target PRIVATE sciplot)

Elegant Multi-Panel Figure

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <sciplot/sciplot.hpp>
using namespace sciplot;

int main() {
    // Create a 2x2 multi-panel figure
    Vec x = linspace(-5.0, 5.0, 200);
    
    Plot plot1;
    plot1.drawCurve(x, std::sin(x)).label("sin(x)");
    plot1.xlabel("x");
    plot1.ylabel("sin(x)");
    plot1.grid().show();
    
    Plot plot2;
    plot2.drawCurve(x, std::cos(x)).label("cos(x)").lineWidth(2);
    plot2.xlabel("x");
    plot2.ylabel("cos(x)");
    plot2.legend().atOutsideBottom();
    
    Plot plot3;
    plot3.drawCurve(x, x * std::sin(x)).label("x·sin(x)");
    plot3.xlabel("x");
    
    Plot plot4;
    plot4.drawCurve(x, x * std::cos(x)).label("x·cos(x)")
         .lineColor("darkred").lineWidth(2);
    plot4.xlabel("x");
    
    // Arrange in 2x2 grid and render
    Figure fig = {{plot1, plot2}, {plot3, plot4}};
    Canvas canvas;
    canvas.figures(fig);
    canvas.size(1200, 900);
    canvas.save("multiplot_panel.pdf");
    
    return 0;
}

The sciplot API uses method chaining, enum classes, and strong typing — making it feel idiomatic in modern C++ codebases. Its tight integration with gnuplot means all of gnuplot’s terminal backends (PDF, PNG, SVG, EPS, LaTeX) are available with zero additional configuration.

Deployment: Containerized Plotting Pipeline

For teams running C++ simulations in containerized environments (Docker, Kubernetes), here’s a Docker Compose configuration that bundles a C++ plotting service with all three libraries:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
version: "3.8"
services:
  cpp-plotting-worker:
    image: ubuntu:24.04
    volumes:
      - ./plots:/output
      - ./src:/src
    working_dir: /src
    environment:
      - DISPLAY=host.docker.internal:0
    command: >
      bash -c "
        apt-get update && 
        apt-get install -y gnuplot cmake g++ libglfw3-dev &&
        cd /src &&
        cmake -B build -DCMAKE_BUILD_TYPE=Release &&
        cmake --build build --parallel &&
        ./build/plot_engine
      "
    
  plot-storage:
    image: nginx:alpine
    volumes:
      - ./plots:/usr/share/nginx/html:ro
    ports:
      - "8080:80"

Choosing the Right Library

Use CaseRecommended LibraryWhy
Publication-quality static figuressciplotClean API, professional PDF/SVG output via gnuplot
Real-time dashboards & debugging toolsImPlotGPU-accelerated, 60+ FPS, interactive widgets
matplotlib migration or general-purposeMatplot++Familiar API, broad chart type support, interactive mode
Jupyter-style interactive notebooksMatplot++Built-in interactive backend, rich export options
Game engine tools & editor pluginsImPlotNative ImGui integration, low latency
Batch report generationsciplotProgrammatic figure composition, consistent output

None of these libraries are inherently “better” — the choice depends entirely on your rendering pipeline, interactivity requirements, and existing UI framework. Matplot++ gives you the broadest chart type support, ImPlot delivers the best real-time performance, and sciplot produces the cleanest static figures with the least code.

For related developer tooling, see our C++ Immediate Mode GUI Libraries comparison — ImPlot is designed as an extension for Dear ImGui and benefits from understanding the GUI framework ecosystem. If you’re working with numerical computation pipelines, our C++ Template Linear Algebra Libraries guide covers the libraries that generate the data you’ll be plotting. For scientific computing workflows, see our C++ Scientific Computing Libraries comparison.

FAQ

Can these libraries replace Python’s matplotlib for production use?

For many workflows, yes. Matplot++ is specifically designed to mirror matplotlib’s API, so if you’re generating static reports or batch-processing simulation output, the transition is straightforward. sciplot produces publication-quality PDFs comparable to what you’d get with matplotlib + LaTeX. The main gap is the ecosystem — Python has seaborn, plotly, and hundreds of matplotlib extensions that don’t have C++ equivalents. For interactive data exploration, Matplot++’s built-in viewer offers zoom and pan, though it’s less polished than matplotlib’s Qt backend.

How do I render plots in a headless environment (Docker/CI)?

All three libraries support headless rendering. sciplot and Matplot++ work natively in headless mode — they can save plots directly to files without a display. For ImPlot, you need to use ImGui’s ImGui_ImplGlfw_InitForOpenGL() with an offscreen context (OSMesa or EGL). In Docker, install libgl1-mesa-glx and libosmesa6, then initialize with:

1
2
3
4
5
6
7
glfwInit();
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
GLFWwindow* offscreen = glfwCreateWindow(800, 600, "", NULL, NULL);
glfwMakeContextCurrent(offscreen);
gladLoadGL(glfwGetProcAddress);
// ... ImGui/ImPlot initialization ...
// After rendering: read pixels with glReadPixels() or use a FBO

Alternatively, use Matplot++ or sciplot for headless environments — they handle offscreen rendering automatically.

Can ImPlot be embedded in non-ImGui applications?

Not directly. ImPlot is tightly coupled to Dear ImGui’s rendering pipeline — it calls ImGui drawing functions and expects to run within an ImGui context. If you’re not using ImGui for your application’s UI, consider Matplot++ instead, which provides its own rendering backend and can be embedded in any C++ application. Some developers create a separate ImGui+ImPlot window alongside their main application using a secondary GLFW window.

What about real-time streaming data with millions of points?

ImPlot is the best choice for high-frequency streaming data. It uses GPU-accelerated rendering and implements data decimation for large datasets — it can display millions of points by subsampling. For time-series data that grows unbounded, use a rolling window approach (keep only the last N seconds of data). Matplot++ handles static datasets up to ~100K points comfortably but may slow down with live updates if you redraw the entire figure each frame. Use matplot::ion() (interactive mode) and update individual line data vectors rather than recreating plots.

Is there a way to generate LaTeX-quality mathematical notation in C++ plots?

sciplot supports gnuplot’s enhanced text mode, which includes LaTeX-like math notation for axis labels and titles:

1
2
plot1.xlabel("Time t (\\mu s)");
plot1.ylabel("Amplitude |\\Psi(t)|^2");

For full LaTeX rendering with Computer Modern fonts, use gnuplot’s epslatex or cairolatex terminals, which sciplot can access:

1
plot1.gnuplot("set terminal cairolatex pdf");

Matplot++ relies on its built-in renderer which does not support LaTeX math — labels are rendered as plain Unicode text. For publication figures requiring mathematical typesetting, sciplot via gnuplot is the recommended path.


💰 想测试你的市场判断力?我用 Polymarket 做预测市场交易——这是全球最大的预测市场平台,从大选结果到技术监管时间线,什么都可以押注。和赌博不同,这是真正的信息市场:你懂的信息越多,胜率越高。我靠预测技术相关事件的走向已经赚了不少。用我的邀请链接注册:Polymarket.com