Skip to content

Commit

Permalink
adds PlotVLines and PlotHLines for plotting infinite reference lines (e…
Browse files Browse the repository at this point in the history
  • Loading branch information
epezent authored Jan 15, 2021
1 parent 4c7bf00 commit 49c26be
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 19 deletions.
27 changes: 18 additions & 9 deletions implot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -429,19 +429,28 @@ void BustPlotCache() {
}

void FitPoint(const ImPlotPoint& p) {
FitPointX(p.x);
FitPointY(p.y);
}

void FitPointX(double x) {
ImPlotContext& gp = *GImPlot;
const ImPlotYAxis y_axis = gp.CurrentPlot->CurrentYAxis;
ImPlotRange& ex_x = gp.ExtentsX;
ImPlotRange& ex_y = gp.ExtentsY[y_axis];
const bool log_x = ImHasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_LogScale);
const bool log_y = ImHasFlag(gp.CurrentPlot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale);
if (!ImNanOrInf(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 (!ImNanOrInf(x) && !(log_x && x <= 0)) {
ex_x.Min = x < ex_x.Min ? x : ex_x.Min;
ex_x.Max = x > ex_x.Max ? x : ex_x.Max;
}
if (!ImNanOrInf(p.y) && !(log_y && p.y <= 0)) {
ex_y.Min = p.y < ex_y.Min ? p.y : ex_y.Min;
ex_y.Max = p.y > ex_y.Max ? p.y : ex_y.Max;
}

void FitPointY(double y) {
ImPlotContext& gp = *GImPlot;
const ImPlotYAxis y_axis = gp.CurrentPlot->CurrentYAxis;
ImPlotRange& ex_y = gp.ExtentsY[y_axis];
const bool log_y = ImHasFlag(gp.CurrentPlot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale);
if (!ImNanOrInf(y) && !(log_y && y <= 0)) {
ex_y.Min = y < ex_y.Min ? y : ex_y.Min;
ex_y.Max = y > ex_y.Max ? y : ex_y.Max;
}
}

Expand Down
4 changes: 4 additions & 0 deletions implot.h
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,10 @@ template <typename T> IMPLOT_API void PlotErrorBarsH(const char* label_id, const
template <typename T> 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 <typename T> 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));

/// Plots infinite vertical or horizontal lines (e.g. for references or asymptotes).
template <typename T> IMPLOT_API void PlotVLines(const char* label_id, const T* xs, int count, int offset=0, int stride=sizeof(T));
template <typename T> IMPLOT_API 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 <typename T> 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);

Expand Down
16 changes: 13 additions & 3 deletions implot_demo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,13 +269,13 @@ void ShowDemoWindow(bool* p_open) {
ImGui::Checkbox("Fills",&show_fills);
if (show_fills) {
ImGui::SameLine();
if (ImGui::RadioButton("To -INF",shade_mode == 0))
if (ImGui::RadioButton("To -INF",shade_mode == 0))
shade_mode = 0;
ImGui::SameLine();
if (ImGui::RadioButton("To +INF",shade_mode == 1))
if (ImGui::RadioButton("To +INF",shade_mode == 1))
shade_mode = 1;
ImGui::SameLine();
if (ImGui::RadioButton("To Ref",shade_mode == 2))
if (ImGui::RadioButton("To Ref",shade_mode == 2))
shade_mode = 2;
if (shade_mode == 2) {
ImGui::SameLine();
Expand Down Expand Up @@ -436,6 +436,7 @@ void ShowDemoWindow(bool* p_open) {
ImPlot::EndPlot();
}
}
//-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Stem Plots##")) {
static double xs[51], ys1[51], ys2[51];
for (int i = 0; i < 51; ++i) {
Expand All @@ -456,6 +457,15 @@ void ShowDemoWindow(bool* p_open) {
}
}
//-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Infinite Lines")) {
static double vals[] = {0.25, 0.5, 0.75};
if (ImPlot::BeginPlot("##Infinite")) {
ImPlot::PlotVLines("VLines",vals,3);
ImPlot::PlotHLines("HLines",vals,3);
ImPlot::EndPlot();
}
}
//-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Pie Charts")) {
static const char* labels1[] = {"Frogs","Hogs","Dogs","Logs"};
static float data1[] = {0.15f, 0.30f, 0.2f, 0.05f};
Expand Down
6 changes: 5 additions & 1 deletion implot_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -762,8 +762,12 @@ inline ImPlotScale GetCurrentScale() { return GImPlot->Scales[GetCurrentYAxis()]

// Returns true if the user has requested data to be fit.
inline bool FitThisFrame() { return GImPlot->FitThisFrame; }
// Extends the current plots axes so that it encompasses point p
// Extends the current plot's axes so that it encompasses point p
IMPLOT_API void FitPoint(const ImPlotPoint& p);
// Extends the current plot's axes so that it encompasses a vertical line at x
IMPLOT_API void FitPointX(double x);
// Extends the current plot's axes so that it encompasses a horizontal line at y
IMPLOT_API void FitPointY(double y);

// Returns true if two ranges overlap
inline bool RangesOverlap(const ImPlotRange& r1, const ImPlotRange& r2)
Expand Down
111 changes: 105 additions & 6 deletions implot_items.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,26 @@ struct GetterXsYRef {
const int Stride;
};

// Interprets an array of Y points as ImPlotPoints where the X value is a constant reference value
template <typename T>
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)
{ }
inline ImPlotPoint operator()(int idx) const {
return ImPlotPoint(XRef, (double)OffsetAndStride(Ys, idx, Count, Offset, Stride));
}
const double XRef;
const T* const Ys;
const int Count;
const int Offset;
const int Stride;
};

/// Interprets a user's function pointer as ImPlotPoints
struct GetterFuncPtr {
GetterFuncPtr(ImPlotPoint (*getter)(void* data, int idx), void* data, int count, int offset) :
Expand Down Expand Up @@ -1123,11 +1143,11 @@ template <typename Getter1, typename Getter2>
inline void PlotShadedEx(const char* label_id, const Getter1& getter1, const Getter2& getter2, bool fit2) {
if (BeginItem(label_id, ImPlotCol_Fill)) {
if (FitThisFrame()) {
for (int i = 0; i < getter1.Count; ++i)
FitPoint(getter1(i));
for (int i = 0; i < getter1.Count; ++i)
FitPoint(getter1(i));
if (fit2) {
for (int i = 0; i < getter2.Count; ++i)
FitPoint(getter2(i));
for (int i = 0; i < getter2.Count; ++i)
FitPoint(getter2(i));
}
}
const ImPlotNextItemData& s = GetItemData();
Expand All @@ -1149,7 +1169,7 @@ template <typename T>
void PlotShaded(const char* label_id, const T* values, int count, double y_ref, double xscale, double x0, int offset, int stride) {
bool fit2 = true;
if (y_ref == -HUGE_VAL) {
fit2 = false;
fit2 = false;
y_ref = GetPlotLimits().Y.Min;
}
if (y_ref == HUGE_VAL) {
Expand All @@ -1176,7 +1196,7 @@ template <typename T>
void PlotShaded(const char* label_id, const T* xs, const T* ys, int count, double y_ref, int offset, int stride) {
bool fit2 = true;
if (y_ref == -HUGE_VAL) {
fit2 = false;
fit2 = false;
y_ref = GetPlotLimits().Y.Min;
}
if (y_ref == HUGE_VAL) {
Expand Down Expand Up @@ -1592,6 +1612,85 @@ template IMPLOT_API void PlotStems<ImU64>(const char* label_id, const ImU64* xs,
template IMPLOT_API void PlotStems<float>(const char* label_id, const float* xs, const float* ys, int count, double y_ref, int offset, int stride);
template IMPLOT_API void PlotStems<double>(const char* label_id, const double* xs, const double* ys, int count, double y_ref, int offset, int stride);

//-----------------------------------------------------------------------------
// INFINITE LINES
//-----------------------------------------------------------------------------

template <typename T>
void PlotVLines(const char* label_id, const T* xs, int count, int offset, int stride) {
if (BeginItem(label_id, ImPlotCol_Line)) {
const ImPlotLimits lims = GetPlotLimits();
GetterXsYRef<T> get_min(xs,lims.Y.Min,count,offset,stride);
GetterXsYRef<T> get_max(xs,lims.Y.Max,count,offset,stride);
if (FitThisFrame()) {
for (int i = 0; i < get_min.Count; ++i)
FitPointX(get_min(i).x);
}
const ImPlotNextItemData& s = GetItemData();
ImDrawList& DrawList = *GetPlotDrawList();
// render stems
if (s.RenderLine) {
const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_Line]);
switch (GetCurrentScale()) {
case ImPlotScale_LinLin: RenderLineSegments(get_min, get_max, TransformerLinLin(), DrawList, s.LineWeight, col_line); break;
case ImPlotScale_LogLin: RenderLineSegments(get_min, get_max, TransformerLogLin(), DrawList, s.LineWeight, col_line); break;
case ImPlotScale_LinLog: RenderLineSegments(get_min, get_max, TransformerLinLog(), DrawList, s.LineWeight, col_line); break;
case ImPlotScale_LogLog: RenderLineSegments(get_min, get_max, TransformerLogLog(), DrawList, s.LineWeight, col_line); break;
}
}
EndItem();
}
}

template IMPLOT_API void PlotVLines<ImS8>(const char* label_id, const ImS8* xs, int count, int offset, int stride);
template IMPLOT_API void PlotVLines<ImU8>(const char* label_id, const ImU8* xs, int count, int offset, int stride);
template IMPLOT_API void PlotVLines<ImS16>(const char* label_id, const ImS16* xs, int count, int offset, int stride);
template IMPLOT_API void PlotVLines<ImU16>(const char* label_id, const ImU16* xs, int count, int offset, int stride);
template IMPLOT_API void PlotVLines<ImS32>(const char* label_id, const ImS32* xs, int count, int offset, int stride);
template IMPLOT_API void PlotVLines<ImU32>(const char* label_id, const ImU32* xs, int count, int offset, int stride);
template IMPLOT_API void PlotVLines<ImS64>(const char* label_id, const ImS64* xs, int count, int offset, int stride);
template IMPLOT_API void PlotVLines<ImU64>(const char* label_id, const ImU64* xs, int count, int offset, int stride);
template IMPLOT_API void PlotVLines<float>(const char* label_id, const float* xs, int count, int offset, int stride);
template IMPLOT_API void PlotVLines<double>(const char* label_id, const double* xs, int count, int offset, int stride);


template <typename T>
void PlotHLines(const char* label_id, const T* ys, int count, int offset, int stride) {
if (BeginItem(label_id, ImPlotCol_Line)) {
const ImPlotLimits lims = GetPlotLimits();
GetterXRefYs<T> get_min(lims.X.Min,ys,count,offset,stride);
GetterXRefYs<T> get_max(lims.X.Max,ys,count,offset,stride);
if (FitThisFrame()) {
for (int i = 0; i < get_min.Count; ++i)
FitPointY(get_min(i).y);
}
const ImPlotNextItemData& s = GetItemData();
ImDrawList& DrawList = *GetPlotDrawList();
// render stems
if (s.RenderLine) {
const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_Line]);
switch (GetCurrentScale()) {
case ImPlotScale_LinLin: RenderLineSegments(get_min, get_max, TransformerLinLin(), DrawList, s.LineWeight, col_line); break;
case ImPlotScale_LogLin: RenderLineSegments(get_min, get_max, TransformerLogLin(), DrawList, s.LineWeight, col_line); break;
case ImPlotScale_LinLog: RenderLineSegments(get_min, get_max, TransformerLinLog(), DrawList, s.LineWeight, col_line); break;
case ImPlotScale_LogLog: RenderLineSegments(get_min, get_max, TransformerLogLog(), DrawList, s.LineWeight, col_line); break;
}
}
EndItem();
}
}

template IMPLOT_API void PlotHLines<ImS8>(const char* label_id, const ImS8* ys, int count, int offset, int stride);
template IMPLOT_API void PlotHLines<ImU8>(const char* label_id, const ImU8* ys, int count, int offset, int stride);
template IMPLOT_API void PlotHLines<ImS16>(const char* label_id, const ImS16* ys, int count, int offset, int stride);
template IMPLOT_API void PlotHLines<ImU16>(const char* label_id, const ImU16* ys, int count, int offset, int stride);
template IMPLOT_API void PlotHLines<ImS32>(const char* label_id, const ImS32* ys, int count, int offset, int stride);
template IMPLOT_API void PlotHLines<ImU32>(const char* label_id, const ImU32* ys, int count, int offset, int stride);
template IMPLOT_API void PlotHLines<ImS64>(const char* label_id, const ImS64* ys, int count, int offset, int stride);
template IMPLOT_API void PlotHLines<ImU64>(const char* label_id, const ImU64* ys, int count, int offset, int stride);
template IMPLOT_API void PlotHLines<float>(const char* label_id, const float* ys, int count, int offset, int stride);
template IMPLOT_API void PlotHLines<double>(const char* label_id, const double* ys, int count, int offset, int stride);

//-----------------------------------------------------------------------------
// PLOT PIE CHART
//-----------------------------------------------------------------------------
Expand Down

0 comments on commit 49c26be

Please sign in to comment.