1
0
Fork 0
mirror of https://github.com/gwm17/implot.git synced 2024-10-09 23:57:26 -04:00

overhaul log plots - improve zoom, labels, and fit

This commit is contained in:
epezent 2020-08-22 22:55:37 -05:00
parent 63e2ce3ddd
commit 9b8270d939
4 changed files with 179 additions and 107 deletions

View File

@ -261,15 +261,18 @@ ImPlotState* GetCurrentPlot() {
void FitPoint(const ImPlotPoint& p) { void FitPoint(const ImPlotPoint& p) {
ImPlotContext& gp = *GImPlot; ImPlotContext& gp = *GImPlot;
ImPlotRange* extents_x = &gp.ExtentsX; const int y_axis = gp.CurrentPlot->CurrentYAxis;
ImPlotRange* extents_y = &gp.ExtentsY[gp.CurrentPlot->CurrentYAxis]; ImPlotRange& ex_x = gp.ExtentsX;
if (!NanOrInf(p.x)) { ImPlotRange& ex_y = gp.ExtentsY[y_axis];
extents_x->Min = p.x < extents_x->Min ? p.x : extents_x->Min; const bool log_x = ImHasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_LogScale);
extents_x->Max = p.x > extents_x->Max ? p.x : extents_x->Max; const bool log_y = ImHasFlag(gp.CurrentPlot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale);
if (!NanOrInf(p.x) && !(log_x && p.x <= 0)) {
ex_x.Min = p.x < ex_x.Min ? p.x : ex_x.Min;
ex_x.Max = p.x > ex_x.Max ? p.x : ex_x.Max;
} }
if (!NanOrInf(p.y)) { if (!NanOrInf(p.y) && !(log_y && p.y <= 0)) {
extents_y->Min = p.y < extents_y->Min ? p.y : extents_y->Min; ex_y.Min = p.y < ex_y.Min ? p.y : ex_y.Min;
extents_y->Max = p.y > extents_y->Max ? p.y : extents_y->Max; ex_y.Max = p.y > ex_y.Max ? p.y : ex_y.Max;
} }
} }
@ -387,6 +390,17 @@ ImPlotItem* GetItem(const char* plot_title, const char* item_label_id) {
return NULL; return NULL;
} }
void BustItemColorCache() {
ImPlotContext& gp = *GImPlot;
for (int p = 0; p < gp.Plots.GetSize(); ++p) {
ImPlotState& plot = *gp.Plots.GetByIndex(p);
for (int i = 0; i < plot.Items.GetSize(); ++i) {
ImPlotItem& item = *plot.Items.GetByIndex(i);
item.Color = IMPLOT_COL_AUTO;
}
}
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Legend Utils // Legend Utils
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -407,26 +421,7 @@ const char* GetLegendLabel(int i) {
// Tick Utils // Tick Utils
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void AddDefaultTicks(const ImPlotRange& range, int nMajor, int nMinor, bool logscale, ImVector<ImPlotTick> &out) { void AddTicksDefault(const ImPlotRange& range, int nMajor, int nMinor, ImVector<ImPlotTick> &out) {
if (logscale) {
if (range.Min <= 0 || range.Max <= 0)
return;
int exp_min = (int)ImLog10(range.Min);
int exp_max = (int)(ceil(ImLog10(range.Max)));
for (int e = exp_min - 1; e < exp_max + 1; ++e) {
double major1 = ImPow(10, (double)(e));
double major2 = ImPow(10, (double)(e + 1));
double interval = (major2 - major1) / 9;
if (major1 >= (range.Min - DBL_EPSILON) && major1 <= (range.Max + DBL_EPSILON))
out.push_back(ImPlotTick(major1, true, true));
for (int i = 1; i < 9; ++i) {
double minor = major1 + i * interval;
if (minor >= (range.Min - DBL_EPSILON) && minor <= (range.Max + DBL_EPSILON))
out.push_back(ImPlotTick(minor, false, false));
}
}
}
else {
const double nice_range = NiceNum(range.Size() * 0.99, false); const double nice_range = NiceNum(range.Size() * 0.99, false);
const double interval = NiceNum(nice_range / (nMajor - 1), true); const double interval = NiceNum(nice_range / (nMajor - 1), true);
const double graphmin = floor(range.Min / interval) * interval; const double graphmin = floor(range.Min / interval) * interval;
@ -440,6 +435,36 @@ void AddDefaultTicks(const ImPlotRange& range, int nMajor, int nMinor, bool logs
out.push_back(ImPlotTick(minor, false, true)); out.push_back(ImPlotTick(minor, false, true));
} }
} }
}
void AddTicksLogarithmic(const ImPlotRange& range, int nMajor, ImVector<ImPlotTick>& out) {
if (range.Min <= 0 || range.Max <= 0)
return;
double log_min = ImLog10(range.Min);
double log_max = ImLog10(range.Max);
int exp_step = ImMax(1,(int)(log_max - log_min) / nMajor);
int exp_min = (int)log_min;
int exp_max = (int)log_max;
if (exp_step != 1) {
while(exp_step % 3 != 0) exp_step++; // make step size multiple of three
while(exp_min % exp_step != 0) exp_min--; // decrease exp_min until exp_min + N * exp_step will be 0
}
for (int e = exp_min - exp_step; e < (exp_max + exp_step); e += exp_step) {
double major1 = ImPow(10, (double)(e));
double major2 = ImPow(10, (double)(e + 1));
double interval = (major2 - major1) / 9;
if (major1 >= (range.Min - DBL_EPSILON) && major1 <= (range.Max + DBL_EPSILON))
out.push_back(ImPlotTick(major1, true, true));
for (int j = 0; j < exp_step; ++j) {
major1 = ImPow(10, (double)(e+j));
major2 = ImPow(10, (double)(e+j+1));
interval = (major2 - major1) / 9;
for (int i = 1; i < (9 + (int)(j < (exp_step - 1))); ++i) {
double minor = major1 + i * interval;
if (minor >= (range.Min - DBL_EPSILON) && minor <= (range.Max + DBL_EPSILON))
out.push_back(ImPlotTick(minor, false, false));
}
}
} }
} }
@ -463,7 +488,7 @@ void LabelTicks(ImVector<ImPlotTick> &ticks, bool scientific, ImGuiTextBuffer& b
if (tk->ShowLabel && !tk->Labeled) { if (tk->ShowLabel && !tk->Labeled) {
tk->BufferOffset = buffer.size(); tk->BufferOffset = buffer.size();
if (scientific) if (scientific)
sprintf(temp, "%.0e", tk->PlotPos); sprintf(temp, "%.0E", tk->PlotPos);
else else
sprintf(temp, "%.10g", tk->PlotPos); sprintf(temp, "%.10g", tk->PlotPos);
buffer.append(temp, temp + strlen(temp) + 1); buffer.append(temp, temp + strlen(temp) + 1);
@ -663,40 +688,40 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
// canvas bb // canvas bb
gp.BB_Canvas = ImRect(gp.BB_Frame.Min + gp.Style.PlotPadding, gp.BB_Frame.Max - gp.Style.PlotPadding); gp.BB_Canvas = ImRect(gp.BB_Frame.Min + gp.Style.PlotPadding, gp.BB_Frame.Max - gp.Style.PlotPadding);
// adaptive divisions
int x_divisions = ImMax(2, (int)IM_ROUND(0.003 * gp.BB_Canvas.GetWidth()));
int y_divisions[IMPLOT_Y_AXES];
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
y_divisions[i] = ImMax(2, (int)IM_ROUND(0.003 * gp.BB_Canvas.GetHeight()));
}
gp.RenderX = (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_GridLines) || gp.RenderX = (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_GridLines) ||
ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickMarks) || ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickMarks) ||
ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickLabels)) && x_divisions > 1; ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickLabels));
for (int i = 0; i < IMPLOT_Y_AXES; i++) { for (int i = 0; i < IMPLOT_Y_AXES; i++) {
gp.RenderY[i] = gp.RenderY[i] =
gp.Y[i].Present && gp.Y[i].Present &&
(ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_GridLines) || (ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_GridLines) ||
ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickMarks) || ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickMarks) ||
ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels)) && y_divisions[i] > 1; ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels));
} }
// get ticks // get ticks
if (gp.RenderX && gp.NextPlotData.ShowDefaultTicksX) if (gp.RenderX && gp.NextPlotData.ShowDefaultTicksX) {
AddDefaultTicks(plot.XAxis.Range, x_divisions, IMPLOT_SUB_DIV, ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale), gp.XTicks); if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale))
AddTicksLogarithmic(plot.XAxis.Range, (int)(gp.BB_Canvas.GetWidth() * 0.01f), gp.XTicks);
else
AddTicksDefault(plot.XAxis.Range, ImMax(2, (int)IM_ROUND(0.003 * gp.BB_Canvas.GetWidth())), IMPLOT_SUB_DIV, gp.XTicks);
}
for (int i = 0; i < IMPLOT_Y_AXES; i++) { for (int i = 0; i < IMPLOT_Y_AXES; i++) {
if (gp.RenderY[i] && gp.NextPlotData.ShowDefaultTicksY[i]) { if (gp.RenderY[i] && gp.NextPlotData.ShowDefaultTicksY[i]) {
AddDefaultTicks(plot.YAxis[i].Range, y_divisions[i], IMPLOT_SUB_DIV, ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LogScale), gp.YTicks[i]); if (ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LogScale))
AddTicksLogarithmic(plot.YAxis[i].Range, (int)(gp.BB_Canvas.GetHeight() * 0.02f) ,gp.YTicks[i]);
else
AddTicksDefault(plot.YAxis[i].Range, ImMax(2, (int)IM_ROUND(0.003 * gp.BB_Canvas.GetHeight())), IMPLOT_SUB_DIV, gp.YTicks[i]);
} }
} }
// label ticks // label ticks
if (gp.X.HasLabels) if (gp.X.HasLabels)
LabelTicks(gp.XTicks, ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_Scientific), gp.XTickLabels); LabelTicks(gp.XTicks, ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_Scientific) || ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale), gp.XTickLabels);
float max_label_widths[IMPLOT_Y_AXES]; float max_label_widths[IMPLOT_Y_AXES];
for (int i = 0; i < IMPLOT_Y_AXES; i++) { for (int i = 0; i < IMPLOT_Y_AXES; i++) {
if (gp.Y[i].Present && gp.Y[i].HasLabels) { if (gp.Y[i].Present && gp.Y[i].HasLabels) {
LabelTicks(gp.YTicks[i], ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_Scientific), gp.YTickLabels[i]); LabelTicks(gp.YTicks[i], ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_Scientific) || ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LogScale), gp.YTickLabels[i]);
max_label_widths[i] = MaxTickLabelWidth(gp.YTicks[i]); max_label_widths[i] = MaxTickLabelWidth(gp.YTicks[i]);
} }
else { else {
@ -1004,7 +1029,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
// set mouse position // set mouse position
for (int i = 0; i < IMPLOT_Y_AXES; i++) { for (int i = 0; i < IMPLOT_Y_AXES; i++) {
gp.LastMousePos[i] = PixelsToPlot(IO.MousePos, i); gp.MousePos[i] = PixelsToPlot(IO.MousePos, i);
} }
// RENDER ----------------------------------------------------------------- // RENDER -----------------------------------------------------------------
@ -1033,17 +1058,31 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
// render grid // render grid
if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_GridLines)) { if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_GridLines)) {
float density = gp.XTicks.Size / gp.BB_Plot.GetWidth();
ImVec4 col_min = ImGui::ColorConvertU32ToFloat4(gp.Col_X.Minor);
col_min.w *= ImClamp(ImRemap(density, 0.1f, 0.2f, 1.0f, 0.0f), 0.0f, 1.0f);
ImU32 col_min32 = ImGui::ColorConvertFloat4ToU32(col_min);
for (int t = 0; t < gp.XTicks.Size; t++) { for (int t = 0; t < gp.XTicks.Size; t++) {
ImPlotTick *xt = &gp.XTicks[t]; ImPlotTick& xt = gp.XTicks[t];
DrawList.AddLine(ImVec2(xt->PixelPos, gp.BB_Plot.Min.y), ImVec2(xt->PixelPos, gp.BB_Plot.Max.y), xt->Major ? gp.Col_X.Major : gp.Col_X.Minor, 1); if (xt.Major)
DrawList.AddLine(ImVec2(xt.PixelPos, gp.BB_Plot.Min.y), ImVec2(xt.PixelPos, gp.BB_Plot.Max.y), gp.Col_X.Major, 1);
else if (density < 0.2f)
DrawList.AddLine(ImVec2(xt.PixelPos, gp.BB_Plot.Min.y), ImVec2(xt.PixelPos, gp.BB_Plot.Max.y), col_min32, 1);
} }
} }
for (int i = 0; i < IMPLOT_Y_AXES; i++) { for (int i = 0; i < IMPLOT_Y_AXES; i++) {
if (gp.Y[i].Present && ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_GridLines)) { if (gp.Y[i].Present && ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_GridLines)) {
float density = gp.YTicks[i].Size / gp.BB_Plot.GetHeight();
ImVec4 col_min = ImGui::ColorConvertU32ToFloat4(gp.Col_Y[i].Minor);
col_min.w *= ImClamp(ImRemap(density, 0.1f, 0.2f, 1.0f, 0.0f), 0.0f, 1.0f);
ImU32 col_min32 = ImGui::ColorConvertFloat4ToU32(col_min);
for (int t = 0; t < gp.YTicks[i].Size; t++) { for (int t = 0; t < gp.YTicks[i].Size; t++) {
ImPlotTick *yt = &gp.YTicks[i][t]; ImPlotTick& yt = gp.YTicks[i][t];
DrawList.AddLine(ImVec2(gp.BB_Plot.Min.x, yt->PixelPos), ImVec2(gp.BB_Plot.Max.x, yt->PixelPos), yt->Major ? gp.Col_Y[i].Major : gp.Col_Y[i].Minor, 1); if (yt.Major)
DrawList.AddLine(ImVec2(gp.BB_Plot.Min.x, yt.PixelPos), ImVec2(gp.BB_Plot.Max.x, yt.PixelPos), gp.Col_Y[i].Major, 1);
else if (density < 0.2f)
DrawList.AddLine(ImVec2(gp.BB_Plot.Min.x, yt.PixelPos), ImVec2(gp.BB_Plot.Max.x, yt.PixelPos), col_min32, 1);
} }
} }
} }
@ -1055,23 +1094,27 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
ImGui::RenderText(ImVec2(gp.BB_Canvas.GetCenter().x - title_size.x * 0.5f, gp.BB_Canvas.Min.y), title, NULL, true); ImGui::RenderText(ImVec2(gp.BB_Canvas.GetCenter().x - title_size.x * 0.5f, gp.BB_Canvas.Min.y), title, NULL, true);
} }
// render labels // render axis labels
if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickLabels)) { if (x_label) {
const ImVec2 xLabel_size = ImGui::CalcTextSize(x_label);
const ImVec2 xLabel_pos(gp.BB_Plot.GetCenter().x - xLabel_size.x * 0.5f, gp.BB_Canvas.Max.y - txt_height);
DrawList.AddText(xLabel_pos, gp.Col_X.MajTxt, x_label);
}
if (y_label) {
const ImVec2 yLabel_size = CalcTextSizeVertical(y_label);
const ImVec2 yLabel_pos(gp.BB_Canvas.Min.x, gp.BB_Plot.GetCenter().y + yLabel_size.y * 0.5f);
AddTextVertical(&DrawList, y_label, yLabel_pos, gp.Col_Y[0].MajTxt);
}
// render tick labels
ImGui::PushClipRect(gp.BB_Frame.Min, gp.BB_Frame.Max, true); ImGui::PushClipRect(gp.BB_Frame.Min, gp.BB_Frame.Max, true);
if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickLabels)) {
for (int t = 0; t < gp.XTicks.Size; t++) { for (int t = 0; t < gp.XTicks.Size; t++) {
ImPlotTick *xt = &gp.XTicks[t]; ImPlotTick *xt = &gp.XTicks[t];
if (xt->ShowLabel && xt->PixelPos >= gp.BB_Plot.Min.x - 1 && xt->PixelPos <= gp.BB_Plot.Max.x + 1) if (xt->ShowLabel && xt->PixelPos >= gp.BB_Plot.Min.x - 1 && xt->PixelPos <= gp.BB_Plot.Max.x + 1)
DrawList.AddText(ImVec2(xt->PixelPos - xt->LabelSize.x * 0.5f, gp.BB_Plot.Max.y + IMPLOT_LABEL_PAD), xt->Major ? gp.Col_X.MajTxt : gp.Col_X.MinTxt, gp.XTickLabels.Buf.Data + xt->BufferOffset); DrawList.AddText(ImVec2(xt->PixelPos - xt->LabelSize.x * 0.5f, gp.BB_Plot.Max.y + IMPLOT_LABEL_PAD), xt->Major ? gp.Col_X.MajTxt : gp.Col_X.MinTxt, gp.XTickLabels.Buf.Data + xt->BufferOffset);
} }
ImGui::PopClipRect();
} }
if (x_label) {
const ImVec2 xLabel_size = ImGui::CalcTextSize(x_label);
const ImVec2 xLabel_pos(gp.BB_Plot.GetCenter().x - xLabel_size.x * 0.5f,
gp.BB_Canvas.Max.y - txt_height);
DrawList.AddText(xLabel_pos, gp.Col_X.MajTxt, x_label);
}
ImGui::PushClipRect(gp.BB_Frame.Min, gp.BB_Frame.Max, true);
for (int i = 0; i < IMPLOT_Y_AXES; i++) { for (int i = 0; i < IMPLOT_Y_AXES; i++) {
if (gp.Y[i].Present && ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels)) { if (gp.Y[i].Present && ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels)) {
for (int t = 0; t < gp.YTicks[i].Size; t++) { for (int t = 0; t < gp.YTicks[i].Size; t++) {
@ -1085,11 +1128,6 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
} }
} }
ImGui::PopClipRect(); ImGui::PopClipRect();
if (y_label) {
const ImVec2 yLabel_size = CalcTextSizeVertical(y_label);
const ImVec2 yLabel_pos(gp.BB_Canvas.Min.x, gp.BB_Plot.GetCenter().y + yLabel_size.y * 0.5f);
AddTextVertical(&DrawList, y_label, yLabel_pos, gp.Col_Y[0].MajTxt);
}
// push plot ID into stack // push plot ID into stack
ImGui::PushID(ID); ImGui::PushID(ID);
@ -1439,17 +1477,41 @@ void EndPlot() {
char buffer[128] = {}; char buffer[128] = {};
ImBufferWriter writer(buffer, sizeof(buffer)); ImBufferWriter writer(buffer, sizeof(buffer));
double range_x = gp.XTicks.Size > 1 ? (gp.XTicks[1].PlotPos - gp.XTicks[0].PlotPos) : plot.XAxis.Range.Size(); // x
double range_y = gp.YTicks[0].Size > 1 ? (gp.YTicks[0][1].PlotPos - gp.YTicks[0][0].PlotPos) : plot.YAxis[0].Range.Size(); if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale)) {
writer.Write("%.3E", gp.MousePos[0].x);
writer.Write("%.*f,%.*f", Precision(range_x), gp.LastMousePos[0].x, Precision(range_y), gp.LastMousePos[0].y);
if (ImHasFlag(plot.Flags, ImPlotFlags_YAxis2)) {
range_y = gp.YTicks[1].Size > 1 ? (gp.YTicks[1][1].PlotPos - gp.YTicks[1][0].PlotPos) : plot.YAxis[1].Range.Size();
writer.Write(",(%.*f)", Precision(range_y), gp.LastMousePos[1].y);
} }
else {
double range_x = gp.XTicks.Size > 1 ? (gp.XTicks[1].PlotPos - gp.XTicks[0].PlotPos) : plot.XAxis.Range.Size();
writer.Write("%.*f", Precision(range_x), gp.MousePos[0].x);
}
// y1
if (ImHasFlag(plot.YAxis[0].Flags, ImPlotAxisFlags_LogScale)) {
writer.Write(",%.3E", gp.MousePos[0].y);
}
else {
double range_y = gp.YTicks[0].Size > 1 ? (gp.YTicks[0][1].PlotPos - gp.YTicks[0][0].PlotPos) : plot.YAxis[0].Range.Size();
writer.Write(",%.*f", Precision(range_y), gp.MousePos[0].y);
}
// y2
if (ImHasFlag(plot.Flags, ImPlotFlags_YAxis2)) {
if (ImHasFlag(plot.YAxis[1].Flags, ImPlotAxisFlags_LogScale)) {
writer.Write(",(%.3E)", gp.MousePos[1].y);
}
else {
double range_y = gp.YTicks[1].Size > 1 ? (gp.YTicks[1][1].PlotPos - gp.YTicks[1][0].PlotPos) : plot.YAxis[1].Range.Size();
writer.Write(",(%.*f)", Precision(range_y), gp.MousePos[1].y);
}
}
// y3
if (ImHasFlag(plot.Flags, ImPlotFlags_YAxis3)) { if (ImHasFlag(plot.Flags, ImPlotFlags_YAxis3)) {
range_y = gp.YTicks[2].Size > 1 ? (gp.YTicks[2][1].PlotPos - gp.YTicks[2][0].PlotPos) : plot.YAxis[2].Range.Size(); if (ImHasFlag(plot.YAxis[2].Flags, ImPlotAxisFlags_LogScale)) {
writer.Write(",(%.*f)", Precision(range_y), gp.LastMousePos[2].y); writer.Write(",(%.3E)", gp.MousePos[2].y);
}
else {
double range_y = gp.YTicks[2].Size > 1 ? (gp.YTicks[2][1].PlotPos - gp.YTicks[2][0].PlotPos) : plot.YAxis[2].Range.Size();
writer.Write(",(%.*f)", Precision(range_y), gp.MousePos[2].y);
}
} }
ImVec2 size = ImGui::CalcTextSize(buffer); ImVec2 size = ImGui::CalcTextSize(buffer);
ImVec2 pos = gp.BB_Plot.Max - size - ImVec2(5, 5); ImVec2 pos = gp.BB_Plot.Max - size - ImVec2(5, 5);
@ -1654,7 +1716,7 @@ ImPlotPoint GetPlotMousePos(int y_axis_in) {
IM_ASSERT_USER_ERROR(y_axis_in >= -1 && y_axis_in < IMPLOT_Y_AXES, "y_axis needs to between -1 and IMPLOT_Y_AXES"); IM_ASSERT_USER_ERROR(y_axis_in >= -1 && y_axis_in < IMPLOT_Y_AXES, "y_axis needs to between -1 and IMPLOT_Y_AXES");
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotMousePos() needs to be called between BeginPlot() and EndPlot()!"); IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotMousePos() needs to be called between BeginPlot() and EndPlot()!");
const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis; const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis;
return gp.LastMousePos[y_axis]; return gp.MousePos[y_axis];
} }
@ -2015,6 +2077,11 @@ const ImVec4* GetColormap(ImPlotColormap colormap, int* size_out) {
return &cdata[coffs.Offsets[colormap]]; return &cdata[coffs.Offsets[colormap]];
} }
const char* GetColormapName(ImPlotColormap colormap) {
static const char* cmap_names[] = {"Default","Dark","Pastel","Paired","Viridis","Plasma","Hot","Cool","Pink","Jet"};
return cmap_names[colormap];
}
void ResampleColormap(const ImVec4* colormap_in, int size_in, ImVec4* colormap_out, int size_out) { void ResampleColormap(const ImVec4* colormap_in, int size_in, ImVec4* colormap_out, int size_out) {
for (int i = 0; i < size_out; ++i) { for (int i = 0; i < size_out; ++i) {
float t = i * 1.0f / (size_out - 1); float t = i * 1.0f / (size_out - 1);
@ -2067,7 +2134,7 @@ void ShowColormapScale(double scale_min, double scale_max, float height) {
range.Max = scale_max; range.Max = scale_max;
ticks.shrink(0); ticks.shrink(0);
txt_buff.Buf.shrink(0); txt_buff.Buf.shrink(0);
AddDefaultTicks(range, 10, 0, false, ticks); AddTicksDefault(range, 10, 0, ticks);
LabelTicks(ticks, false, txt_buff); LabelTicks(ticks, false, txt_buff);
float max_width = 0; float max_width = 0;
for (int i = 0; i < ticks.Size; ++i) for (int i = 0; i < ticks.Size; ++i)

View File

@ -385,6 +385,8 @@ ImVec4 GetColormapColor(int index);
ImVec4 LerpColormap(float t); ImVec4 LerpColormap(float t);
// Returns the next unused colormap color and advances the colormap. Can be used to skip colors if desired. Call between BeginPlot/EndPlot. // Returns the next unused colormap color and advances the colormap. Can be used to skip colors if desired. Call between BeginPlot/EndPlot.
ImVec4 NextColormapColor(); ImVec4 NextColormapColor();
// Returns a null terminated string name for a built-in colormap
const char* GetColormapName(ImPlotColormap colormap);
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Plot Utils // Plot Utils

View File

@ -137,18 +137,17 @@ struct BenchmarkItem {
}; };
void ShowDemoWindow(bool* p_open) { void ShowDemoWindow(bool* p_open) {
static const char* cmap_names[] = {"Default","Dark","Pastel","Paired","Viridis","Plasma","Hot","Cool","Pink","Jet"}; static bool show_imgui_metrics = false;
static bool show_app_metrics = false; static bool show_imgui_style_editor = false;
static bool show_app_style_editor = false; if (show_imgui_metrics) { ImGui::ShowMetricsWindow(&show_imgui_metrics); }
if (show_app_metrics) { ImGui::ShowMetricsWindow(&show_app_metrics); } if (show_imgui_style_editor) { ImGui::Begin("Style Editor", &show_imgui_style_editor); ImGui::ShowStyleEditor(); ImGui::End(); }
if (show_app_style_editor) { ImGui::Begin("Style Editor", &show_app_style_editor); ImGui::ShowStyleEditor(); ImGui::End(); }
ImGui::SetNextWindowPos(ImVec2(50, 50), ImGuiCond_FirstUseEver); ImGui::SetNextWindowPos(ImVec2(50, 50), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(530, 750), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(530, 750), ImGuiCond_FirstUseEver);
ImGui::Begin("ImPlot Demo", p_open, ImGuiWindowFlags_MenuBar); ImGui::Begin("ImPlot Demo", p_open, ImGuiWindowFlags_MenuBar);
if (ImGui::BeginMenuBar()) { if (ImGui::BeginMenuBar()) {
if (ImGui::BeginMenu("Tools")) { if (ImGui::BeginMenu("Tools")) {
ImGui::MenuItem("Metrics", NULL, &show_app_metrics); ImGui::MenuItem("Metrics", NULL, &show_imgui_metrics);
ImGui::MenuItem("Style Editor (ImGui)", NULL, &show_app_style_editor); ImGui::MenuItem("Style Editor (ImGui)", NULL, &show_imgui_style_editor);
ImGui::EndMenu(); ImGui::EndMenu();
} }
ImGui::EndMenuBar(); ImGui::EndMenuBar();
@ -412,7 +411,7 @@ void ShowDemoWindow(bool* p_open) {
map = (map + 1) % ImPlotColormap_COUNT; map = (map + 1) % ImPlotColormap_COUNT;
ImPlot::PushColormap(map); ImPlot::PushColormap(map);
ImGui::SameLine(); ImGui::SameLine();
ImGui::LabelText("##Colormap Index", "%s", cmap_names[map]); ImGui::LabelText("##Colormap Index", "%s", ImPlot::GetColormapName(map));
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_LockMin | ImPlotAxisFlags_LockMax | ImPlotAxisFlags_TickLabels; static ImPlotAxisFlags axes_flags = ImPlotAxisFlags_LockMin | ImPlotAxisFlags_LockMax | ImPlotAxisFlags_TickLabels;
@ -485,7 +484,7 @@ void ShowDemoWindow(bool* p_open) {
if (ImGui::Button("Change Colormap##2")) if (ImGui::Button("Change Colormap##2"))
map = (map + 1) % ImPlotColormap_COUNT; map = (map + 1) % ImPlotColormap_COUNT;
ImGui::SameLine(); ImGui::SameLine();
ImGui::LabelText("##Colormap Index", "%s", cmap_names[map]); ImGui::LabelText("##Colormap Index", "%s", ImPlot::GetColormapName(map));
static float mk_size = ImPlot::GetStyle().MarkerSize; static float mk_size = ImPlot::GetStyle().MarkerSize;
static float mk_weight = ImPlot::GetStyle().MarkerWeight; static float mk_weight = ImPlot::GetStyle().MarkerWeight;
ImGui::DragFloat("Marker Size",&mk_size,0.1f,2.0f,10.0f,"%.2f px"); ImGui::DragFloat("Marker Size",&mk_size,0.1f,2.0f,10.0f,"%.2f px");

View File

@ -404,7 +404,7 @@ struct ImPlotContext {
int DigitalPlotOffset; int DigitalPlotOffset;
ImPlotNextPlotData NextPlotData; ImPlotNextPlotData NextPlotData;
ImPlotInputMap InputMap; ImPlotInputMap InputMap;
ImPlotPoint LastMousePos[IMPLOT_Y_AXES]; ImPlotPoint MousePos[IMPLOT_Y_AXES];
}; };
struct ImPlotAxisScale struct ImPlotAxisScale
@ -448,14 +448,18 @@ ImPlotItem* GetItem(int i);
ImPlotItem* GetItem(const char* label_id); ImPlotItem* GetItem(const char* label_id);
// Gets a plot item from a specific plot // Gets a plot item from a specific plot
ImPlotItem* GetItem(const char* plot_title, const char* item_label_id); ImPlotItem* GetItem(const char* plot_title, const char* item_label_id);
// Busts the cached color for the every item (i.e. sets ImPlotItem.Color to IMPLOT_COL_AUTO) for every plot in the current context
void BustItemColorCache();
// Returns the number of entries in the current legend // Returns the number of entries in the current legend
int GetLegendCount(); int GetLegendCount();
// Gets the ith entry string for the current legend // Gets the ith entry string for the current legend
const char* GetLegendLabel(int i); const char* GetLegendLabel(int i);
// Populates a list of ImPlotTicks with automatically spaced ticks // Populates a list of ImPlotTicks with normal spaced and formatted ticks
void AddDefaultTicks(const ImPlotRange& range, int nMajor, int nMinor, bool logscale, ImVector<ImPlotTick> &out); void AddTicksDefault(const ImPlotRange& range, int nMajor, int nMinor, ImVector<ImPlotTick> &out);
// Populates a list of ImPlotTicks with logarithmic space and formatted ticks
void AddTicksLogarithmic(const ImPlotRange& range, int nMajor, ImVector<ImPlotTick>& out);
// Populates a list of ImPlotTicks with custom spaced and labeled ticks // Populates a list of ImPlotTicks with custom spaced and labeled ticks
void AddCustomTicks(const double* values, const char** labels, int n, ImVector<ImPlotTick>& ticks, ImGuiTextBuffer& buffer); void AddCustomTicks(const double* values, const char** labels, int n, ImVector<ImPlotTick>& ticks, ImGuiTextBuffer& buffer);
// Creates label information for a list of ImPlotTick // Creates label information for a list of ImPlotTick