1
0
Fork 0
mirror of https://github.com/gwm17/implot.git synced 2024-11-26 12:18:52 -05:00

Adds PlotHistogram and PlotHistogram2D, Improves Colormaps and Heatmap (#148)

This commit is contained in:
Evan Pezent 2021-03-17 07:38:45 -05:00 committed by GitHub
parent b85a2c0800
commit 1d9381a004
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 1417 additions and 720 deletions

File diff suppressed because it is too large Load Diff

270
implot.h
View File

@ -1,6 +1,6 @@
// MIT License // MIT License
// Copyright (c) 2020 Evan Pezent // Copyright (c) 2021 Evan Pezent
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@ -32,7 +32,7 @@
// Define attributes of all API symbols declarations (e.g. for DLL under Windows) // Define attributes of all API symbols declarations (e.g. for DLL under Windows)
// Using ImPlot via a shared library is not recommended, because we don't guarantee // Using ImPlot via a shared library is not recommended, because we don't guarantee
// backward nor forward ABI compatibility and also function call overhead. If you // backward nor forward ABI compatibility and also function call overhead. If you
// do use ImPlot as a DLL, be sure to call SetImGuiContext (details below). // do use ImPlot as a DLL, be sure to call SetImGuiContext (see Miscellanous section).
#ifndef IMPLOT_API #ifndef IMPLOT_API
#define IMPLOT_API #define IMPLOT_API
#endif #endif
@ -61,6 +61,7 @@ typedef int ImPlotColormap; // -> enum ImPlotColormap_
typedef int ImPlotLocation; // -> enum ImPlotLocation_ typedef int ImPlotLocation; // -> enum ImPlotLocation_
typedef int ImPlotOrientation; // -> enum ImPlotOrientation_ typedef int ImPlotOrientation; // -> enum ImPlotOrientation_
typedef int ImPlotYAxis; // -> enum ImPlotYAxis_; typedef int ImPlotYAxis; // -> enum ImPlotYAxis_;
typedef int ImPlotBin; // -> enum ImPlotBin_
// Options for plots. // Options for plots.
enum ImPlotFlags_ { enum ImPlotFlags_ {
@ -85,14 +86,15 @@ enum ImPlotFlags_ {
enum ImPlotAxisFlags_ { enum ImPlotAxisFlags_ {
ImPlotAxisFlags_None = 0, // default ImPlotAxisFlags_None = 0, // default
ImPlotAxisFlags_NoLabel = 1 << 0, // the axis label will not be displayed (axis labels also hidden if the supplied string name is NULL) ImPlotAxisFlags_NoLabel = 1 << 0, // the axis label will not be displayed (axis labels also hidden if the supplied string name is NULL)
ImPlotAxisFlags_NoGridLines = 1 << 1, // the axis grid lines will not be displayed ImPlotAxisFlags_NoGridLines = 1 << 1, // no grid lines will be displayed
ImPlotAxisFlags_NoTickMarks = 1 << 2, // the axis tick marks will not be displayed ImPlotAxisFlags_NoTickMarks = 1 << 2, // no tick marks will be displayed
ImPlotAxisFlags_NoTickLabels = 1 << 3, // the axis tick labels will not be displayed ImPlotAxisFlags_NoTickLabels = 1 << 3, // no text labels will be displayed
ImPlotAxisFlags_LogScale = 1 << 4, // a logartithmic (base 10) axis scale will be used (mutually exclusive with ImPlotAxisFlags_Time) ImPlotAxisFlags_LogScale = 1 << 4, // a logartithmic (base 10) axis scale will be used (mutually exclusive with ImPlotAxisFlags_Time)
ImPlotAxisFlags_Time = 1 << 5, // axis will display date/time formatted labels (mutually exclusive with ImPlotAxisFlags_LogScale) ImPlotAxisFlags_Time = 1 << 5, // axis will display date/time formatted labels (mutually exclusive with ImPlotAxisFlags_LogScale)
ImPlotAxisFlags_Invert = 1 << 6, // the axis will be inverted ImPlotAxisFlags_Invert = 1 << 6, // the axis will be inverted
ImPlotAxisFlags_LockMin = 1 << 7, // the axis minimum value will be locked when panning/zooming ImPlotAxisFlags_AutoFit = 1 << 7, // axis will be auto-fitting to data extents
ImPlotAxisFlags_LockMax = 1 << 8, // the axis maximum value will be locked when panning/zooming ImPlotAxisFlags_LockMin = 1 << 8, // the axis minimum value will be locked when panning/zooming
ImPlotAxisFlags_LockMax = 1 << 9, // the axis maximum value will be locked when panning/zooming
ImPlotAxisFlags_Lock = ImPlotAxisFlags_LockMin | ImPlotAxisFlags_LockMax, ImPlotAxisFlags_Lock = ImPlotAxisFlags_LockMin | ImPlotAxisFlags_LockMax,
ImPlotAxisFlags_NoDecorations = ImPlotAxisFlags_NoLabel | ImPlotAxisFlags_NoGridLines | ImPlotAxisFlags_NoTickMarks | ImPlotAxisFlags_NoTickLabels ImPlotAxisFlags_NoDecorations = ImPlotAxisFlags_NoLabel | ImPlotAxisFlags_NoGridLines | ImPlotAxisFlags_NoTickMarks | ImPlotAxisFlags_NoTickLabels
}; };
@ -180,18 +182,22 @@ enum ImPlotMarker_ {
// Built-in colormaps // Built-in colormaps
enum ImPlotColormap_ { enum ImPlotColormap_ {
ImPlotColormap_Default = 0, // ImPlot default colormap (n=10) ImPlotColormap_Deep = 0, // a.k.a. seaborn deep (qual=true, n=10) (default)
ImPlotColormap_Deep = 1, // a.k.a. seaborn deep (n=10) ImPlotColormap_Dark = 1, // a.k.a. matplotlib "Set1" (qual=true, n=9 )
ImPlotColormap_Dark = 2, // a.k.a. matplotlib "Set1" (n=9) ImPlotColormap_Pastel = 2, // a.k.a. matplotlib "Pastel1" (qual=true, n=9 )
ImPlotColormap_Pastel = 3, // a.k.a. matplotlib "Pastel1" (n=9) ImPlotColormap_Paired = 3, // a.k.a. matplotlib "Paired" (qual=true, n=12)
ImPlotColormap_Paired = 4, // a.k.a. matplotlib "Paired" (n=12) ImPlotColormap_Viridis = 4, // a.k.a. matplotlib "viridis" (qual=false, n=11)
ImPlotColormap_Viridis = 5, // a.k.a. matplotlib "viridis" (n=11) ImPlotColormap_Plasma = 5, // a.k.a. matplotlib "plasma" (qual=false, n=11)
ImPlotColormap_Plasma = 6, // a.k.a. matplotlib "plasma" (n=11) ImPlotColormap_Hot = 6, // a.k.a. matplotlib/MATLAB "hot" (qual=false, n=11)
ImPlotColormap_Hot = 7, // a.k.a. matplotlib/MATLAB "hot" (n=11) ImPlotColormap_Cool = 7, // a.k.a. matplotlib/MATLAB "cool" (qual=false, n=11)
ImPlotColormap_Cool = 8, // a.k.a. matplotlib/MATLAB "cool" (n=11) ImPlotColormap_Pink = 8, // a.k.a. matplotlib/MATLAB "pink" (qual=false, n=11)
ImPlotColormap_Pink = 9, // a.k.a. matplotlib/MATLAB "pink" (n=11) ImPlotColormap_Jet = 9, // a.k.a. MATLAB "jet" (qual=false, n=11)
ImPlotColormap_Jet = 10, // a.k.a. MATLAB "jet" (n=11) ImPlotColormap_Twilight = 10, // a.k.a. matplotlib "twilight" (qual=false, n=11)
ImPlotColormap_COUNT ImPlotColormap_RdBu = 11, // red/blue, Color Brewer (qual=false, n=11)
ImPlotColormap_BrBG = 12, // brown/blue-green, Color Brewer (qual=false, n=11)
ImPlotColormap_PiYG = 13, // pink/yellow-green, Color Brewer (qual=false, n=11)
ImPlotColormap_Spectral = 14, // color spectrum, Color Brewer (qual=false, n=11)
ImPlotColormap_Greys = 15, // white/black (qual=false, n=2 )
}; };
// Used to position items on a plot (e.g. legends, labels, etc.) // Used to position items on a plot (e.g. legends, labels, etc.)
@ -220,6 +226,14 @@ enum ImPlotYAxis_ {
ImPlotYAxis_3 = 2 // second on right side ImPlotYAxis_3 = 2 // second on right side
}; };
// Enums for different automatic histogram binning methods (k = bin count or w = bin width)
enum ImPlotBin_ {
ImPlotBin_Sqrt = -1, // k = sqrt(n)
ImPlotBin_Sturges = -2, // k = 1 + log2(n)
ImPlotBin_Rice = -3, // k = 2 * cbrt(n)
ImPlotBin_Scott = -4, // w = 3.49 * sigma / cbrt(n)
};
// Double precision version of ImVec2 used by ImPlot. Extensible by end users. // Double precision version of ImVec2 used by ImPlot. Extensible by end users.
struct ImPlotPoint { struct ImPlotPoint {
double x, y; double x, y;
@ -246,8 +260,12 @@ struct ImPlotRange {
// Combination of two ranges for X and Y axes. // Combination of two ranges for X and Y axes.
struct ImPlotLimits { struct ImPlotLimits {
ImPlotRange X, Y; ImPlotRange X, Y;
bool Contains(const ImPlotPoint& p) const { return Contains(p.x, p.y); } ImPlotLimits() { }
bool Contains(double x, double y) const { return X.Contains(x) && Y.Contains(y); } ImPlotLimits(double x_min, double x_max, double y_min, double y_max) { X.Min = x_min; X.Max = x_max; Y.Min = y_min; Y.Max = y_max; }
bool Contains(const ImPlotPoint& p) const { return Contains(p.x, p.y); }
bool Contains(double x, double y) const { return X.Contains(x) && Y.Contains(y); }
ImPlotPoint Min() const { return ImPlotPoint(X.Min, Y.Min); }
ImPlotPoint Max() const { return ImPlotPoint(X.Max, Y.Max); }
}; };
// Plot style structure // Plot style structure
@ -275,14 +293,16 @@ struct ImPlotStyle {
ImVec2 LabelPadding; // = 5,5 padding between axes labels, tick labels, and plot edge ImVec2 LabelPadding; // = 5,5 padding between axes labels, tick labels, and plot edge
ImVec2 LegendPadding; // = 10,10 legend padding from plot edges ImVec2 LegendPadding; // = 10,10 legend padding from plot edges
ImVec2 LegendInnerPadding; // = 5,5 legend inner padding from legend edges ImVec2 LegendInnerPadding; // = 5,5 legend inner padding from legend edges
ImVec2 LegendSpacing; // = 0,0 spacing between legend entries ImVec2 LegendSpacing; // = 5,0 spacing between legend entries
ImVec2 MousePosPadding; // = 10,10 padding between plot edge and interior mouse location text ImVec2 MousePosPadding; // = 10,10 padding between plot edge and interior mouse location text
ImVec2 AnnotationPadding; // = 2,2 text padding around annotation labels ImVec2 AnnotationPadding; // = 2,2 text padding around annotation labels
ImVec2 FitPadding; // = 0,0 additional fit padding as a percentage of the fit extents (e.g. ImVec2(0.1f,0.1f) adds 10% to the fit extents of X and Y) ImVec2 FitPadding; // = 0,0 additional fit padding as a percentage of the fit extents (e.g. ImVec2(0.1f,0.1f) adds 10% to the fit extents of X and Y)
ImVec2 PlotDefaultSize; // = 400,300 default size used when ImVec2(0,0) is passed to BeginPlot ImVec2 PlotDefaultSize; // = 400,300 default size used when ImVec2(0,0) is passed to BeginPlot
ImVec2 PlotMinSize; // = 300,225 minimum size plot frame can be when shrunk ImVec2 PlotMinSize; // = 300,225 minimum size plot frame can be when shrunk
// colors // style colors
ImVec4 Colors[ImPlotCol_COUNT]; // array of plot specific colors ImVec4 Colors[ImPlotCol_COUNT]; // Array of styling colors. Indexable with ImPlotCol_ enums.
// colormap
ImPlotColormap Colormap; // The current colormap. Set this to either an ImPlotColormap_ enum or an index returned by AddColormap.
// settings/flags // settings/flags
bool AntiAliasedLines; // = false, enable global anti-aliasing on plot lines (overrides ImPlotFlags_AntiAliased) bool AntiAliasedLines; // = false, enable global anti-aliasing on plot lines (overrides ImPlotFlags_AntiAliased)
bool UseLocalTime; // = false, axis labels will be formatted for your timezone when ImPlotAxisFlag_Time is enabled bool UseLocalTime; // = false, axis labels will be formatted for your timezone when ImPlotAxisFlag_Time is enabled
@ -303,22 +323,43 @@ namespace ImPlot {
// Creates a new ImPlot context. Call this after ImGui::CreateContext. // Creates a new ImPlot context. Call this after ImGui::CreateContext.
IMPLOT_API ImPlotContext* CreateContext(); IMPLOT_API ImPlotContext* CreateContext();
// Destroys an ImPlot context. Call this before ImGui::DestroyContext. NULL = destroy current context // Destroys an ImPlot context. Call this before ImGui::DestroyContext. NULL = destroy current context.
IMPLOT_API void DestroyContext(ImPlotContext* ctx = NULL); IMPLOT_API void DestroyContext(ImPlotContext* ctx = NULL);
// Returns the current ImPlot context. NULL if no context has ben set. // Returns the current ImPlot context. NULL if no context has ben set.
IMPLOT_API ImPlotContext* GetCurrentContext(); IMPLOT_API ImPlotContext* GetCurrentContext();
// Sets the current ImPlot context. // Sets the current ImPlot context.
IMPLOT_API void SetCurrentContext(ImPlotContext* ctx); IMPLOT_API void SetCurrentContext(ImPlotContext* ctx);
// Sets the current **ImGui** context. This is ONLY necessary if you are compiling
// ImPlot as a DLL (not recommended) separate from your ImGui compilation. It
// sets the global variable GImGui, which is not shared across DLL boundaries.
// See GImGui documentation in imgui.cpp for more details.
IMPLOT_API void SetImGuiContext(ImGuiContext* ctx);
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Begin/End Plot // Begin/End Plot
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Starts a 2D plotting context. If this function returns true, EndPlot() must // Starts a 2D plotting context. If this function returns true, EndPlot() must
// be called, e.g. "if (BeginPlot(...)) { ... EndPlot(); }". #title_id must // be called! You are encouraged to use the following call convention:
// be unique. If you need to avoid ID collisions or don't want to display a //
// title in the plot, use double hashes (e.g. "MyPlot##Hidden" or "##NoTitle"). // if (BeginPlot(...)) {
// If #x_label and/or #y_label are provided, axes labels will be displayed. // ImPlot::PlotLine(...);
// EndPlot();
// }
//
// Important notes:
//
// - #title_id must be unique to the current ImGui window. If you need to avoid ID
// collisions or don't want to display a title in the plot, use double hashes
// (e.g. "MyPlot##Hidden" or "##NoTitle").
// - If #x_label and/or #y_label are provided, axes labels will be displayed.
// - #size is the **frame** size of the plot widget, not the plot area. The default
// size of plots (i.e. when ImVec2(0,0)) can be modified in your ImPlotStyle
// (default is 400x300).
// - Auxiliary y-axes must be enabled with ImPlotFlags_YAxis2/3 to be displayed.
// - See ImPlotFlags and ImPlotAxisFlags for more available options.
IMPLOT_API bool BeginPlot(const char* title_id, IMPLOT_API bool BeginPlot(const char* title_id,
const char* x_label = NULL, const char* x_label = NULL,
const char* y_label = NULL, const char* y_label = NULL,
@ -332,7 +373,7 @@ IMPLOT_API bool BeginPlot(const char* title_id,
const char* y3_label = NULL); const char* y3_label = NULL);
// Only call EndPlot() if BeginPlot() returns true! Typically called at the end // Only call EndPlot() if BeginPlot() returns true! Typically called at the end
// of an if statement conditioned on BeginPlot(). // of an if statement conditioned on BeginPlot(). See above.
IMPLOT_API void EndPlot(); IMPLOT_API void EndPlot();
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -356,9 +397,9 @@ IMPLOT_API void EndPlot();
// Vector2f data[42]; // Vector2f data[42];
// ImPlot::PlotLine("line", &data[0].x, &data[0].y, 42, 0, sizeof(Vector2f)); // or sizeof(float)*2 // ImPlot::PlotLine("line", &data[0].x, &data[0].y, 42, 0, sizeof(Vector2f)); // or sizeof(float)*2
// //
// 2. Write a custom getter function or C++ lambda and pass it and your data to // 2. Write a custom getter C function or C++ lambda and pass it and your data to
// an ImPlot function post-fixed with a G (e.g. PlotScatterG). This has a // an ImPlot function post-fixed with a G (e.g. PlotScatterG). This has a
// slight performance cost, but probably not enough to worry about. // slight performance cost, but probably not enough to worry about. Example:
// //
// ImPlotPoint MyDataGetter(void* data, int idx) { // ImPlotPoint MyDataGetter(void* data, int idx) {
// MyData* my_data = (MyData*)data; // MyData* my_data = (MyData*)data;
@ -368,8 +409,17 @@ IMPLOT_API void EndPlot();
// return p // return p
// } // }
// ... // ...
// MyData my_data; // auto my_lambda = [](void*, int idx) {
// ImPlot::PlotScatterG("scatter", MyDataGetter, &my_data, my_data.Size()); // double t = idx / 999.0;
// return ImPlotPoint(t, 0.5+0.5*std::sin(2*PI*10*t));
// };
// ...
// if (ImPlot::BeginPlot("MyPlot")) {
// MyData my_data;
// ImPlot::PlotScatterG("scatter", MyDataGetter, &my_data, my_data.Size());
// ImPlot::PlotLineG("line", my_lambda, nullptr, 1000);
// ImPlot::EndPlot();
// }
// //
// NB: All types are converted to double before plotting. You may lose information // NB: All types are converted to double before plotting. You may lose information
// if you try plotting extremely large 64-bit integral types. Proceed with caution! // if you try plotting extremely large 64-bit integral types. Proceed with caution!
@ -427,6 +477,16 @@ template <typename T> IMPLOT_API void PlotPieChart(const char* const label_ids[]
// Plots a 2D heatmap chart. Values are expected to be in row-major order. #label_fmt can be set to NULL for no labels. // Plots a 2D heatmap chart. Values are expected to be in row-major order. #label_fmt can be set to NULL for no labels.
template <typename T> IMPLOT_API void PlotHeatmap(const char* label_id, const T* values, int rows, int cols, double scale_min, double scale_max, const char* label_fmt="%.1f", const ImPlotPoint& bounds_min=ImPlotPoint(0,0), const ImPlotPoint& bounds_max=ImPlotPoint(1,1)); template <typename T> IMPLOT_API void PlotHeatmap(const char* label_id, const T* values, int rows, int cols, double scale_min, double scale_max, const char* label_fmt="%.1f", const ImPlotPoint& bounds_min=ImPlotPoint(0,0), const ImPlotPoint& bounds_max=ImPlotPoint(1,1));
// Plots a horizontal histogram. #bins can be a positive integer or an ImPlotBin_ method. If #cumulative is true, each bin contains its count plus the counts of all previous bins.
// If #density is true, the PDF is visualized. If both are true, the CDF is visualized. If #range is left unspecified, the min/max of #values will be used as the range.
// If #range is specified, outlier values outside of the range are not binned. However, outliers still count toward normalizing and cumulative counts unless #outliers is false. The largest bin count or density is returned.
template <typename T> IMPLOT_API double PlotHistogram(const char* label_id, const T* values, int count, int bins=ImPlotBin_Sturges, bool cumulative=false, bool density=false, ImPlotRange range=ImPlotRange(), bool outliers=true, double bar_scale=1.0);
// Plots two dimensional, bivariate histogram as a heatmap. #x_bins and #y_bins can be a positive integer or an ImPlotBin. If #density is true, the PDF is visualized.
// If #range is left unspecified, the min/max of #xs an #ys will be used as the ranges. If #range is specified, outlier values outside of range are not binned.
// However, outliers still count toward the normalizing count for density plots unless #outliers is false. The largest bin count or density is returned.
template <typename T> IMPLOT_API double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count, int x_bins=ImPlotBin_Sturges, int y_bins=ImPlotBin_Sturges, bool density=false, ImPlotLimits range=ImPlotLimits(), bool outliers=true);
// Plots digital data. Digital plots do not respond to y drag or zoom, and are always referenced to the bottom of the plot. // Plots digital data. Digital plots do not respond to y drag or zoom, and are always referenced to the bottom of the plot.
template <typename T> IMPLOT_API void PlotDigital(const char* label_id, const T* xs, const T* ys, int count, int offset=0, int stride=sizeof(T)); template <typename T> IMPLOT_API void PlotDigital(const char* label_id, const T* xs, const T* ys, int count, int offset=0, int stride=sizeof(T));
IMPLOT_API void PlotDigitalG(const char* label_id, ImPlotPoint (*getter)(void* data, int idx), void* data, int count, int offset=0); IMPLOT_API void PlotDigitalG(const char* label_id, ImPlotPoint (*getter)(void* data, int idx), void* data, int count, int offset=0);
@ -437,7 +497,7 @@ IMPLOT_API void PlotImage(const char* label_id, ImTextureID user_texture_id, con
// Plots a centered text label at point x,y with optional pixel offset. Text color can be changed with ImPlot::PushStyleColor(ImPlotCol_InlayText, ...). // Plots a centered text label at point x,y with optional pixel offset. Text color can be changed with ImPlot::PushStyleColor(ImPlotCol_InlayText, ...).
IMPLOT_API void PlotText(const char* text, double x, double y, bool vertical=false, const ImVec2& pix_offset=ImVec2(0,0)); IMPLOT_API void PlotText(const char* text, double x, double y, bool vertical=false, const ImVec2& pix_offset=ImVec2(0,0));
// Plots an dummy item (i.e. adds a legend entry colored by ImPlotCol_Line) // Plots a dummy item (i.e. adds a legend entry colored by ImPlotCol_Line)
IMPLOT_API void PlotDummy(const char* label_id); IMPLOT_API void PlotDummy(const char* label_id);
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -529,7 +589,7 @@ IMPLOT_API bool DragPoint(const char* id, double* x, double* y, bool show_label
// The following functions MUST be called BETWEEN Begin/EndPlot! // The following functions MUST be called BETWEEN Begin/EndPlot!
// Set the location of the current plot's legend. // Set the location of the current plot's legend (default = North|West).
IMPLOT_API void SetLegendLocation(ImPlotLocation location, ImPlotOrientation orientation = ImPlotOrientation_Vertical, bool outside = false); IMPLOT_API void SetLegendLocation(ImPlotLocation location, ImPlotOrientation orientation = ImPlotOrientation_Vertical, bool outside = false);
// Set the location of the current plot's mouse position text (default = South|East). // Set the location of the current plot's mouse position text (default = South|East).
IMPLOT_API void SetMousePosLocation(ImPlotLocation location); IMPLOT_API void SetMousePosLocation(ImPlotLocation location);
@ -576,26 +636,55 @@ IMPLOT_API void EndDragDropSource();
// Plot and Item Styling // Plot and Item Styling
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Styling colors in ImPlot works similarly to styling colors in ImGui, but
// with one important difference. Like ImGui, all style colors are stored in an
// indexable array in ImPlotStyle. You can permanently modify these values through
// GetStyle().Colors, or temporarily modify them with Push/Pop functions below.
// However, by default all style colors in ImPlot default to a special color
// IMPLOT_AUTO_COL. The behavior of this color depends upon the style color to
// which it as applied:
//
// 1) For style colors associated with plot items (e.g. ImPlotCol_Line),
// IMPLOT_AUTO_COL tells ImPlot to color the item with the next unused
// color in the current colormap. Thus, every item will have a different
// color up to the number of colors in the colormap, at which point the
// colormap will roll over. For most use cases, you should not need to
// modify these style colors to anything but IMPLOT_COL_AUTO. You are
// probably better off changing the current colormap. However, if you
// need to explicitly color a particular item you may either Push/Pop
// the style color around the item in question, or use the SetNextXXXStyle
// API below. If you permanently set one of these style colors to a specific
// color, or forget to call Pop, then all subsequent items will be styled
// with the color you set.
//
// 2) For style colors associated with plot styling (e.g. ImPlotCol_PlotBg),
// IMPLOT_AUTO_COL tells ImPlot to set that color from color data in your
// **ImGuiStyle**. The ImGuiCol_ that these style colors default to are
// detailed above, and in general have been mapped to produce plots visually
// consistent with your current ImGui style. Of course, you are free to
// manually set these colors to whatever you like, and further can Push/Pop
// them around individual plots.
// Provides access to plot style structure for permanant modifications to colors, sizes, etc. // Provides access to plot style structure for permanant modifications to colors, sizes, etc.
IMPLOT_API ImPlotStyle& GetStyle(); IMPLOT_API ImPlotStyle& GetStyle();
// Style colors for current ImGui style (default). // Style plot colors for current ImGui style (default).
IMPLOT_API void StyleColorsAuto(ImPlotStyle* dst = NULL); IMPLOT_API void StyleColorsAuto(ImPlotStyle* dst = NULL);
// Style colors for ImGui "Classic". // Style plot colors for ImGui "Classic".
IMPLOT_API void StyleColorsClassic(ImPlotStyle* dst = NULL); IMPLOT_API void StyleColorsClassic(ImPlotStyle* dst = NULL);
// Style colors for ImGui "Dark". // Style plot colors for ImGui "Dark".
IMPLOT_API void StyleColorsDark(ImPlotStyle* dst = NULL); IMPLOT_API void StyleColorsDark(ImPlotStyle* dst = NULL);
// Style colors for ImGui "Light". // Style plot colors for ImGui "Light".
IMPLOT_API void StyleColorsLight(ImPlotStyle* dst = NULL); IMPLOT_API void StyleColorsLight(ImPlotStyle* dst = NULL);
// Use PushStyleX to temporarily modify your ImPlotStyle. The modification // Use PushStyleX to temporarily modify your ImPlotStyle. The modification
// will last until the matching call to PopStyleX. You MUST call a pop for // will last until the matching call to PopStyleX. You MUST call a pop for
// every push, otherwise you will leak memory! This behaves just like ImGui. // every push, otherwise you will leak memory! This behaves just like ImGui.
// Temporarily modify a plot color. Don't forget to call PopStyleColor! // Temporarily modify a style color. Don't forget to call PopStyleColor!
IMPLOT_API void PushStyleColor(ImPlotCol idx, ImU32 col); IMPLOT_API void PushStyleColor(ImPlotCol idx, ImU32 col);
IMPLOT_API void PushStyleColor(ImPlotCol idx, const ImVec4& col); IMPLOT_API void PushStyleColor(ImPlotCol idx, const ImVec4& col);
// Undo temporary color modification. Undo multiple pushes at once by increasing count. // Undo temporary style color modification(s). Undo multiple pushes at once by increasing count.
IMPLOT_API void PopStyleColor(int count = 1); IMPLOT_API void PopStyleColor(int count = 1);
// Temporarily modify a style variable of float type. Don't forget to call PopStyleVar! // Temporarily modify a style variable of float type. Don't forget to call PopStyleVar!
@ -604,7 +693,7 @@ IMPLOT_API void PushStyleVar(ImPlotStyleVar idx, float val);
IMPLOT_API void PushStyleVar(ImPlotStyleVar idx, int val); IMPLOT_API void PushStyleVar(ImPlotStyleVar idx, int val);
// Temporarily modify a style variable of ImVec2 type. Don't forget to call PopStyleVar! // Temporarily modify a style variable of ImVec2 type. Don't forget to call PopStyleVar!
IMPLOT_API void PushStyleVar(ImPlotStyleVar idx, const ImVec2& val); IMPLOT_API void PushStyleVar(ImPlotStyleVar idx, const ImVec2& val);
// Undo temporary style modification. Undo multiple pushes at once by increasing count. // Undo temporary style variable modification(s). Undo multiple pushes at once by increasing count.
IMPLOT_API void PopStyleVar(int count = 1); IMPLOT_API void PopStyleVar(int count = 1);
// The following can be used to modify the style of the next plot item ONLY. They do // The following can be used to modify the style of the next plot item ONLY. They do
@ -633,55 +722,82 @@ IMPLOT_API const char* GetMarkerName(ImPlotMarker idx);
// Colormaps // Colormaps
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Item styling is based on Colormaps when the relevant ImPlotCol_ is set to // Item styling is based on colormaps when the relevant ImPlotCol_XXX is set to
// IMPLOT_AUTO_COL (default). Several built in colormaps are available and can be // IMPLOT_AUTO_COL (default). Several built-in colormaps are available. You can
// toggled in the demo. You can push/pop or set your own colormaps as well. // add and then push/pop your own colormaps as well. To permanently set a colormap,
// modify the Colormap index member of your ImPlotStyle.
// The Colormap data will be ignored and a custom color will be used if you have done one of the following: // Colormap data will be ignored and a custom color will be used if you have done one of the following:
// 1) Modified an item style color in your ImPlotStyle to anything other than IMPLOT_AUTO_COL. // 1) Modified an item style color in your ImPlotStyle to anything other than IMPLOT_AUTO_COL.
// 2) Pushed an item style color using PushStyleColor(). // 2) Pushed an item style color using PushStyleColor().
// 3) Set the next item style with a SetNextXStyle function. // 3) Set the next item style with a SetNextXXXStyle function.
// Temporarily switch to one of the built-in colormaps. // Add a new colormap. The colormap can be used by pushing either the returned index or the string name with PushColormap.
IMPLOT_API void PushColormap(ImPlotColormap colormap); // The colormap name must be unique and the size must be greater than 1. You will receive an assert otherwise! By default
// Temporarily switch to your custom colormap. The pointer data must persist until the matching call to PopColormap! // colormaps are considered to be qualitative (i.e. discrete). If you want to create a continuous colormap, set #qual=false.
IMPLOT_API void PushColormap(const ImVec4* colormap, int size); // This will treat the colors you provide as keys, and ImPlot will build a linearly interpolated lookup table that fills
// Undo temporary colormap modification. // in the gaps. The memory footprint of this table will be exactly ((size-1)*255+1)*4 bytes.
IMPLOT_API ImPlotColormap AddColormap(const char* name, const ImVec4* cols, int size, bool qual=true);
IMPLOT_API ImPlotColormap AddColormap(const char* name, const ImU32* cols, int size, bool qual=true);
// Returns the number of available colormaps.
IMPLOT_API int GetColormapCount();
// Returns a null terminated string name for a colormap given an index. Returns NULL if index is invalid.
IMPLOT_API const char* GetColormapName(ImPlotColormap cmap);
// Returns an index number for a colormap given a valid string name. Returns -1 if name is invalid.
IMPLOT_API ImPlotColormap GetColormapIndex(const char* name);
// Temporarily switch to one of the built-in (i.e. ImPlotColormap_XXX) or user-added colormaps (i.e. a return value of AddColormap). Don't forget to call PopColormap!
IMPLOT_API void PushColormap(ImPlotColormap cmap);
// Push a colormap by string name. Use built-in names such as "Default", "Deep", "Jet", etc or a string you provided to AddColormap. Don't forget to call PopColormap!
IMPLOT_API void PushColormap(const char* name);
// Undo temporary colormap modification(s). Undo multiple pushes at once by increasing count.
IMPLOT_API void PopColormap(int count = 1); IMPLOT_API void PopColormap(int count = 1);
// Permanently sets a custom colormap. The colors will be copied to internal memory. Typically used on startup. Prefer PushColormap instead of calling this each frame. // Returns the next color from the current colormap and advances the colormap for the current plot.
IMPLOT_API void SetColormap(const ImVec4* colormap, int size); // Can also be used with no return value to skip colors if desired. You need to call this between Begin/EndPlot!
// Permanently switch to one of the built-in colormaps. If samples is greater than 1, the map will be linearly resampled. Typically used on startup. Don't call this each frame.
IMPLOT_API void SetColormap(ImPlotColormap colormap, int samples = 0);
// Returns the size of the current colormap.
IMPLOT_API int GetColormapSize();
// Returns a color from the Color map given an index >= 0 (modulo will be performed).
IMPLOT_API ImVec4 GetColormapColor(int index);
// Linearly interpolates a color from the current colormap given t between 0 and 1.
IMPLOT_API ImVec4 LerpColormap(float t);
// Returns the next unused colormap color and advances the colormap. Can be used to skip colors if desired.
IMPLOT_API ImVec4 NextColormapColor(); IMPLOT_API ImVec4 NextColormapColor();
// Renders a vertical color scale using the current color map. Call this before or after Begin/EndPlot. // Colormap utils. If cmap = IMPLOT_AUTO (default), the current colormap is assumed.
IMPLOT_API void ShowColormapScale(double scale_min, double scale_max, const ImVec2& size = ImVec2(0,0)); // Pass an explicit colormap index (built-in or user added) to specify otherwise.
// Returns a null terminated string name for a built-in colormap. // Returns the size of a colormap.
IMPLOT_API const char* GetColormapName(ImPlotColormap colormap); IMPLOT_API int GetColormapSize(ImPlotColormap cmap = IMPLOT_AUTO);
// Returns a color from a colormap given an index >= 0 (modulo will be performed).
IMPLOT_API ImVec4 GetColormapColor(int idx, ImPlotColormap cmap = IMPLOT_AUTO);
// Sample a color from the current colormap given t between 0 and 1.
IMPLOT_API ImVec4 SampleColormap(float t, ImPlotColormap cmap = IMPLOT_AUTO);
// Shows a vertical color scale with linear spaced ticks using the specified color map. Use double hashes to hide label (e.g. "##NoLabel").
IMPLOT_API void ColormapScale(const char* label, double scale_min, double scale_max, const ImVec2& size = ImVec2(0,0), ImPlotColormap cmap = IMPLOT_AUTO);
// Shows a horizontal slider with a colormap gradient background. Optionally returns the color sampled at t in [0 1].
IMPLOT_API bool ColormapSlider(const char* label, float* t, ImVec4* out = NULL, const char* format = "", ImPlotColormap cmap = IMPLOT_AUTO);
// Shows a button with a colormap gradient brackground.
IMPLOT_API bool ColormapButton(const char* label, const ImVec2& size = ImVec2(0,0), ImPlotColormap cmap = IMPLOT_AUTO);
// When items in a plot sample their color from a colormap, the color is cached and does not change
// unless explicitly overriden. Therefore, if you change the colormap after the item has already been plotted,
// item colors will not update. If you need item colors to resample the new colormap, then use this
// function to bust the cached colors. If #plot_title_id is NULL, then every item in EVERY existing plot
// will be cache busted. Otherwise only the plot specified by #plot_title_id will be busted. For the
// latter, this function must be called in the ImGui window that the plot is in. You should rarely if ever
// need this function, but it is available for applications that require runtime swaps (see Heatmaps demo).
IMPLOT_API void BustColorCache(const char* plot_title_id = NULL);
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Miscellaneous // Miscellaneous
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Render a icon similar to those that appear in legends (nifty for data lists). // Render icons similar to those that appear in legends (nifty for data lists).
IMPLOT_API void ItemIcon(const ImVec4& col); IMPLOT_API void ItemIcon(const ImVec4& col);
IMPLOT_API void ItemIcon(ImU32 col); IMPLOT_API void ItemIcon(ImU32 col);
IMPLOT_API void ColormapIcon(ImPlotColormap cmap);
// Get the plot draw list for rendering to the current plot area. // Get the plot draw list for custom rendering to the current plot area. Call between Begin/EndPlot.
IMPLOT_API ImDrawList* GetPlotDrawList(); IMPLOT_API ImDrawList* GetPlotDrawList();
// Push clip rect for rendering to current plot area. // Push clip rect for rendering to current plot area. Call between Begin/EndPlot.
IMPLOT_API void PushPlotClipRect(); IMPLOT_API void PushPlotClipRect();
// Pop plot clip rect. // Pop plot clip rect. Call between Begin/EndPlot.
IMPLOT_API void PopPlotClipRect(); IMPLOT_API void PopPlotClipRect();
// Shows ImPlot style selector dropdown menu. // Shows ImPlot style selector dropdown menu.
@ -690,17 +806,11 @@ IMPLOT_API bool ShowStyleSelector(const char* label);
IMPLOT_API bool ShowColormapSelector(const char* label); IMPLOT_API bool ShowColormapSelector(const char* label);
// Shows ImPlot style editor block (not a window). // Shows ImPlot style editor block (not a window).
IMPLOT_API void ShowStyleEditor(ImPlotStyle* ref = NULL); IMPLOT_API void ShowStyleEditor(ImPlotStyle* ref = NULL);
// Add basic help/info block (not a window): how to manipulate ImPlot as an end-user. // Add basic help/info block for end users (not a window).
IMPLOT_API void ShowUserGuide(); IMPLOT_API void ShowUserGuide();
// Shows ImPlot metrics/debug information. // Shows ImPlot metrics/debug information.
IMPLOT_API void ShowMetricsWindow(bool* p_popen = NULL); IMPLOT_API void ShowMetricsWindow(bool* p_popen = NULL);
// Sets the current _ImGui_ context. This is ONLY necessary if you are compiling
// ImPlot as a DLL (not recommended) separate from your ImGui compilation. It
// sets the global variable GImGui, which is not shared across DLL boundaries.
// See GImGui documentation in imgui.cpp for more details.
IMPLOT_API void SetImGuiContext(ImGuiContext* ctx);
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Demo (add implot_demo.cpp to your sources!) // Demo (add implot_demo.cpp to your sources!)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -1,6 +1,6 @@
// MIT License // MIT License
// Copyright (c) 2020 Evan Pezent // Copyright (c) 2021 Evan Pezent
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@ -27,7 +27,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
#include <iostream>
#ifdef _MSC_VER #ifdef _MSC_VER
#define sprintf sprintf_s #define sprintf sprintf_s
@ -76,6 +75,44 @@ inline T RandomRange(T min, T max) {
return min + scale * ( max - min ); return min + scale * ( max - min );
} }
ImVec4 RandomColor() {
ImVec4 col;
col.x = RandomRange(0.0f,1.0f);
col.y = RandomRange(0.0f,1.0f);
col.z = RandomRange(0.0f,1.0f);
col.w = 1.0f;
return col;
}
double RandomGauss() {
static double V1, V2, S;
static int phase = 0;
double X;
if(phase == 0) {
do {
double U1 = (double)rand() / RAND_MAX;
double U2 = (double)rand() / RAND_MAX;
V1 = 2 * U1 - 1;
V2 = 2 * U2 - 1;
S = V1 * V1 + V2 * V2;
} while(S >= 1 || S == 0);
X = V1 * sqrt(-2 * log(S) / S);
} else
X = V2 * sqrt(-2 * log(S) / S);
phase = 1 - phase;
return X;
}
template <int N>
struct NormalDistribution {
NormalDistribution(double mean, double sd) {
for (int i = 0; i < N; ++i)
Data[i] = RandomGauss()*sd + mean;
}
double Data[N];
};
// utility structure for realtime plot // utility structure for realtime plot
struct ScrollingBuffer { struct ScrollingBuffer {
int MaxSize; int MaxSize;
@ -511,11 +548,17 @@ void ShowDemoWindow(bool* p_open) {
static const char* ylabels[] = {"R1","R2","R3","R4","R5","R6","R7"}; static const char* ylabels[] = {"R1","R2","R3","R4","R5","R6","R7"};
static ImPlotColormap map = ImPlotColormap_Viridis; static ImPlotColormap map = ImPlotColormap_Viridis;
if (ImGui::Button("Change Colormap",ImVec2(225,0))) if (ImPlot::ColormapButton(ImPlot::GetColormapName(map),ImVec2(225,0),map)) {
map = (map + 1) % ImPlotColormap_COUNT; map = (map + 1) % ImPlot::GetColormapCount();
// We bust the color cache of our plots so that item colors will
// resample the new colormap in the event that they have already
// been created. See documentation in implot.h.
BustColorCache("##Heatmap1");
BustColorCache("##Heatmap2");
}
ImGui::SameLine(); ImGui::SameLine();
ImGui::LabelText("##Colormap Index", "%s", ImPlot::GetColormapName(map)); ImGui::LabelText("##Colormap Index", "%s", "Change Colormap");
ImGui::SetNextItemWidth(225); ImGui::SetNextItemWidth(225);
ImGui::DragFloatRange2("Min / Max",&scale_min, &scale_max, 0.01f, -20, 20); ImGui::DragFloatRange2("Min / Max",&scale_min, &scale_max, 0.01f, -20, 20);
static ImPlotAxisFlags axes_flags = ImPlotAxisFlags_Lock | ImPlotAxisFlags_NoGridLines | ImPlotAxisFlags_NoTickMarks; static ImPlotAxisFlags axes_flags = ImPlotAxisFlags_Lock | ImPlotAxisFlags_NoGridLines | ImPlotAxisFlags_NoTickMarks;
@ -528,25 +571,153 @@ void ShowDemoWindow(bool* p_open) {
ImPlot::EndPlot(); ImPlot::EndPlot();
} }
ImGui::SameLine(); ImGui::SameLine();
ImPlot::ShowColormapScale(scale_min, scale_max, ImVec2(60,225)); ImPlot::ColormapScale("##HeatScale",scale_min, scale_max, ImVec2(60,225));
ImPlot::PopColormap();
ImGui::SameLine(); ImGui::SameLine();
static double values2[100*100]; const int size = 200;
static double values2[size*size];
srand((unsigned int)(DEMO_TIME*1000000)); srand((unsigned int)(DEMO_TIME*1000000));
for (int i = 0; i < 100*100; ++i) for (int i = 0; i < size*size; ++i)
values2[i] = RandomRange(0.0,1.0); values2[i] = RandomRange(0.0,1.0);
static ImVec4 gray[2] = {ImVec4(0,0,0,1), ImVec4(1,1,1,1)};
ImPlot::PushColormap(gray, 2);
ImPlot::SetNextPlotLimits(-1,1,-1,1); ImPlot::SetNextPlotLimits(-1,1,-1,1);
if (ImPlot::BeginPlot("##Heatmap2",NULL,NULL,ImVec2(225,225),0,ImPlotAxisFlags_NoDecorations,ImPlotAxisFlags_NoDecorations)) { if (ImPlot::BeginPlot("##Heatmap2",NULL,NULL,ImVec2(225,225),0,ImPlotAxisFlags_NoDecorations,ImPlotAxisFlags_NoDecorations)) {
ImPlot::PlotHeatmap("heat1",values2,100,100,0,1,NULL); ImPlot::PlotHeatmap("heat1",values2,size,size,0,1,NULL);
ImPlot::PlotHeatmap("heat2",values2,100,100,0,1,NULL, ImPlotPoint(-1,-1), ImPlotPoint(0,0)); ImPlot::PlotHeatmap("heat2",values2,size,size,0,1,NULL, ImPlotPoint(-1,-1), ImPlotPoint(0,0));
ImPlot::EndPlot(); ImPlot::EndPlot();
} }
ImPlot::PopColormap(); ImPlot::PopColormap();
}
//-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Histograms")) {
static int bins = 50;
static bool cumulative = false;
static bool density = true;
static bool outliers = true;
static double mu = 5;
static double sigma = 2;
static NormalDistribution<10000> dist(mu, sigma);
static double x[100];
static double y[100];
if (density) {
for (int i = 0; i < 100; ++i) {
x[i] = -3 + 16 * (double)i/99.0;
y[i] = exp( - (x[i]-mu)*(x[i]-mu) / (2*sigma*sigma)) / (sigma * sqrt(2*3.141592653589793238));
}
if (cumulative) {
for (int i = 1; i < 100; ++i)
y[i] += y[i-1];
for (int i = 0; i < 100; ++i)
y[i] /= y[99];
}
}
ImGui::SetNextItemWidth(200);
if (ImGui::RadioButton("Sqrt",bins==ImPlotBin_Sqrt)) { bins = ImPlotBin_Sqrt; } ImGui::SameLine();
if (ImGui::RadioButton("Sturges",bins==ImPlotBin_Sturges)) { bins = ImPlotBin_Sturges; } ImGui::SameLine();
if (ImGui::RadioButton("Rice",bins==ImPlotBin_Rice)) { bins = ImPlotBin_Rice; } ImGui::SameLine();
if (ImGui::RadioButton("Scott",bins==ImPlotBin_Scott)) { bins = ImPlotBin_Scott; } ImGui::SameLine();
if (ImGui::RadioButton("N Bins",bins>=0)) bins = 50;
if (bins>=0) {
ImGui::SameLine();
ImGui::SetNextItemWidth(200);
ImGui::SliderInt("##Bins", &bins, 1, 100);
}
ImGui::Checkbox("Density", &density);
ImGui::SameLine();
ImGui::Checkbox("Cumulative", &cumulative);
ImGui::SameLine();
static bool range = false;
ImGui::Checkbox("Range", &range);
static float rmin = -3;
static float rmax = 13;
if (range) {
ImGui::SameLine();
ImGui::SetNextItemWidth(200);
ImGui::DragFloat2("##Range",&rmin,0.1f,-3,13);
ImGui::SameLine();
ImGui::Checkbox("Outliers",&outliers);
}
ImPlot::SetNextPlotLimits(-3, 13, 0, 0.25);
if (ImPlot::BeginPlot("##Histograms")) {
ImPlot::SetNextFillStyle(IMPLOT_AUTO_COL, 0.5f);
ImPlot::PlotHistogram("Empirical", dist.Data, 10000, bins, cumulative, density, range ? ImPlotRange(rmin,rmax) : ImPlotRange(), outliers);
if (density && outliers)
ImPlot::PlotLine("Theoretical",x,y,100);
ImPlot::EndPlot();
}
static int count = 500000;
static int xybins[2] = {200,200};
static bool density2 = false;
ImGui::SliderInt("Count",&count,100,500000);
ImGui::SliderInt2("Bins",xybins,1,500);
ImGui::SameLine();
ImGui::Checkbox("Density##2",&density2);
static NormalDistribution<500000> dist1(1, 2);
static NormalDistribution<500000> dist2(1, 1);
double max_count = 0;
ImPlot::PushColormap("Twilight");
if (ImPlot::BeginPlot("##Hist2D",0,0,ImVec2(ImGui::GetContentRegionAvail().x-100-ImGui::GetStyle().ItemSpacing.x,0),0,ImPlotAxisFlags_AutoFit,ImPlotAxisFlags_AutoFit)) {
max_count = ImPlot::PlotHistogram2D("Hist2D",dist1.Data,dist2.Data,count,xybins[0],xybins[1],density2,ImPlotLimits(-6,6,-6,6));
ImPlot::EndPlot();
}
ImGui::SameLine();
ImPlot::ColormapScale(density2 ? "Density" : "Count",0,max_count,ImVec2(100,0));
ImPlot::PopColormap();
}
//-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Digital Plots")) {
ImGui::BulletText("Digital plots do not respond to Y drag and zoom, so that");
ImGui::Indent();
ImGui::Text("you can drag analog plots over the rising/falling digital edge.");
ImGui::Unindent();
static bool paused = false;
static ScrollingBuffer dataDigital[2];
static ScrollingBuffer dataAnalog[2];
static bool showDigital[2] = {true, false};
static bool showAnalog[2] = {true, false};
char label[32];
ImGui::Checkbox("digital_0", &showDigital[0]); ImGui::SameLine();
ImGui::Checkbox("digital_1", &showDigital[1]); ImGui::SameLine();
ImGui::Checkbox("analog_0", &showAnalog[0]); ImGui::SameLine();
ImGui::Checkbox("analog_1", &showAnalog[1]);
static float t = 0;
if (!paused) {
t += ImGui::GetIO().DeltaTime;
//digital signal values
if (showDigital[0])
dataDigital[0].AddPoint(t, sinf(2*t) > 0.45);
if (showDigital[1])
dataDigital[1].AddPoint(t, sinf(2*t) < 0.45);
//Analog signal values
if (showAnalog[0])
dataAnalog[0].AddPoint(t, sinf(2*t));
if (showAnalog[1])
dataAnalog[1].AddPoint(t, cosf(2*t));
}
ImPlot::SetNextPlotLimitsY(-1, 1);
ImPlot::SetNextPlotLimitsX(t - 10.0, t, paused ? ImGuiCond_Once : ImGuiCond_Always);
if (ImPlot::BeginPlot("##Digital")) {
for (int i = 0; i < 2; ++i) {
if (showDigital[i] && dataDigital[i].Data.size() > 0) {
sprintf(label, "digital_%d", i);
ImPlot::PlotDigital(label, &dataDigital[i].Data[0].x, &dataDigital[i].Data[0].y, dataDigital[i].Data.size(), dataDigital[i].Offset, 2 * sizeof(float));
}
}
for (int i = 0; i < 2; ++i) {
if (showAnalog[i]) {
sprintf(label, "analog_%d", i);
if (dataAnalog[i].Data.size() > 0)
ImPlot::PlotLine(label, &dataAnalog[i].Data[0].x, &dataAnalog[i].Data[0].y, dataAnalog[i].Data.size(), dataAnalog[i].Offset, 2 * sizeof(float));
}
}
ImPlot::EndPlot();
}
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Images")) { if (ImGui::CollapsingHeader("Images")) {
@ -650,7 +821,7 @@ void ShowDemoWindow(bool* p_open) {
ys2[i] = log(xs[i]); ys2[i] = log(xs[i]);
ys3[i] = pow(10.0, xs[i]); ys3[i] = pow(10.0, xs[i]);
} }
ImGui::BulletText("Open the plot context menu (double right click) to change scales."); ImGui::BulletText("Open the plot context menu (right click) to change scales.");
ImPlot::SetNextPlotLimits(0.1, 100, 0, 10); ImPlot::SetNextPlotLimits(0.1, 100, 0, 10);
if (ImPlot::BeginPlot("Log Plot", NULL, NULL, ImVec2(-1,0), 0, ImPlotAxisFlags_LogScale )) { if (ImPlot::BeginPlot("Log Plot", NULL, NULL, ImVec2(-1,0), 0, ImPlotAxisFlags_LogScale )) {
@ -826,9 +997,9 @@ void ShowDemoWindow(bool* p_open) {
} }
ImGui::Text("The current plot limits are: [%g,%g,%g,%g]", range.X.Min, range.X.Max, range.Y.Min, range.Y.Max); ImGui::Text("The current plot limits are: [%g,%g,%g,%g]", range.X.Min, range.X.Max, range.Y.Min, range.Y.Max);
ImGui::Text("The current query limits are: [%g,%g,%g,%g]", query.X.Min, query.X.Max, query.Y.Min, query.Y.Max); ImGui::Text("The current query limits are: [%g,%g,%g,%g]", query.X.Min, query.X.Max, query.Y.Min, query.Y.Max);
}
//------------------------------------------------------------------------- ImGui::Separator();
if (ImGui::CollapsingHeader("Views")) {
// mimic's soulthread's imgui_plot demo // mimic's soulthread's imgui_plot demo
static float x_data[512]; static float x_data[512];
static float y_data1[512]; static float y_data1[512];
@ -847,15 +1018,15 @@ void ShowDemoWindow(bool* p_open) {
ImGui::BulletText("Query the first plot to render a subview in the second plot (see above for controls)."); ImGui::BulletText("Query the first plot to render a subview in the second plot (see above for controls).");
ImPlot::SetNextPlotLimits(0,0.01,-1,1); ImPlot::SetNextPlotLimits(0,0.01,-1,1);
ImPlotAxisFlags flags = ImPlotAxisFlags_NoTickLabels; ImPlotAxisFlags flags = ImPlotAxisFlags_NoTickLabels;
ImPlotLimits query; ImPlotLimits query2;
if (ImPlot::BeginPlot("##View1",NULL,NULL,ImVec2(-1,150), ImPlotFlags_Query, flags, flags)) { if (ImPlot::BeginPlot("##View1",NULL,NULL,ImVec2(-1,150), ImPlotFlags_Query, flags, flags)) {
ImPlot::PlotLine("Signal 1", x_data, y_data1, 512); ImPlot::PlotLine("Signal 1", x_data, y_data1, 512);
ImPlot::PlotLine("Signal 2", x_data, y_data2, 512); ImPlot::PlotLine("Signal 2", x_data, y_data2, 512);
ImPlot::PlotLine("Signal 3", x_data, y_data3, 512); ImPlot::PlotLine("Signal 3", x_data, y_data3, 512);
query = ImPlot::GetPlotQuery(); query2 = ImPlot::GetPlotQuery();
ImPlot::EndPlot(); ImPlot::EndPlot();
} }
ImPlot::SetNextPlotLimits(query.X.Min, query.X.Max, query.Y.Min, query.Y.Max, ImGuiCond_Always); ImPlot::SetNextPlotLimits(query2.X.Min, query2.X.Max, query2.Y.Min, query2.Y.Max, ImGuiCond_Always);
if (ImPlot::BeginPlot("##View2",NULL,NULL,ImVec2(-1,150), ImPlotFlags_CanvasOnly, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations)) { if (ImPlot::BeginPlot("##View2",NULL,NULL,ImVec2(-1,150), ImPlotFlags_CanvasOnly, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations)) {
ImPlot::PlotLine("Signal 1", x_data, y_data1, 512); ImPlot::PlotLine("Signal 1", x_data, y_data1, 512);
ImPlot::PlotLine("Signal 2", x_data, y_data2, 512); ImPlot::PlotLine("Signal 2", x_data, y_data2, 512);
@ -871,7 +1042,7 @@ void ShowDemoWindow(bool* p_open) {
ImGui::CheckboxFlags("South", (unsigned int*)&loc, ImPlotLocation_South); ImGui::SameLine(); ImGui::CheckboxFlags("South", (unsigned int*)&loc, ImPlotLocation_South); ImGui::SameLine();
ImGui::CheckboxFlags("West", (unsigned int*)&loc, ImPlotLocation_West); ImGui::SameLine(); ImGui::CheckboxFlags("West", (unsigned int*)&loc, ImPlotLocation_West); ImGui::SameLine();
ImGui::CheckboxFlags("East", (unsigned int*)&loc, ImPlotLocation_East); ImGui::SameLine(); ImGui::CheckboxFlags("East", (unsigned int*)&loc, ImPlotLocation_East); ImGui::SameLine();
ImGui::Checkbox("Horizontal", &h); ImGui::SameLine(); ImGui::Checkbox("Horizontal##2", &h); ImGui::SameLine();
ImGui::Checkbox("Outside", &o); ImGui::Checkbox("Outside", &o);
ImGui::SliderFloat2("LegendPadding", (float*)&GetStyle().LegendPadding, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("LegendPadding", (float*)&GetStyle().LegendPadding, 0.0f, 20.0f, "%.0f");
@ -908,8 +1079,8 @@ void ShowDemoWindow(bool* p_open) {
ImPlot::DragLineY("y2",&y2,show_labels); ImPlot::DragLineY("y2",&y2,show_labels);
double xs[1000], ys[1000]; double xs[1000], ys[1000];
for (int i = 0; i < 1000; ++i) { for (int i = 0; i < 1000; ++i) {
xs[i] = (x2+x1)/2+abs(x2-x1)*(i/1000.0f - 0.5f); xs[i] = (x2+x1)/2+fabs(x2-x1)*(i/1000.0f - 0.5f);
ys[i] = (y1+y2)/2+abs(y2-y1)/2*sin(f*i/10); ys[i] = (y1+y2)/2+fabs(y2-y1)/2*sin(f*i/10);
} }
ImPlot::PlotLine("Interactive Data", xs, ys, 1000); ImPlot::PlotLine("Interactive Data", xs, ys, 1000);
ImPlot::SetPlotYAxis(ImPlotYAxis_2); ImPlot::SetPlotYAxis(ImPlotYAxis_2);
@ -992,7 +1163,7 @@ void ShowDemoWindow(bool* p_open) {
Plt = 0; Plt = 0;
Yax = ImPlotYAxis_1; Yax = ImPlotYAxis_1;
sprintf(Label, "%02d Hz", Idx+1); sprintf(Label, "%02d Hz", Idx+1);
Color = ImPlot::GetColormapColor(Idx); Color = RandomColor();
Data.reserve(1001); Data.reserve(1001);
for (int k = 0; k < 1001; ++k) { for (int k = 0; k < 1001; ++k) {
float t = k * 1.0f / 999; float t = k * 1.0f / 999;
@ -1134,59 +1305,6 @@ void ShowDemoWindow(bool* p_open) {
ImGui::EndChild(); ImGui::EndChild();
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Digital and Analog Signals")) {
ImGui::BulletText("You can plot digital and analog signals on the same plot.");
ImGui::BulletText("Digital signals do not respond to Y drag and zoom, so that");
ImGui::Indent();
ImGui::Text("you can drag analog signals over the rising/falling digital edge.");
ImGui::Unindent();
static bool paused = false;
static ScrollingBuffer dataDigital[2];
static ScrollingBuffer dataAnalog[2];
static bool showDigital[2] = {true, false};
static bool showAnalog[2] = {true, false};
char label[32];
ImGui::Checkbox("digital_0", &showDigital[0]); ImGui::SameLine();
ImGui::Checkbox("digital_1", &showDigital[1]); ImGui::SameLine();
ImGui::Checkbox("analog_0", &showAnalog[0]); ImGui::SameLine();
ImGui::Checkbox("analog_1", &showAnalog[1]);
static float t = 0;
if (!paused) {
t += ImGui::GetIO().DeltaTime;
//digital signal values
if (showDigital[0])
dataDigital[0].AddPoint(t, sinf(2*t) > 0.45);
if (showDigital[1])
dataDigital[1].AddPoint(t, sinf(2*t) < 0.45);
//Analog signal values
if (showAnalog[0])
dataAnalog[0].AddPoint(t, sinf(2*t));
if (showAnalog[1])
dataAnalog[1].AddPoint(t, cosf(2*t));
}
ImPlot::SetNextPlotLimitsY(-1, 1);
ImPlot::SetNextPlotLimitsX(t - 10.0, t, paused ? ImGuiCond_Once : ImGuiCond_Always);
if (ImPlot::BeginPlot("##Digital")) {
for (int i = 0; i < 2; ++i) {
if (showDigital[i] && dataDigital[i].Data.size() > 0) {
sprintf(label, "digital_%d", i);
ImPlot::PlotDigital(label, &dataDigital[i].Data[0].x, &dataDigital[i].Data[0].y, dataDigital[i].Data.size(), dataDigital[i].Offset, 2 * sizeof(float));
}
}
for (int i = 0; i < 2; ++i) {
if (showAnalog[i]) {
sprintf(label, "analog_%d", i);
if (dataAnalog[i].Data.size() > 0)
ImPlot::PlotLine(label, &dataAnalog[i].Data[0].x, &dataAnalog[i].Data[0].y, dataAnalog[i].Data.size(), dataAnalog[i].Offset, 2 * sizeof(float));
}
}
ImPlot::EndPlot();
}
}
if (ImGui::CollapsingHeader("Tables")) { if (ImGui::CollapsingHeader("Tables")) {
#ifdef IMGUI_HAS_TABLE #ifdef IMGUI_HAS_TABLE
static ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_RowBg; static ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_RowBg;
@ -1590,7 +1708,7 @@ void PlotCandlestick(const char* label_id, const double* xs, const double* opens
// begin plot item // begin plot item
if (ImPlot::BeginItem(label_id)) { if (ImPlot::BeginItem(label_id)) {
// override legend icon color // override legend icon color
ImPlot::GetCurrentItem()->Color = ImVec4(0.25f,0.25f,0.25f,1); ImPlot::GetCurrentItem()->Color = IM_COL32(64,64,64,255);
// fit data if requested // fit data if requested
if (ImPlot::FitThisFrame()) { if (ImPlot::FitThisFrame()) {
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {

View File

@ -1,6 +1,6 @@
// MIT License // MIT License
// Copyright (c) 2020 Evan Pezent // Copyright (c) 2021 Evan Pezent
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@ -43,26 +43,7 @@
#endif #endif
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] Forward Declarations // [SECTION] Constants
//-----------------------------------------------------------------------------
struct ImPlotTick;
struct ImPlotAxis;
struct ImPlotAxisState;
struct ImPlotAxisColor;
struct ImPlotItem;
struct ImPlotLegendData;
struct ImPlotPlot;
struct ImPlotNextPlotData;
//-----------------------------------------------------------------------------
// [SECTION] Context Pointer
//-----------------------------------------------------------------------------
extern IMPLOT_API ImPlotContext* GImPlot; // Current implicit context pointer
//-----------------------------------------------------------------------------
// [SECTION] Macros and Constants
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Constants can be changed unless stated otherwise. We may move some of these // Constants can be changed unless stated otherwise. We may move some of these
@ -79,6 +60,34 @@ extern IMPLOT_API ImPlotContext* GImPlot; // Current implicit context pointer
// Maximum allowable timestamp value 01/01/3000 @ 12:00am (UTC) (DO NOT INCREASE THIS) // Maximum allowable timestamp value 01/01/3000 @ 12:00am (UTC) (DO NOT INCREASE THIS)
#define IMPLOT_MAX_TIME 32503680000 #define IMPLOT_MAX_TIME 32503680000
//-----------------------------------------------------------------------------
// [SECTION] Macros
//-----------------------------------------------------------------------------
// Split ImU32 color into RGB components [0 255]
#define IM_COL32_SPLIT_RGB(col,r,g,b) \
ImU32 r = ((col >> IM_COL32_R_SHIFT) & 0xFF); \
ImU32 g = ((col >> IM_COL32_G_SHIFT) & 0xFF); \
ImU32 b = ((col >> IM_COL32_B_SHIFT) & 0xFF);
//-----------------------------------------------------------------------------
// [SECTION] Forward Declarations
//-----------------------------------------------------------------------------
struct ImPlotTick;
struct ImPlotAxis;
struct ImPlotAxisColor;
struct ImPlotItem;
struct ImPlotLegendData;
struct ImPlotPlot;
struct ImPlotNextPlotData;
//-----------------------------------------------------------------------------
// [SECTION] Context Pointer
//-----------------------------------------------------------------------------
extern IMPLOT_API ImPlotContext* GImPlot; // Current implicit context pointer
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] Generic Helpers // [SECTION] Generic Helpers
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -95,6 +104,9 @@ inline void ImFlipFlag(TSet& set, TFlag flag) { ImHasFlag(set, flag) ? set &= ~f
// Linearly remaps x from [x0 x1] to [y0 y1]. // Linearly remaps x from [x0 x1] to [y0 y1].
template <typename T> template <typename T>
inline T ImRemap(T x, T x0, T x1, T y0, T y1) { return y0 + (x - x0) * (y1 - y0) / (x1 - x0); } inline T ImRemap(T x, T x0, T x1, T y0, T y1) { return y0 + (x - x0) * (y1 - y0) / (x1 - x0); }
// Linear rempas x from [x0 x1] to [0 1]
template <typename T>
inline T ImRemap01(T x, T x0, T x1) { return (x - x0) / (x1 - x0); }
// Returns always positive modulo (assumes r != 0) // Returns always positive modulo (assumes r != 0)
inline int ImPosMod(int l, int r) { return (l % r + r) % r; } inline int ImPosMod(int l, int r) { return (l % r + r) % r; }
// Returns true if val is NAN or INFINITY // Returns true if val is NAN or INFINITY
@ -109,17 +121,80 @@ inline double ImConstrainLog(double val) { return val <= 0 ? 0.001f : val; }
inline double ImConstrainTime(double val) { return val < IMPLOT_MIN_TIME ? IMPLOT_MIN_TIME : (val > IMPLOT_MAX_TIME ? IMPLOT_MAX_TIME : val); } inline double ImConstrainTime(double val) { return val < IMPLOT_MIN_TIME ? IMPLOT_MIN_TIME : (val > IMPLOT_MAX_TIME ? IMPLOT_MAX_TIME : val); }
// True if two numbers are approximately equal using units in the last place. // True if two numbers are approximately equal using units in the last place.
inline bool ImAlmostEqual(double v1, double v2, int ulp = 2) { return ImAbs(v1-v2) < DBL_EPSILON * ImAbs(v1+v2) * ulp || ImAbs(v1-v2) < DBL_MIN; } inline bool ImAlmostEqual(double v1, double v2, int ulp = 2) { return ImAbs(v1-v2) < DBL_EPSILON * ImAbs(v1+v2) * ulp || ImAbs(v1-v2) < DBL_MIN; }
// Finds min value in an unsorted array
// Offset calculator helper template <typename T>
template <int Count> inline T ImMinArray(const T* values, int count) { T m = values[0]; for (int i = 1; i < count; ++i) { if (values[i] < m) { m = values[i]; } } return m; }
struct ImOffsetCalculator { // Finds the max value in an unsorted array
ImOffsetCalculator(const int* sizes) { template <typename T>
Offsets[0] = 0; inline T ImMaxArray(const T* values, int count) { T m = values[0]; for (int i = 1; i < count; ++i) { if (values[i] > m) { m = values[i]; } } return m; }
for (int i = 1; i < Count; ++i) // Finds the min and max value in an unsorted array
Offsets[i] = Offsets[i-1] + sizes[i-1]; template <typename T>
inline void ImMinMaxArray(const T* values, int count, T* min_out, T* max_out) {
T Min = values[0]; T Max = values[0];
for (int i = 1; i < count; ++i) {
if (values[i] < Min) { Min = values[i]; }
if (values[i] > Max) { Max = values[i]; }
} }
int Offsets[Count]; *min_out = Min; *max_out = Max;
}; }
// Finds the mean of an array
template <typename T>
inline double ImMean(const T* values, int count) {
double den = 1.0 / count;
double mu = 0;
for (int i = 0; i < count; ++i)
mu += values[i] * den;
return mu;
}
// Finds the sample standard deviation of an array
template <typename T>
inline double ImStdDev(const T* values, int count) {
double den = 1.0 / (count - 1.0);
double mu = ImMean(values, count);
double x = 0;
for (int i = 0; i < count; ++i)
x += (values[i] - mu) * (values[i] - mu) * den;
return sqrt(x);
}
// Mix color a and b by factor s in [0 256]
inline ImU32 ImMixU32(ImU32 a, ImU32 b, ImU32 s) {
#ifdef IMPLOT_MIX64
const ImU32 af = 256-s;
const ImU32 bf = s;
const ImU64 al = (a & 0x00ff00ff) | (((ImU64)(a & 0xff00ff00)) << 24);
const ImU64 bl = (b & 0x00ff00ff) | (((ImU64)(b & 0xff00ff00)) << 24);
const ImU64 mix = (al * af + bl * bf);
return ((mix >> 32) & 0xff00ff00) | ((mix & 0xff00ff00) >> 8);
#else
const ImU32 af = 256-s;
const ImU32 bf = s;
const ImU32 al = (a & 0x00ff00ff);
const ImU32 ah = (a & 0xff00ff00) >> 8;
const ImU32 bl = (b & 0x00ff00ff);
const ImU32 bh = (b & 0xff00ff00) >> 8;
const ImU32 ml = (al * af + bl * bf);
const ImU32 mh = (ah * af + bh * bf);
return (mh & 0xff00ff00) | ((ml & 0xff00ff00) >> 8);
#endif
}
// Lerp across an array of 32-bit collors given t in [0.0 1.0]
inline ImU32 ImLerpU32(const ImU32* colors, int size, float t) {
int i1 = (int)((size - 1 ) * t);
int i2 = i1 + 1;
if (i2 == size || size == 1)
return colors[i1];
float den = 1.0f / (size - 1);
float t1 = i1 * den;
float t2 = i2 * den;
float tr = ImRemap01(t, t1, t2);
return ImMixU32(colors[i1], colors[i2], (ImU32)(tr*256));
}
// Set alpha channel of 32-bit color from float in range [0.0 1.0]
inline ImU32 ImAlphaU32(ImU32 col, float alpha) {
return col & ~((ImU32)((1.0f-alpha)*255)<<IM_COL32_A_SHIFT);
}
// Character buffer writer helper (FIXME: Can't we replace this with ImGuiTextBuffer?) // Character buffer writer helper (FIXME: Can't we replace this with ImGuiTextBuffer?)
struct ImBufferWriter struct ImBufferWriter
@ -268,19 +343,111 @@ static inline bool operator<=(const ImPlotTime& lhs, const ImPlotTime& rhs)
static inline bool operator>=(const ImPlotTime& lhs, const ImPlotTime& rhs) static inline bool operator>=(const ImPlotTime& lhs, const ImPlotTime& rhs)
{ return lhs > rhs || lhs == rhs; } { return lhs > rhs || lhs == rhs; }
// Storage for colormap modifiers // Colormap data storage
struct ImPlotColormapMod { struct ImPlotColormapData {
ImPlotColormapMod(const ImVec4* colormap, int colormap_size) { ImVector<ImU32> Keys;
Colormap = colormap; ImVector<int> KeyCounts;
ColormapSize = colormap_size; ImVector<int> KeyOffsets;
ImVector<ImU32> Tables;
ImVector<int> TableSizes;
ImVector<int> TableOffsets;
ImGuiTextBuffer Text;
ImVector<int> TextOffsets;
ImVector<bool> Quals;
ImGuiStorage Map;
int Count;
ImPlotColormapData() { Count = 0; }
int Append(const char* name, const ImU32* keys, int count, bool qual) {
if (GetIndex(name) != -1)
return -1;
KeyOffsets.push_back(Keys.size());
KeyCounts.push_back(count);
Keys.reserve(Keys.size()+count);
for (int i = 0; i < count; ++i)
Keys.push_back(keys[i]);
TextOffsets.push_back(Text.size());
Text.append(name, name + strlen(name) + 1);
Quals.push_back(qual);
ImGuiID id = ImHashStr(name);
int idx = Count++;
Map.SetInt(id,idx);
_AppendTable(idx);
return idx;
} }
const ImVec4* Colormap;
int ColormapSize; void _AppendTable(ImPlotColormap cmap) {
int key_count = GetKeyCount(cmap);
const ImU32* keys = GetKeys(cmap);
int off = Tables.size();
TableOffsets.push_back(off);
if (IsQual(cmap)) {
Tables.reserve(key_count);
for (int i = 0; i < key_count; ++i)
Tables.push_back(keys[i]);
TableSizes.push_back(key_count);
}
else {
int max_size = 255 * (key_count-1) + 1;
Tables.reserve(off + max_size);
// ImU32 last = keys[0];
// Tables.push_back(last);
// int n = 1;
for (int i = 0; i < key_count-1; ++i) {
for (int s = 0; s < 255; ++s) {
ImU32 a = keys[i];
ImU32 b = keys[i+1];
ImU32 c = ImMixU32(a,b,s);
// if (c != last) {
Tables.push_back(c);
// last = c;
// n++;
// }
}
}
ImU32 c = keys[key_count-1];
// if (c != last) {
Tables.push_back(c);
// n++;
// }
// TableSizes.push_back(n);
TableSizes.push_back(max_size);
}
}
void RebuildTables() {
Tables.resize(0);
TableSizes.resize(0);
TableOffsets.resize(0);
for (int i = 0; i < Count; ++i)
_AppendTable(i);
}
inline bool IsQual(ImPlotColormap cmap) const { return Quals[cmap]; }
inline const char* GetName(ImPlotColormap cmap) const { return cmap < Count ? Text.Buf.Data + TextOffsets[cmap] : NULL; }
inline ImPlotColormap GetIndex(const char* name) const { ImGuiID key = ImHashStr(name); return Map.GetInt(key,-1); }
inline const ImU32* GetKeys(ImPlotColormap cmap) const { return &Keys[KeyOffsets[cmap]]; }
inline int GetKeyCount(ImPlotColormap cmap) const { return KeyCounts[cmap]; }
inline ImU32 GetKeyColor(ImPlotColormap cmap, int idx) const { return Keys[KeyOffsets[cmap]+idx]; }
inline void SetKeyColor(ImPlotColormap cmap, int idx, ImU32 value) { Keys[KeyOffsets[cmap]+idx] = value; RebuildTables(); }
inline const ImU32* GetTable(ImPlotColormap cmap) const { return &Tables[TableOffsets[cmap]]; }
inline int GetTableSize(ImPlotColormap cmap) const { return TableSizes[cmap]; }
inline ImU32 GetTableColor(ImPlotColormap cmap, int idx) const { return Tables[TableOffsets[cmap]+idx]; }
inline ImU32 LerpTable(ImPlotColormap cmap, float t) const {
int off = TableOffsets[cmap];
int siz = TableSizes[cmap];
int idx = Quals[cmap] ? ImClamp((int)(siz*t),0,siz-1) : (int)((siz - 1) * t + 0.5f);
return Tables[off + idx];
}
}; };
// ImPlotPoint with positive/negative error values // ImPlotPoint with positive/negative error values
struct ImPlotPointError struct ImPlotPointError {
{
double X, Y, Neg, Pos; double X, Y, Neg, Pos;
ImPlotPointError(double x, double y, double neg, double pos) { ImPlotPointError(double x, double y, double neg, double pos) {
X = x; Y = y; Neg = neg; Pos = pos; X = x; Y = y; Neg = neg; Pos = pos;
@ -387,7 +554,7 @@ struct ImPlotTickCollection {
Append(tick); Append(tick);
} }
const char* GetText(int idx) { const char* GetText(int idx) const {
return TextBuffer.Buf.Data + Ticks[idx].TextOffset; return TextBuffer.Buf.Data + Ticks[idx].TextOffset;
} }
@ -502,10 +669,12 @@ struct ImPlotAxis
inline bool IsLabeled() const { return !ImHasFlag(Flags, ImPlotAxisFlags_NoTickLabels); } inline bool IsLabeled() const { return !ImHasFlag(Flags, ImPlotAxisFlags_NoTickLabels); }
inline bool IsInverted() const { return ImHasFlag(Flags, ImPlotAxisFlags_Invert); } inline bool IsInverted() const { return ImHasFlag(Flags, ImPlotAxisFlags_Invert); }
inline bool IsAlwaysLocked() const { return HasRange && RangeCond == ImGuiCond_Always; } inline bool IsAutoFitting() const { return ImHasFlag(Flags, ImPlotAxisFlags_AutoFit); }
inline bool IsLockedMin() const { return ImHasFlag(Flags, ImPlotAxisFlags_LockMin) || IsAlwaysLocked(); } inline bool IsRangeLocked() const { return HasRange && RangeCond == ImGuiCond_Always; }
inline bool IsLockedMax() const { return ImHasFlag(Flags, ImPlotAxisFlags_LockMax) || IsAlwaysLocked(); } inline bool IsLockedMin() const { return ImHasFlag(Flags, ImPlotAxisFlags_LockMin) || IsRangeLocked(); }
inline bool IsLocked() const { return !Present || ((IsLockedMin() && IsLockedMax()) || IsAlwaysLocked()); } inline bool IsLockedMax() const { return ImHasFlag(Flags, ImPlotAxisFlags_LockMax) || IsRangeLocked(); }
inline bool IsLocked() const { return !Present || ((IsLockedMin() && IsLockedMax()) || IsRangeLocked()); }
inline bool IsInputLocked() const { return IsLocked() || IsAutoFitting(); }
inline bool IsTime() const { return ImHasFlag(Flags, ImPlotAxisFlags_Time); } inline bool IsTime() const { return ImHasFlag(Flags, ImPlotAxisFlags_Time); }
inline bool IsLog() const { return ImHasFlag(Flags, ImPlotAxisFlags_LogScale); } inline bool IsLog() const { return ImHasFlag(Flags, ImPlotAxisFlags_LogScale); }
}; };
@ -514,7 +683,7 @@ struct ImPlotAxis
struct ImPlotItem struct ImPlotItem
{ {
ImGuiID ID; ImGuiID ID;
ImVec4 Color; ImU32 Color;
int NameOffset; int NameOffset;
bool Show; bool Show;
bool LegendHovered; bool LegendHovered;
@ -522,7 +691,7 @@ struct ImPlotItem
ImPlotItem() { ImPlotItem() {
ID = 0; ID = 0;
Color = ImPlot::NextColormapColor(); // Color = ImPlot::NextColormapColor();
NameOffset = -1; NameOffset = -1;
Show = true; Show = true;
SeenThisFrame = false; SeenThisFrame = false;
@ -591,7 +760,7 @@ struct ImPlotPlot
ImPlotItem* GetLegendItem(int i); ImPlotItem* GetLegendItem(int i);
const char* GetLegendLabel(int i); const char* GetLegendLabel(int i);
inline bool IsLocked() const { return XAxis.IsLocked() && YAxis[0].IsLocked() && YAxis[1].IsLocked() && YAxis[2].IsLocked(); } inline bool IsInputLocked() const { return XAxis.IsInputLocked() && YAxis[0].IsInputLocked() && YAxis[1].IsInputLocked() && YAxis[2].IsInputLocked(); }
}; };
// Temporary data storage for upcoming plot // Temporary data storage for upcoming plot
@ -701,13 +870,15 @@ struct ImPlotContext {
ImPlotStyle Style; ImPlotStyle Style;
ImVector<ImGuiColorMod> ColorModifiers; ImVector<ImGuiColorMod> ColorModifiers;
ImVector<ImGuiStyleMod> StyleModifiers; ImVector<ImGuiStyleMod> StyleModifiers;
const ImVec4* Colormap; ImPlotColormapData ColormapData;
int ColormapSize; ImVector<ImPlotColormap> ColormapModifiers;
ImVector<ImPlotColormapMod> ColormapModifiers;
// Time // Time
tm Tm; tm Tm;
// Temp data for general use
ImVector<double> Temp1, Temp2;
// Misc // Misc
int VisibleItemCount; int VisibleItemCount;
int DigitalPlotItemCnt; int DigitalPlotItemCnt;
@ -862,19 +1033,16 @@ IMPLOT_API ImVec4 GetAutoColor(ImPlotCol idx);
inline ImVec4 GetStyleColorVec4(ImPlotCol idx) { return IsColorAuto(idx) ? GetAutoColor(idx) : GImPlot->Style.Colors[idx]; } inline ImVec4 GetStyleColorVec4(ImPlotCol idx) { return IsColorAuto(idx) ? GetAutoColor(idx) : GImPlot->Style.Colors[idx]; }
inline ImU32 GetStyleColorU32(ImPlotCol idx) { return ImGui::ColorConvertFloat4ToU32(GetStyleColorVec4(idx)); } inline ImU32 GetStyleColorU32(ImPlotCol idx) { return ImGui::ColorConvertFloat4ToU32(GetStyleColorVec4(idx)); }
// Get built-in colormap data and size
IMPLOT_API const ImVec4* GetColormap(ImPlotColormap colormap, int* size_out);
// Linearly interpolates a color from the current colormap given t between 0 and 1.
IMPLOT_API ImVec4 LerpColormap(const ImVec4* colormap, int size, float t);
// Resamples a colormap. #size_out must be greater than 1.
IMPLOT_API void ResampleColormap(const ImVec4* colormap_in, int size_in, ImVec4* colormap_out, int size_out);
// Draws vertical text. The position is the bottom left of the text rect. // Draws vertical text. The position is the bottom left of the text rect.
IMPLOT_API void AddTextVertical(ImDrawList *DrawList, ImVec2 pos, ImU32 col, const char* text_begin, const char* text_end = NULL); IMPLOT_API void AddTextVertical(ImDrawList *DrawList, ImVec2 pos, ImU32 col, const char* text_begin, const char* text_end = NULL);
// Calculates the size of vertical text // Calculates the size of vertical text
inline ImVec2 CalcTextSizeVertical(const char *text) { ImVec2 sz = ImGui::CalcTextSize(text); return ImVec2(sz.y, sz.x); } inline ImVec2 CalcTextSizeVertical(const char *text) {
ImVec2 sz = ImGui::CalcTextSize(text);
return ImVec2(sz.y, sz.x);
}
// Returns white or black text given background color // Returns white or black text given background color
inline ImU32 CalcTextColor(const ImVec4& bg) { return (bg.x * 0.299 + bg.y * 0.587 + bg.z * 0.114) > 0.5 ? IM_COL32_BLACK : IM_COL32_WHITE; } inline ImU32 CalcTextColor(const ImVec4& bg) { return (bg.x * 0.299 + bg.y * 0.587 + bg.z * 0.114) > 0.5 ? IM_COL32_BLACK : IM_COL32_WHITE; }
inline ImU32 CalcTextColor(ImU32 bg) { return CalcTextColor(ImGui::ColorConvertU32ToFloat4(bg)); }
// Clamps a label position so that it fits a rect defined by Min/Max // Clamps a label position so that it fits a rect defined by Min/Max
inline ImVec2 ClampLabelPos(ImVec2 pos, const ImVec2& size, const ImVec2& Min, const ImVec2& Max) { inline ImVec2 ClampLabelPos(ImVec2 pos, const ImVec2& size, const ImVec2& Min, const ImVec2& Max) {
@ -885,6 +1053,16 @@ inline ImVec2 ClampLabelPos(ImVec2 pos, const ImVec2& size, const ImVec2& Min, c
return pos; return pos;
} }
// Returns a color from the Color map given an index >= 0 (modulo will be performed).
IMPLOT_API ImU32 GetColormapColorU32(int idx, ImPlotColormap cmap);
// Returns the next unused colormap color and advances the colormap. Can be used to skip colors if desired.
IMPLOT_API ImU32 NextColormapColorU32();
// Linearly interpolates a color from the current colormap given t between 0 and 1.
IMPLOT_API ImU32 SampleColormapU32(float t, ImPlotColormap cmap);
// Render a colormap bar
IMPLOT_API void RenderColorBar(const ImU32* colors, int size, ImDrawList& DrawList, const ImRect& bounds, bool vert, bool reversed, bool continuous);
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] Math and Misc Utils // [SECTION] Math and Misc Utils
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -922,6 +1100,27 @@ inline T OffsetAndStride(const T* data, int idx, int count, int offset, int stri
return *(const T*)(const void*)((const unsigned char*)data + (size_t)idx * stride); return *(const T*)(const void*)((const unsigned char*)data + (size_t)idx * stride);
} }
// Calculate histogram bin counts and widths
template <typename T>
void CalculateBins(const T* values, int count, ImPlotBin meth, const ImPlotRange& range, int& bins_out, double& width_out) {
switch (meth) {
case ImPlotBin_Sqrt:
bins_out = (int)ceil(sqrt(count));
break;
case ImPlotBin_Sturges:
bins_out = (int)ceil(1.0 + log2(count));
break;
case ImPlotBin_Rice:
bins_out = (int)ceil(2 * cbrt(count));
break;
case ImPlotBin_Scott:
width_out = 3.49 * ImStdDev(values, count) / cbrt(count);
bins_out = (int)round(range.Size() / width_out);
break;
}
width_out = range.Size() / bins_out;
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Time Utils // Time Utils
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -982,14 +1181,4 @@ IMPLOT_API bool ShowDatePicker(const char* id, int* level, ImPlotTime* t, const
// #t will be set when a new hour, minute, or sec is selected or am/pm is toggled, and the function will return true. // #t will be set when a new hour, minute, or sec is selected or am/pm is toggled, and the function will return true.
IMPLOT_API bool ShowTimePicker(const char* id, ImPlotTime* t); IMPLOT_API bool ShowTimePicker(const char* id, ImPlotTime* t);
//-----------------------------------------------------------------------------
// [SECTION] Internal / Experimental Plotters
// No guarantee of forward compatibility here!
//-----------------------------------------------------------------------------
// Plots axis-aligned, filled rectangles. Every two consecutive points defines opposite corners of a single rectangle.
IMPLOT_API void PlotRects(const char* label_id, const float* xs, const float* ys, int count, int offset = 0, int stride = sizeof(float));
IMPLOT_API void PlotRects(const char* label_id, const double* xs, const double* ys, int count, int offset = 0, int stride = sizeof(double));
IMPLOT_API void PlotRects(const char* label_id, ImPlotPoint (*getter)(void* data, int idx), void* data, int count, int offset = 0);
} // namespace ImPlot } // namespace ImPlot

View File

@ -119,7 +119,7 @@ void SetNextErrorBarStyle(const ImVec4& col, float size, float weight) {
ImVec4 GetLastItemColor() { ImVec4 GetLastItemColor() {
ImPlotContext& gp = *GImPlot; ImPlotContext& gp = *GImPlot;
if (gp.PreviousItem) if (gp.PreviousItem)
return gp.PreviousItem->Color; return ImGui::ColorConvertU32ToFloat4(gp.PreviousItem->Color);
return ImVec4(); return ImVec4();
} }
@ -140,6 +140,21 @@ void BustItemCache() {
} }
} }
void BustColorCache(const char* plot_title_id) {
ImPlotContext& gp = *GImPlot;
if (plot_title_id == NULL) {
BustItemCache();
}
else {
ImPlotPlot* plot = gp.Plots.GetByKey(ImGui::GetCurrentWindow()->GetID(plot_title_id));
if (plot == NULL)
return;
plot->ColormapIdx = 0;
plot->Items.Clear();
plot->LegendData.Reset();
}
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Begin/EndItem // Begin/EndItem
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -153,12 +168,17 @@ bool BeginItem(const char* label_id, ImPlotCol recolor_from) {
// set current item // set current item
gp.CurrentItem = item; gp.CurrentItem = item;
ImPlotNextItemData& s = gp.NextItemData; ImPlotNextItemData& s = gp.NextItemData;
// override item color // set/override item color
if (recolor_from != -1) { if (recolor_from != -1) {
if (!IsColorAuto(s.Colors[recolor_from])) if (!IsColorAuto(s.Colors[recolor_from]))
item->Color = s.Colors[recolor_from]; item->Color = ImGui::ColorConvertFloat4ToU32(s.Colors[recolor_from]);
else if (!IsColorAuto(gp.Style.Colors[recolor_from])) else if (!IsColorAuto(gp.Style.Colors[recolor_from]))
item->Color = gp.Style.Colors[recolor_from]; item->Color = ImGui::ColorConvertFloat4ToU32(gp.Style.Colors[recolor_from]);
else if (just_created)
item->Color = NextColormapColorU32();
}
else if (just_created) {
item->Color = NextColormapColorU32();
} }
// hide/show item // hide/show item
if (gp.NextItemData.HasHidden) { if (gp.NextItemData.HasHidden) {
@ -173,9 +193,10 @@ bool BeginItem(const char* label_id, ImPlotCol recolor_from) {
return false; return false;
} }
else { else {
ImVec4 item_color = ImGui::ColorConvertU32ToFloat4(item->Color);
// stage next item colors // stage next item colors
s.Colors[ImPlotCol_Line] = IsColorAuto(s.Colors[ImPlotCol_Line]) ? ( IsColorAuto(ImPlotCol_Line) ? item->Color : gp.Style.Colors[ImPlotCol_Line] ) : s.Colors[ImPlotCol_Line]; s.Colors[ImPlotCol_Line] = IsColorAuto(s.Colors[ImPlotCol_Line]) ? ( IsColorAuto(ImPlotCol_Line) ? item_color : gp.Style.Colors[ImPlotCol_Line] ) : s.Colors[ImPlotCol_Line];
s.Colors[ImPlotCol_Fill] = IsColorAuto(s.Colors[ImPlotCol_Fill]) ? ( IsColorAuto(ImPlotCol_Fill) ? item->Color : gp.Style.Colors[ImPlotCol_Fill] ) : s.Colors[ImPlotCol_Fill]; s.Colors[ImPlotCol_Fill] = IsColorAuto(s.Colors[ImPlotCol_Fill]) ? ( IsColorAuto(ImPlotCol_Fill) ? item_color : gp.Style.Colors[ImPlotCol_Fill] ) : s.Colors[ImPlotCol_Fill];
s.Colors[ImPlotCol_MarkerOutline] = IsColorAuto(s.Colors[ImPlotCol_MarkerOutline]) ? ( IsColorAuto(ImPlotCol_MarkerOutline) ? s.Colors[ImPlotCol_Line] : gp.Style.Colors[ImPlotCol_MarkerOutline] ) : s.Colors[ImPlotCol_MarkerOutline]; s.Colors[ImPlotCol_MarkerOutline] = IsColorAuto(s.Colors[ImPlotCol_MarkerOutline]) ? ( IsColorAuto(ImPlotCol_MarkerOutline) ? s.Colors[ImPlotCol_Line] : gp.Style.Colors[ImPlotCol_MarkerOutline] ) : s.Colors[ImPlotCol_MarkerOutline];
s.Colors[ImPlotCol_MarkerFill] = IsColorAuto(s.Colors[ImPlotCol_MarkerFill]) ? ( IsColorAuto(ImPlotCol_MarkerFill) ? s.Colors[ImPlotCol_Line] : gp.Style.Colors[ImPlotCol_MarkerFill] ) : s.Colors[ImPlotCol_MarkerFill]; s.Colors[ImPlotCol_MarkerFill] = IsColorAuto(s.Colors[ImPlotCol_MarkerFill]) ? ( IsColorAuto(ImPlotCol_MarkerFill) ? s.Colors[ImPlotCol_Line] : gp.Style.Colors[ImPlotCol_MarkerFill] ) : s.Colors[ImPlotCol_MarkerFill];
s.Colors[ImPlotCol_ErrorBar] = IsColorAuto(s.Colors[ImPlotCol_ErrorBar]) ? ( GetStyleColorVec4(ImPlotCol_ErrorBar) ) : s.Colors[ImPlotCol_ErrorBar]; s.Colors[ImPlotCol_ErrorBar] = IsColorAuto(s.Colors[ImPlotCol_ErrorBar]) ? ( GetStyleColorVec4(ImPlotCol_ErrorBar) ) : s.Colors[ImPlotCol_ErrorBar];
@ -659,51 +680,6 @@ struct ShadedRenderer {
static const int VtxConsumed = 5; static const int VtxConsumed = 5;
}; };
template <typename TGetter, typename TTransformer>
struct RectRenderer {
inline RectRenderer(const TGetter& getter, const TTransformer& transformer, ImU32 col) :
Getter(getter),
Transformer(transformer),
Prims(Getter.Count / 2),
Col(col)
{}
inline bool operator()(ImDrawList& DrawList, const ImRect& /*cull_rect*/, const ImVec2& uv, int prim) const {
// TODO: Culling
ImVec2 P1 = Transformer(Getter(2*prim));
ImVec2 P2 = Transformer(Getter(2*prim+1));
DrawList._VtxWritePtr[0].pos = P1;
DrawList._VtxWritePtr[0].uv = uv;
DrawList._VtxWritePtr[0].col = Col;
DrawList._VtxWritePtr[1].pos.x = P1.x;
DrawList._VtxWritePtr[1].pos.y = P2.y;
DrawList._VtxWritePtr[1].uv = uv;
DrawList._VtxWritePtr[1].col = Col;
DrawList._VtxWritePtr[2].pos = P2;
DrawList._VtxWritePtr[2].uv = uv;
DrawList._VtxWritePtr[2].col = Col;
DrawList._VtxWritePtr[3].pos.x = P2.x;
DrawList._VtxWritePtr[3].pos.y = P1.y;
DrawList._VtxWritePtr[3].uv = uv;
DrawList._VtxWritePtr[3].col = Col;
DrawList._VtxWritePtr += 4;
DrawList._IdxWritePtr[0] = (ImDrawIdx)(DrawList._VtxCurrentIdx);
DrawList._IdxWritePtr[1] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 1);
DrawList._IdxWritePtr[2] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 3);
DrawList._IdxWritePtr[3] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 1);
DrawList._IdxWritePtr[4] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 2);
DrawList._IdxWritePtr[5] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 3);
DrawList._IdxWritePtr += 6;
DrawList._VtxCurrentIdx += 4;
return true;
}
const TGetter& Getter;
const TTransformer& Transformer;
const int Prims;
const ImU32 Col;
static const int IdxConsumed = 6;
static const int VtxConsumed = 4;
};
// Stupid way of calculating maximum index size of ImDrawIdx without integer overflow issues // Stupid way of calculating maximum index size of ImDrawIdx without integer overflow issues
template <typename T> template <typename T>
struct MaxIdx { static const unsigned int Value; }; struct MaxIdx { static const unsigned int Value; };
@ -1462,6 +1438,7 @@ void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* neg,
GetterError<T> getter(xs, ys, neg, pos, count, offset, stride); GetterError<T> getter(xs, ys, neg, pos, count, offset, stride);
PlotErrorBarsEx(label_id, getter); PlotErrorBarsEx(label_id, getter);
} }
template IMPLOT_API void PlotErrorBars<ImS8>(const char* label_id, const ImS8* xs, const ImS8* ys, const ImS8* neg, const ImS8* pos, int count, int offset, int stride); template IMPLOT_API void PlotErrorBars<ImS8>(const char* label_id, const ImS8* xs, const ImS8* ys, const ImS8* neg, const ImS8* pos, int count, int offset, int stride);
template IMPLOT_API void PlotErrorBars<ImU8>(const char* label_id, const ImU8* xs, const ImU8* ys, const ImU8* neg, const ImU8* pos, int count, int offset, int stride); template IMPLOT_API void PlotErrorBars<ImU8>(const char* label_id, const ImU8* xs, const ImU8* ys, const ImU8* neg, const ImU8* pos, int count, int offset, int stride);
template IMPLOT_API void PlotErrorBars<ImS16>(const char* label_id, const ImS16* xs, const ImS16* ys, const ImS16* neg, const ImS16* pos, int count, int offset, int stride); template IMPLOT_API void PlotErrorBars<ImS16>(const char* label_id, const ImS16* xs, const ImS16* ys, const ImS16* neg, const ImS16* pos, int count, int offset, int stride);
@ -1729,7 +1706,7 @@ void PlotPieChart(const char* const label_ids[], const T* values, int count, dou
double percent = normalize ? (double)values[i] / sum : (double)values[i]; double percent = normalize ? (double)values[i] / sum : (double)values[i];
a1 = a0 + 2 * IM_PI * percent; a1 = a0 + 2 * IM_PI * percent;
if (BeginItem(label_ids[i])) { if (BeginItem(label_ids[i])) {
ImU32 col = ImGui::GetColorU32(GetCurrentItem()->Color); ImU32 col = GetCurrentItem()->Color;
if (percent < 0.5) { if (percent < 0.5) {
RenderPieSlice(DrawList, center, radius, a0, a1, col); RenderPieSlice(DrawList, center, radius, a0, a1, col);
} }
@ -1754,7 +1731,7 @@ void PlotPieChart(const char* const label_ids[], const T* values, int count, dou
ImVec2 size = ImGui::CalcTextSize(buffer); ImVec2 size = ImGui::CalcTextSize(buffer);
double angle = a0 + (a1 - a0) * 0.5; double angle = a0 + (a1 - a0) * 0.5;
ImVec2 pos = PlotToPixels(center.x + 0.5 * radius * cos(angle), center.y + 0.5 * radius * sin(angle)); ImVec2 pos = PlotToPixels(center.x + 0.5 * radius * cos(angle), center.y + 0.5 * radius * sin(angle));
ImU32 col = CalcTextColor(item->Color); ImU32 col = CalcTextColor(ImGui::ColorConvertU32ToFloat4(item->Color));
DrawList.AddText(pos - size * 0.5f, col, buffer); DrawList.AddText(pos - size * 0.5f, col, buffer);
} }
a0 = a1; a0 = a1;
@ -1778,41 +1755,130 @@ template IMPLOT_API void PlotPieChart<double>(const char* const label_ids[], con
// PLOT HEATMAP // PLOT HEATMAP
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
struct RectInfo {
ImPlotPoint Min, Max;
ImU32 Color;
};
template <typename TGetter, typename TTransformer>
struct RectRenderer {
inline RectRenderer(const TGetter& getter, const TTransformer& transformer) :
Getter(getter),
Transformer(transformer),
Prims(Getter.Count)
{}
inline bool operator()(ImDrawList& DrawList, const ImRect& cull_rect, const ImVec2& uv, int prim) const {
RectInfo rect = Getter(prim);
ImVec2 P1 = Transformer(rect.Min);
ImVec2 P2 = Transformer(rect.Max);
if ((rect.Color & IM_COL32_A_MASK) == 0 || !cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2))))
return false;
DrawList._VtxWritePtr[0].pos = P1;
DrawList._VtxWritePtr[0].uv = uv;
DrawList._VtxWritePtr[0].col = rect.Color;
DrawList._VtxWritePtr[1].pos.x = P1.x;
DrawList._VtxWritePtr[1].pos.y = P2.y;
DrawList._VtxWritePtr[1].uv = uv;
DrawList._VtxWritePtr[1].col = rect.Color;
DrawList._VtxWritePtr[2].pos = P2;
DrawList._VtxWritePtr[2].uv = uv;
DrawList._VtxWritePtr[2].col = rect.Color;
DrawList._VtxWritePtr[3].pos.x = P2.x;
DrawList._VtxWritePtr[3].pos.y = P1.y;
DrawList._VtxWritePtr[3].uv = uv;
DrawList._VtxWritePtr[3].col = rect.Color;
DrawList._VtxWritePtr += 4;
DrawList._IdxWritePtr[0] = (ImDrawIdx)(DrawList._VtxCurrentIdx);
DrawList._IdxWritePtr[1] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 1);
DrawList._IdxWritePtr[2] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 3);
DrawList._IdxWritePtr[3] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 1);
DrawList._IdxWritePtr[4] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 2);
DrawList._IdxWritePtr[5] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 3);
DrawList._IdxWritePtr += 6;
DrawList._VtxCurrentIdx += 4;
return true;
}
const TGetter& Getter;
const TTransformer& Transformer;
const int Prims;
static const int IdxConsumed = 6;
static const int VtxConsumed = 4;
};
template <typename T>
struct GetterHeatmap {
GetterHeatmap(const T* values, int rows, int cols, double scale_min, double scale_max, double width, double height, double xref, double yref, double ydir) :
Values(values),
Count(rows*cols),
Rows(rows),
Cols(cols),
ScaleMin(scale_min),
ScaleMax(scale_max),
Width(width),
Height(height),
XRef(xref),
YRef(yref),
YDir(ydir),
HalfSize(Width*0.5, Height*0.5)
{ }
inline RectInfo operator()(int idx) const {
double val = (double)Values[idx];
const int r = idx / Cols;
const int c = idx % Cols;
const ImPlotPoint p(XRef + HalfSize.x + c*Width, YRef + YDir * (HalfSize.y + r*Height));
RectInfo rect;
rect.Min.x = p.x - HalfSize.x;
rect.Min.y = p.y - HalfSize.y;
rect.Max.x = p.x + HalfSize.x;
rect.Max.y = p.y + HalfSize.y;
const float t = ImClamp((float)ImRemap01(val, ScaleMin, ScaleMax),0.0f,1.0f);
rect.Color = GImPlot->ColormapData.LerpTable(GImPlot->Style.Colormap, t);
return rect;
}
const T* const Values;
const int Count, Rows, Cols;
const double ScaleMin, ScaleMax, Width, Height, XRef, YRef, YDir;
const ImPlotPoint HalfSize;
};
template <typename T, typename Transformer> template <typename T, typename Transformer>
void RenderHeatmap(Transformer transformer, ImDrawList& DrawList, const T* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max) { void RenderHeatmap(Transformer transformer, ImDrawList& DrawList, const T* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max, bool reverse_y) {
ImPlotContext& gp = *GImPlot; ImPlotContext& gp = *GImPlot;
const double w = (bounds_max.x - bounds_min.x) / cols; if (scale_min == scale_max) {
const double h = (bounds_max.y - bounds_min.y) / rows; ImVec2 a = transformer(bounds_min);
const ImPlotPoint half_size(w*0.5,h*0.5); ImVec2 b = transformer(bounds_max);
int i = 0; ImU32 col = GetColormapColorU32(0,gp.Style.Colormap);
for (int r = 0; r < rows; ++r) { DrawList.AddRectFilled(a, b, col);
for (int c = 0; c < cols; ++c) { return;
ImPlotPoint p; }
p.x = bounds_min.x + 0.5*w + c*w; const double yref = reverse_y ? bounds_max.y : bounds_min.y;
p.y = bounds_max.y - (0.5*h + r*h); const double ydir = reverse_y ? -1 : 1;
ImVec2 a = transformer(ImPlotPoint(p.x - half_size.x, p.y - half_size.y)); GetterHeatmap<T> getter(values, rows, cols, scale_min, scale_max, (bounds_max.x - bounds_min.x) / cols, (bounds_max.y - bounds_min.y) / rows, bounds_min.x, yref, ydir);
ImVec2 b = transformer(ImPlotPoint(p.x + half_size.x, p.y + half_size.y)); switch (GetCurrentScale()) {
double t = ImRemap((double)values[i], scale_min, scale_max, 0.0, 1.0); case ImPlotScale_LinLin: RenderPrimitives(RectRenderer<GetterHeatmap<T>, TransformerLinLin>(getter, TransformerLinLin()), DrawList, gp.CurrentPlot->PlotRect); break;
ImVec4 color = LerpColormap((float)t); case ImPlotScale_LogLin: RenderPrimitives(RectRenderer<GetterHeatmap<T>, TransformerLogLin>(getter, TransformerLogLin()), DrawList, gp.CurrentPlot->PlotRect); break;;
color.w *= gp.Style.FillAlpha; case ImPlotScale_LinLog: RenderPrimitives(RectRenderer<GetterHeatmap<T>, TransformerLinLog>(getter, TransformerLinLog()), DrawList, gp.CurrentPlot->PlotRect); break;;
ImU32 col = ImGui::GetColorU32(color); case ImPlotScale_LogLog: RenderPrimitives(RectRenderer<GetterHeatmap<T>, TransformerLogLog>(getter, TransformerLogLog()), DrawList, gp.CurrentPlot->PlotRect); break;;
DrawList.AddRectFilled(a, b, col);
i++;
}
} }
if (fmt != NULL) { if (fmt != NULL) {
i = 0; const double w = (bounds_max.x - bounds_min.x) / cols;
const double h = (bounds_max.y - bounds_min.y) / rows;
const ImPlotPoint half_size(w*0.5,h*0.5);
int i = 0;
for (int r = 0; r < rows; ++r) { for (int r = 0; r < rows; ++r) {
for (int c = 0; c < cols; ++c) { for (int c = 0; c < cols; ++c) {
ImPlotPoint p; ImPlotPoint p;
p.x = bounds_min.x + 0.5*w + c*w; p.x = bounds_min.x + 0.5*w + c*w;
p.y = bounds_max.y - (0.5*h + r*h); p.y = yref + ydir * (0.5*h + r*h);
ImVec2 px = transformer(p); ImVec2 px = transformer(p);
char buff[32]; char buff[32];
sprintf(buff, fmt, values[i]); sprintf(buff, fmt, values[i]);
ImVec2 size = ImGui::CalcTextSize(buff); ImVec2 size = ImGui::CalcTextSize(buff);
double t = ImRemap((double)values[i], scale_min, scale_max, 0.0, 1.0); double t = ImClamp(ImRemap01((double)values[i], scale_min, scale_max),0.0,1.0);
ImVec4 color = LerpColormap((float)t); ImVec4 color = SampleColormap((float)t);
ImU32 col = CalcTextColor(color); ImU32 col = CalcTextColor(color);
DrawList.AddText(px - size * 0.5f, col, buff); DrawList.AddText(px - size * 0.5f, col, buff);
i++; i++;
@ -1823,7 +1889,6 @@ void RenderHeatmap(Transformer transformer, ImDrawList& DrawList, const T* value
template <typename T> template <typename T>
void PlotHeatmap(const char* label_id, const T* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max) { void PlotHeatmap(const char* label_id, const T* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max) {
IM_ASSERT_USER_ERROR(scale_min != scale_max, "Scale values must be different!");
if (BeginItem(label_id)) { if (BeginItem(label_id)) {
if (FitThisFrame()) { if (FitThisFrame()) {
FitPoint(bounds_min); FitPoint(bounds_min);
@ -1831,10 +1896,10 @@ void PlotHeatmap(const char* label_id, const T* values, int rows, int cols, doub
} }
ImDrawList& DrawList = *GetPlotDrawList(); ImDrawList& DrawList = *GetPlotDrawList();
switch (GetCurrentScale()) { switch (GetCurrentScale()) {
case ImPlotScale_LinLin: RenderHeatmap(TransformerLinLin(), DrawList, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max); break; case ImPlotScale_LinLin: RenderHeatmap(TransformerLinLin(), DrawList, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max, true); break;
case ImPlotScale_LogLin: RenderHeatmap(TransformerLogLin(), DrawList, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max); break; case ImPlotScale_LogLin: RenderHeatmap(TransformerLogLin(), DrawList, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max, true); break;
case ImPlotScale_LinLog: RenderHeatmap(TransformerLinLog(), DrawList, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max); break; case ImPlotScale_LinLog: RenderHeatmap(TransformerLinLog(), DrawList, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max, true); break;
case ImPlotScale_LogLog: RenderHeatmap(TransformerLogLog(), DrawList, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max); break; case ImPlotScale_LogLog: RenderHeatmap(TransformerLogLog(), DrawList, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max, true); break;
} }
EndItem(); EndItem();
} }
@ -1851,6 +1916,181 @@ template IMPLOT_API void PlotHeatmap<ImU64>(const char* label_id, const ImU64* v
template IMPLOT_API void PlotHeatmap<float>(const char* label_id, const float* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max); template IMPLOT_API void PlotHeatmap<float>(const char* label_id, const float* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max);
template IMPLOT_API void PlotHeatmap<double>(const char* label_id, const double* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max); template IMPLOT_API void PlotHeatmap<double>(const char* label_id, const double* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max);
//-----------------------------------------------------------------------------
// PLOT HISTOGRAM
//-----------------------------------------------------------------------------
template <typename T>
double PlotHistogram(const char* label_id, const T* values, int count, int bins, bool cumulative, bool density, ImPlotRange range, bool outliers, double bar_scale) {
if (count <= 0 || bins == 0)
return 0;
if (range.Min == 0 && range.Max == 0) {
T Min, Max;
ImMinMaxArray(values, count, &Min, &Max);
range.Min = (double)Min;
range.Max = (double)Max;
}
double width;
if (bins < 0)
CalculateBins(values, count, bins, range, bins, width);
else
width = range.Size() / bins;
ImVector<double>& bin_centers = GImPlot->Temp1;
ImVector<double>& bin_counts = GImPlot->Temp2;
bin_centers.resize(bins);
bin_counts.resize(bins);
int below = 0;
for (int b = 0; b < bins; ++b) {
bin_centers[b] = range.Min + b * width + width * 0.5;
bin_counts[b] = 0;
}
int counted = 0;
double max_count = 0;
for (int i = 0; i < count; ++i) {
double val = (double)values[i];
if (range.Contains(val)) {
const int b = ImClamp((int)((val - range.Min) / width), 0, bins - 1);
bin_counts[b] += 1.0;
if (bin_counts[b] > max_count)
max_count = bin_counts[b];
counted++;
}
else if (val < range.Min) {
below++;
}
}
if (cumulative && density) {
if (outliers)
bin_counts[0] += below;
for (int b = 1; b < bins; ++b)
bin_counts[b] += bin_counts[b-1];
double scale = 1.0 / (outliers ? count : counted);
for (int b = 0; b < bins; ++b)
bin_counts[b] *= scale;
max_count = bin_counts[bins-1];
}
else if (cumulative) {
if (outliers)
bin_counts[0] += below;
for (int b = 1; b < bins; ++b)
bin_counts[b] += bin_counts[b-1];
max_count = bin_counts[bins-1];
}
else if (density) {
double scale = 1.0 / ((outliers ? count : counted) * width);
for (int b = 0; b < bins; ++b)
bin_counts[b] *= scale;
max_count *= scale;
}
PlotBars(label_id, &bin_centers.Data[0], &bin_counts.Data[0], bins, bar_scale*width);
return max_count;
}
template IMPLOT_API double PlotHistogram<ImS8>(const char* label_id, const ImS8* values, int count, int bins, bool cumulative, bool density, ImPlotRange range, bool outliers, double bar_scale);
template IMPLOT_API double PlotHistogram<ImU8>(const char* label_id, const ImU8* values, int count, int bins, bool cumulative, bool density, ImPlotRange range, bool outliers, double bar_scale);
template IMPLOT_API double PlotHistogram<ImS16>(const char* label_id, const ImS16* values, int count, int bins, bool cumulative, bool density, ImPlotRange range, bool outliers, double bar_scale);
template IMPLOT_API double PlotHistogram<ImU16>(const char* label_id, const ImU16* values, int count, int bins, bool cumulative, bool density, ImPlotRange range, bool outliers, double bar_scale);
template IMPLOT_API double PlotHistogram<ImS32>(const char* label_id, const ImS32* values, int count, int bins, bool cumulative, bool density, ImPlotRange range, bool outliers, double bar_scale);
template IMPLOT_API double PlotHistogram<ImU32>(const char* label_id, const ImU32* values, int count, int bins, bool cumulative, bool density, ImPlotRange range, bool outliers, double bar_scale);
template IMPLOT_API double PlotHistogram<ImS64>(const char* label_id, const ImS64* values, int count, int bins, bool cumulative, bool density, ImPlotRange range, bool outliers, double bar_scale);
template IMPLOT_API double PlotHistogram<ImU64>(const char* label_id, const ImU64* values, int count, int bins, bool cumulative, bool density, ImPlotRange range, bool outliers, double bar_scale);
template IMPLOT_API double PlotHistogram<float>(const char* label_id, const float* values, int count, int bins, bool cumulative, bool density, ImPlotRange range, bool outliers, double bar_scale);
template IMPLOT_API double PlotHistogram<double>(const char* label_id, const double* values, int count, int bins, bool cumulative, bool density, ImPlotRange range, bool outliers, double bar_scale);
//-----------------------------------------------------------------------------
// PLOT HISTOGRAM 2D
//-----------------------------------------------------------------------------
template <typename T>
double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers) {
if (count <= 0 || x_bins == 0 || y_bins == 0)
return 0;
if (range.X.Min == 0 && range.X.Max == 0) {
T Min, Max;
ImMinMaxArray(xs, count, &Min, &Max);
range.X.Min = (double)Min;
range.X.Max = (double)Max;
}
if (range.Y.Min == 0 && range.Y.Max == 0) {
T Min, Max;
ImMinMaxArray(ys, count, &Min, &Max);
range.Y.Min = (double)Min;
range.Y.Max = (double)Max;
}
double width, height;
if (x_bins < 0)
CalculateBins(xs, count, x_bins, range.X, x_bins, width);
else
width = range.X.Size() / x_bins;
if (y_bins < 0)
CalculateBins(ys, count, y_bins, range.Y, y_bins, height);
else
height = range.Y.Size() / y_bins;
const int bins = x_bins * y_bins;
ImVector<double>& bin_counts = GImPlot->Temp1;
bin_counts.resize(bins);
for (int b = 0; b < bins; ++b)
bin_counts[b] = 0;
int counted = 0;
double max_count = 0;
for (int i = 0; i < count; ++i) {
if (range.Contains((double)xs[i], (double)ys[i])) {
const int xb = ImClamp( (int)((double)(xs[i] - range.X.Min) / width) , 0, x_bins - 1);
const int yb = ImClamp( (int)((double)(ys[i] - range.Y.Min) / height) , 0, y_bins - 1);
const int b = yb * x_bins + xb;
bin_counts[b] += 1.0;
if (bin_counts[b] > max_count)
max_count = bin_counts[b];
counted++;
}
}
if (density) {
double scale = 1.0 / ((outliers ? count : counted) * width * height);
for (int b = 0; b < bins; ++b)
bin_counts[b] *= scale;
max_count *= scale;
}
if (BeginItem(label_id)) {
if (FitThisFrame()) {
FitPoint(range.Min());
FitPoint(range.Max());
}
ImDrawList& DrawList = *GetPlotDrawList();
switch (GetCurrentScale()) {
case ImPlotScale_LinLin: RenderHeatmap(TransformerLinLin(), DrawList, &bin_counts.Data[0], y_bins, x_bins, 0, max_count, NULL, range.Min(), range.Max(), false); break;
case ImPlotScale_LogLin: RenderHeatmap(TransformerLogLin(), DrawList, &bin_counts.Data[0], y_bins, x_bins, 0, max_count, NULL, range.Min(), range.Max(), false); break;
case ImPlotScale_LinLog: RenderHeatmap(TransformerLinLog(), DrawList, &bin_counts.Data[0], y_bins, x_bins, 0, max_count, NULL, range.Min(), range.Max(), false); break;
case ImPlotScale_LogLog: RenderHeatmap(TransformerLogLog(), DrawList, &bin_counts.Data[0], y_bins, x_bins, 0, max_count, NULL, range.Min(), range.Max(), false); break;
}
EndItem();
}
return max_count;
}
template IMPLOT_API double PlotHistogram2D<ImS8>(const char* label_id, const ImS8* xs, const ImS8* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers);
template IMPLOT_API double PlotHistogram2D<ImU8>(const char* label_id, const ImU8* xs, const ImU8* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers);
template IMPLOT_API double PlotHistogram2D<ImS16>(const char* label_id, const ImS16* xs, const ImS16* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers);
template IMPLOT_API double PlotHistogram2D<ImU16>(const char* label_id, const ImU16* xs, const ImU16* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers);
template IMPLOT_API double PlotHistogram2D<ImS32>(const char* label_id, const ImS32* xs, const ImS32* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers);
template IMPLOT_API double PlotHistogram2D<ImU32>(const char* label_id, const ImU32* xs, const ImU32* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers);
template IMPLOT_API double PlotHistogram2D<ImS64>(const char* label_id, const ImS64* xs, const ImS64* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers);
template IMPLOT_API double PlotHistogram2D<ImU64>(const char* label_id, const ImU64* xs, const ImU64* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers);
template IMPLOT_API double PlotHistogram2D<float>(const char* label_id, const float* xs, const float* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers);
template IMPLOT_API double PlotHistogram2D<double>(const char* label_id, const double* xs, const double* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers);
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// PLOT DIGITAL // PLOT DIGITAL
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -1937,51 +2177,6 @@ void PlotDigitalG(const char* label_id, ImPlotPoint (*getter_func)(void* data, i
return PlotDigitalEx(label_id, getter); return PlotDigitalEx(label_id, getter);
} }
//-----------------------------------------------------------------------------
// PLOT RECTS
//-----------------------------------------------------------------------------
template <typename Getter>
void PlotRectsEx(const char* label_id, const Getter& getter) {
if (BeginItem(label_id, ImPlotCol_Fill)) {
if (FitThisFrame()) {
for (int i = 0; i < getter.Count; ++i) {
ImPlotPoint p = getter(i);
FitPoint(p);
}
}
const ImPlotNextItemData& s = GetItemData();
if (s.RenderFill) {
ImDrawList& DrawList = *GetPlotDrawList();
ImU32 col = ImGui::GetColorU32(s.Colors[ImPlotCol_Fill]);
switch (GetCurrentScale()) {
case ImPlotScale_LinLin: RenderPrimitives(RectRenderer<Getter,TransformerLinLin>(getter, TransformerLinLin(), col), DrawList, GImPlot->CurrentPlot->PlotRect); break;
case ImPlotScale_LogLin: RenderPrimitives(RectRenderer<Getter,TransformerLogLin>(getter, TransformerLogLin(), col), DrawList, GImPlot->CurrentPlot->PlotRect); break;
case ImPlotScale_LinLog: RenderPrimitives(RectRenderer<Getter,TransformerLinLog>(getter, TransformerLinLog(), col), DrawList, GImPlot->CurrentPlot->PlotRect); break;
case ImPlotScale_LogLog: RenderPrimitives(RectRenderer<Getter,TransformerLogLog>(getter, TransformerLogLog(), col), DrawList, GImPlot->CurrentPlot->PlotRect); break;
}
}
EndItem();
}
}
// float
void PlotRects(const char* label_id, const float* xs, const float* ys, int count, int offset, int stride) {
GetterXsYs<float> getter(xs,ys,count,offset,stride);
PlotRectsEx(label_id, getter);
}
// double
void PlotRects(const char* label_id, const double* xs, const double* ys, int count, int offset, int stride) {
GetterXsYs<double> getter(xs,ys,count,offset,stride);
PlotRectsEx(label_id, getter);
}
// custom
void PlotRects(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, int offset) {
GetterFuncPtr getter(getter_func,data,count,offset);
return PlotRectsEx(label_id, getter);
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// PLOT IMAGE // PLOT IMAGE
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -1992,12 +2187,13 @@ void PlotImage(const char* label_id, ImTextureID user_texture_id, const ImPlotPo
FitPoint(bmin); FitPoint(bmin);
FitPoint(bmax); FitPoint(bmax);
} }
GetCurrentItem()->Color = tint_col; ImU32 tint_col32 = ImGui::ColorConvertFloat4ToU32(tint_col);
GetCurrentItem()->Color = tint_col32;
ImDrawList& DrawList = *GetPlotDrawList(); ImDrawList& DrawList = *GetPlotDrawList();
ImVec2 p1 = PlotToPixels(bmin.x, bmax.y); ImVec2 p1 = PlotToPixels(bmin.x, bmax.y);
ImVec2 p2 = PlotToPixels(bmax.x, bmin.y); ImVec2 p2 = PlotToPixels(bmax.x, bmin.y);
PushPlotClipRect(); PushPlotClipRect();
DrawList.AddImage(user_texture_id, p1, p2, uv0, uv1, ImGui::ColorConvertFloat4ToU32(tint_col)); DrawList.AddImage(user_texture_id, p1, p2, uv0, uv1, tint_col32);
PopPlotClipRect(); PopPlotClipRect();
EndItem(); EndItem();
} }