From c0da6fea0401886a7f592e410992b888011b0e54 Mon Sep 17 00:00:00 2001 From: Evan Pezent Date: Sun, 24 Oct 2021 00:25:46 -0700 Subject: [PATCH] add PlotBarGroups --- implot.cpp | 22 ++- implot.h | 120 ++++++++------ implot_demo.cpp | 101 +++++++++--- implot_internal.h | 4 +- implot_items.cpp | 405 +++++++++++++++++++++++++++++----------------- 5 files changed, 422 insertions(+), 230 deletions(-) diff --git a/implot.cpp b/implot.cpp index 234f2e9..f04bfe6 100644 --- a/implot.cpp +++ b/implot.cpp @@ -199,6 +199,7 @@ const char* GetStyleColorName(ImPlotCol col) { "InlayText", "AxisText", "AxisGrid", + "AxisTick", "AxisBg", "AxisBgHovered", "AxisBgActive", @@ -243,6 +244,7 @@ ImVec4 GetAutoColor(ImPlotCol idx) { case ImPlotCol_InlayText: return ImGui::GetStyleColorVec4(ImGuiCol_Text); case ImPlotCol_AxisText: return ImGui::GetStyleColorVec4(ImGuiCol_Text); case ImPlotCol_AxisGrid: return GetStyleColorVec4(ImPlotCol_AxisText) * ImVec4(1,1,1,0.25f); + case ImPlotCol_AxisTick: return GetStyleColorVec4(ImPlotCol_AxisGrid); case ImPlotCol_AxisBg: return ImVec4(0,0,0,0); case ImPlotCol_AxisBgHovered: return ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered); case ImPlotCol_AxisBgActive: return ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive); @@ -1531,6 +1533,7 @@ void UpdateAxisColors(ImPlotAxis& axis) { const ImVec4 col_grid = GetStyleColorVec4(ImPlotCol_AxisGrid); axis.ColorMaj = ImGui::GetColorU32(col_grid); axis.ColorMin = ImGui::GetColorU32(col_grid*ImVec4(1,1,1,GImPlot->Style.MinorAlpha)); + axis.ColorTick = GetStyleColorU32(ImPlotCol_AxisTick); axis.ColorTxt = GetStyleColorU32(ImPlotCol_AxisText); axis.ColorBg = GetStyleColorU32(ImPlotCol_AxisBg); axis.ColorHov = GetStyleColorU32(ImPlotCol_AxisBgHovered); @@ -2492,7 +2495,8 @@ void SetupFinish() { const float txt_height = ImGui::GetTextLineHeight(); // render frame - ImGui::RenderFrame(plot.FrameRect.Min, plot.FrameRect.Max, GetStyleColorU32(ImPlotCol_FrameBg), true, Style.FrameRounding); + if (!ImHasFlag(plot.Flags, ImPlotFlags_NoFrame)) + ImGui::RenderFrame(plot.FrameRect.Min, plot.FrameRect.Max, GetStyleColorU32(ImPlotCol_FrameBg), true, Style.FrameRounding); // grid bg DrawList.AddRectFilled(plot.PlotRect.Min, plot.PlotRect.Max, GetStyleColorU32(ImPlotCol_PlotBg)); @@ -2599,7 +2603,7 @@ void SetupFinish() { // clear legend (TODO: put elsewhere) plot.Items.Legend.Reset(); - // push ID to set item hashes + // push ID to set item hashes (NB: !!!THIS PROBABLY NEEDS TO BE IN BEGIN PLOT!!!!) ImGui::PushOverrideID(gp.CurrentItems->ID); } @@ -2622,7 +2626,7 @@ void EndPlot() { // FINAL RENDER ----------------------------------------------------------- - const bool render_border = gp.Style.PlotBorderSize > 0 && gp.Style.Colors[ImPlotCol_PlotBorder].z > 0; + const bool render_border = gp.Style.PlotBorderSize > 0 && gp.Style.Colors[ImPlotCol_PlotBorder].w > 0; const bool any_x_held = plot.Held || AnyAxesHeld(&plot.Axes[ImAxis_X1], IMPLOT_NUM_X_AXES); const bool any_y_held = plot.Held || AnyAxesHeld(&plot.Axes[ImAxis_Y1], IMPLOT_NUM_Y_AXES); @@ -2665,10 +2669,10 @@ void EndPlot() { const ImVec2 start(tk.PixelPos, ax.Datum1); const float len = (!aux && tk.Major) ? gp.Style.MajorTickLen.x : gp.Style.MinorTickLen.x; const float thk = (!aux && tk.Major) ? gp.Style.MajorTickSize.x : gp.Style.MinorTickSize.x; - DrawList.AddLine(start, start + ImVec2(0,direction*len), ax.ColorMaj, thk); + DrawList.AddLine(start, start + ImVec2(0,direction*len), ax.ColorTick, thk); } if (aux || !render_border) - DrawList.AddLine(ImVec2(plot.PlotRect.Min.x,ax.Datum1), ImVec2(plot.PlotRect.Max.x,ax.Datum1), ax.ColorMaj, gp.Style.MinorTickSize.x); + DrawList.AddLine(ImVec2(plot.PlotRect.Min.x,ax.Datum1), ImVec2(plot.PlotRect.Max.x,ax.Datum1), ax.ColorTick, gp.Style.MinorTickSize.x); } count_B += !opp; count_T += opp; @@ -2692,10 +2696,10 @@ void EndPlot() { const ImVec2 start(ax.Datum1, tk.PixelPos); const float len = (!aux && tk.Major) ? gp.Style.MajorTickLen.y : gp.Style.MinorTickLen.y; const float thk = (!aux && tk.Major) ? gp.Style.MajorTickSize.y : gp.Style.MinorTickSize.y; - DrawList.AddLine(start, start + ImVec2(direction*len,0), ax.ColorMaj, thk); + DrawList.AddLine(start, start + ImVec2(direction*len,0), ax.ColorTick, thk); } if (aux || !render_border) - DrawList.AddLine(ImVec2(ax.Datum1, plot.PlotRect.Min.y), ImVec2(ax.Datum1, plot.PlotRect.Max.y), ax.ColorMaj, gp.Style.MinorTickSize.y); + DrawList.AddLine(ImVec2(ax.Datum1, plot.PlotRect.Min.y), ImVec2(ax.Datum1, plot.PlotRect.Max.y), ax.ColorTick, gp.Style.MinorTickSize.y); } count_L += !opp; count_R += opp; @@ -5452,6 +5456,7 @@ void StyleColorsAuto(ImPlotStyle* dst) { colors[ImPlotCol_PlotBorder] = IMPLOT_AUTO_COL; colors[ImPlotCol_AxisText] = IMPLOT_AUTO_COL; colors[ImPlotCol_AxisGrid] = IMPLOT_AUTO_COL; + colors[ImPlotCol_AxisTick] = IMPLOT_AUTO_COL; colors[ImPlotCol_AxisBg] = IMPLOT_AUTO_COL; colors[ImPlotCol_AxisBgHovered] = IMPLOT_AUTO_COL; colors[ImPlotCol_AxisBgActive] = IMPLOT_AUTO_COL; @@ -5480,6 +5485,7 @@ void StyleColorsClassic(ImPlotStyle* dst) { colors[ImPlotCol_InlayText] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); colors[ImPlotCol_AxisText] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); colors[ImPlotCol_AxisGrid] = ImVec4(0.90f, 0.90f, 0.90f, 0.25f); + colors[ImPlotCol_AxisTick] = IMPLOT_AUTO_COL; // TODO colors[ImPlotCol_AxisBg] = IMPLOT_AUTO_COL; // TODO colors[ImPlotCol_AxisBgHovered] = IMPLOT_AUTO_COL; // TODO colors[ImPlotCol_AxisBgActive] = IMPLOT_AUTO_COL; // TODO @@ -5508,6 +5514,7 @@ void StyleColorsDark(ImPlotStyle* dst) { colors[ImPlotCol_InlayText] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); colors[ImPlotCol_AxisText] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); colors[ImPlotCol_AxisGrid] = ImVec4(1.00f, 1.00f, 1.00f, 0.25f); + colors[ImPlotCol_AxisTick] = IMPLOT_AUTO_COL; // TODO colors[ImPlotCol_AxisBg] = IMPLOT_AUTO_COL; // TODO colors[ImPlotCol_AxisBgHovered] = IMPLOT_AUTO_COL; // TODO colors[ImPlotCol_AxisBgActive] = IMPLOT_AUTO_COL; // TODO @@ -5536,6 +5543,7 @@ void StyleColorsLight(ImPlotStyle* dst) { colors[ImPlotCol_InlayText] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); colors[ImPlotCol_AxisText] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); colors[ImPlotCol_AxisGrid] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); + colors[ImPlotCol_AxisTick] = ImVec4(0.00f, 0.00f, 0.00f, 0.25f); colors[ImPlotCol_AxisBg] = IMPLOT_AUTO_COL; // TODO colors[ImPlotCol_AxisBgHovered] = IMPLOT_AUTO_COL; // TODO colors[ImPlotCol_AxisBgActive] = IMPLOT_AUTO_COL; // TODO diff --git a/implot.h b/implot.h index 693e14e..8226eda 100644 --- a/implot.h +++ b/implot.h @@ -65,6 +65,8 @@ #define IMPLOT_AUTO -1 // Special color used to indicate that a color should be deduced automatically. #define IMPLOT_AUTO_COL ImVec4(0,0,0,-1) +// Macro for templated plotting functions; keeps header clean. +#define IMPLOT_TMP template IMPLOT_API //----------------------------------------------------------------------------- // [SECTION] Enums and Types @@ -81,6 +83,8 @@ typedef int ImPlotSubplotFlags; // -> enum ImPlotSubplotFlags_ typedef int ImPlotLegendFlags; // -> enum ImPlotLegendFlags_ typedef int ImPlotMouseTextFlags; // -> enum ImPlotMouseTextFlags_ typedef int ImPlotDragToolFlags; // -> ImPlotDragToolFlags_ +typedef int ImPlotBarGroupsFlags; // -> ImPlotBarGroupsFlags_ + typedef int ImPlotCond; // -> enum ImPlotCond_ typedef int ImPlotCol; // -> enum ImPlotCol_ typedef int ImPlotStyleVar; // -> enum ImPlotStyleVar_ @@ -105,17 +109,18 @@ enum ImAxis_ { // Options for plots (see BeginPlot). enum ImPlotFlags_ { - ImPlotFlags_None = 0, // default - ImPlotFlags_NoTitle = 1 << 0, // the plot title will not be displayed (titles are also hidden if preceeded by double hashes, e.g. "##MyPlot") - ImPlotFlags_NoLegend = 1 << 1, // the legend will not be displayed - ImPlotFlags_NoMouseText = 1 << 2, // the mouse position, in plot coordinates, will not be displayed inside of the plot - ImPlotFlags_NoInputs = 1 << 3, // the user will not be able to interact with the plot - ImPlotFlags_NoMenus = 1 << 4, // the user will not be able to open context menus - ImPlotFlags_NoBoxSelect = 1 << 5, // the user will not be able to box-select - ImPlotFlags_NoChild = 1 << 6, // a child window region will not be used to capture mouse scroll (can boost performance for single ImGui window applications) - ImPlotFlags_Equal = 1 << 7, // x and y axes pairs will be constrained to have the same units/pixel - ImPlotFlags_Crosshairs = 1 << 8, // the default mouse cursor will be replaced with a crosshair when hovered - ImPlotFlags_AntiAliased = 1 << 9, // plot items will be software anti-aliased (not recommended for high density plots, prefer MSAA) + ImPlotFlags_None = 0, // default + ImPlotFlags_NoTitle = 1 << 0, // the plot title will not be displayed (titles are also hidden if preceeded by double hashes, e.g. "##MyPlot") + ImPlotFlags_NoLegend = 1 << 1, // the legend will not be displayed + ImPlotFlags_NoMouseText = 1 << 2, // the mouse position, in plot coordinates, will not be displayed inside of the plot + ImPlotFlags_NoInputs = 1 << 3, // the user will not be able to interact with the plot + ImPlotFlags_NoMenus = 1 << 4, // the user will not be able to open context menus + ImPlotFlags_NoBoxSelect = 1 << 5, // the user will not be able to box-select + ImPlotFlags_NoChild = 1 << 6, // a child window region will not be used to capture mouse scroll (can boost performance for single ImGui window applications) + ImPlotFlags_NoFrame = 1 << 7, // the ImGui frame will not be rendered + ImPlotFlags_Equal = 1 << 8, // x and y axes pairs will be constrained to have the same units/pixel + ImPlotFlags_Crosshairs = 1 << 9, // the default mouse cursor will be replaced with a crosshair when hovered + ImPlotFlags_AntiAliased = 1 << 10, // plot items will be software anti-aliased (not recommended for high density plots, prefer MSAA) ImPlotFlags_CanvasOnly = ImPlotFlags_NoTitle | ImPlotFlags_NoLegend | ImPlotFlags_NoMenus | ImPlotFlags_NoBoxSelect | ImPlotFlags_NoMouseText }; @@ -186,6 +191,12 @@ enum ImPlotDragToolFlags_ { ImPlotDragToolFlags_Delayed = 1 << 3, // tool rendering will be delayed one frame; useful when applying position-constraints }; +// 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 +}; + // Represents a condition for SetupAxisLimits etc. (same as ImGuiCond, but we only support a subset of those enums) enum ImPlotCond_ { @@ -212,7 +223,8 @@ enum ImPlotCol_ { ImPlotCol_TitleText, // plot title text color (defaults to ImGuiCol_Text) ImPlotCol_InlayText, // color of text appearing inside of plots (defaults to ImGuiCol_Text) ImPlotCol_AxisText, // axis label and tick lables color (defaults to ImGuiCol_Text) - ImPlotCol_AxisGrid, // axis grid and tick color (defaults to 25% ImPlotCol_XAxis) + ImPlotCol_AxisGrid, // axis grid color (defaults to 25% ImPlotCol_AxisText) + ImPlotCol_AxisTick, // axis tick color (defaults to AxisGrid) ImPlotCol_AxisBg, // background color of axis hover region (defaults to transparent) ImPlotCol_AxisBgHovered, // axis hover color (defaults to ImGuiCol_ButtonHovered) ImPlotCol_AxisBgActive, // axis active color (defaults to ImGuiCol_ButtonActive) @@ -630,7 +642,7 @@ IMPLOT_API void SetNextAxesToFit(); // Begin/EndPlot and after any Setup API calls. Each plots data on the current // x and y axes, which can be changed with `SetAxis/Axes`. // -// The templates are explicitly instantiated in implot_items.cpp. +// The templated functions are explicitly instantiated in implot_items.cpp. // They are not intended to be used generically with custom types. You will get // a linker error if you try! All functions support the following scalar types: // @@ -675,71 +687,77 @@ IMPLOT_API void SetNextAxesToFit(); // if you try plotting extremely large 64-bit integral types. Proceed with caution! // Plots a standard 2D line plot. -template IMPLOT_API void PlotLine(const char* label_id, const T* values, int count, double xscale=1, double x0=0, int offset=0, int stride=sizeof(T)); -template IMPLOT_API void PlotLine(const char* label_id, const T* xs, const T* ys, int count, int offset=0, int stride=sizeof(T)); - IMPLOT_API void PlotLineG(const char* label_id, ImPlotGetter getter, void* data, int count); +IMPLOT_TMP void PlotLine(const char* label_id, const T* values, int count, double xscale=1, double x0=0, int offset=0, int stride=sizeof(T)); +IMPLOT_TMP void PlotLine(const char* label_id, const T* xs, const T* ys, int count, int offset=0, int stride=sizeof(T)); +IMPLOT_API void PlotLineG(const char* label_id, ImPlotGetter getter, void* data, int count); // Plots a standard 2D scatter plot. Default marker is ImPlotMarker_Circle. -template IMPLOT_API void PlotScatter(const char* label_id, const T* values, int count, double xscale=1, double x0=0, int offset=0, int stride=sizeof(T)); -template IMPLOT_API void PlotScatter(const char* label_id, const T* xs, const T* ys, int count, int offset=0, int stride=sizeof(T)); - IMPLOT_API void PlotScatterG(const char* label_id, ImPlotGetter getter, void* data, int count); +IMPLOT_TMP void PlotScatter(const char* label_id, const T* values, int count, double xscale=1, double x0=0, int offset=0, int stride=sizeof(T)); +IMPLOT_TMP void PlotScatter(const char* label_id, const T* xs, const T* ys, int count, int offset=0, int stride=sizeof(T)); +IMPLOT_API void PlotScatterG(const char* label_id, ImPlotGetter getter, void* data, int count); // Plots a a stairstep graph. The y value is continued constantly from every x position, i.e. the interval [x[i], x[i+1]) has the value y[i]. -template IMPLOT_API void PlotStairs(const char* label_id, const T* values, int count, double xscale=1, double x0=0, int offset=0, int stride=sizeof(T)); -template IMPLOT_API void PlotStairs(const char* label_id, const T* xs, const T* ys, int count, int offset=0, int stride=sizeof(T)); - IMPLOT_API void PlotStairsG(const char* label_id, ImPlotGetter getter, void* data, int count); +IMPLOT_TMP void PlotStairs(const char* label_id, const T* values, int count, double xscale=1, double x0=0, int offset=0, int stride=sizeof(T)); +IMPLOT_TMP void PlotStairs(const char* label_id, const T* xs, const T* ys, int count, int offset=0, int stride=sizeof(T)); +IMPLOT_API void PlotStairsG(const char* label_id, ImPlotGetter getter, void* data, int count); -// Plots a shaded (filled) region between two lines, or a line and a horizontal reference. Set y_ref to +/-INFINITY for infinite fill extents. -template IMPLOT_API void PlotShaded(const char* label_id, const T* values, int count, double y_ref=0, double xscale=1, double x0=0, int offset=0, int stride=sizeof(T)); -template IMPLOT_API void PlotShaded(const char* label_id, const T* xs, const T* ys, int count, double y_ref=0, int offset=0, int stride=sizeof(T)); -template IMPLOT_API void PlotShaded(const char* label_id, const T* xs, const T* ys1, const T* ys2, int count, int offset=0, int stride=sizeof(T)); - IMPLOT_API void PlotShadedG(const char* label_id, ImPlotGetter getter1, void* data1, ImPlotGetter getter2, void* data2, int count); +// Plots a shaded (filled) region between two lines, or a line and a horizontal reference. Set yref to +/-INFINITY for infinite fill extents. +IMPLOT_TMP void PlotShaded(const char* label_id, const T* values, int count, double yref=0, double xscale=1, double x0=0, int offset=0, int stride=sizeof(T)); +IMPLOT_TMP void PlotShaded(const char* label_id, const T* xs, const T* ys, int count, double yref=0, int offset=0, int stride=sizeof(T)); +IMPLOT_TMP void PlotShaded(const char* label_id, const T* xs, const T* ys1, const T* ys2, int count, int offset=0, int stride=sizeof(T)); +IMPLOT_API void PlotShadedG(const char* label_id, ImPlotGetter getter1, void* data1, ImPlotGetter getter2, void* data2, int count); -// Plots a vertical bar graph. #width and #shift are in X units. -template IMPLOT_API void PlotBars(const char* label_id, const T* values, int count, double width=0.67, double shift=0, int offset=0, int stride=sizeof(T)); -template IMPLOT_API void PlotBars(const char* label_id, const T* xs, const T* ys, int count, double width, int offset=0, int stride=sizeof(T)); - IMPLOT_API void PlotBarsG(const char* label_id, ImPlotGetter getter, void* data, int count, double width); +// Plots a vertical bar graph. #bar_width and #x0 are in X units. +IMPLOT_TMP void PlotBars(const char* label_id, const T* values, int count, double bar_width=0.67, double x0=0, int offset=0, int stride=sizeof(T)); +IMPLOT_TMP void PlotBars(const char* label_id, const T* xs, const T* ys, int count, double bar_width, int offset=0, int stride=sizeof(T)); +IMPLOT_API void PlotBarsG(const char* label_id, ImPlotGetter getter, void* data, int count, double bar_width); -// Plots a horizontal bar graph. #height and #shift are in Y units. -template IMPLOT_API void PlotBarsH(const char* label_id, const T* values, int count, double height=0.67, double shift=0, int offset=0, int stride=sizeof(T)); -template IMPLOT_API void PlotBarsH(const char* label_id, const T* xs, const T* ys, int count, double height, int offset=0, int stride=sizeof(T)); - IMPLOT_API void PlotBarsHG(const char* label_id, ImPlotGetter getter, void* data, int count, double height); +// Plots a horizontal bar graph. #bar_height and #y0 are in Y units. +IMPLOT_TMP void PlotBarsH(const char* label_id, const T* values, int count, double bar_height=0.67, double y0=0, int offset=0, int stride=sizeof(T)); +IMPLOT_TMP void PlotBarsH(const char* label_id, const T* xs, const T* ys, int count, double bar_height, int offset=0, int stride=sizeof(T)); +IMPLOT_API void PlotBarsHG(const char* label_id, ImPlotGetter getter, void* data, int count, double bar_height); + +// 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. +IMPLOT_TMP 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. +IMPLOT_TMP 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); // Plots vertical error bar. The label_id should be the same as the label_id of the associated line or bar plot. -template IMPLOT_API void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* err, int count, int offset=0, int stride=sizeof(T)); -template IMPLOT_API void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* neg, const T* pos, int count, int offset=0, int stride=sizeof(T)); +IMPLOT_TMP void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* err, int count, int offset=0, int stride=sizeof(T)); +IMPLOT_TMP void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* neg, const T* pos, int count, int offset=0, int stride=sizeof(T)); // Plots horizontal error bars. The label_id should be the same as the label_id of the associated line or bar plot. -template IMPLOT_API void PlotErrorBarsH(const char* label_id, const T* xs, const T* ys, const T* err, int count, int offset=0, int stride=sizeof(T)); -template IMPLOT_API void PlotErrorBarsH(const char* label_id, const T* xs, const T* ys, const T* neg, const T* pos, int count, int offset=0, int stride=sizeof(T)); +IMPLOT_TMP void PlotErrorBarsH(const char* label_id, const T* xs, const T* ys, const T* err, int count, int offset=0, int stride=sizeof(T)); +IMPLOT_TMP void PlotErrorBarsH(const char* label_id, const T* xs, const T* ys, const T* neg, const T* pos, int count, int offset=0, int stride=sizeof(T)); /// Plots vertical stems. -template IMPLOT_API void PlotStems(const char* label_id, const T* values, int count, double y_ref=0, double xscale=1, double x0=0, int offset=0, int stride=sizeof(T)); -template IMPLOT_API void PlotStems(const char* label_id, const T* xs, const T* ys, int count, double y_ref=0, int offset=0, int stride=sizeof(T)); +IMPLOT_TMP void PlotStems(const char* label_id, const T* values, int count, double yref=0, double xscale=1, double x0=0, int offset=0, int stride=sizeof(T)); +IMPLOT_TMP void PlotStems(const char* label_id, const T* xs, const T* ys, int count, double yref=0, int offset=0, int stride=sizeof(T)); /// Plots infinite vertical or horizontal lines (e.g. for references or asymptotes). -template IMPLOT_API void PlotVLines(const char* label_id, const T* xs, int count, int offset=0, int stride=sizeof(T)); -template IMPLOT_API void PlotHLines(const char* label_id, const T* ys, int count, int offset=0, int stride=sizeof(T)); +IMPLOT_TMP void PlotVLines(const char* label_id, const T* xs, int count, int offset=0, int stride=sizeof(T)); +IMPLOT_TMP void PlotHLines(const char* label_id, const T* ys, int count, int offset=0, int stride=sizeof(T)); // Plots a pie chart. If the sum of values > 1 or normalize is true, each value will be normalized. Center and radius are in plot units. #label_fmt can be set to NULL for no labels. -template IMPLOT_API void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, bool normalize=false, const char* label_fmt="%.1f", double angle0=90); +IMPLOT_TMP void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, bool normalize=false, const char* label_fmt="%.1f", double angle0=90); // Plots a 2D heatmap chart. Values are expected to be in row-major order. Leave #scale_min and scale_max both at 0 for automatic color scaling, or set them to a predefined range. #label_fmt can be set to NULL for no labels. -template IMPLOT_API void PlotHeatmap(const char* label_id, const T* values, int rows, int cols, double scale_min=0, double scale_max=0, const char* label_fmt="%.1f", const ImPlotPoint& bounds_min=ImPlotPoint(0,0), const ImPlotPoint& bounds_max=ImPlotPoint(1,1)); +IMPLOT_TMP void PlotHeatmap(const char* label_id, const T* values, int rows, int cols, double scale_min=0, double scale_max=0, 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 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); +IMPLOT_TMP 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 #bounds is left unspecified, the min/max of #xs an #ys will be used as the ranges. If #bounds 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 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, ImPlotRect range=ImPlotRect(), bool outliers=true); +IMPLOT_TMP 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, ImPlotRect range=ImPlotRect(), 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. -template 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, ImPlotGetter getter, void* data, int count); +IMPLOT_TMP 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, ImPlotGetter getter, void* data, int count); // Plots an axis-aligned image. #bounds_min/bounds_max are in plot coordinates (y-up) and #uv0/uv1 are in texture coordinates (y-down). IMPLOT_API void PlotImage(const char* label_id, ImTextureID user_texture_id, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max, const ImVec2& uv0=ImVec2(0,0), const ImVec2& uv1=ImVec2(1,1), const ImVec4& tint_col=ImVec4(1,1,1,1)); @@ -1101,8 +1119,8 @@ IMPLOT_API void ShowDemoWindow(bool* p_open = NULL); #endif enum ImPlotFlagsObsolete_ { - ImPlotFlags_YAxis2 = 1 << 10, - ImPlotFlags_YAxis3 = 1 << 11, + ImPlotFlags_YAxis2 = 1 << 20, + ImPlotFlags_YAxis3 = 1 << 21, }; namespace ImPlot { diff --git a/implot_demo.cpp b/implot_demo.cpp index 9d9ebf3..be1548c 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -437,40 +437,99 @@ void ShowDemo_StairstepPlots() { //----------------------------------------------------------------------------- void ShowDemo_BarPlots() { - static bool horz = false; - static ImS8 midtm[10] = {83, 67, 23, 89, 83, 78, 91, 82, 85, 90}; - static ImS16 final[10] = {80, 62, 56, 99, 55, 78, 88, 78, 90, 100}; - static ImS32 grade[10] = {80, 69, 52, 92, 72, 78, 75, 76, 89, 95}; + static ImS8 data[10] = {1,2,3,4,5,6,7,8,9,10}; + if (ImPlot::BeginPlot("Bar Plot")) { + ImPlot::PlotBars("Bars",data,10,0.7,1); + ImPlot::PlotBarsH("BarsH",data,10,0.4,1); + ImPlot::EndPlot(); + } +} - static const char* labels[] = {"S1","S2","S3","S4","S5","S6","S7","S8","S9","S10"}; +void ShowDemo_BarGroups() { + static ImS8 data[30] = {83, 67, 23, 89, 83, 78, 91, 82, 85, 90, // midterm + 80, 62, 56, 99, 55, 78, 88, 78, 90, 100, // final + 80, 69, 52, 92, 72, 78, 75, 76, 89, 95}; // course + + static const char* ilabels[] = {"Midterm Exam","Final Exam","Course Grade"}; + static const char* glabels[] = {"S1","S2","S3","S4","S5","S6","S7","S8","S9","S10"}; static const double positions[] = {0,1,2,3,4,5,6,7,8,9}; + static int items = 3; + static int groups = 10; + static float size = 0.67f; + + static ImPlotBarGroupsFlags flags = 0; + static bool horz = false; + + ImGui::CheckboxFlags("Stacked", (unsigned int*)&flags, ImPlotBarGroupsFlags_Stacked); + ImGui::SameLine(); ImGui::Checkbox("Horizontal",&horz); + ImGui::SliderInt("Items",&items,1,3); + ImGui::SliderFloat("Size",&size,0,1); - if (ImPlot::BeginPlot("Bar Plot")) - { + if (ImPlot::BeginPlot("Bar Group")) { ImPlot::SetupLegend(ImPlotLocation_East, ImPlotLegendFlags_Outside); if (horz) { - ImPlot::SetupAxesLimits(0, 110, -0.5, 9.5, ImGuiCond_Always); - ImPlot::SetupAxes("Score","Student",0,ImPlotAxisFlags_Invert); - ImPlot::SetupAxisTicks(ImAxis_Y1,positions, 10, labels); - ImPlot::PlotBarsH("Midterm Exam", midtm, 10, 0.2, -0.2); - ImPlot::PlotBarsH("Final Exam", final, 10, 0.2, 0); - ImPlot::PlotBarsH("Course Grade", grade, 10, 0.2, 0.2); + ImPlot::SetupAxes("Score","Student",ImPlotAxisFlags_AutoFit,ImPlotAxisFlags_AutoFit); + ImPlot::SetupAxisTicks(ImAxis_Y1,positions, groups, glabels); + ImPlot::PlotBarGroupsH(ilabels,data,items,groups,size,0,flags); } else { - ImPlot::SetupAxesLimits(-0.5, 9.5, 0, 110, ImGuiCond_Always); - ImPlot::SetupAxes("Student","Score"); - ImPlot::SetupAxisTicks(ImAxis_X1,positions, 10, labels); - ImPlot::PlotBars("Midterm Exam", midtm, 10, 0.2, -0.2); - ImPlot::PlotBars("Final Exam", final, 10, 0.2, 0); - ImPlot::PlotBars("Course Grade", grade, 10, 0.2, 0.2); + ImPlot::SetupAxes("Student","Score",ImPlotAxisFlags_AutoFit,ImPlotAxisFlags_AutoFit); + ImPlot::SetupAxisTicks(ImAxis_X1,positions, groups, glabels); + ImPlot::PlotBarGroups(ilabels,data,items,groups,size,0,flags); } ImPlot::EndPlot(); } } +void ShowDemo_BarStacks() { + + static ImPlotColormap Liars = -1; + if (Liars == -1) { + static const ImU32 Liars_Data[6] = { 4282515870, 4282609140, 4287357182, 4294630301, 4294945280, 4294921472 }; + Liars = ImPlot::AddColormap("Liars", Liars_Data, 6); + } + + static bool diverging = true; + ImGui::Checkbox("Diverging",&diverging); + + static const char* politicians[] = {"Trump","Bachman","Cruz","Gingrich","Palin","Santorum","Walker","Perry","Ryan","McCain","Rubio","Romney","Rand Paul","Christie","Biden","Kasich","Sanders","J Bush","H Clinton","Obama"}; + static int data_reg[] = {18,26,7,14,10,8,6,11,4,4,3,8,6,8,6,5,0,3,1,2, // Pants on Fire + 43,36,30,21,30,27,25,17,11,22,15,16,16,17,12,12,14,6,13,12, // False + 16,13,28,22,15,21,15,18,30,17,24,18,13,10,14,15,17,22,14,12, // Mostly False + 17,10,13,25,12,22,19,26,23,17,22,27,20,26,29,17,18,22,21,27, // Half True + 5,7,16,10,10,12,23,13,17,20,22,16,23,19,20,26,36,29,27,26, // Mostly True + 1,8,6,8,23,10,12,15,15,20,14,15,22,20,19,25,15,18,24,21}; // True + static const char* labels_reg[] = {"Pants on Fire","False","Mostly False","Half True","Mostly True","True"}; + + + static int data_div[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // Pants on Fire (dummy, to order legend logically) + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // False (dummy, to order legend logically) + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // Mostly False (dummy, to order legend logically) + -16,-13,-28,-22,-15,-21,-15,-18,-30,-17,-24,-18,-13,-10,-14,-15,-17,-22,-14,-12, // Mostly False + -43,-36,-30,-21,-30,-27,-25,-17,-11,-22,-15,-16,-16,-17,-12,-12,-14,-6,-13,-12, // False + -18,-26,-7,-14,-10,-8,-6,-11,-4,-4,-3,-8,-6,-8,-6,-5,0,-3,-1,-2, // Pants on Fire + 17,10,13,25,12,22,19,26,23,17,22,27,20,26,29,17,18,22,21,27, // Half True + 5,7,16,10,10,12,23,13,17,20,22,16,23,19,20,26,36,29,27,26, // Mostly True + 1,8,6,8,23,10,12,15,15,20,14,15,22,20,19,25,15,18,24,21}; // True + static const char* labels_div[] = {"Pants on Fire","False","Mostly False","Mostly False","False","Pants on Fire","Half True","Mostly True","True"}; + + ImPlot::PushColormap(Liars); + if (ImPlot::BeginPlot("PolitiFact: Who Lies More?",ImVec2(-1,400),ImPlotFlags_NoMouseText)) { + ImPlot::SetupLegend(ImPlotLocation_South, ImPlotLegendFlags_Outside|ImPlotLegendFlags_Horizontal); + ImPlot::SetupAxes(NULL,NULL,ImPlotAxisFlags_AutoFit|ImPlotAxisFlags_NoDecorations,ImPlotAxisFlags_AutoFit|ImPlotAxisFlags_Invert); + ImPlot::SetupAxisTicks(ImAxis_Y1,0,19,20,politicians,false); + if (diverging) + ImPlot::PlotBarGroupsH(labels_div,data_div,9,20,0.75,0,ImPlotBarGroupsFlags_Stacked); + else + ImPlot::PlotBarGroupsH(labels_reg,data_reg,6,20,0.75,0,ImPlotBarGroupsFlags_Stacked); + ImPlot::EndPlot(); + } + ImPlot::PopColormap(); +} + //----------------------------------------------------------------------------- void ShowDemo_ErrorBars() { @@ -1949,6 +2008,10 @@ void ShowDemoWindow(bool* p_open) { ShowDemo_StairstepPlots(); if (ImGui::CollapsingHeader("Bar Plots")) ShowDemo_BarPlots(); + if (ImGui::CollapsingHeader("Bar Groups")) + ShowDemo_BarGroups(); + if (ImGui::CollapsingHeader("Bar Stacks")) + ShowDemo_BarStacks(); if (ImGui::CollapsingHeader("Error Bars")) ShowDemo_ErrorBars(); if (ImGui::CollapsingHeader("Stem Plots##")) diff --git a/implot_internal.h b/implot_internal.h index 2ebe6a3..6ec2b0f 100644 --- a/implot_internal.h +++ b/implot_internal.h @@ -613,7 +613,7 @@ struct ImPlotAxis double LinM, LogD; ImRect HoverRect; int LabelOffset; - ImU32 ColorMaj, ColorMin, ColorTxt, ColorBg, ColorHov, ColorAct, ColorHiLi; + ImU32 ColorMaj, ColorMin, ColorTick, ColorTxt, ColorBg, ColorHov, ColorAct, ColorHiLi; char FormatSpec[16]; ImPlotFormatter Formatter; void* FormatterData; @@ -637,7 +637,7 @@ struct ImPlotAxis PickerLevel = 0; Datum1 = Datum2 = 0; LabelOffset = -1; - ColorMaj = ColorMin = ColorTxt = ColorBg = ColorHov = ColorAct = 0; + ColorMaj = ColorMin = ColorTick = ColorTxt = ColorBg = ColorHov = ColorAct = 0; ColorHiLi = IM_COL32_BLACK_TRANS; Formatter = NULL; FormatterData = NULL; diff --git a/implot_items.cpp b/implot_items.cpp index c211e8e..0209238 100644 --- a/implot_items.cpp +++ b/implot_items.cpp @@ -110,6 +110,11 @@ ImPlotItem* GetItem(const char* label_id) { return gp.CurrentItems->GetItem(label_id); } +bool IsItemHidden(const char* label_id) { + ImPlotItem* item = GetItem(label_id); + return item != NULL && !item->Show; +} + ImPlotItem* GetCurrentItem() { ImPlotContext& gp = *GImPlot; return gp.CurrentItem; @@ -187,6 +192,7 @@ void BustColorCache(const char* plot_title_id) { static const float ITEM_HIGHLIGHT_LINE_SCALE = 2.0f; static const float ITEM_HIGHLIGHT_MARK_SCALE = 1.25f; + // Begins a new item. Returns false if the item should not be plotted. bool BeginItem(const char* label_id, ImPlotCol recolor_from) { ImPlotContext& gp = *GImPlot; @@ -304,101 +310,67 @@ IMPLOT_INLINE T IndexData(const T* data, int idx, int count, int offset, int str // Getters can be thought of as iterators that convert user data (e.g. raw arrays) // to ImPlotPoints +template +struct GetterIdx { + GetterIdx(const T* data, int count, int offset = 0, int stride = sizeof(T)) : + Data(data), + Count(count), + Offset(count ? ImPosMod(offset, count) : 0), + Stride(stride) + { } + template IMPLOT_INLINE double operator()(I idx) const { + return (double)IndexData(Data, idx, Count, Offset, Stride); + } + const T* Data; + int Count; + int Offset; + int Stride; +}; + +struct GetterLin { + GetterLin(double m, double b) : M(m), B(b) { } + template IMPLOT_INLINE double operator()(I idx) const { + return M * idx + B; + } + const double M; + const double B; +}; + +struct GetterRef { + GetterRef(double ref) : Ref(ref) { } + template IMPLOT_INLINE double operator()(I) const { return Ref; } + const double Ref; +}; + +template +struct GetterXY { + GetterXY(TGetterX x, TGetterY y, int count) : GetterX(x), GetterY(y), Count(count) { } + template IMPLOT_INLINE ImPlotPoint operator()(I idx) const { + return ImPlotPoint(GetterX(idx),GetterY(idx)); + } + const TGetterX GetterX; + const TGetterY GetterY; + const int Count; +}; + // Interprets an array of Y points as ImPlotPoints where the X value is the index template -struct GetterYs { - GetterYs(const T* ys, int count, double xscale, double x0, int offset, int stride) : - Ys(ys), - Count(count), - XScale(xscale), - X0(x0), - Offset(count ? ImPosMod(offset, count) : 0), - Stride(stride) - { } - template IMPLOT_INLINE ImPlotPoint operator()(I idx) const { - return ImPlotPoint(X0 + XScale * idx, (double)IndexData(Ys, idx, Count, Offset, Stride)); - } - const T* const Ys; - const int Count; - const double XScale; - const double X0; - const int Offset; - const int Stride; -}; - -// Interprets separate arrays for X and Y points as ImPlotPoints -template -struct GetterXsYs { - GetterXsYs(const T* xs, const T* ys, int count, int offset, int stride) : +struct GetterXs { + GetterXs(const T* xs, int count, double yscale, double y0, int offset, int stride) : Xs(xs), - Ys(ys), Count(count), + YScale(yscale), + Y0(y0), Offset(count ? ImPosMod(offset, count) : 0), Stride(stride) { } template IMPLOT_INLINE ImPlotPoint operator()(I idx) const { - return ImPlotPoint((double)IndexData(Xs, idx, Count, Offset, Stride), (double)IndexData(Ys, idx, Count, Offset, Stride)); + return ImPlotPoint((double)IndexData(Xs, idx, Count, Offset, Stride), Y0 + YScale * idx); } const T* const Xs; - const T* const Ys; - const int Count; - const int Offset; - const int Stride; -}; - -// Always returns a constant Y reference value where the X value is the index -struct GetterYRef { - GetterYRef(double y_ref, int count, double xscale, double x0) : - YRef(y_ref), - Count(count), - XScale(xscale), - X0(x0) - { } - template IMPLOT_INLINE ImPlotPoint operator()(I idx) const { - return ImPlotPoint(X0 + XScale*idx, YRef); - } - const double YRef; - const int Count; - const double XScale; - const double X0; -}; - -// Interprets an array of X points as ImPlotPoints where the Y value is a constant reference value -template -struct GetterXsYRef { - GetterXsYRef(const T* xs, double y_ref, int count, int offset, int stride) : - Xs(xs), - YRef(y_ref), - Count(count), - Offset(count ? ImPosMod(offset, count) : 0), - Stride(stride) - { } - template IMPLOT_INLINE ImPlotPoint operator()(I idx) const { - return ImPlotPoint((double)IndexData(Xs, idx, Count, Offset, Stride), YRef); - } - const T* const Xs; - const double YRef; - const int Count; - const int Offset; - const int Stride; -}; - -// Interprets an array of Y points as ImPlotPoints where the X value is a constant reference value -template -struct GetterXRefYs { - GetterXRefYs(double x_ref, const T* ys, int count, int offset, int stride) : - XRef(x_ref), - Ys(ys), - Count(count), - Offset(count ? ImPosMod(offset, count) : 0), - Stride(stride) - { } - template IMPLOT_INLINE ImPlotPoint operator()(I idx) const { - return ImPlotPoint(XRef, (double)IndexData(Ys, idx, Count, Offset, Stride)); - } - const double XRef; - const T* const Ys; const int Count; + const double YScale; + const double Y0; const int Offset; const int Stride; }; @@ -418,18 +390,30 @@ struct GetterFuncPtr { const int Count; }; -template -struct GetterBarV { - const T* Ys; double XShift; int Count; int Offset; int Stride; - GetterBarV(const T* ys, double xshift, int count, int offset, int stride) { Ys = ys; XShift = xshift; Count = count; Offset = offset; Stride = stride; } - template IMPLOT_INLINE ImPlotPoint operator()(I idx) const { return ImPlotPoint((double)idx + (double)XShift, (double)IndexData(Ys, idx, Count, Offset, Stride)); } +template +struct GetterOverrideX { + GetterOverrideX(const TGetter& getter, double x) : Getter(getter), X(x), Count(getter.Count) { } + template IMPLOT_INLINE ImPlotPoint operator()(I idx) const { + ImPlotPoint p = Getter(idx); + p.x = X; + return p; + } + const TGetter& Getter; + const double X; + const int Count; }; -template -struct GetterBarH { - const T* Xs; double YShift; int Count; int Offset; int Stride; - GetterBarH(const T* xs, double yshift, int count, int offset, int stride) { Xs = xs; YShift = yshift; Count = count; Offset = offset; Stride = stride; } - template IMPLOT_INLINE ImPlotPoint operator()(I idx) const { return ImPlotPoint((double)IndexData(Xs, idx, Count, Offset, Stride), (double)idx + (double)YShift); } +template +struct GetterOverrideY { + GetterOverrideY(const TGetter& getter, double y) : Getter(getter), Y(y), Count(getter.Count) { } + template IMPLOT_INLINE ImPlotPoint operator()(I idx) const { + ImPlotPoint p = Getter(idx); + p.y = Y; + return p; + } + const TGetter& Getter; + const double Y; + const int Count; }; template @@ -484,7 +468,6 @@ struct TransformerLog { template struct TransformerXY { TransformerXY(const ImPlotAxis& x_axis, const ImPlotAxis& y_axis) : - Tx(x_axis.PixelMin, x_axis.Range.Min, x_axis.Range.Max, @@ -986,7 +969,7 @@ IMPLOT_INLINE void PlotLineEx(const char* label_id, const Getter& getter) { template void PlotLine(const char* label_id, const T* values, int count, double xscale, double x0, int offset, int stride) { - GetterYs getter(values,count,xscale,x0,offset,stride); + GetterXY> getter(GetterLin(xscale,x0),GetterIdx(values,count,offset,stride),count); PlotLineEx(label_id, getter); } @@ -1003,7 +986,7 @@ template IMPLOT_API void PlotLine(const char* label_id, const double* va template void PlotLine(const char* label_id, const T* xs, const T* ys, int count, int offset, int stride) { - GetterXsYs getter(xs,ys,count,offset,stride); + GetterXY,GetterIdx> getter(GetterIdx(xs,count,offset,stride),GetterIdx(ys,count,offset,stride),count); return PlotLineEx(label_id, getter); } @@ -1060,7 +1043,7 @@ IMPLOT_INLINE void PlotScatterEx(const char* label_id, const Getter& getter) { template void PlotScatter(const char* label_id, const T* values, int count, double xscale, double x0, int offset, int stride) { - GetterYs getter(values,count,xscale,x0,offset,stride); + GetterXY> getter(GetterLin(xscale,x0),GetterIdx(values,count,offset,stride),count); PlotScatterEx(label_id, getter); } @@ -1077,7 +1060,7 @@ template IMPLOT_API void PlotScatter(const char* label_id, const double* template void PlotScatter(const char* label_id, const T* xs, const T* ys, int count, int offset, int stride) { - GetterXsYs getter(xs,ys,count,offset,stride); + GetterXY,GetterIdx> getter(GetterIdx(xs,count,offset,stride),GetterIdx(ys,count,offset,stride),count); return PlotScatterEx(label_id, getter); } @@ -1141,7 +1124,7 @@ IMPLOT_INLINE void PlotStairsEx(const char* label_id, const Getter& getter) { template void PlotStairs(const char* label_id, const T* values, int count, double xscale, double x0, int offset, int stride) { - GetterYs getter(values,count,xscale,x0,offset,stride); + GetterXY> getter(GetterLin(xscale,x0),GetterIdx(values,count,offset,stride),count); PlotStairsEx(label_id, getter); } @@ -1158,7 +1141,7 @@ template IMPLOT_API void PlotStairs(const char* label_id, const double* template void PlotStairs(const char* label_id, const T* xs, const T* ys, int count, int offset, int stride) { - GetterXsYs getter(xs,ys,count,offset,stride); + GetterXY,GetterIdx> getter(GetterIdx(xs,count,offset,stride),GetterIdx(ys,count,offset,stride),count); return PlotStairsEx(label_id, getter); } @@ -1220,8 +1203,8 @@ void PlotShaded(const char* label_id, const T* values, int count, double y_ref, fit2 = false; y_ref = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO).Y.Max; } - GetterYs getter1(values,count,xscale,x0,offset,stride); - GetterYRef getter2(y_ref,count,xscale,x0); + GetterXY> getter1(GetterLin(xscale,x0),GetterIdx(values,count,offset,stride),count); + GetterXY getter2(GetterLin(xscale,x0),GetterRef(y_ref),count); PlotShadedEx(label_id, getter1, getter2, fit2); } @@ -1247,8 +1230,8 @@ void PlotShaded(const char* label_id, const T* xs, const T* ys, int count, doubl fit2 = false; y_ref = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO).Y.Max; } - GetterXsYs getter1(xs, ys, count, offset, stride); - GetterXsYRef getter2(xs, y_ref, count, offset, stride); + GetterXY,GetterIdx> getter1(GetterIdx(xs,count,offset,stride),GetterIdx(ys,count,offset,stride),count); + GetterXY,GetterRef> getter2(GetterIdx(xs,count,offset,stride),GetterRef(y_ref),count); PlotShadedEx(label_id, getter1, getter2, fit2); } @@ -1265,8 +1248,8 @@ template IMPLOT_API void PlotShaded(const char* label_id, const double* template void PlotShaded(const char* label_id, const T* xs, const T* ys1, const T* ys2, int count, int offset, int stride) { - GetterXsYs getter1(xs, ys1, count, offset, stride); - GetterXsYs getter2(xs, ys2, count, offset, stride); + GetterXY,GetterIdx> getter1(GetterIdx(xs,count,offset,stride),GetterIdx(ys1,count,offset,stride),count); + GetterXY,GetterIdx> getter2(GetterIdx(xs,count,offset,stride),GetterIdx(ys2,count,offset,stride),count); PlotShadedEx(label_id, getter1, getter2, true); } @@ -1294,15 +1277,16 @@ void PlotShadedG(const char* label_id, ImPlotGetter getter_func1, void* data1, I // TODO: Migrate to RenderPrimitives -template -void PlotBarsEx(const char* label_id, const Getter& getter, double width) { +template +void PlotBarsEx(const char* label_id, const Getter1& getter1, const Getter2 getter2, double width) { if (BeginItem(label_id, ImPlotCol_Fill)) { const double half_width = width / 2; if (FitThisFrame()) { - for (int i = 0; i < getter.Count; ++i) { - ImPlotPoint p = getter(i); - FitPoint(ImPlotPoint(p.x - half_width, p.y)); - FitPoint(ImPlotPoint(p.x + half_width, 0)); + for (int i = 0; i < getter1.Count; ++i) { + ImPlotPoint p1 = getter1(i); + ImPlotPoint p2 = getter2(i); + FitPoint(ImPlotPoint(p1.x - half_width, p1.y)); + FitPoint(ImPlotPoint(p2.x + half_width, p2.y)); } } const ImPlotNextItemData& s = GetItemData(); @@ -1312,12 +1296,13 @@ void PlotBarsEx(const char* label_id, const Getter& getter, double width) { bool rend_line = s.RenderLine; if (s.RenderFill && col_line == col_fill) rend_line = false; - for (int i = 0; i < getter.Count; ++i) { - ImPlotPoint p = getter(i); - if (p.y == 0) + for (int i = 0; i < getter1.Count; ++i) { + ImPlotPoint p1 = getter1(i); + ImPlotPoint p2 = getter2(i); + if (p1.y == p2.y) continue; - ImVec2 a = PlotToPixels(p.x - half_width, p.y,IMPLOT_AUTO,IMPLOT_AUTO); - ImVec2 b = PlotToPixels(p.x + half_width, 0,IMPLOT_AUTO,IMPLOT_AUTO); + ImVec2 a = PlotToPixels(p1.x - half_width, p1.y,IMPLOT_AUTO,IMPLOT_AUTO); + ImVec2 b = PlotToPixels(p2.x + half_width, p2.y,IMPLOT_AUTO,IMPLOT_AUTO); float width_px = ImAbs(a.x-b.x); if (width_px < 1.0f) { a.x += a.x > b.x ? (1-width_px) / 2 : (width_px-1) / 2; @@ -1336,8 +1321,9 @@ void PlotBarsEx(const char* label_id, const Getter& getter, double width) { template void PlotBars(const char* label_id, const T* values, int count, double width, double shift, int offset, int stride) { - GetterBarV getter(values,shift,count,offset,stride); - PlotBarsEx(label_id, getter, width); + GetterXY> getter1(GetterLin(1.0,shift),GetterIdx(values,count,offset,stride),count); + GetterXY getter2(GetterLin(1.0,shift),GetterRef(0),count); + PlotBarsEx(label_id, getter1, getter2, width); } template IMPLOT_API void PlotBars(const char* label_id, const ImS8* values, int count, double width, double shift, int offset, int stride); @@ -1353,8 +1339,9 @@ template IMPLOT_API void PlotBars(const char* label_id, const double* va template void PlotBars(const char* label_id, const T* xs, const T* ys, int count, double width, int offset, int stride) { - GetterXsYs getter(xs,ys,count,offset,stride); - PlotBarsEx(label_id, getter, width); + GetterXY,GetterIdx> getter1(GetterIdx(xs,count,offset,stride),GetterIdx(ys,count,offset,stride),count); + GetterXY,GetterRef> getter2(GetterIdx(xs,count,offset,stride),GetterRef(0),count); + PlotBarsEx(label_id, getter1, getter2, width); } template IMPLOT_API void PlotBars(const char* label_id, const ImS8* xs, const ImS8* ys, int count, double width, int offset, int stride); @@ -1370,8 +1357,9 @@ template IMPLOT_API void PlotBars(const char* label_id, const double* xs // custom void PlotBarsG(const char* label_id, ImPlotGetter getter_func, void* data, int count, double width) { - GetterFuncPtr getter(getter_func, data, count); - PlotBarsEx(label_id, getter, width); + GetterFuncPtr getter1(getter_func, data, count); + GetterOverrideY getter2(getter1,0); + PlotBarsEx(label_id, getter1, getter2, width); } //----------------------------------------------------------------------------- @@ -1380,15 +1368,16 @@ void PlotBarsG(const char* label_id, ImPlotGetter getter_func, void* data, int c // TODO: Migrate to RenderPrimitives -template -void PlotBarsHEx(const char* label_id, const Getter& getter, THeight height) { +template +void PlotBarsHEx(const char* label_id, const Getter1& getter1, const Getter2& getter2, double height) { if (BeginItem(label_id, ImPlotCol_Fill)) { - const THeight half_height = height / 2; + const double half_height = height / 2; if (FitThisFrame()) { - for (int i = 0; i < getter.Count; ++i) { - ImPlotPoint p = getter(i); - FitPoint(ImPlotPoint(0, p.y - half_height)); - FitPoint(ImPlotPoint(p.x, p.y + half_height)); + for (int i = 0; i < getter1.Count; ++i) { + ImPlotPoint p1 = getter1(i); + ImPlotPoint p2 = getter2(i); + FitPoint(ImPlotPoint(p1.x, p1.y - half_height)); + FitPoint(ImPlotPoint(p2.x, p2.y + half_height)); } } const ImPlotNextItemData& s = GetItemData(); @@ -1398,12 +1387,13 @@ void PlotBarsHEx(const char* label_id, const Getter& getter, THeight height) { bool rend_line = s.RenderLine; if (s.RenderFill && col_line == col_fill) rend_line = false; - for (int i = 0; i < getter.Count; ++i) { - ImPlotPoint p = getter(i); - if (p.x == 0) + for (int i = 0; i < getter1.Count; ++i) { + ImPlotPoint p1 = getter1(i); + ImPlotPoint p2 = getter2(i); + if (p1.x == p2.x) continue; - ImVec2 a = PlotToPixels(0, p.y - half_height,IMPLOT_AUTO,IMPLOT_AUTO); - ImVec2 b = PlotToPixels(p.x, p.y + half_height,IMPLOT_AUTO,IMPLOT_AUTO); + ImVec2 a = PlotToPixels(p1.x, p1.y - half_height,IMPLOT_AUTO,IMPLOT_AUTO); + ImVec2 b = PlotToPixels(p2.x, p2.y + half_height,IMPLOT_AUTO,IMPLOT_AUTO); if (s.RenderFill) DrawList.AddRectFilled(a, b, col_fill); if (rend_line) @@ -1415,8 +1405,9 @@ void PlotBarsHEx(const char* label_id, const Getter& getter, THeight height) { template void PlotBarsH(const char* label_id, const T* values, int count, double height, double shift, int offset, int stride) { - GetterBarH getter(values,shift,count,offset,stride); - PlotBarsHEx(label_id, getter, height); + GetterXY,GetterLin> getter1(GetterIdx(values,count,offset,stride),GetterLin(1.0,shift),count); + GetterXY getter2(GetterRef(0),GetterLin(1.0,shift),count); + PlotBarsHEx(label_id, getter1, getter2, height); } template IMPLOT_API void PlotBarsH(const char* label_id, const ImS8* values, int count, double height, double shift, int offset, int stride); @@ -1432,8 +1423,9 @@ template IMPLOT_API void PlotBarsH(const char* label_id, const double* v template void PlotBarsH(const char* label_id, const T* xs, const T* ys, int count, double height, int offset, int stride) { - GetterXsYs getter(xs,ys,count,offset,stride); - PlotBarsHEx(label_id, getter, height); + GetterXY,GetterIdx> getter1(GetterIdx(xs,count,offset,stride),GetterIdx(ys,count,offset,stride),count); + GetterXY> getter2(GetterRef(0),GetterIdx(ys,count,offset,stride),count); + PlotBarsHEx(label_id, getter1, getter2, height); } template IMPLOT_API void PlotBarsH(const char* label_id, const ImS8* xs, const ImS8* ys, int count, double height, int offset, int stride); @@ -1449,10 +1441,121 @@ template IMPLOT_API void PlotBarsH(const char* label_id, const double* x // custom void PlotBarsHG(const char* label_id, ImPlotGetter getter_func, void* data, int count, double height) { - GetterFuncPtr getter(getter_func, data, count); - PlotBarsHEx(label_id, getter, height); + GetterFuncPtr getter1(getter_func, data, count); + GetterOverrideX getter2(getter1,0); + PlotBarsHEx(label_id, getter1, getter2, height); } +//----------------------------------------------------------------------------- +// PLOT BAR GROUPS +//----------------------------------------------------------------------------- + +template +void PlotBarGroups(const char* const label_ids[], const T* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags) { + if (ImHasFlag(flags, ImPlotBarGroupsFlags_Stacked)) { + SetupLock(); + GImPlot->TempDouble1.resize(4*groups); + double* temp = GImPlot->TempDouble1.Data; + double* neg = &temp[0]; + double* pos = &temp[groups]; + double* curr_min = &temp[groups*2]; + double* curr_max = &temp[groups*3]; + for (int g = 0; g < groups*2; ++g) + temp[g] = 0; + for (int i = 0; i < items; ++i) { + if (!IsItemHidden(label_ids[i])) { + for (int g = 0; g < groups; ++g) { + double v = (double)values[i*groups+g]; + if (v > 0) { + curr_min[g] = pos[g]; + curr_max[g] = curr_min[g] + v; + pos[g] += v; + } + else { + curr_max[g] = neg[g]; + curr_min[g] = curr_max[g] + v; + neg[g] += v; + } + } + } + GetterXY> getter1(GetterLin(1.0,shift),GetterIdx(curr_min,groups),groups); + GetterXY> getter2(GetterLin(1.0,shift),GetterIdx(curr_max,groups),groups); + PlotBarsEx(label_ids[i],getter1,getter2,width); + } + } + else { + const double subwidth = width / items; + for (int i = 0; i < items; ++i) { + const double subshift = (i+0.5)*subwidth - width/2; + PlotBars(label_ids[i],&values[i*groups],groups,subwidth,subshift+shift); + } + } +} + +template IMPLOT_API void PlotBarGroups(const char* const label_ids[], const ImS8* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroups(const char* const label_ids[], const ImU8* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroups(const char* const label_ids[], const ImS16* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroups(const char* const label_ids[], const ImU16* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroups(const char* const label_ids[], const ImS32* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroups(const char* const label_ids[], const ImU32* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroups(const char* const label_ids[], const ImS64* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroups(const char* const label_ids[], const ImU64* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroups(const char* const label_ids[], const float* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroups(const char* const label_ids[], const double* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); + +template +void PlotBarGroupsH(const char* const label_ids[], const T* values, int items, int groups, double height, double shift, ImPlotBarGroupsFlags flags) { + if (ImHasFlag(flags, ImPlotBarGroupsFlags_Stacked)) { + SetupLock(); + GImPlot->TempDouble1.resize(4*groups); + double* temp = GImPlot->TempDouble1.Data; + double* neg = &temp[0]; + double* pos = &temp[groups]; + double* curr_min = &temp[groups*2]; + double* curr_max = &temp[groups*3]; + for (int g = 0; g < groups*2; ++g) + temp[g] = 0; + for (int i = 0; i < items; ++i) { + if (!IsItemHidden(label_ids[i])) { + for (int g = 0; g < groups; ++g) { + double v = (double)values[i*groups+g]; + if (v > 0) { + curr_min[g] = pos[g]; + curr_max[g] = curr_min[g] + v; + pos[g] += v; + } + else { + curr_max[g] = neg[g]; + curr_min[g] = curr_max[g] + v; + neg[g] += v; + } + } + } + GetterXY,GetterLin> getter1(GetterIdx(curr_min,groups),GetterLin(1.0,shift),groups); + GetterXY,GetterLin> getter2(GetterIdx(curr_max,groups),GetterLin(1.0,shift),groups); + PlotBarsHEx(label_ids[i],getter1,getter2,height); + } + } + else { + const double subheight = height / items; + for (int i = 0; i < items; ++i) { + const double subshift = (i+0.5)*subheight - height/2; + PlotBarsH(label_ids[i],&values[i*groups],groups,subheight,subshift+shift); + } + } +} + +template IMPLOT_API void PlotBarGroupsH(const char* const label_ids[], const ImS8* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroupsH(const char* const label_ids[], const ImU8* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroupsH(const char* const label_ids[], const ImS16* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroupsH(const char* const label_ids[], const ImU16* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroupsH(const char* const label_ids[], const ImS32* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroupsH(const char* const label_ids[], const ImU32* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroupsH(const char* const label_ids[], const ImS64* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroupsH(const char* const label_ids[], const ImU64* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroupsH(const char* const label_ids[], const float* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroupsH(const char* const label_ids[], const double* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); + //----------------------------------------------------------------------------- // PLOT ERROR BARS //----------------------------------------------------------------------------- @@ -1632,8 +1735,8 @@ IMPLOT_INLINE void PlotStemsEx(const char* label_id, const GetterM& get_mark, co template void PlotStems(const char* label_id, const T* values, int count, double y_ref, double xscale, double x0, int offset, int stride) { - GetterYs get_mark(values,count,xscale,x0,offset,stride); - GetterYRef get_base(y_ref,count,xscale,x0); + GetterXY> get_mark(GetterLin(xscale,x0),GetterIdx(values,count,offset,stride),count); + GetterXY get_base(GetterLin(xscale,x0),GetterRef(y_ref),count); PlotStemsEx(label_id, get_mark, get_base); } @@ -1650,8 +1753,8 @@ template IMPLOT_API void PlotStems(const char* label_id, const double* v template void PlotStems(const char* label_id, const T* xs, const T* ys, int count, double y_ref, int offset, int stride) { - GetterXsYs get_mark(xs,ys,count,offset,stride); - GetterXsYRef get_base(xs,y_ref,count,offset,stride); + GetterXY,GetterIdx> get_mark(GetterIdx(xs,count,offset,stride),GetterIdx(ys,count,offset,stride),count); + GetterXY,GetterRef> get_base(GetterIdx(xs,count,offset,stride),GetterRef(y_ref),count); PlotStemsEx(label_id, get_mark, get_base); } @@ -1674,8 +1777,8 @@ template void PlotVLines(const char* label_id, const T* xs, int count, int offset, int stride) { if (BeginItem(label_id, ImPlotCol_Line)) { const ImPlotRect lims = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO); - GetterXsYRef get_min(xs,lims.Y.Min,count,offset,stride); - GetterXsYRef get_max(xs,lims.Y.Max,count,offset,stride); + GetterXY,GetterRef> get_min(GetterIdx(xs,count,offset,stride),GetterRef(lims.Y.Min),count); + GetterXY,GetterRef> get_max(GetterIdx(xs,count,offset,stride),GetterRef(lims.Y.Max),count); if (FitThisFrame()) { for (int i = 0; i < get_min.Count; ++i) FitPointX(get_min(i).x); @@ -1712,8 +1815,8 @@ template void PlotHLines(const char* label_id, const T* ys, int count, int offset, int stride) { if (BeginItem(label_id, ImPlotCol_Line)) { const ImPlotRect lims = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO); - GetterXRefYs get_min(lims.X.Min,ys,count,offset,stride); - GetterXRefYs get_max(lims.X.Max,ys,count,offset,stride); + GetterXY> get_min(GetterRef(lims.X.Min),GetterIdx(ys,count,offset,stride),count); + GetterXY> get_max(GetterRef(lims.X.Max),GetterIdx(ys,count,offset,stride),count); if (FitThisFrame()) { for (int i = 0; i < get_min.Count; ++i) FitPointY(get_min(i).y); @@ -2241,7 +2344,7 @@ IMPLOT_INLINE void PlotDigitalEx(const char* label_id, Getter getter) { template void PlotDigital(const char* label_id, const T* xs, const T* ys, int count, int offset, int stride) { - GetterXsYs getter(xs,ys,count,offset,stride); + GetterXY,GetterIdx> getter(GetterIdx(xs,count,offset,stride),GetterIdx(ys,count,offset,stride),count); return PlotDigitalEx(label_id, getter); }