mirror of
https://github.com/gwm17/implot.git
synced 2024-11-13 14:38:51 -05:00
Adds SetNextPlotFormatX/Y for custom tick label formatting (#198)
* add SetNextPlotFormat * work on pruning * finish up fmt
This commit is contained in:
parent
4b0f9c9495
commit
ed1baf471a
166
implot.cpp
166
implot.cpp
|
@ -689,45 +689,55 @@ void ShowLegendEntries(ImPlotPlot& plot, const ImRect& legend_bb, bool interacta
|
|||
// Tick Utils
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void LabelTickDefault(ImPlotTick& tick, ImGuiTextBuffer& buffer) {
|
||||
char temp[32];
|
||||
if (tick.ShowLabel) {
|
||||
tick.TextOffset = buffer.size();
|
||||
snprintf(temp, 32, "%.10g", tick.PlotPos);
|
||||
buffer.append(temp, temp + strlen(temp) + 1);
|
||||
tick.LabelSize = ImGui::CalcTextSize(buffer.Buf.Data + tick.TextOffset);
|
||||
}
|
||||
}
|
||||
|
||||
void LabelTickScientific(ImPlotTick& tick, ImGuiTextBuffer& buffer) {
|
||||
char temp[32];
|
||||
if (tick.ShowLabel) {
|
||||
tick.TextOffset = buffer.size();
|
||||
snprintf(temp, 32, "%.0E", tick.PlotPos);
|
||||
buffer.append(temp, temp + strlen(temp) + 1);
|
||||
tick.LabelSize = ImGui::CalcTextSize(buffer.Buf.Data + tick.TextOffset);
|
||||
}
|
||||
}
|
||||
|
||||
void AddTicksDefault(const ImPlotRange& range, int nMajor, int nMinor, ImPlotTickCollection& ticks) {
|
||||
void AddTicksDefault(const ImPlotRange& range, float pix, ImPlotOrientation orn, ImPlotTickCollection& ticks, const char* fmt) {
|
||||
const int idx0 = ticks.Size;
|
||||
const int nMinor = 10;
|
||||
const int nMajor = ImMax(2, (int)IM_ROUND(pix / (orn == ImPlotOrientation_Horizontal ? 400.0f : 300.0f)));
|
||||
const double nice_range = NiceNum(range.Size() * 0.99, false);
|
||||
const double interval = NiceNum(nice_range / (nMajor - 1), true);
|
||||
const double graphmin = floor(range.Min / interval) * interval;
|
||||
const double graphmax = ceil(range.Max / interval) * interval;
|
||||
bool first_major_set = false;
|
||||
int first_major_idx = 0;
|
||||
|
||||
char dummy[32];
|
||||
sprintf(dummy,fmt,-ImAbs(interval / nMinor));
|
||||
ImVec2 dummy_size = ImGui::CalcTextSize(dummy);
|
||||
ImVec2 total_size(0,0);
|
||||
|
||||
for (double major = graphmin; major < graphmax + 0.5 * interval; major += interval) {
|
||||
if (range.Contains(major))
|
||||
ticks.Append(major, true, true, LabelTickDefault);
|
||||
// is this zero? combat zero formatting issues
|
||||
if (major-interval < 0 && major+interval > 0)
|
||||
major = 0;
|
||||
if (range.Contains(major)) {
|
||||
if (!first_major_set) {
|
||||
first_major_idx = ticks.Size;
|
||||
first_major_set = true;
|
||||
}
|
||||
ticks.Append(major, true, true, fmt);
|
||||
total_size += dummy_size;
|
||||
}
|
||||
for (int i = 1; i < nMinor; ++i) {
|
||||
double minor = major + i * interval / nMinor;
|
||||
if (range.Contains(minor))
|
||||
ticks.Append(minor, false, true, LabelTickDefault);
|
||||
if (range.Contains(minor)) {
|
||||
ticks.Append(minor, false, true, fmt);
|
||||
total_size += dummy_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
// prune if necessary
|
||||
if ((orn == ImPlotOrientation_Horizontal && total_size.x > pix) || (orn == ImPlotOrientation_Vertical && total_size.y > pix)) {
|
||||
for (int i = first_major_idx-1; i >= idx0; i -= 2)
|
||||
ticks.Ticks[i].ShowLabel = false;
|
||||
for (int i = first_major_idx+1; i < ticks.Size; i += 2)
|
||||
ticks.Ticks[i].ShowLabel = false;
|
||||
}
|
||||
}
|
||||
|
||||
void AddTicksLogarithmic(const ImPlotRange& range, int nMajor, ImPlotTickCollection& ticks) {
|
||||
void AddTicksLogarithmic(const ImPlotRange& range, float pix, ImPlotOrientation orn, ImPlotTickCollection& ticks, const char* fmt) {
|
||||
if (range.Min <= 0 || range.Max <= 0)
|
||||
return;
|
||||
const int nMajor = orn == ImPlotOrientation_Horizontal ? ImMax(2, (int)IM_ROUND(pix * 0.01f)) : ImMax(2, (int)IM_ROUND(pix * 0.02f));
|
||||
double log_min = ImLog10(range.Min);
|
||||
double log_max = ImLog10(range.Max);
|
||||
int exp_step = ImMax(1,(int)(log_max - log_min) / nMajor);
|
||||
|
@ -742,7 +752,7 @@ void AddTicksLogarithmic(const ImPlotRange& range, int nMajor, ImPlotTickCollect
|
|||
double major2 = ImPow(10, (double)(e + 1));
|
||||
double interval = (major2 - major1) / 9;
|
||||
if (major1 >= (range.Min - DBL_EPSILON) && major1 <= (range.Max + DBL_EPSILON))
|
||||
ticks.Append(major1, true, true, LabelTickScientific);
|
||||
ticks.Append(major1, true, true, fmt);
|
||||
for (int j = 0; j < exp_step; ++j) {
|
||||
major1 = ImPow(10, (double)(e+j));
|
||||
major2 = ImPow(10, (double)(e+j+1));
|
||||
|
@ -750,25 +760,25 @@ void AddTicksLogarithmic(const ImPlotRange& range, int nMajor, ImPlotTickCollect
|
|||
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))
|
||||
ticks.Append(minor, false, false, LabelTickScientific);
|
||||
ticks.Append(minor, false, false, fmt);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddTicksCustom(const double* values, const char* const labels[], int n, ImPlotTickCollection& ticks) {
|
||||
void AddTicksCustom(const double* values, const char* const labels[], int n, ImPlotTickCollection& ticks, const char* fmt) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
ImPlotTick tick(values[i], false, true);
|
||||
if (labels != NULL) {
|
||||
ImPlotTick tick(values[i], false, true);
|
||||
tick.TextOffset = ticks.TextBuffer.size();
|
||||
ticks.TextBuffer.append(labels[i], labels[i] + strlen(labels[i]) + 1);
|
||||
tick.LabelSize = ImGui::CalcTextSize(labels[i]);
|
||||
ticks.Append(tick);
|
||||
}
|
||||
else {
|
||||
LabelTickDefault(tick, ticks.TextBuffer);
|
||||
ticks.Append(values[i], false, true, fmt);
|
||||
}
|
||||
ticks.Append(tick);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1256,12 +1266,18 @@ void AddTicksTime(const ImPlotRange& range, float plot_width, ImPlotTickCollecti
|
|||
// Axis Utils
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static inline int AxisPrecision(const ImPlotAxis& axis, const ImPlotTickCollection& ticks) {
|
||||
const double range = ticks.Size > 1 ? (ticks.Ticks[1].PlotPos - ticks.Ticks[0].PlotPos) : axis.Range.Size();
|
||||
return Precision(range);
|
||||
}
|
||||
|
||||
static inline double RoundAxisValue(const ImPlotAxis& axis, const ImPlotTickCollection& ticks, double value) {
|
||||
return RoundTo(value, AxisPrecision(axis,ticks));
|
||||
}
|
||||
|
||||
int LabelAxisValue(const ImPlotAxis& axis, const ImPlotTickCollection& ticks, double value, char* buff, int size) {
|
||||
ImPlotContext& gp = *GImPlot;
|
||||
if (ImHasFlag(axis.Flags, ImPlotAxisFlags_LogScale)) {
|
||||
return snprintf(buff, size, "%.3E", value);
|
||||
}
|
||||
else if (ImHasFlag(axis.Flags, ImPlotAxisFlags_Time)) {
|
||||
if (ImHasFlag(axis.Flags, ImPlotAxisFlags_Time)) {
|
||||
ImPlotTimeUnit unit = (axis.Orientation == ImPlotOrientation_Horizontal)
|
||||
? GetUnitForRange(axis.Range.Size() / (gp.CurrentPlot->PlotRect.GetWidth() / 100))
|
||||
: GetUnitForRange(axis.Range.Size() / (gp.CurrentPlot->PlotRect.GetHeight() / 100));
|
||||
|
@ -1521,9 +1537,9 @@ bool BeginPlot(const char* title, const char* x_label, const char* y1_label, con
|
|||
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
|
||||
if (gp.RenderY[i] && gp.NextPlotData.ShowDefaultTicksY[i]) {
|
||||
if (ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LogScale))
|
||||
AddTicksLogarithmic(plot.YAxis[i].Range, ImMax(2, (int)IM_ROUND(plot_height * 0.02f)) ,gp.YTicks[i]);
|
||||
AddTicksLogarithmic(plot.YAxis[i].Range, plot_height, ImPlotOrientation_Vertical, gp.YTicks[i], GetFormatY(i));
|
||||
else
|
||||
AddTicksDefault(plot.YAxis[i].Range, ImMax(2, (int)IM_ROUND(0.0025 * plot_height)), IMPLOT_SUB_DIV, gp.YTicks[i]);
|
||||
AddTicksDefault(plot.YAxis[i].Range, plot_height, ImPlotOrientation_Vertical, gp.YTicks[i], GetFormatY(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1547,9 +1563,9 @@ bool BeginPlot(const char* title, const char* x_label, const char* y1_label, con
|
|||
if (plot.XAxis.IsTime())
|
||||
AddTicksTime(plot.XAxis.Range, plot_width, gp.XTicks);
|
||||
else if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale))
|
||||
AddTicksLogarithmic(plot.XAxis.Range, (int)IM_ROUND(plot_width * 0.01f), gp.XTicks);
|
||||
AddTicksLogarithmic(plot.XAxis.Range, plot_width, ImPlotOrientation_Horizontal, gp.XTicks, GetFormatX());
|
||||
else
|
||||
AddTicksDefault(plot.XAxis.Range, ImMax(2, (int)IM_ROUND(0.0025 * plot_width)), IMPLOT_SUB_DIV, gp.XTicks);
|
||||
AddTicksDefault(plot.XAxis.Range, plot_width, ImPlotOrientation_Horizontal, gp.XTicks, GetFormatX());
|
||||
}
|
||||
|
||||
// (5) calc plot bb
|
||||
|
@ -2242,10 +2258,8 @@ void EndPlot() {
|
|||
|
||||
// AXIS STATES ------------------------------------------------------------
|
||||
|
||||
const bool any_y_locked = plot.AnyYInputLocked();
|
||||
const bool any_y_dragging = plot.YAxis[0].Dragging || plot.YAxis[1].Dragging || plot.YAxis[2].Dragging;
|
||||
|
||||
|
||||
// FINAL RENDER -----------------------------------------------------------
|
||||
|
||||
// render ticks
|
||||
|
@ -2284,10 +2298,7 @@ void EndPlot() {
|
|||
|
||||
if (axis_count >= 3) {
|
||||
// Draw a bar next to the ticks to act as a visual separator.
|
||||
DrawList.AddLine(
|
||||
ImVec2(x_start, plot.PlotRect.Min.y),
|
||||
ImVec2(x_start, plot.PlotRect.Max.y),
|
||||
GetStyleColorU32(ImPlotCol_YAxisGrid3), 1);
|
||||
DrawList.AddLine(ImVec2(x_start, plot.PlotRect.Min.y), ImVec2(x_start, plot.PlotRect.Max.y), GetStyleColorU32(ImPlotCol_YAxisGrid3), 1);
|
||||
}
|
||||
}
|
||||
ImGui::PopClipRect();
|
||||
|
@ -2358,52 +2369,34 @@ void EndPlot() {
|
|||
DrawList.AddLine(v3, v4, col);
|
||||
}
|
||||
|
||||
// render mouse pos (TODO: use LabelAxisValue)
|
||||
// render mouse pos
|
||||
if (!ImHasFlag(plot.Flags, ImPlotFlags_NoMousePos) && plot.PlotHovered) {
|
||||
char buffer[128] = {};
|
||||
ImBufferWriter writer(buffer, sizeof(buffer));
|
||||
|
||||
// x
|
||||
if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale)) {
|
||||
writer.Write("%.3E", gp.MousePos[0].x);
|
||||
}
|
||||
else if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_Time)) {
|
||||
if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_Time)) {
|
||||
ImPlotTimeUnit unit = GetUnitForRange(plot.XAxis.Range.Size() / (plot.PlotRect.GetWidth() / 100));
|
||||
const int written = FormatDateTime(ImPlotTime::FromDouble(gp.MousePos[0].x), &writer.Buffer[writer.Pos], writer.Size - writer.Pos - 1, GetDateTimeFmt(TimeFormatMouseCursor, unit));
|
||||
if (written > 0)
|
||||
writer.Pos += ImMin(written, writer.Size - writer.Pos - 1);
|
||||
}
|
||||
else {
|
||||
double range_x = gp.XTicks.Size > 1 ? (gp.XTicks.Ticks[1].PlotPos - gp.XTicks.Ticks[0].PlotPos) : plot.XAxis.Range.Size();
|
||||
writer.Write("%.*f", Precision(range_x), gp.MousePos[0].x);
|
||||
writer.Write(GetFormatX(), RoundAxisValue(plot.XAxis, gp.XTicks, 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].Ticks[1].PlotPos - gp.YTicks[0].Ticks[0].PlotPos) : plot.YAxis[0].Range.Size();
|
||||
writer.Write(",%.*f", Precision(range_y), gp.MousePos[0].y);
|
||||
}
|
||||
writer.Write(", ");
|
||||
writer.Write(GetFormatY(0), RoundAxisValue(plot.YAxis[0], gp.YTicks[0], 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].Ticks[1].PlotPos - gp.YTicks[1].Ticks[0].PlotPos) : plot.YAxis[1].Range.Size();
|
||||
writer.Write(",(%.*f)", Precision(range_y), gp.MousePos[1].y);
|
||||
}
|
||||
writer.Write(", (");
|
||||
writer.Write(GetFormatY(1), RoundAxisValue(plot.YAxis[1], gp.YTicks[1], gp.MousePos[1].y));
|
||||
writer.Write(")");
|
||||
}
|
||||
// y3
|
||||
if (ImHasFlag(plot.Flags, ImPlotFlags_YAxis3)) {
|
||||
if (ImHasFlag(plot.YAxis[2].Flags, ImPlotAxisFlags_LogScale)) {
|
||||
writer.Write(",(%.3E)", gp.MousePos[2].y);
|
||||
}
|
||||
else {
|
||||
double range_y = gp.YTicks[2].Size > 1 ? (gp.YTicks[2].Ticks[1].PlotPos - gp.YTicks[2].Ticks[0].PlotPos) : plot.YAxis[2].Range.Size();
|
||||
writer.Write(",(%.*f)", Precision(range_y), gp.MousePos[2].y);
|
||||
}
|
||||
writer.Write(", (");
|
||||
writer.Write(GetFormatY(2), RoundAxisValue(plot.YAxis[2], gp.YTicks[2], gp.MousePos[2].y));
|
||||
writer.Write(")");
|
||||
}
|
||||
const ImVec2 size = ImGui::CalcTextSize(buffer);
|
||||
const ImVec2 pos = GetLocationPos(plot.PlotRect, size, plot.MousePosLocation, gp.Style.MousePosPadding);
|
||||
|
@ -2618,7 +2611,7 @@ void SetNextPlotTicksX(const double* values, int n_ticks, const char* const labe
|
|||
ImPlotContext& gp = *GImPlot;
|
||||
IM_ASSERT_USER_ERROR(gp.CurrentPlot == NULL, "SetNextPlotTicksX() needs to be called before BeginPlot()!");
|
||||
gp.NextPlotData.ShowDefaultTicksX = show_default;
|
||||
AddTicksCustom(values, labels, n_ticks, gp.XTicks);
|
||||
AddTicksCustom(values, labels, n_ticks, gp.XTicks, GetFormatX());
|
||||
}
|
||||
|
||||
void SetNextPlotTicksX(double x_min, double x_max, int n_ticks, const char* const labels[], bool show_default) {
|
||||
|
@ -2633,7 +2626,7 @@ void SetNextPlotTicksY(const double* values, int n_ticks, const char* const labe
|
|||
IM_ASSERT_USER_ERROR(gp.CurrentPlot == NULL, "SetNextPlotTicksY() needs to be called before BeginPlot()!");
|
||||
IM_ASSERT_USER_ERROR(y_axis >= 0 && y_axis < IMPLOT_Y_AXES, "y_axis needs to be between 0 and IMPLOT_Y_AXES");
|
||||
gp.NextPlotData.ShowDefaultTicksY[y_axis] = show_default;
|
||||
AddTicksCustom(values, labels, n_ticks, gp.YTicks[y_axis]);
|
||||
AddTicksCustom(values, labels, n_ticks, gp.YTicks[y_axis], GetFormatY(y_axis));
|
||||
}
|
||||
|
||||
void SetNextPlotTicksY(double y_min, double y_max, int n_ticks, const char* const labels[], bool show_default, ImPlotYAxis y_axis) {
|
||||
|
@ -2643,6 +2636,21 @@ void SetNextPlotTicksY(double y_min, double y_max, int n_ticks, const char* cons
|
|||
SetNextPlotTicksY(&buffer[0], n_ticks, labels, show_default,y_axis);
|
||||
}
|
||||
|
||||
void SetNextPlotFormatX(const char* fmt){
|
||||
ImPlotContext& gp = *GImPlot;
|
||||
IM_ASSERT_USER_ERROR(gp.CurrentPlot == NULL, "SetNextPlotFormatX() needs to be called before BeginPlot()!");
|
||||
gp.NextPlotData.HasFmtX = true;
|
||||
ImStrncpy(gp.NextPlotData.FmtX, fmt, 16);
|
||||
}
|
||||
|
||||
void SetNextPlotFormatY(const char* fmt, ImPlotYAxis y_axis) {
|
||||
ImPlotContext& gp = *GImPlot;
|
||||
IM_ASSERT_USER_ERROR(gp.CurrentPlot == NULL, "SetNextPlotFormatY() needs to be called before BeginPlot()!");
|
||||
IM_ASSERT_USER_ERROR(y_axis >= 0 && y_axis < IMPLOT_Y_AXES, "y_axis needs to be between 0 and IMPLOT_Y_AXES");
|
||||
gp.NextPlotData.HasFmtY[y_axis] = true;
|
||||
ImStrncpy(gp.NextPlotData.FmtY[y_axis], fmt, 16);
|
||||
}
|
||||
|
||||
void SetPlotYAxis(ImPlotYAxis y_axis) {
|
||||
ImPlotContext& gp = *GImPlot;
|
||||
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "SetPlotYAxis() needs to be called between BeginPlot() and EndPlot()!");
|
||||
|
@ -3453,7 +3461,7 @@ void RenderColorBar(const ImU32* colors, int size, ImDrawList& DrawList, const I
|
|||
}
|
||||
}
|
||||
|
||||
void ColormapScale(const char* label, double scale_min, double scale_max, const ImVec2& size, ImPlotColormap cmap) {
|
||||
void ColormapScale(const char* label, double scale_min, double scale_max, const ImVec2& size, ImPlotColormap cmap, const char* fmt) {
|
||||
ImGuiContext &G = *GImGui;
|
||||
ImGuiWindow * Window = G.CurrentWindow;
|
||||
if (Window->SkipItems)
|
||||
|
@ -3473,7 +3481,7 @@ void ColormapScale(const char* label, double scale_min, double scale_max, const
|
|||
|
||||
ImPlotRange range(scale_min,scale_max);
|
||||
gp.CTicks.Reset();
|
||||
AddTicksDefault(range, ImMax(2, (int)IM_ROUND(0.0025 * frame_size.y)), IMPLOT_SUB_DIV, gp.CTicks);
|
||||
AddTicksDefault(range, frame_size.y, ImPlotOrientation_Vertical, gp.CTicks, fmt);
|
||||
|
||||
const float txt_off = gp.Style.LabelPadding.x;
|
||||
const float pad_right = txt_off + gp.CTicks.MaxWidth + (label_size.x > 0 ? txt_off + label_size.y : 0);
|
||||
|
|
20
implot.h
20
implot.h
|
@ -513,19 +513,23 @@ IMPLOT_API void SetNextPlotLimits(double xmin, double xmax, double ymin, double
|
|||
// Set the X axis range limits of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the X axis limits will be locked.
|
||||
IMPLOT_API void SetNextPlotLimitsX(double xmin, double xmax, ImGuiCond cond = ImGuiCond_Once);
|
||||
// Set the Y axis range limits of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the Y axis limits will be locked.
|
||||
IMPLOT_API void SetNextPlotLimitsY(double ymin, double ymax, ImGuiCond cond = ImGuiCond_Once, ImPlotYAxis y_axis = 0);
|
||||
IMPLOT_API void SetNextPlotLimitsY(double ymin, double ymax, ImGuiCond cond = ImGuiCond_Once, ImPlotYAxis y_axis = ImPlotYAxis_1);
|
||||
// Links the next plot limits to external values. Set to NULL for no linkage. The pointer data must remain valid until the matching call to EndPlot.
|
||||
IMPLOT_API void LinkNextPlotLimits(double* xmin, double* xmax, double* ymin, double* ymax, double* ymin2 = NULL, double* ymax2 = NULL, double* ymin3 = NULL, double* ymax3 = NULL);
|
||||
// Fits the next plot axes to all plotted data if they are unlocked (equivalent to double-clicks).
|
||||
IMPLOT_API void FitNextPlotAxes(bool x = true, bool y = true, bool y2 = true, bool y3 = true);
|
||||
|
||||
// Set the X axis ticks and optionally the labels for the next plot. To keep the default ticks, set #show_default=true.
|
||||
IMPLOT_API void SetNextPlotTicksX(const double* values, int n_ticks, const char* const labels[] = NULL, bool show_default = false);
|
||||
IMPLOT_API void SetNextPlotTicksX(double x_min, double x_max, int n_ticks, const char* const labels[] = NULL, bool show_default = false);
|
||||
// Set the X axis ticks and optionally the labels for the next plot. To keep the default ticks, set #keep_default=true.
|
||||
IMPLOT_API void SetNextPlotTicksX(const double* values, int n_ticks, const char* const labels[] = NULL, bool keep_default = false);
|
||||
IMPLOT_API void SetNextPlotTicksX(double x_min, double x_max, int n_ticks, const char* const labels[] = NULL, bool keep_default = false);
|
||||
// Set the Y axis ticks and optionally the labels for the next plot. To keep the default ticks, set #keep_default=true.
|
||||
IMPLOT_API void SetNextPlotTicksY(const double* values, int n_ticks, const char* const labels[] = NULL, bool keep_default = false, ImPlotYAxis y_axis = ImPlotYAxis_1);
|
||||
IMPLOT_API void SetNextPlotTicksY(double y_min, double y_max, int n_ticks, const char* const labels[] = NULL, bool keep_default = false, ImPlotYAxis y_axis = ImPlotYAxis_1);
|
||||
|
||||
// Set the Y axis ticks and optionally the labels for the next plot. To keep the default ticks, set #show_default=true.
|
||||
IMPLOT_API void SetNextPlotTicksY(const double* values, int n_ticks, const char* const labels[] = NULL, bool show_default = false, ImPlotYAxis y_axis = 0);
|
||||
IMPLOT_API void SetNextPlotTicksY(double y_min, double y_max, int n_ticks, const char* const labels[] = NULL, bool show_default = false, ImPlotYAxis y_axis = 0);
|
||||
// Set the format for numeric X axis labels (default="%g"). Formated values will be doubles (i.e. don't supply %d, %i, etc.). Not applicable if ImPlotAxisFlags_Time enabled.
|
||||
IMPLOT_API void SetNextPlotFormatX(const char* fmt);
|
||||
// Set the format for numeric Y axis labels (default="%g"). Formated values will be doubles (i.e. don't supply %d, %i, etc.).
|
||||
IMPLOT_API void SetNextPlotFormatY(const char* fmt, ImPlotYAxis y_axis=ImPlotYAxis_1);
|
||||
|
||||
// The following functions MUST be called BETWEEN Begin/EndPlot!
|
||||
|
||||
|
@ -778,7 +782,7 @@ IMPLOT_API ImVec4 GetColormapColor(int idx, ImPlotColormap cmap = IMPLOT_AUTO);
|
|||
IMPLOT_API ImVec4 SampleColormap(float t, ImPlotColormap cmap = IMPLOT_AUTO);
|
||||
|
||||
// Shows a vertical color scale with linear spaced ticks using the specified color map. Use double hashes to hide label (e.g. "##NoLabel").
|
||||
IMPLOT_API void ColormapScale(const char* label, double scale_min, double scale_max, const ImVec2& size = ImVec2(0,0), ImPlotColormap cmap = IMPLOT_AUTO);
|
||||
IMPLOT_API void ColormapScale(const char* label, double scale_min, double scale_max, const ImVec2& size = ImVec2(0,0), ImPlotColormap cmap = IMPLOT_AUTO, const char* fmt = "%g");
|
||||
// Shows a horizontal slider with a colormap gradient background. Optionally returns the color sampled at t in [0 1].
|
||||
IMPLOT_API bool ColormapSlider(const char* label, float* t, ImVec4* out = NULL, const char* format = "", ImPlotColormap cmap = IMPLOT_AUTO);
|
||||
// Shows a button with a colormap gradient brackground.
|
||||
|
|
|
@ -1420,8 +1420,11 @@ void ShowDemoWindow(bool* p_open) {
|
|||
}
|
||||
//-------------------------------------------------------------------------
|
||||
if (ImGui::CollapsingHeader("Custom Ticks##")) {
|
||||
static bool custom_ticks = true;
|
||||
static bool custom_fmt = true;
|
||||
static bool custom_ticks = false;
|
||||
static bool custom_labels = true;
|
||||
ImGui::Checkbox("Show Custom Format", &custom_fmt);
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("Show Custom Ticks", &custom_ticks);
|
||||
if (custom_ticks) {
|
||||
ImGui::SameLine();
|
||||
|
@ -1433,11 +1436,17 @@ void ShowDemoWindow(bool* p_open) {
|
|||
static const char* ylabels[] = {"One","Three","Seven","Nine"};
|
||||
static double yticks_aux[] = {0.2,0.4,0.6};
|
||||
static const char* ylabels_aux[] = {"A","B","C","D","E","F"};
|
||||
if (custom_fmt) {
|
||||
ImPlot::SetNextPlotFormatX("%g ms");
|
||||
ImPlot::SetNextPlotFormatY("%g Hz", ImPlotYAxis_1);
|
||||
ImPlot::SetNextPlotFormatY("%g dB", ImPlotYAxis_2);
|
||||
ImPlot::SetNextPlotFormatY("%g km", ImPlotYAxis_3);
|
||||
}
|
||||
if (custom_ticks) {
|
||||
ImPlot::SetNextPlotTicksX(&pi,1,custom_labels ? pi_str : NULL, true);
|
||||
ImPlot::SetNextPlotTicksY(yticks, 4, custom_labels ? ylabels : NULL);
|
||||
ImPlot::SetNextPlotTicksY(yticks_aux, 3, custom_labels ? ylabels_aux : NULL, false, 1);
|
||||
ImPlot::SetNextPlotTicksY(0, 1, 6, custom_labels ? ylabels_aux : NULL, false, 2);
|
||||
ImPlot::SetNextPlotTicksY(yticks, 4, custom_labels ? ylabels : NULL, ImPlotYAxis_1);
|
||||
ImPlot::SetNextPlotTicksY(yticks_aux, 3, custom_labels ? ylabels_aux : NULL, false, ImPlotYAxis_2);
|
||||
ImPlot::SetNextPlotTicksY(0, 1, 6, custom_labels ? ylabels_aux : NULL, false, ImPlotYAxis_3);
|
||||
}
|
||||
ImPlot::SetNextPlotLimits(2.5,5,0,10);
|
||||
if (ImPlot::BeginPlot("Custom Ticks", NULL, NULL, ImVec2(-1,0), ImPlotFlags_YAxis2 | ImPlotFlags_YAxis3)) {
|
||||
|
@ -1545,8 +1554,9 @@ void ShowDemoWindow(bool* p_open) {
|
|||
ImGui::SameLine(); ImGui::ColorEdit4("##Bull", &bullCol.x, ImGuiColorEditFlags_NoInputs);
|
||||
ImGui::SameLine(); ImGui::ColorEdit4("##Bear", &bearCol.x, ImGuiColorEditFlags_NoInputs);
|
||||
ImPlot::GetStyle().UseLocalTime = false;
|
||||
ImPlot::SetNextPlotFormatY("$%.0f");
|
||||
ImPlot::SetNextPlotLimits(1546300800, 1571961600, 1250, 1600);
|
||||
if (ImPlot::BeginPlot("Candlestick Chart","Day","USD",ImVec2(-1,0),0,ImPlotAxisFlags_Time)) {
|
||||
if (ImPlot::BeginPlot("Candlestick Chart",NULL,NULL,ImVec2(-1,0),0,ImPlotAxisFlags_Time)) {
|
||||
MyImPlot::PlotCandlestick("GOOGL",dates, opens, closes, lows, highs, 218, tooltip, 0.25f, bullCol, bearCol);
|
||||
ImPlot::EndPlot();
|
||||
}
|
||||
|
|
|
@ -51,14 +51,14 @@
|
|||
|
||||
// The maximum number of supported y-axes (DO NOT CHANGE THIS)
|
||||
#define IMPLOT_Y_AXES 3
|
||||
// The number of times to subdivided grid divisions (best if a multiple of 1, 2, and 5)
|
||||
#define IMPLOT_SUB_DIV 10
|
||||
// Zoom rate for scroll (e.g. 0.1f = 10% plot range every scroll click)
|
||||
#define IMPLOT_ZOOM_RATE 0.1f
|
||||
// Mimimum allowable timestamp value 01/01/1970 @ 12:00am (UTC) (DO NOT DECREASE THIS)
|
||||
#define IMPLOT_MIN_TIME 0
|
||||
// Maximum allowable timestamp value 01/01/3000 @ 12:00am (UTC) (DO NOT INCREASE THIS)
|
||||
#define IMPLOT_MAX_TIME 32503680000
|
||||
// Default label format for axis labels
|
||||
#define IMPLOT_LABEL_FMT "%g"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Macros
|
||||
|
@ -528,6 +528,7 @@ struct ImPlotTick
|
|||
struct ImPlotTickCollection {
|
||||
ImVector<ImPlotTick> Ticks;
|
||||
ImGuiTextBuffer TextBuffer;
|
||||
float TotalWidthMax;
|
||||
float TotalWidth;
|
||||
float TotalHeight;
|
||||
float MaxWidth;
|
||||
|
@ -536,22 +537,28 @@ struct ImPlotTickCollection {
|
|||
|
||||
ImPlotTickCollection() { Reset(); }
|
||||
|
||||
void Append(const ImPlotTick& tick) {
|
||||
const ImPlotTick& Append(const ImPlotTick& tick) {
|
||||
if (tick.ShowLabel) {
|
||||
TotalWidth += tick.ShowLabel ? tick.LabelSize.x : 0;
|
||||
TotalHeight += tick.ShowLabel ? tick.LabelSize.y : 0;
|
||||
MaxWidth = tick.LabelSize.x > MaxWidth ? tick.LabelSize.x : MaxWidth;
|
||||
MaxHeight = tick.LabelSize.y > MaxHeight ? tick.LabelSize.y : MaxHeight;
|
||||
TotalWidth += tick.ShowLabel ? tick.LabelSize.x : 0;
|
||||
TotalHeight += tick.ShowLabel ? tick.LabelSize.y : 0;
|
||||
MaxWidth = tick.LabelSize.x > MaxWidth ? tick.LabelSize.x : MaxWidth;
|
||||
MaxHeight = tick.LabelSize.y > MaxHeight ? tick.LabelSize.y : MaxHeight;
|
||||
}
|
||||
Ticks.push_back(tick);
|
||||
Size++;
|
||||
return Ticks.back();
|
||||
}
|
||||
|
||||
void Append(double value, bool major, bool show_label, void (*labeler)(ImPlotTick& tick, ImGuiTextBuffer& buf)) {
|
||||
const ImPlotTick& Append(double value, bool major, bool show_label, const char* fmt) {
|
||||
ImPlotTick tick(value, major, show_label);
|
||||
if (labeler)
|
||||
labeler(tick, TextBuffer);
|
||||
Append(tick);
|
||||
if (show_label && fmt != NULL) {
|
||||
char temp[32];
|
||||
tick.TextOffset = TextBuffer.size();
|
||||
snprintf(temp, 32, fmt, tick.PlotPos);
|
||||
TextBuffer.append(temp, temp + strlen(temp) + 1);
|
||||
tick.LabelSize = ImGui::CalcTextSize(TextBuffer.Buf.Data + tick.TextOffset);
|
||||
}
|
||||
return Append(tick);
|
||||
}
|
||||
|
||||
const char* GetText(int idx) const {
|
||||
|
@ -788,6 +795,10 @@ struct ImPlotNextPlotData
|
|||
bool HasYRange[IMPLOT_Y_AXES];
|
||||
bool ShowDefaultTicksX;
|
||||
bool ShowDefaultTicksY[IMPLOT_Y_AXES];
|
||||
char FmtX[16];
|
||||
char FmtY[IMPLOT_Y_AXES][16];
|
||||
bool HasFmtX;
|
||||
bool HasFmtY[IMPLOT_Y_AXES];
|
||||
bool FitX;
|
||||
bool FitY[IMPLOT_Y_AXES];
|
||||
double* LinkedXmin;
|
||||
|
@ -800,11 +811,13 @@ struct ImPlotNextPlotData
|
|||
void Reset() {
|
||||
HasXRange = false;
|
||||
ShowDefaultTicksX = true;
|
||||
HasFmtX = false;
|
||||
FitX = false;
|
||||
LinkedXmin = LinkedXmax = NULL;
|
||||
for (int i = 0; i < IMPLOT_Y_AXES; ++i) {
|
||||
HasYRange[i] = false;
|
||||
ShowDefaultTicksY[i] = true;
|
||||
HasFmtY[i] = false;
|
||||
FitY[i] = false;
|
||||
LinkedYmin[i] = LinkedYmax[i] = NULL;
|
||||
}
|
||||
|
@ -993,6 +1006,10 @@ IMPLOT_API void PullLinkedAxis(ImPlotAxis& axis);
|
|||
// Shows an axis's context menu.
|
||||
IMPLOT_API void ShowAxisContextMenu(ImPlotAxis& axis, ImPlotAxis* equal_axis, bool time_allowed = false);
|
||||
|
||||
// Get format spec for axis
|
||||
static inline const char* GetFormatX() { return GImPlot->NextPlotData.HasFmtX ? GImPlot->NextPlotData.FmtX : IMPLOT_LABEL_FMT; }
|
||||
static inline const char* GetFormatY(ImPlotYAxis y) { return GImPlot->NextPlotData.HasFmtY[y] ? GImPlot->NextPlotData.FmtY[y] : IMPLOT_LABEL_FMT; }
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Legend Utils
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -1010,21 +1027,17 @@ IMPLOT_API void ShowAltLegend(const char* title_id, ImPlotOrientation orientatio
|
|||
// [SECTION] Tick Utils
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Label a tick with default formatting.
|
||||
IMPLOT_API void LabelTickDefault(ImPlotTick& tick, ImGuiTextBuffer& buffer);
|
||||
// Label a tick with scientific formating.
|
||||
IMPLOT_API void LabelTickScientific(ImPlotTick& tick, ImGuiTextBuffer& buffer);
|
||||
// Label a tick with time formatting.
|
||||
IMPLOT_API void LabelTickTime(ImPlotTick& tick, ImGuiTextBuffer& buffer, const ImPlotTime& t, ImPlotDateTimeFmt fmt);
|
||||
|
||||
// Populates a list of ImPlotTicks with normal spaced and formatted ticks
|
||||
IMPLOT_API void AddTicksDefault(const ImPlotRange& range, int nMajor, int nMinor, ImPlotTickCollection& ticks);
|
||||
IMPLOT_API void AddTicksDefault(const ImPlotRange& range, float pix, ImPlotOrientation orn, ImPlotTickCollection& ticks, const char* fmt);
|
||||
// Populates a list of ImPlotTicks with logarithmic space and formatted ticks
|
||||
IMPLOT_API void AddTicksLogarithmic(const ImPlotRange& range, int nMajor, ImPlotTickCollection& ticks);
|
||||
IMPLOT_API void AddTicksLogarithmic(const ImPlotRange& range, float pix, ImPlotOrientation orn, ImPlotTickCollection& ticks, const char* fmt);
|
||||
// Populates a list of ImPlotTicks with time formatted ticks.
|
||||
IMPLOT_API void AddTicksTime(const ImPlotRange& range, float plot_width, ImPlotTickCollection& ticks);
|
||||
// Populates a list of ImPlotTicks with custom spaced and labeled ticks
|
||||
IMPLOT_API void AddTicksCustom(const double* values, const char* const labels[], int n, ImPlotTickCollection& ticks);
|
||||
IMPLOT_API void AddTicksCustom(const double* values, const char* const labels[], int n, ImPlotTickCollection& ticks, const char* fmt);
|
||||
|
||||
// Create a a string label for a an axis value
|
||||
IMPLOT_API int LabelAxisValue(const ImPlotAxis& axis, const ImPlotTickCollection& ticks, double value, char* buff, int size);
|
||||
|
@ -1057,7 +1070,7 @@ static inline ImVec2 CalcTextSizeVertical(const char *text) {
|
|||
// Returns white or black text given background color
|
||||
static inline ImU32 CalcTextColor(const ImVec4& bg) { return (bg.x * 0.299 + bg.y * 0.587 + bg.z * 0.114) > 0.5 ? IM_COL32_BLACK : IM_COL32_WHITE; }
|
||||
static inline ImU32 CalcTextColor(ImU32 bg) { return CalcTextColor(ImGui::ColorConvertU32ToFloat4(bg)); }
|
||||
// Lights or darkens a color for hover
|
||||
// Lightens or darkens a color for hover
|
||||
static inline ImU32 CalcHoverColor(ImU32 col) { return ImMixU32(col, CalcTextColor(col), 32); }
|
||||
|
||||
// Clamps a label position so that it fits a rect defined by Min/Max
|
||||
|
@ -1091,6 +1104,8 @@ static inline int OrderOfMagnitude(double val) { return val == 0 ? 0 : (int)(flo
|
|||
static inline int OrderToPrecision(int order) { return order > 0 ? 0 : 1 - order; }
|
||||
// Returns a floating point precision to use given a value
|
||||
static inline int Precision(double val) { return OrderToPrecision(OrderOfMagnitude(val)); }
|
||||
// Round a value to a given precision
|
||||
static inline double RoundTo(double val, int prec) { double p = pow(10,(double)prec); return floor(val*p+0.5)/p; }
|
||||
|
||||
// Returns the intersection point of two lines A and B (assumes they are not parallel!)
|
||||
static inline ImVec2 Intersection(const ImVec2& a1, const ImVec2& a2, const ImVec2& b1, const ImVec2& b2) {
|
||||
|
@ -1118,7 +1133,7 @@ static inline T OffsetAndStride(const T* data, int idx, int count, int offset, i
|
|||
|
||||
// Calculate histogram bin counts and widths
|
||||
template <typename T>
|
||||
void CalculateBins(const T* values, int count, ImPlotBin meth, const ImPlotRange& range, int& bins_out, double& width_out) {
|
||||
static inline void CalculateBins(const T* values, int count, ImPlotBin meth, const ImPlotRange& range, int& bins_out, double& width_out) {
|
||||
switch (meth) {
|
||||
case ImPlotBin_Sqrt:
|
||||
bins_out = (int)ceil(sqrt(count));
|
||||
|
|
Loading…
Reference in New Issue
Block a user