Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds PlotVLines and PlotHLines for plotting infinite reference lines #166

Merged
merged 1 commit into from
Jan 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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