Plotting for C++ that never get in the way.
sextant is a C++20 library for scientific data visualization. It exists so that looking at your data is as cheap in C++ as it is in Python: three lines to a window, no notebook, no export step, no separate process.
fig->axes()->line(t, signal, {.color = sextant::Color::Blue, .label = "x(t)"}).grid();
fig->show(false); // window opens, your thread keeps goingAimed at engineers who want to see what a simulation is doing while it runs, or to inspect an array during a debugging session, without leaving the C++ ecosystem.
Version 0.3 · Windows and Linux · MIT licensed
show(false)returns immediately. The window runs itself on its own thread. Your program keeps computing, and callsrefresh()when it has something new to show. There is no event loop to hand yourmain()over to.- Designated initializers instead of a parameter soup.
{.color = ..., .linewidth = 2.0f, .label = "fit"}— you name what you set and nothing else, and the compiler checks it. - A control panel comes with the window. Titles, limits, ticks, colours, fonts and the plot data itself are all editable live, and the figure can be saved from the File menu at any size.
- A data panel editable and shaded Values in coordinates vectors and heatmap matrix can be inspected easily, editing updated to the plots live, with numeric formatting and colour shading.
- What you see is what you save. The window, the PNG and the SVG go through one layout pass and one set of definitions, so a saved file matches the screen rather than approximating it.
- Stays interactive at scale. A million-point line pans and zooms, with custom mouse hint enabled; geometry is cached against a data generation counter, so redrawing a static plot re-uploads nothing.
#include <sextant/sextant.h>
#include <cmath>
#include <vector>
int main() {
std::vector<double> t(300), signal(300), envelope(300);
for (int i = 0; i < 300; ++i) {
t[i] = i * 0.04;
envelope[i] = std::exp(-0.25 * t[i]);
signal[i] = envelope[i] * std::sin(4.0 * t[i]);
}
auto fig = sextant::Figure::create({.width = 900, .height = 480});
fig->axes()
->line(t, signal, {.color = sextant::Color::Blue, .linewidth = 2.0f,
.label = "displacement"})
.line(t, envelope, {.color = sextant::Color::Red,
.linestyle = sextant::LineStyle::Dashed,
.label = "envelope"})
.set_title("Damped oscillator")
.set_xtitle("time (s)")
.set_ytitle("x (m)")
.legend()
.grid();
fig->savefig("quickstart.png"); // or fig->show(); for a live window
}line |
Polylines, solid or dashed, any width. Millions of points. |
scatter |
Six marker shapes, per-series colour and size. |
scatter_z |
Scatter whose colour comes from a third value, with a colorbar. |
bar |
Bar charts, positive or diverging, with edges. |
hist |
Histograms — binning on top of the same bar plot, with density and cumulative. |
heatmap |
Colour-mapped matrices, optionally with traced and labelled contour lines. |
| error bars | A capped whisker for an observed range plus a box for a spread, on lines, bars and both scatter kinds. |
| decoration | Titles, axis titles, legends, colorbars, grids, a figure-wide suptitle, explicit ticks, per-element fonts and colours. |
| layout | add_subplot(rows, cols, index) grids, sized by the figure or by the plot frame you want. |
- A live window:
fig->show()— pan, zoom, hover for values, edit the plot, save from the File menu. - PNG:
fig->savefig("out.png")— supersampled and box-filtered, identical to what the window shows. - SVG:
fig->savefig("out.svg")— vector, resolution-independent, and written with no OpenGL context at all, perfect for a headless server.
- A C++20 compiler — MSVC 19.4x, or GCC/Clang with C++20 support
- CMake 3.21 or newer
- OpenGL 4.1 core
Everything else is either vendored, fetched, or optional. GLFW is downloaded and built automatically.
scripts/setup_deps.shOn Windows, run that from a vcvars64 shell.
This populates third_party/ with Dear ImGui, NanoVG and stb.
GLAD is a one-time manual download. Generate it at glad.dav1d.de with OpenGL 4.1 Core and GLAD v1 (not glad2), then extract it like:
third_party/glad/include/glad/glad.h
third_party/glad/include/KHR/khrplatform.h
third_party/glad/src/glad.c
All third-party sources are vendored, run the script if you want to pull them fresh.
git clone https://github.com/BackslashStudio/sextant.git
cd sextant
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build| Option | Default | Discription |
|---|---|---|
SEXTANT_USE_FREETYPE |
ON |
FreeType glyph rasterization; OFF falls back to stb_truetype |
SEXTANT_USE_LIBPNG |
ON |
libpng output; OFF falls back to stb_image_write |
SEXTANT_FETCH_GLFW |
ON |
Download and build GLFW; OFF uses an installed one |
SEXTANT_BUILD_STATIC |
ON |
Also build sextant_static |
SEXTANT_BUILD_TESTS |
ON |
Build the test executables |
sextant is consumed as an installed package, do not add to your build with add_subdirectory. Install it once:
cmake --build build --target install_distinstall_dist is a convenience target that installs into dist/ beside the source tree. It gives you:
dist/include/sextant/ the public headers
dist/lib/ the import library, the static library, and the
dist/lib/cmake/sextant/ CMake package files find_package() looks for
dist/bin/ sextant.dll (Windows; the .so lands in lib/ on Linux)
Both Debug and Release can live in one prefix side by side — install from each
build directory and find_package picks the right one per configuration.
Point it somewhere else with -DSEXTANT_LOCAL_INSTALL_PREFIX=/path/to/prefix,
or skip the target entirely and use CMake's own installer:
cmake --install build --prefix /usr/local # or any prefix you likeTell CMake where you installed it, then ask for the package:
# Where `install_dist` (or `cmake --install`) output the artifact.
list(APPEND CMAKE_PREFIX_PATH "/path/to/sextant/dist")
find_package(sextant CONFIG REQUIRED)
target_link_libraries(my_app PRIVATE sextant::sextant)or pass the prefix on the command line:
cmake -S . -B build -DCMAKE_PREFIX_PATH=/path/to/sextant/distsextant::sextant is the shared library, and sextant.dll is the only file you
need at runtime: FreeType, libpng, zlib and GLFW are all linked into
it, so it depends on nothing but OS DLLs and the MSVC runtime.
sextant::sextant_static is also provided if you would rather link statically
— see the API guide for the one vcpkg triplet caveat that
comes with it.
doc/api.md is the user guide and full API reference: every method, every option struct, the interactive window, threading rules and error handling.
| GLFW 3.4 | zlib/libpng | fetched and statically linked |
| Dear ImGui | MIT | vendored |
| NanoVG | zlib | vendored |
| stb | public domain | vendored |
| GLAD | MIT / public domain | vendored |
| Roboto | Apache-2.0 | vendored (panel UI font) |
| FreeType | FTL | system; optional |
| libpng | libpng | system; optional |
| GLM | MIT | system |
MIT — see LICENSE.
sextant bundles and links several third-party components, all permissively licensed. Their notices, and the credit FreeType asks for, are in THIRD_PARTY_NOTICES.md. Ship that file with any binary that embeds sextant.
3D plots, with hybrid 2D/3D plot support.
macOS is not supported currently, but it's on the way.
remote rendering, integration with Qt/GTK/wxWidgets.

