Immediate Mode Plotting
This release mostly exists to fix my blunder when releasing v0.15 (forgot to update versioning in headers, oops!) @ocornut kindly attempted to rectify the issue, but this seems to have caused issues for some users (https://github.com/epezent/implot/issues/499). Also included are a few trivial bug fixes and a handful of small PRs.
Full Change Log: https://github.com/epezent/implot/compare/v0.15...v0.16
Full Changelog: https://github.com/epezent/implot/compare/v0.14...v0.15
Each of ImPlot's PlotX
functions now takes an optional ImPlotXFlags
parameter. This decision (1) allows us to easily add more options for plot items and (2) allows us to consolidate and clean up some of the API. Here's what this looks like for PlotLine
:
// Flags for ANY PlotX function
enum ImPlotItemFlags_ {
ImPlotItemFlags_None = 0,
ImPlotItemFlags_NoLegend = 1 << 0, // the item won't have a legend entry displayed
ImPlotItemFlags_NoFit = 1 << 1, // the item won't be considered for plot fits
};
// Flags for PlotLine
enum ImPlotLineFlags_ {
ImPlotLineFlags_None = 0, // default
ImPlotLineFlags_Segments = 1 << 10, // a line segment will be rendered from every two consecutive points
ImPlotLineFlags_Loop = 1 << 11, // the last and first point will be connected to form a closed loop
ImPlotLineFlags_SkipNaN = 1 << 12, // NaNs values will be skipped instead of rendered as missing data
ImPlotLineFlags_NoClip = 1 << 13, // markers (if displayed) on the edge of a plot will not be clipped
};
...
void PlotLine(const char* label_id, const T* xs, const T* ys, int count, ImPlotLineFlags flags=0, int offset=0, int stride=sizeof(T));
As you can see, PlotLine
has some new bells and whistles that are enabled with the ImPlotLineFlags_
parameter, like rendering lines as segments or as a closed loop. Several other plotters have also gained new abilities through their respective flags (see the full list below). The special flags in ImPlotItemFlags
can be combined with ANY ImPlotXFlags
, e.g. ImPlotItemFlags_NoLegend|ImPlotLineFlags_Segments
is valid code.
Here's a complete list of flags available for our current plotters:
ImPlotItemFlags_NoLegend // the item won't have a legend entry displayed
ImPlotItemFlags_NoFit // the item won't be considered for plot fits
ImPlotLineFlags_Segments // a line segment will be rendered from every two consecutive points
ImPlotLineFlags_Loop // the last and first point will be connected to form a closed loop
ImPlotLineFlags_SkipNaN // NaNs values will be skipped instead of rendered as missing data
ImPlotLineFlags_NoClip // markers (if displayed) on the edge of a plot will not be clipped
ImPlotScatterFlags_NoClip // markers on the edge of a plot will not be clipped
ImPlotStairsFlags_PreStep // the y value is continued constantly to the left from every x position, i.e. the interval (x[i-1], x[i]] has the value y[i]
ImPlotBarsFlags_Horizontal // bars will be rendered horizontally on the current y-axis
ImPlotBarGroupsFlags_Horizontal // bar groups will be rendered horizontally on the current y-axis
ImPlotBarGroupsFlags_Stacked // items in a group will be stacked on top of each other
ImPlotErrorBarsFlags_Horizontal // error bars will be rendered horizontally on the current y-axis
ImPlotStemsFlags_Horizontal // stems will be rendered horizontally on the current y-axis
ImPlotInfLinesFlags_Horizontal // lines will be rendered horizontally on the current y-axis
ImPlotPieChartFlags_Normalize // force normalization of pie chart values (i.e. always make a full circle if sum < 0)
ImPlotHeatmapFlags_ColMajor // data will be read in column major order
ImPlotHistogramFlags_Horizontal // histogram bars will be rendered horizontally (not supported by PlotHistogram2D)
ImPlotHistogramFlags_Cumulative // each bin will contain its count plus the counts of all previous bins (not supported by PlotHistogram2D)
ImPlotHistogramFlags_Density // counts will be normalized, i.e. the PDF will be visualized, or the CDF will be visualized if Cumulative is also set
ImPlotHistogramFlags_NoOutliers // exclude values outside the specifed histogram range from the count toward normalizing and cumulative counts
ImPlotHistogramFlags_ColMajor // data will be read in column major order (not supported by PlotHistogram)
ImPlotTextFlags_Vertical // text will be rendered vertically
SUPER IMPORTANT NOTE: Each PlotX
function's ImPlotLineFlags flags=0
parameter has been positioned before int offset=0, int stride=sizeof(T)
where applicable. This unfortunately means that folks making use of offset and/or stride will need to update their function calls to include a flags parameter, else they will likely see strange results or crashes without any warning. This may rub some users the wrong way, but it was a necessary evil as it stylistically makes the most sense for the flags parameter to take priority over stride and offset in the default argument order for most use cases and users.
Besides that, items flags brings about a few other API breaking changes users should be aware of:
PlotBarsH
has been removed; use PlotBars
+ ImPlotBarsFlags_Horizontal
insteadPlotErrorBarsH
has been removed; use PlotErrorBars
+ ImPlotErrorBarsFlags_Horizontal
PlotVLines
and PlotHLines
replaced with PlotInfLines
(+ ImPlotInfLinesFlags_Horizontal
)PlotHistogram
/PlotHistogram2D
signatures changed; cumulative
, density
, and outliers
options now specified via ImPlotHistogramFlags
PlotPieChart
signature changed; normalize
option now specified via ImPlotPieChartFlags
PlotText
signature changes; vertical
option now specified via ImPlotTextFlags_Vertical
Again, this change will likely cause headaches for some users, but with this new system in place you can expect more plotting options to be added in future updates in a flexible and, importantly, maintainable way. Thanks for understanding.
Previously, users could define time and log scales with ImPlotAxisFlags_Log
, and ImPlotAxisFlags_Time
. These flags have been replaced with a more general system using a new the setup function SetupAxisScale
:
// Axis scale
enum ImPlotScale_ {
ImPlotScale_Linear = 0, // default linear scale
ImPlotScale_Time, // date/time scale
ImPlotScale_Log10, // base 10 logartithmic scale
ImPlotScale_SymLog, // symmetric log scale
};
// Sets an axis' scale using built-in options.
void SetupAxisScale(ImAxis axis, ImPlotScale scale);
ImPlotScale_SymLog
is a new scale that produces a symmertic log scale with a linear region roughly between -1 and 1:
More built-in scales may be added in the future. Until then, you can also now define YOUR OWN scales using ImPlotTransform
to provide a forward and inverse function:
// Callback signature for axis transform.
typedef double (*ImPlotTransform)(double value, void* user_data);
// Sets an axis' scale using user supplied forward and inverse transfroms.
void SetupAxisScale(ImAxis axis, ImPlotTransform forward, ImPlotTransform inverse, void* data=NULL);
Example:
static inline double TransformForward_Sqrt(double v, void*) {
return sqrt(v);
}
static inline double TransformInverse_Sqrt(double v, void*) {
return v*v;
}
...
if (ImPlot::BeginPlot("Sqrt")) {
ImPlot::SetupAxis(ImAxis_X1, "Linear");
ImPlot::SetupAxis(ImAxis_Y1, "Sqrt");
ImPlot::SetupAxisScale(ImAxis_Y1, TransformForward_Sqrt, TransformInverse_Sqrt);
ImPlot::PlotLine(...);
ImPlot::EndPlot();
}
You can now constrain axes limits so that users can't pan beyond a min or max value, or zoom beyond a min or max width/height. This is nice if you don't want users straying away from displayed data or zooming too far into view. It is demonstrated in the candlestick demo in implot_demo.cpp
(see Custom Plotters and Tooltips).
// Sets an axis' limits constraints.
void SetupAxisLimitsConstraints(ImAxis axis, double v_min, double v_max);
// Sets an axis' zoom constraints.
void SetupAxisZoomConstraints(ImAxis axis, double z_min, double z_max);
You can now customize the supported types by defining IMPLOT_CUSTOM_NUMERIC_TYPES
at compile time to define your own type list. As an example, you could use the compile time define given by the line below in order to support only float and double.
-DIMPLOT_CUSTOM_NUMERIC_TYPES="(float)(double)"
In order to support all known C++ types, use:
-DIMPLOT_CUSTOM_NUMERIC_TYPES="(signed char)(unsigned char)(signed short)(unsigned short)(signed int)(unsigned int)(signed long)(unsigned long)(signed long long)(unsigned long long)(float)(double)(long double)"
Special thanks to @pthom for inplementing this feature (#397) and greatly simplifying our plotter insantiation pipeline with some mean macro magic!
The ImPlot repository now provides CI through GitHub Actions. The jobs are setup to build ImPlot and a headless example application against the latest ImGui version across several compilers and platforms. Jobs are triggered for all new PRs.
Special thanks to @rokups for setting this up (#395), @ozlb for the initial push (#393), @pthom for further improvements (#397), and @ocornut for his thoughtful comments.
AntiAliasedLines
and AntiAliasedLinesUseTex
. That's right, ImPlot now uses texture based AA! If you weren't using MSAA, you can now expect signficantly smoother lines for very little performance cost.implot_items.cpp
should now be much quicker now.ImPlotLegendFlags_Sort
Previously, setting up a plot and its axes was done by passing several args to BeginPlot
and leveraging a handful of preceding SetNextXXX
functions. The former was becoming unwieldy with BeginPlot
requiring additional args for each newly introduced feature, while the latter was always awkward and a bit of a nightmare to manage under the hood. Neither approach offered room to scale the API gracefully.
Taking a page out of ImGui's Tables
API, plots and axes can now be configured by calling a host of optional SetupXXX
functions immediately after BeginPlot
. With this, the signature of BeginPlot
has be greatly simplified. Here's a quick example:
if (BeginPlot("My Plot",ImVec2(-1,-1),ImPlotFlags_Crosshairs) { // 1) begin a new plot
SetupAxis(ImAxis_X1, "Time", ImPlotAxisFlags_Time); // 2) make Setup calls
SetupAxis(ImAxis_Y1, "My Y-Axis");
SetupAxisLimits(ImAxis_Y1, 0, 1000);
SetupAxisFormat(ImAxis_Y1, "$%.0f");
SetupLegend(ImPlotLocation_North);
...
SetupFinish(); // 3) [optional] explicitly finish setup
PlotLine(...); // 4) plot items
...
EndPlot(); // 5) end the plot
}
All of the functionality you previously had with the original signature of BeginPlot
and SetNextXXX
is now available through the Setup API:
// Begin a new plot.
bool BeginPlot(const char* title_id, const ImVec2& size = ImVec2(-1,0), ImPlotFlags flags = ImPlotFlags_None);
// Enables an axis or sets the label and/or flags for an existing axis. Leave #label = NULL for no label.
void SetupAxis(ImAxis axis, const char* label = NULL, ImPlotAxisFlags flags = ImPlotAxisFlags_None);
// Sets an axis range limits. If ImPlotCond_Always is used, the axes limits will be locked.
void SetupAxisLimits(ImAxis axis, double v_min, double v_max, ImPlotCond cond = ImPlotCond_Once);
// Links an axis range limits to external values. Set to NULL for no linkage. The pointer data must remain valid until EndPlot.
void SetupAxisLinks(ImAxis axis, double* link_min, double* link_max);
// Sets the format of numeric axis labels via formater specifier (default="%g"). Formated values will be double (i.e. use %f).
void SetupAxisFormat(ImAxis axis, const char* fmt);
// Sets the format of numeric axis labels via formatter callback. Given #value, write a label into #buff. Optionally pass user data.
void SetupAxisFormat(ImAxis axis, ImPlotFormatter formatter, void* data = NULL);
// Sets an axis' ticks and optionally the labels. To keep the default ticks, set #keep_default=true.
void SetupAxisTicks(ImAxis axis, const double* values, int n_ticks, const char* const labels[] = NULL, bool keep_default = false);
// Sets an axis' ticks and optionally the labels for the next plot. To keep the default ticks, set #keep_default=true.
void SetupAxisTicks(ImAxis axis, double v_min, double v_max, int n_ticks, const char* const labels[] = NULL, bool keep_default = false);
// Sets the label and/or flags for primary X and Y axes (shorthand for two calls to SetupAxis).
void SetupAxes(const char* x_label, const char* y_label, ImPlotAxisFlags x_flags = ImPlotAxisFlags_None, ImPlotAxisFlags y_flags = ImPlotAxisFlags_None);
// Sets the primary X and Y axes range limits. If ImPlotCond_Always is used, the axes limits will be locked (shorthand for two calls to SetupAxisLimits).
void SetupAxesLimits(double x_min, double x_max, double y_min, double y_max, ImPlotCond cond = ImPlotCond_Once);
// Sets up the plot legend.
void SetupLegend(ImPlotLocation location, ImPlotLegendFlags flags = ImPlotLegendFlags_None);
// Set the location of the current plot's mouse position text (default = South|East).
void SetupMouseText(ImPlotLocation location, ImPlotMouseTextFlags flags = ImPlotMouseTextFlags_None);
// Explicitly finalize plot setup. Once you call this, you cannot make anymore Setup calls for the current plot!
// Note that calling this function is OPTIONAL; it will be called by the first subsequent setup-locking API call.
void SetupFinish();
A few notes:
BeginPlot
conditional statement.SetupFinish
. Do NOT call Setup code after you begin plotting or after you make any non-Setup API calls (e.g. utils like PlotToPixels
also lock Setup)SetupFinish
is OPTIONAL, but probably good practice. If you do not all it yourself, then the first subsequent plotting or utility function will call it for you.ImAxis_X1
and ImAxis_Y1
) are always enabled. To enable auxiliary axes, you must call, e.g. SetupAxis(ImAxis_Y2,...)
. This replaces the existing method of enabling auxiliary axes, i.e. passing ImPlotFlags_YAxis2/3
.SetNextXXX
API has been removed or renamed; check the top of implot.cpp
for changelogsBeginPlot
signature has been deprecated, and usage will result in compiler warnings. Please begin transitioning your code before its removal v1.0! You can define IMPLOT_DISABLE_OBSOLETE_FUNCTIONS
to remove it now.
The new Setup API allows us to easily extend and add functionality to axes. Here are a few new features you can start using today, with more expected to come in the near future.
ImAxis_
enums replace ImPlotYAxis_
SetAxis
replaces SetPlotYAxis
ImPlotAxisFlags_Opposite
or simply by dragging the axis to the other sideImPlotCol_AxisBgHovered
and ImPlotCol_AxisBgActive
ImGui::ButtonBehavior
under the hood for more robust interactionImPlotFormatter
callbacks passed to SetupAxisFormat
Query
has been removed and replaced with a more flexible tool, DragRect
. Unlike the previous query system, these can be resized and multiple can exist in one plot. An example in the demo shows how you can convert plot selections in to new query rects.
TagX
and TagY
have been added and allow you to add custom labels to axes. These use either the axis' formatter, or a custom provided string. You can combine these with other tools like DragLine
to create custom interactivity.DragPoint
and DragLine
no longer take a string ID. Instead they now expect an int
ID, and as a result no longer display the optional label. Instead, use TagX/Y
and Annotation
to add labels too these tools if needed.ImPlotDragToolFlags
// Flags for ImPlot::PlotBarGroups
enum ImPlotBarGroupsFlags_ {
ImPlotBarGroupsFlags_None = 0, // default
ImPlotBarGroupsFlags_Stacked = 1 << 0, // items in a group will be stacked on top of each other
};
// Plots a group of vertical bars. #values is a row-major matrix with #item_count rows and #group_count cols. #label_ids should have #item_count elements.
void PlotBarGroups(const char* const label_ids[], const T* values, int item_count, int group_count, double group_width=0.67, double x0=0, ImPlotBarGroupsFlags flags=ImPlotBarGroupsFlags_None);
// Plots a group of horizontal bars. #values is a row-major matrix with #item_count rows and #group_count cols. #label_ids should have #item_count elements.
void PlotBarGroupsH(const char* const label_ids[], const T* values, int item_count, int group_count, double group_height=0.67, double y0=0, ImPlotBarGroupsFlags flags=ImPlotBarGroupsFlags_None);
ImPlotInputMap
has been revamped and brought back into the public API, and two presets are now provided: Default
and Reverse
struct ImPlotInputMap {
ImGuiMouseButton Pan; // LMB enables panning when held,
ImGuiKeyModFlags PanMod; // none optional modifier that must be held for panning/fitting
ImGuiMouseButton Fit; // LMB initiates fit when double clicked
ImGuiMouseButton Select; // RMB begins box selection when pressed and confirms selection when released
ImGuiMouseButton SelectCancel; // LMB cancels active box selection when pressed; cannot be same as Select
ImGuiKeyModFlags SelectMod; // none optional modifier that must be held for box selection
ImGuiKeyModFlags SelectHorzMod; // Alt expands active box selection horizontally to plot edge when held
ImGuiKeyModFlags SelectVertMod; // Shift expands active box selection vertically to plot edge when held
ImGuiMouseButton Menu; // RMB opens context menus (if enabled) when clicked
ImGuiKeyModFlags OverrideMod; // Ctrl when held, all input is ignored; used to enable axis/plots as DND sources
ImGuiKeyModFlags ZoomMod; // none optional modifier that must be held for scroll wheel zooming
float ZoomRate; // 0.1f zoom rate for scroll (e.g. 0.1f = 10% plot range every scroll click); make negative to invert
ImPlotInputMap();
};
// Provides access to input mapping structure for permanent modifications to controls for pan, select, etc.
ImPlotInputMap& GetInputMap();
// Default input mapping: pan = LMB drag, box select = RMB drag, fit = LMB double click, context menu = RMB click, zoom = scroll.
void MapInputDefault(ImPlotInputMap* dst = NULL);
// Reverse input mapping: pan = RMB drag, box select = LMB drag, fit = LMB double click, context menu = RMB click, zoom = scroll.
void MapInputReverse(ImPlotInputMap* dst = NULL);
sprintf/snprintf
calls with ImFormatString
for overridability (#310)format-nonliteral
warnings (#304)PlotText
fitable (#286)Represents a stable release before API breaking changes to be introduced in v0.13.
Merely fixes a bug released in v0.10 that caused incompatibility with pre-v1.84 ImGui.
SampleColormapU32
return value #213GetColormapSize
return value #241PlotHistogram
and PlotHistogram2D
#148 https://github.com/epezent/implot/discussions/168#discussioncomment-493609
PlotVLines
/ PlotHLines
- plot infinite reference lines #166ImPlotFlags_Equal
- constrain x and y axes to have equal spacing #111 #147ImPlotAxisFlags_AutoFit
- auto fit axis all the timeImPlotInputMap
moved to implot_internal.h
SetColormap
and PushColormap(ImVec4*)
have been removed in favor of AddColormap
LerpColormap
was changed to SampleColormap
.ShowColormapScale
is now ColormapScale
and requires a label and ImVec2 size. The label will be displayed as an axis label (see above).BeginLegendDragDropSource
was changed to BeginDragDropSourceItem
See #168 for more information and screenshots!
PlotImage
PlotStairs
See https://github.com/epezent/implot/issues/48 for more details.
SetColormap
https://github.com/epezent/implot/issues/127
DisplayOffset
in ImGui https://github.com/epezent/implot/issues/127
ImPlotFlags
and ImPlotAxisFlags
were simplified https://github.com/epezent/implot/issues/48#issuecomment-687888961