Skip to content

Commit 22ef01e

Browse files
authored
Small Pie Chart enhancements (epezent#412)
* Added ImPlotPieChartFlags_IgnoreHidden flag. Added PlotPieChart overload that accepts an ImPlotFormatter. * Fixed a potential division by zero in PlotPieChart. * Removed PlotPieChart overload code duplication
1 parent 538a306 commit 22ef01e

File tree

3 files changed

+104
-40
lines changed

3 files changed

+104
-40
lines changed

implot.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,8 +286,9 @@ enum ImPlotInfLinesFlags_ {
286286

287287
// Flags for PlotPieChart
288288
enum ImPlotPieChartFlags_ {
289-
ImPlotPieChartFlags_None = 0, // default
290-
ImPlotPieChartFlags_Normalize = 1 << 10 // force normalization of pie chart values (i.e. always make a full circle if sum < 0)
289+
ImPlotPieChartFlags_None = 0, // default
290+
ImPlotPieChartFlags_Normalize = 1 << 10, // force normalization of pie chart values (i.e. always make a full circle if sum < 0)
291+
ImPlotPieChartFlags_IgnoreHidden = 1 << 11 // ignore hidden slices when drawing the pie chart (as if they were not there)
291292
};
292293

293294
// Flags for PlotHeatmap
@@ -892,6 +893,7 @@ IMPLOT_TMP void PlotStems(const char* label_id, const T* xs, const T* ys, int co
892893
IMPLOT_TMP void PlotInfLines(const char* label_id, const T* values, int count, ImPlotInfLinesFlags flags=0, int offset=0, int stride=sizeof(T));
893894

894895
// Plots a pie chart. Center and radius are in plot units. #label_fmt can be set to nullptr for no labels.
896+
IMPLOT_TMP void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, ImPlotFormatter fmt, void* fmt_data=nullptr, double angle0=90, ImPlotPieChartFlags flags=0);
895897
IMPLOT_TMP void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, const char* label_fmt="%.1f", double angle0=90, ImPlotPieChartFlags flags=0);
896898

897899
// Plots a 2D heatmap chart. Values are expected to be in row-major order by default. 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 nullptr for no labels.

implot_demo.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -610,10 +610,8 @@ void Demo_PieCharts() {
610610
static ImPlotPieChartFlags flags = 0;
611611
ImGui::SetNextItemWidth(250);
612612
ImGui::DragFloat4("Values", data1, 0.01f, 0, 1);
613-
if ((data1[0] + data1[1] + data1[2] + data1[3]) < 1) {
614-
ImGui::SameLine();
615-
CHECKBOX_FLAG(flags,ImPlotPieChartFlags_Normalize);
616-
}
613+
CHECKBOX_FLAG(flags, ImPlotPieChartFlags_Normalize);
614+
CHECKBOX_FLAG(flags, ImPlotPieChartFlags_IgnoreHidden);
617615

618616
if (ImPlot::BeginPlot("##Pie1", ImVec2(250,250), ImPlotFlags_Equal | ImPlotFlags_NoMouseText)) {
619617
ImPlot::SetupAxes(nullptr, nullptr, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations);

implot_items.cpp

Lines changed: 98 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2216,57 +2216,121 @@ IMPLOT_INLINE void RenderPieSlice(ImDrawList& draw_list, const ImPlotPoint& cent
22162216
}
22172217

22182218
template <typename T>
2219-
void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, const char* fmt, double angle0, ImPlotPieChartFlags flags) {
2220-
IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != nullptr, "PlotPieChart() needs to be called between BeginPlot() and EndPlot()!");
2221-
ImDrawList & draw_list = *GetPlotDrawList();
2219+
double PieChartSum(const T* values, int count, bool ignore_hidden) {
22222220
double sum = 0;
2223-
for (int i = 0; i < count; ++i)
2224-
sum += (double)values[i];
2225-
const bool normalize = ImHasFlag(flags,ImPlotPieChartFlags_Normalize) || sum > 1.0;
2226-
ImPlotPoint center(x,y);
2227-
PushPlotClipRect();
2221+
if (ignore_hidden) {
2222+
ImPlotContext& gp = *GImPlot;
2223+
ImPlotItemGroup& Items = *gp.CurrentItems;
2224+
for (int i = 0; i < count; ++i) {
2225+
if (i >= Items.GetItemCount())
2226+
break;
2227+
2228+
ImPlotItem* item = Items.GetItemByIndex(i);
2229+
IM_ASSERT(item != nullptr);
2230+
if (item->Show) {
2231+
sum += (double)values[i];
2232+
}
2233+
}
2234+
}
2235+
else {
2236+
for (int i = 0; i < count; ++i) {
2237+
sum += (double)values[i];
2238+
}
2239+
}
2240+
return sum;
2241+
}
2242+
2243+
template <typename T>
2244+
void PlotPieChartEx(const char* const label_ids[], const T* values, int count, ImPlotPoint center, double radius, double angle0, ImPlotPieChartFlags flags) {
2245+
ImDrawList& draw_list = *GetPlotDrawList();
2246+
2247+
const bool ignore_hidden = ImHasFlag(flags, ImPlotPieChartFlags_IgnoreHidden);
2248+
const double sum = PieChartSum(values, count, ignore_hidden);
2249+
const bool normalize = ImHasFlag(flags, ImPlotPieChartFlags_Normalize) || sum > 1.0;
2250+
22282251
double a0 = angle0 * 2 * IM_PI / 360.0;
22292252
double a1 = angle0 * 2 * IM_PI / 360.0;
2230-
ImPlotPoint Pmin = ImPlotPoint(x-radius,y-radius);
2231-
ImPlotPoint Pmax = ImPlotPoint(x+radius,y+radius);
2253+
ImPlotPoint Pmin = ImPlotPoint(center.x - radius, center.y - radius);
2254+
ImPlotPoint Pmax = ImPlotPoint(center.x + radius, center.y + radius);
22322255
for (int i = 0; i < count; ++i) {
2233-
double percent = normalize ? (double)values[i] / sum : (double)values[i];
2234-
a1 = a0 + 2 * IM_PI * percent;
2235-
if (BeginItemEx(label_ids[i], FitterRect(Pmin,Pmax))) {
2236-
ImU32 col = GetCurrentItem()->Color;
2237-
if (percent < 0.5) {
2238-
RenderPieSlice(draw_list, center, radius, a0, a1, col);
2239-
}
2240-
else {
2241-
RenderPieSlice(draw_list, center, radius, a0, a0 + (a1 - a0) * 0.5, col);
2242-
RenderPieSlice(draw_list, center, radius, a0 + (a1 - a0) * 0.5, a1, col);
2256+
ImPlotItem* item = GetItem(label_ids[i]);
2257+
2258+
const double percent = normalize ? (double)values[i] / sum : (double)values[i];
2259+
const bool skip = sum <= 0.0 || (ignore_hidden && item != nullptr && !item->Show);
2260+
if (!skip)
2261+
a1 = a0 + 2 * IM_PI * percent;
2262+
2263+
if (BeginItemEx(label_ids[i], FitterRect(Pmin, Pmax))) {
2264+
if (sum > 0.0) {
2265+
ImU32 col = GetCurrentItem()->Color;
2266+
if (percent < 0.5) {
2267+
RenderPieSlice(draw_list, center, radius, a0, a1, col);
2268+
}
2269+
else {
2270+
RenderPieSlice(draw_list, center, radius, a0, a0 + (a1 - a0) * 0.5, col);
2271+
RenderPieSlice(draw_list, center, radius, a0 + (a1 - a0) * 0.5, a1, col);
2272+
}
22432273
}
22442274
EndItem();
22452275
}
2246-
a0 = a1;
2276+
if (!skip)
2277+
a0 = a1;
22472278
}
2279+
}
2280+
2281+
int PieChartFormatter(double value, char* buff, int size, void* data) {
2282+
const char* fmt = (const char*)data;
2283+
return snprintf(buff, size, fmt, value);
2284+
};
2285+
2286+
template <typename T>
2287+
void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, const char* fmt, double angle0, ImPlotPieChartFlags flags) {
2288+
PlotPieChart<T>(label_ids, values, count, x, y, radius, PieChartFormatter, (void*)fmt, angle0, flags);
2289+
}
2290+
#define INSTANTIATE_MACRO(T) template IMPLOT_API void PlotPieChart<T>(const char* const label_ids[], const T* values, int count, double x, double y, double radius, const char* fmt, double angle0, ImPlotPieChartFlags flags);
2291+
CALL_INSTANTIATE_FOR_NUMERIC_TYPES()
2292+
#undef INSTANTIATE_MACRO
2293+
2294+
template <typename T>
2295+
void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, ImPlotFormatter fmt, void* fmt_data, double angle0, ImPlotPieChartFlags flags) {
2296+
IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != nullptr, "PlotPieChart() needs to be called between BeginPlot() and EndPlot()!");
2297+
ImDrawList& draw_list = *GetPlotDrawList();
2298+
2299+
const bool ignore_hidden = ImHasFlag(flags, ImPlotPieChartFlags_IgnoreHidden);
2300+
const double sum = PieChartSum(values, count, ignore_hidden);
2301+
const bool normalize = ImHasFlag(flags, ImPlotPieChartFlags_Normalize) || sum > 1.0;
2302+
ImPlotPoint center(x, y);
2303+
2304+
PushPlotClipRect();
2305+
PlotPieChartEx(label_ids, values, count, center, radius, angle0, flags);
22482306
if (fmt != nullptr) {
2249-
a0 = angle0 * 2 * IM_PI / 360.0;
2250-
a1 = angle0 * 2 * IM_PI / 360.0;
2307+
double a0 = angle0 * 2 * IM_PI / 360.0;
2308+
double a1 = angle0 * 2 * IM_PI / 360.0;
22512309
char buffer[32];
22522310
for (int i = 0; i < count; ++i) {
22532311
ImPlotItem* item = GetItem(label_ids[i]);
2254-
double percent = normalize ? (double)values[i] / sum : (double)values[i];
2255-
a1 = a0 + 2 * IM_PI * percent;
2256-
if (item->Show) {
2257-
ImFormatString(buffer, 32, fmt, (double)values[i]);
2258-
ImVec2 size = ImGui::CalcTextSize(buffer);
2259-
double angle = a0 + (a1 - a0) * 0.5;
2260-
ImVec2 pos = PlotToPixels(center.x + 0.5 * radius * cos(angle), center.y + 0.5 * radius * sin(angle),IMPLOT_AUTO,IMPLOT_AUTO);
2261-
ImU32 col = CalcTextColor(ImGui::ColorConvertU32ToFloat4(item->Color));
2262-
draw_list.AddText(pos - size * 0.5f, col, buffer);
2312+
IM_ASSERT(item != nullptr);
2313+
2314+
const double percent = normalize ? (double)values[i] / sum : (double)values[i];
2315+
const bool skip = ignore_hidden && item != nullptr && !item->Show;
2316+
2317+
if (!skip) {
2318+
a1 = a0 + 2 * IM_PI * percent;
2319+
if (item->Show) {
2320+
fmt((double)values[i], buffer, 32, fmt_data);
2321+
ImVec2 size = ImGui::CalcTextSize(buffer);
2322+
double angle = a0 + (a1 - a0) * 0.5;
2323+
ImVec2 pos = PlotToPixels(center.x + 0.5 * radius * cos(angle), center.y + 0.5 * radius * sin(angle), IMPLOT_AUTO, IMPLOT_AUTO);
2324+
ImU32 col = CalcTextColor(ImGui::ColorConvertU32ToFloat4(item->Color));
2325+
draw_list.AddText(pos - size * 0.5f, col, buffer);
2326+
}
2327+
a0 = a1;
22632328
}
2264-
a0 = a1;
22652329
}
22662330
}
22672331
PopPlotClipRect();
22682332
}
2269-
#define INSTANTIATE_MACRO(T) template IMPLOT_API void PlotPieChart<T>(const char* const label_ids[], const T* values, int count, double x, double y, double radius, const char* fmt, double angle0, ImPlotPieChartFlags flags);
2333+
#define INSTANTIATE_MACRO(T) template IMPLOT_API void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, ImPlotFormatter fmt, void* fmt_data, double angle0, ImPlotPieChartFlags flags);
22702334
CALL_INSTANTIATE_FOR_NUMERIC_TYPES()
22712335
#undef INSTANTIATE_MACRO
22722336

0 commit comments

Comments
 (0)