Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions implot3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3069,6 +3069,15 @@ ImU32 SampleColormapU32(float t, ImPlot3DColormap cmap) {

ImVec4 SampleColormap(float t, ImPlot3DColormap cmap) { return ImGui::ColorConvertU32ToFloat4(SampleColormapU32(t, cmap)); }

template <typename T>
void ConvertValueToColor(T* value, ImU32* cs, int count, float v_min, float v_max, ImPlot3DColormap colormap) {
for (int i = 0; i < count; i++)
cs[i] = SampleColormapU32(ImClamp(ImRemap01(static_cast<float>(value[i]), v_min, v_max), 0.0f, 1.0f), colormap);
}
template void ConvertValueToColor<double>(double* value, ImU32* cs, int count, float v_min, float v_max, ImPlot3DColormap colormap);
template void ConvertValueToColor<float>(float* value, ImU32* cs, int count, float v_min, float v_max, ImPlot3DColormap colormap);
template void ConvertValueToColor<int>(int* value, ImU32* cs, int count, float v_min, float v_max, ImPlot3DColormap colormap);

void RenderColorBar(const ImU32* colors, int size, ImDrawList& DrawList, const ImRect& bounds, bool vert, bool reversed, bool continuous) {
const int n = continuous ? size - 1 : size;
ImU32 col1, col2;
Expand Down
30 changes: 25 additions & 5 deletions implot3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,16 +193,18 @@ enum ImPlot3DScatterFlags_ {
ImPlot3DScatterFlags_None = 0, // Default
ImPlot3DScatterFlags_NoLegend = ImPlot3DItemFlags_NoLegend,
ImPlot3DScatterFlags_NoFit = ImPlot3DItemFlags_NoFit,
ImPlot3DScatterFlags_PerPointCustomColor = 1 << 2, // Each point is assigned with a specific color according to its value
};

// Flags for PlotLine
enum ImPlot3DLineFlags_ {
ImPlot3DLineFlags_None = 0, // Default
ImPlot3DLineFlags_NoLegend = ImPlot3DItemFlags_NoLegend,
ImPlot3DLineFlags_NoFit = ImPlot3DItemFlags_NoFit,
ImPlot3DLineFlags_Segments = 1 << 10, // A line segment will be rendered from every two consecutive points
ImPlot3DLineFlags_Loop = 1 << 11, // The last and first point will be connected to form a closed loop
ImPlot3DLineFlags_SkipNaN = 1 << 12, // NaNs values will be skipped instead of rendered as missing data
ImPlot3DLineFlags_Segments = 1 << 10, // A line segment will be rendered from every two consecutive points
ImPlot3DLineFlags_Loop = 1 << 11, // The last and first point will be connected to form a closed loop
ImPlot3DLineFlags_SkipNaN = 1 << 12, // NaNs values will be skipped instead of rendered as missing data
ImPlot3DLineFlags_PerPointCustomColor = 1 << 13, // Each point is assigned with a specific color according to its value
};

// Flags for PlotTriangle
Expand Down Expand Up @@ -233,6 +235,7 @@ enum ImPlot3DSurfaceFlags_ {
ImPlot3DSurfaceFlags_NoLines = 1 << 10, // No lines will be rendered
ImPlot3DSurfaceFlags_NoFill = 1 << 11, // No fill will be rendered
ImPlot3DSurfaceFlags_NoMarkers = 1 << 12, // No markers will be rendered
ImPlot3DSurfaceFlags_PerPointCustomColor = 1 << 13, // No markers will be rendered
};

// Flags for PlotMesh
Expand Down Expand Up @@ -504,10 +507,18 @@ IMPLOT3D_API void SetupLegend(ImPlot3DLocation location, ImPlot3DLegendFlags fla
IMPLOT3D_TMP void PlotScatter(const char* label_id, const T* xs, const T* ys, const T* zs, int count, ImPlot3DScatterFlags flags = 0, int offset = 0,
int stride = sizeof(T));

// Plots a scatter plot in 3D. Each point is assigned with specific color
IMPLOT3D_TMP void PlotScatter(const char* label_id, const T* xs, const T* ys, const T* zs, const ImU32* cs, int count, ImPlot3DScatterFlags flags = 0,
int offset = 0, int stride = sizeof(T));

// Plots a line in 3D. Consecutive points are connected with line segments
IMPLOT3D_TMP void PlotLine(const char* label_id, const T* xs, const T* ys, const T* zs, int count, ImPlot3DLineFlags flags = 0, int offset = 0,
int stride = sizeof(T));

// Plots a line in 3D. Each point is assigned with specific color
IMPLOT3D_TMP void PlotLine(const char* label_id, const T* xs, const T* ys, const T* zs, const ImU32* cs, int count, ImPlot3DLineFlags flags = 0,
int offset = 0, int stride = sizeof(T));

// Plots triangles in 3D. Every 3 consecutive points define a triangle
IMPLOT3D_TMP void PlotTriangle(const char* label_id, const T* xs, const T* ys, const T* zs, int count, ImPlot3DTriangleFlags flags = 0,
int offset = 0, int stride = sizeof(T));
Expand All @@ -522,6 +533,10 @@ IMPLOT3D_TMP void PlotQuad(const char* label_id, const T* xs, const T* ys, const
IMPLOT3D_TMP void PlotSurface(const char* label_id, const T* xs, const T* ys, const T* zs, int x_count, int y_count, double scale_min = 0.0,
double scale_max = 0.0, ImPlot3DSurfaceFlags flags = 0, int offset = 0, int stride = sizeof(T));

// Plot the surface defined by a grid of vertices. Each vertex is assigned with a specific color
IMPLOT3D_TMP void PlotSurface(const char* label_id, const T* xs, const T* ys, const T* zs, const ImU32* cs, int x_count, int y_count,
double scale_min = 0.0, double scale_max = 0.0, ImPlot3DSurfaceFlags flags = 0, int offset = 0, int stride = sizeof(T));

// Plots a 3D mesh given vertex positions and indices. Triangles are defined by the index buffer (every 3 indices form a triangle)
IMPLOT3D_API void PlotMesh(const char* label_id, const ImPlot3DPoint* vtx, const unsigned int* idx, int vtx_count, int idx_count,
ImPlot3DMeshFlags flags = 0);
Expand Down Expand Up @@ -672,6 +687,9 @@ IMPLOT3D_API ImVec4 GetColormapColor(int idx, ImPlot3DColormap cmap = IMPLOT3D_A
// Sample a color from the current colormap given t between 0 and 1
IMPLOT3D_API ImVec4 SampleColormap(float t, ImPlot3DColormap cmap = IMPLOT3D_AUTO);

// Convert values to colors using a specific colormap.
IMPLOT3D_TMP void ConvertValueToColor(T* value, ImU32* cs, int count, float v_min, float v_max, ImPlot3DColormap colormap);

//-----------------------------------------------------------------------------
// [SECTION] Demo
//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -704,8 +722,10 @@ IMPLOT3D_API void ShowAboutWindow(bool* p_open = nullptr);
// ImPlot3DPoint: 3D vector to store points in 3D space
struct ImPlot3DPoint {
double x, y, z; // Coordinates
constexpr ImPlot3DPoint() : x(0.0), y(0.0), z(0.0) {}
constexpr ImPlot3DPoint(double _x, double _y, double _z) : x(_x), y(_y), z(_z) {}
ImU32 c; //color
constexpr ImPlot3DPoint() : x(0.0), y(0.0), z(0.0), c(ImU32()) {}
constexpr ImPlot3DPoint(double _x, double _y, double _z) : x(_x), y(_y), z(_z), c(ImU32()) {}
constexpr ImPlot3DPoint(double _x, double _y, double _z, ImU32 _c) : x(_x), y(_y), z(_z), c(_c) {}

// Accessors
double& operator[](size_t idx) {
Expand Down
129 changes: 107 additions & 22 deletions implot3d_demo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#define IMPLOT_DISABLE_OBSOLETE_FUNCTIONS
#endif

#include "implot.h"
#include "implot3d.h"
#include "implot3d_internal.h"

Expand Down Expand Up @@ -106,49 +107,114 @@ int MetricFormatter(double value, char* buff, int size, void* data) {
//-----------------------------------------------------------------------------

void DemoLinePlots() {
static float xs1[1001], ys1[1001], zs1[1001];
static ImU32 colors1[1001], colors2[20];
static float scale_min = FLT_MAX;
static float scale_max = -FLT_MAX;
const char* colormaps[] = { "Viridis", "Plasma", "Hot", "Cool", "Pink", "Jet", "Twilight", "RdBu", "BrBG", "PiYG", "Spectral", "Greys" };
static int sel_colormap = 5; // Jet by default

static float xs1[1001], ys1[1001], zs1[1001], vs1[1001];
for (int i = 0; i < 1001; i++) {
xs1[i] = i * 0.001f;
ys1[i] = 0.5f + 0.5f * cosf(50 * (xs1[i] + (float)ImGui::GetTime() / 10));
zs1[i] = 0.5f + 0.5f * sinf(50 * (xs1[i] + (float)ImGui::GetTime() / 10));
vs1[i] = sin(i * 0.15f);
scale_min = (scale_min > vs1[i]) ? vs1[i] : scale_min;
scale_max = (scale_max < vs1[i]) ? vs1[i] : scale_max;
}
static double xs2[20], ys2[20], zs2[20];
static float xs2[20], ys2[20], zs2[20], vs2[20];
for (int i = 0; i < 20; i++) {
xs2[i] = i * 1 / 19.0f;
ys2[i] = xs2[i] * xs2[i];
zs2[i] = xs2[i] * ys2[i];
vs2[i] = cos(i * 0.15f);
}

static bool ppc_color = false;
ImGui::Checkbox("Per Point Custom Color", &ppc_color);
if(!ppc_color) {
if (ImPlot3D::BeginPlot("Line Plots")) {
ImPlot3D::SetupAxes("x", "y", "z");
ImPlot3D::PlotLine("f(x)", xs1, ys1, zs1, 1001);
ImPlot3D::SetNextMarkerStyle(ImPlot3DMarker_Circle);
ImPlot3D::PlotLine("g(x)", xs2, ys2, zs2, 20, ImPlot3DLineFlags_Segments);
ImPlot3D::EndPlot();
}
}
if (ImPlot3D::BeginPlot("Line Plots")) {
ImPlot3D::SetupAxes("x", "y", "z");
ImPlot3D::PlotLine("f(x)", xs1, ys1, zs1, 1001);
ImPlot3D::SetNextMarkerStyle(ImPlot3DMarker_Circle);
ImPlot3D::PlotLine("g(x)", xs2, ys2, zs2, 20, ImPlot3DLineFlags_Segments);
ImPlot3D::EndPlot();
else {
ImGui::Combo("##ScatterColormap", &sel_colormap, colormaps, IM_ARRAYSIZE(colormaps));
ImGui::SameLine();
ImGui::Text("Choose colormap");
ImGui::DragFloatRange2("Min / Max", &scale_min, &scale_max, 0.05);
ImPlot3DColormap cmap = ImPlot3D::GetColormapIndex(colormaps[sel_colormap]);
ImPlot3D::ConvertValueToColor(vs1, colors1, 1001, scale_min, scale_max, cmap);
ImPlot3D::ConvertValueToColor(vs2, colors2, 20, scale_min, scale_max, cmap);
ImPlot::ColormapScale("##Z-Scale", scale_min, scale_max, ImVec2(60, 400), "%.2f", 0, cmap);
ImGui::SameLine();
if (ImPlot3D::BeginPlot("Line Plots with Per Point Custom Colors")) {
ImPlot3D::SetupAxes("x", "y", "z");
ImPlot3D::PlotLine("f(x)", xs1, ys1, zs1, colors1, 1001, ImPlot3DLineFlags_PerPointCustomColor);
ImPlot3D::SetNextMarkerStyle(ImPlot3DMarker_Circle);
ImPlot3D::PlotLine("g(x)", xs2, ys2, zs2, colors2, 20, ImPlot3DLineFlags_Segments | ImPlot3DLineFlags_PerPointCustomColor);
ImPlot3D::EndPlot();
}
}
}

void DemoScatterPlots() {
static ImU32 colors1[100], colors2[50];
static float scale_min = FLT_MAX;
static float scale_max = -FLT_MAX;
const char* colormaps[] = { "Viridis", "Plasma", "Hot", "Cool", "Pink", "Jet", "Twilight", "RdBu", "BrBG", "PiYG", "Spectral", "Greys" };
static int sel_colormap = 5; // Jet by default

srand(0);
static float xs1[100], ys1[100], zs1[100];
static float xs1[100], ys1[100], zs1[100], vs1[100];
for (int i = 0; i < 100; i++) {
xs1[i] = i * 0.01f;
ys1[i] = xs1[i] + 0.1f * ((float)rand() / (float)RAND_MAX);
zs1[i] = xs1[i] + 0.1f * ((float)rand() / (float)RAND_MAX);
vs1[i] = cos(i * 0.1f);
scale_min = (scale_min > vs1[i]) ? vs1[i] : scale_min;
scale_max = (scale_max < vs1[i]) ? vs1[i] : scale_max;
}
static float xs2[50], ys2[50], zs2[50];
static float xs2[50], ys2[50], zs2[50], vs2[50];
for (int i = 0; i < 50; i++) {
xs2[i] = 0.25f + 0.2f * ((float)rand() / (float)RAND_MAX);
ys2[i] = 0.50f + 0.2f * ((float)rand() / (float)RAND_MAX);
zs2[i] = 0.75f + 0.2f * ((float)rand() / (float)RAND_MAX);
vs2[i] = cos(i * 0.1f);
}

static bool ppc_color = false;
ImGui::Checkbox("Per Point Custom Color", &ppc_color);
if (!ppc_color) {
if (ImPlot3D::BeginPlot("Scatter Plots")) {
ImPlot3D::PlotScatter("Data 1", xs1, ys1, zs1, 100);
ImPlot3D::PushStyleVar(ImPlot3DStyleVar_FillAlpha, 0.25f);
ImPlot3D::SetNextMarkerStyle(ImPlot3DMarker_Square, 6, ImPlot3D::GetColormapColor(1), IMPLOT3D_AUTO, ImPlot3D::GetColormapColor(1));
ImPlot3D::PlotScatter("Data 2", xs2, ys2, zs2, 50);
ImPlot3D::PopStyleVar();
ImPlot3D::EndPlot();
}
}

if (ImPlot3D::BeginPlot("Scatter Plots")) {
ImPlot3D::PlotScatter("Data 1", xs1, ys1, zs1, 100);
ImPlot3D::PushStyleVar(ImPlot3DStyleVar_FillAlpha, 0.25f);
ImPlot3D::SetNextMarkerStyle(ImPlot3DMarker_Square, 6, ImPlot3D::GetColormapColor(1), IMPLOT3D_AUTO, ImPlot3D::GetColormapColor(1));
ImPlot3D::PlotScatter("Data 2", xs2, ys2, zs2, 50);
ImPlot3D::PopStyleVar();
ImPlot3D::EndPlot();
else {
ImGui::Combo("##ScatterColormap", &sel_colormap, colormaps, IM_ARRAYSIZE(colormaps));
ImGui::SameLine();
ImGui::Text("Choose colormap");
ImGui::DragFloatRange2("Min / Max", &scale_min, &scale_max, 0.05);
ImPlot3DColormap cmap = ImPlot3D::GetColormapIndex(colormaps[sel_colormap]);
ImPlot3D::ConvertValueToColor(vs1, colors1, 100, scale_min, scale_max, cmap);
ImPlot3D::ConvertValueToColor(vs2, colors2, 50, scale_min, scale_max, cmap);
ImPlot::ColormapScale("##Z-Scale", scale_min, scale_max, ImVec2(60, 400), "%.2f", 0, cmap);
ImGui::SameLine();
if (ImPlot3D::BeginPlot("Scatter Plots with Per Point Custom Colors")) {
ImPlot3D::PlotScatter("Data 1", xs1, ys1, zs1, colors1, 100, ImPlot3DScatterFlags_PerPointCustomColor);
ImPlot3D::PushStyleVar(ImPlot3DStyleVar_FillAlpha, 0.25f);
ImPlot3D::SetNextMarkerStyle(ImPlot3DMarker_Square, 6);
ImPlot3D::PlotScatter("Data 2", xs2, ys2, zs2, colors2, 50, ImPlot3DScatterFlags_PerPointCustomColor);
ImPlot3D::EndPlot();
}
}
}

Expand Down Expand Up @@ -314,7 +380,7 @@ void DemoQuadPlots() {

void DemoSurfacePlots() {
constexpr int N = 20;
static float xs[N * N], ys[N * N], zs[N * N];
static float xs[N * N], ys[N * N], zs[N * N], vs[N * N];
static float t = 0.0f;
t += ImGui::GetIO().DeltaTime;

Expand All @@ -323,16 +389,25 @@ void DemoSurfacePlots() {
constexpr float max_val = 1.0f;
constexpr float step = (max_val - min_val) / (N - 1);

// Define parameters for per-point color
ImU32 colors[N * N];
static float scale_min = FLT_MAX;
static float scale_max = -FLT_MAX;
ImPlot3DColormap cmap;

// Populate the xs, ys, and zs arrays
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
int idx = i * N + j;
xs[idx] = min_val + j * step; // X values are constant along rows
ys[idx] = min_val + i * step; // Y values are constant along columns
zs[idx] = ImSin(2 * t + ImSqrt((xs[idx] * xs[idx] + ys[idx] * ys[idx]))); // z = sin(2t + sqrt(x^2 + y^2))
vs[idx] = ImSin(10 * ImSqrt((xs[idx] * xs[idx] + ys[idx] * ys[idx])));
scale_min = (scale_min > vs[i]) ? vs[i] : scale_min;
scale_max = (scale_max < vs[i]) ? vs[i] : scale_max;
}
}

// Choose fill color
ImGui::Text("Fill color");
static int selected_fill = 1; // Colormap by default
Expand Down Expand Up @@ -381,6 +456,7 @@ void DemoSurfacePlots() {
CHECKBOX_FLAG(flags, ImPlot3DSurfaceFlags_NoLines);
CHECKBOX_FLAG(flags, ImPlot3DSurfaceFlags_NoFill);
CHECKBOX_FLAG(flags, ImPlot3DSurfaceFlags_NoMarkers);
CHECKBOX_FLAG(flags, ImPlot3DSurfaceFlags_PerPointCustomColor);

// Begin the plot
if (selected_fill == 1)
Expand All @@ -401,9 +477,18 @@ void DemoSurfacePlots() {

// Plot the surface
if (custom_range)
ImPlot3D::PlotSurface("Wave Surface", xs, ys, zs, N, N, (double)range_min, (double)range_max, flags);
if(flags & ImPlot3DSurfaceFlags_PerPointCustomColor)
ImPlot3D::PlotSurface("Wave Surface", xs, ys, zs, colors, N, N, (double)range_min, (double)range_max, flags);
else
ImPlot3D::PlotSurface("Wave Surface", xs, ys, zs, N, N, (double)range_min, (double)range_max, flags);
else
ImPlot3D::PlotSurface("Wave Surface", xs, ys, zs, N, N, 0.0, 0.0, flags);
if (flags & ImPlot3DSurfaceFlags_PerPointCustomColor) {
// Map values to colors
ImPlot3D::ConvertValueToColor(vs, colors, N * N, scale_min, scale_max, ImPlot3D::GetColormapIndex(colormaps[sel_colormap]));
ImPlot3D::PlotSurface("Wave Surface", xs, ys, zs, colors, N, N, 0.0, 0.0, flags);
}
else
ImPlot3D::PlotSurface("Wave Surface", xs, ys, zs, N, N, 0.0, 0.0, flags);

// End the plot
ImPlot3D::PopStyleVar();
Expand Down
Loading