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

tidy up multi y axis support

This commit is contained in:
Evan Pezent 2020-05-11 00:45:46 -05:00
parent bece676929
commit 329ad9dd80
3 changed files with 237 additions and 180 deletions

View File

@ -20,7 +20,26 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE. // SOFTWARE.
// ImPlot v0.1 WIP // ImPlot v0.2 WIP
/*
API BREAKING CHANGES
====================
Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix.
Below is a change-log of API breaking changes only. If you are using one of the functions listed, expect to have to fix some code.
When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all implot files.
You can read releases logs https://github.com/epezent/implot/releases for more details.
- 2020/05/10 (0.2) - The following function/struct names were changes:
- ImPlotRange -> ImPlotLimits
- GetPlotRange() -> GetPlotLimits()
- SetNextPlotRange -> SetNextPlotLimits
- SetNextPlotRangeX -> SetNextPlotLimitsX
- SetNextPlotRangeY -> SetNextPlotLimitsY
- 2020/05/10 (0.2) - Plot queries are pixel based by default. Query rects that maintain relative plot position have been removed. This was done to support multi-y-axis.
*/
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
@ -30,6 +49,7 @@
#define IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS
#endif #endif
#include <implot.h> #include <implot.h>
#include <imgui_internal.h> #include <imgui_internal.h>
@ -45,6 +65,8 @@
// Special Color used to specific that a plot item color should set determined automatically. // Special Color used to specific that a plot item color should set determined automatically.
#define IM_COL_AUTO ImVec4(0,0,0,-1) #define IM_COL_AUTO ImVec4(0,0,0,-1)
// The maximum number of support y-axes
#define MAX_Y_AXES 3
ImPlotStyle::ImPlotStyle() { ImPlotStyle::ImPlotStyle() {
LineWeight = 1; LineWeight = 1;
@ -65,8 +87,8 @@ ImPlotStyle::ImPlotStyle() {
Colors[ImPlotCol_PlotBorder] = IM_COL_AUTO; Colors[ImPlotCol_PlotBorder] = IM_COL_AUTO;
Colors[ImPlotCol_XAxis] = IM_COL_AUTO; Colors[ImPlotCol_XAxis] = IM_COL_AUTO;
Colors[ImPlotCol_YAxis] = IM_COL_AUTO; Colors[ImPlotCol_YAxis] = IM_COL_AUTO;
Colors[ImPlotCol_Y2Axis] = IM_COL_AUTO; Colors[ImPlotCol_YAxis2] = IM_COL_AUTO;
Colors[ImPlotCol_Y3Axis] = IM_COL_AUTO; Colors[ImPlotCol_YAxis3] = IM_COL_AUTO;
Colors[ImPlotCol_Selection] = ImVec4(1,1,0,1); Colors[ImPlotCol_Selection] = ImVec4(1,1,0,1);
Colors[ImPlotCol_Query] = ImVec4(0,1,0,1); Colors[ImPlotCol_Query] = ImVec4(0,1,0,1);
} }
@ -81,9 +103,9 @@ float ImPlotRange::Size() const {
return Max - Min; return Max - Min;
} }
ImPlotBounds::ImPlotBounds() {} ImPlotLimits::ImPlotLimits() {}
bool ImPlotBounds::Contains(const ImVec2& p) const { bool ImPlotLimits::Contains(const ImVec2& p) const {
return X.Contains(p.x) && Y.Contains(p.y); return X.Contains(p.x) && Y.Contains(p.y);
} }
@ -91,8 +113,6 @@ namespace ImGui {
namespace { namespace {
#define MAX_Y_AXES 3
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Private Utils // Private Utils
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -242,13 +262,13 @@ struct ImPlotAxis {
Range.Max = 1; Range.Max = 1;
Divisions = 3; Divisions = 3;
Subdivisions = 10; Subdivisions = 10;
Flags = ImAxisFlags_Default; Flags = PreviousFlags = ImAxisFlags_Default;
} }
bool Dragging; bool Dragging;
ImPlotRange Range; ImPlotRange Range;
int Divisions; int Divisions;
int Subdivisions; int Subdivisions;
ImAxisFlags Flags; ImAxisFlags Flags, PreviousFlags;
}; };
/// Holds Plot state information that must persist between frames /// Holds Plot state information that must persist between frames
@ -256,7 +276,7 @@ struct ImPlot {
ImPlot() { ImPlot() {
Selecting = Querying = Queried = DraggingQuery = false; Selecting = Querying = Queried = DraggingQuery = false;
SelectStart = QueryStart = ImVec2(0,0); SelectStart = QueryStart = ImVec2(0,0);
Flags = ImPlotFlags_Default; Flags = PreviousFlags = ImPlotFlags_Default;
ColorIdx = 0; ColorIdx = 0;
CurrentYAxis = 0; CurrentYAxis = 0;
} }
@ -274,17 +294,17 @@ struct ImPlot {
ImPlotAxis XAxis; ImPlotAxis XAxis;
ImPlotAxis YAxis[MAX_Y_AXES]; ImPlotAxis YAxis[MAX_Y_AXES];
ImPlotFlags Flags; ImPlotFlags Flags, PreviousFlags;
int ColorIdx; int ColorIdx;
int CurrentYAxis; int CurrentYAxis;
}; };
struct ImNextPlotData { struct ImNextPlotData {
ImNextPlotData() : HasXBounds{}, HasYBounds{} {} ImNextPlotData() : HasXRange{}, HasYRange{} {}
ImGuiCond XBoundsCond; ImGuiCond XRangeCond;
ImGuiCond YBoundsCond[MAX_Y_AXES]; ImGuiCond YRangeCond[MAX_Y_AXES];
bool HasXBounds; bool HasXRange;
bool HasYBounds[MAX_Y_AXES]; bool HasYRange[MAX_Y_AXES];
ImPlotRange X; ImPlotRange X;
ImPlotRange Y[MAX_Y_AXES]; ImPlotRange Y[MAX_Y_AXES];
}; };
@ -642,7 +662,7 @@ ImRect GetAxisScale(int y_axis, float tx, float ty, float zoom_rate) {
class YPadCalculator { class YPadCalculator {
public: public:
YPadCalculator(const AxisState* axis_states, const float* max_label_widths, int txt_off) YPadCalculator(const AxisState* axis_states, const float* max_label_widths, float txt_off)
: AxisStates(axis_states), MaxLabelWidths(max_label_widths), TxtOff(txt_off) {} : AxisStates(axis_states), MaxLabelWidths(max_label_widths), TxtOff(txt_off) {}
float operator()(int y_axis) { float operator()(int y_axis) {
@ -650,9 +670,9 @@ class YPadCalculator {
if (!AxisStates[y_axis].present) { return 0; } if (!AxisStates[y_axis].present) { return 0; }
// If we have more than 1 axis present before us, then we need // If we have more than 1 axis present before us, then we need
// extra space to account for our tick bar. // extra space to account for our tick bar.
int pad_result = 0; float pad_result = 0;
if (AxisStates[y_axis].present_so_far >= 3) { if (AxisStates[y_axis].present_so_far >= 3) {
pad_result += 6; pad_result += 6.0f;
} }
if (!HasFlag(plot.YAxis[y_axis].Flags, ImAxisFlags_TickLabels)) { if (!HasFlag(plot.YAxis[y_axis].Flags, ImAxisFlags_TickLabels)) {
return pad_result; return pad_result;
@ -664,7 +684,7 @@ class YPadCalculator {
private: private:
const AxisState* const AxisStates; const AxisState* const AxisStates;
const float* const MaxLabelWidths; const float* const MaxLabelWidths;
const int TxtOff; const float TxtOff;
}; };
} // namespace } // namespace
@ -695,13 +715,31 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
plot.CurrentYAxis = 0; plot.CurrentYAxis = 0;
plot.Flags = flags;
if (just_created) { if (just_created) {
plot.Flags = flags;
plot.XAxis.Flags = x_flags; plot.XAxis.Flags = x_flags;
plot.YAxis[0].Flags = y_flags; plot.YAxis[0].Flags = y_flags;
plot.YAxis[1].Flags = y2_flags; plot.YAxis[1].Flags = y2_flags;
plot.YAxis[2].Flags = y3_flags; plot.YAxis[2].Flags = y3_flags;
} }
else {
// TODO: Check which individual flags changed, and only reset those!
// There's probably an easy bit mask trick I'm not aware of.
if (flags != plot.PreviousFlags)
plot.Flags = flags;
if (y_flags != plot.YAxis[0].PreviousFlags)
plot.YAxis[0].PreviousFlags = y_flags;
if (y2_flags != plot.YAxis[1].PreviousFlags)
plot.YAxis[1].PreviousFlags = y2_flags;
if (y3_flags != plot.YAxis[2].PreviousFlags)
plot.YAxis[2].PreviousFlags = y3_flags;
}
plot.PreviousFlags = flags;
plot.XAxis.PreviousFlags = x_flags;
plot.YAxis[0].PreviousFlags = y_flags;
plot.YAxis[1].PreviousFlags = y2_flags;
plot.YAxis[2].PreviousFlags = y3_flags;
// capture scroll with a child region // capture scroll with a child region
if (!HasFlag(plot.Flags, ImPlotFlags_NoChild)) { if (!HasFlag(plot.Flags, ImPlotFlags_NoChild)) {
@ -714,16 +752,16 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
// NextPlotData ----------------------------------------------------------- // NextPlotData -----------------------------------------------------------
if (gp.NextPlotData.HasXBounds) { if (gp.NextPlotData.HasXRange) {
if (just_created || gp.NextPlotData.XBoundsCond == ImGuiCond_Always) if (just_created || gp.NextPlotData.XRangeCond == ImGuiCond_Always)
{ {
plot.XAxis.Range = gp.NextPlotData.X; plot.XAxis.Range = gp.NextPlotData.X;
} }
} }
for (int i = 0; i < MAX_Y_AXES; i++) { for (int i = 0; i < MAX_Y_AXES; i++) {
if (gp.NextPlotData.HasYBounds[i]) { if (gp.NextPlotData.HasYRange[i]) {
if (just_created || gp.NextPlotData.YBoundsCond[i] == ImGuiCond_Always) if (just_created || gp.NextPlotData.YRangeCond[i] == ImGuiCond_Always)
{ {
plot.YAxis[i].Range = gp.NextPlotData.Y[i]; plot.YAxis[i].Range = gp.NextPlotData.Y[i];
} }
@ -731,13 +769,13 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
} }
// AXIS STATES ------------------------------------------------------------ // AXIS STATES ------------------------------------------------------------
AxisState x(plot.XAxis, gp.NextPlotData.HasXBounds, gp.NextPlotData.XBoundsCond, true, 0); AxisState x(plot.XAxis, gp.NextPlotData.HasXRange, gp.NextPlotData.XRangeCond, true, 0);
AxisState y[MAX_Y_AXES]; AxisState y[MAX_Y_AXES];
y[0] = AxisState(plot.YAxis[0], gp.NextPlotData.HasYBounds[0], gp.NextPlotData.YBoundsCond[0], true, 0); y[0] = AxisState(plot.YAxis[0], gp.NextPlotData.HasYRange[0], gp.NextPlotData.YRangeCond[0], true, 0);
y[1] = AxisState(plot.YAxis[1], gp.NextPlotData.HasYBounds[1], gp.NextPlotData.YBoundsCond[1], y[1] = AxisState(plot.YAxis[1], gp.NextPlotData.HasYRange[1], gp.NextPlotData.YRangeCond[1],
HasFlag(plot.Flags, ImPlotFlags_Y2Axis), y[0].present_so_far); HasFlag(plot.Flags, ImPlotFlags_YAxis2), y[0].present_so_far);
y[2] = AxisState(plot.YAxis[2], gp.NextPlotData.HasYBounds[2], gp.NextPlotData.YBoundsCond[2], y[2] = AxisState(plot.YAxis[2], gp.NextPlotData.HasYRange[2], gp.NextPlotData.YRangeCond[2],
HasFlag(plot.Flags, ImPlotFlags_Y3Axis), y[1].present_so_far); HasFlag(plot.Flags, ImPlotFlags_YAxis3), y[1].present_so_far);
const bool lock_plot = x.lock && y[0].lock && y[1].lock && y[2].lock; const bool lock_plot = x.lock && y[0].lock && y[1].lock && y[2].lock;
@ -790,8 +828,8 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
UpdateAxisColor(ImPlotCol_XAxis, &gp.Col_X); UpdateAxisColor(ImPlotCol_XAxis, &gp.Col_X);
UpdateAxisColor(ImPlotCol_YAxis, &gp.Col_Y[0]); UpdateAxisColor(ImPlotCol_YAxis, &gp.Col_Y[0]);
UpdateAxisColor(ImPlotCol_Y2Axis, &gp.Col_Y[1]); UpdateAxisColor(ImPlotCol_YAxis2, &gp.Col_Y[1]);
UpdateAxisColor(ImPlotCol_Y3Axis, &gp.Col_Y[2]); UpdateAxisColor(ImPlotCol_YAxis3, &gp.Col_Y[2]);
gp.Col_Txt = GetColorU32(ImGuiCol_Text); gp.Col_Txt = GetColorU32(ImGuiCol_Text);
gp.Col_TxtDis = GetColorU32(ImGuiCol_TextDisabled); gp.Col_TxtDis = GetColorU32(ImGuiCol_TextDisabled);
@ -866,7 +904,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
gp.Hov_Grid = gp.BB_Grid.Contains(IO.MousePos); gp.Hov_Grid = gp.BB_Grid.Contains(IO.MousePos);
// axis region bbs // axis region bbs
const ImRect xAxisRegion_bb(gp.BB_Grid.Min + ImVec2(10, 0), {gp.BB_Grid.Max.x, gp.BB_Frame.Max.y}); const ImRect xAxisRegion_bb(gp.BB_Grid.Min + ImVec2(10, 0), ImVec2(gp.BB_Grid.Max.x, gp.BB_Frame.Max.y) - ImVec2(10, 0));
const bool hov_x_axis_region = xAxisRegion_bb.Contains(IO.MousePos); const bool hov_x_axis_region = xAxisRegion_bb.Contains(IO.MousePos);
// The left labels are referenced to the left of the bounding box. // The left labels are referenced to the left of the bounding box.
@ -897,14 +935,13 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
y[1].present && (yAxisRegion_bb[1].Contains(IO.MousePos) || centralRegion.Contains(IO.MousePos)), y[1].present && (yAxisRegion_bb[1].Contains(IO.MousePos) || centralRegion.Contains(IO.MousePos)),
y[2].present && (yAxisRegion_bb[2].Contains(IO.MousePos) || centralRegion.Contains(IO.MousePos)), y[2].present && (yAxisRegion_bb[2].Contains(IO.MousePos) || centralRegion.Contains(IO.MousePos)),
}; };
const bool any_hov_y_axis_region = const bool any_hov_y_axis_region = hov_y_axis_region[0] || hov_y_axis_region[1] || hov_y_axis_region[2];
hov_y_axis_region[0] || hov_y_axis_region[1] || hov_y_axis_region[2];
// legend hovered from last frame // legend hovered from last frame
const bool hov_legend = HasFlag(plot.Flags, ImPlotFlags_Legend) ? gp.Hov_Frame && plot.BB_Legend.Contains(IO.MousePos) : false; const bool hov_legend = HasFlag(plot.Flags, ImPlotFlags_Legend) ? gp.Hov_Frame && plot.BB_Legend.Contains(IO.MousePos) : false;
bool hov_query = false; bool hov_query = false;
if (plot.Queried && !plot.Querying) { if (gp.Hov_Frame && gp.Hov_Grid && plot.Queried && !plot.Querying) {
ImRect bb_query = plot.QueryRect; ImRect bb_query = plot.QueryRect;
bb_query.Min += gp.BB_Grid.Min; bb_query.Min += gp.BB_Grid.Min;
@ -922,10 +959,9 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
plot.QueryRect.Min += IO.MouseDelta; plot.QueryRect.Min += IO.MouseDelta;
plot.QueryRect.Max += IO.MouseDelta; plot.QueryRect.Max += IO.MouseDelta;
} }
if (gp.Hov_Frame && hov_query && !plot.DraggingQuery && !plot.Selecting && !hov_legend) { if (gp.Hov_Frame && gp.Hov_Grid && hov_query && !plot.DraggingQuery && !plot.Selecting && !hov_legend) {
SetMouseCursor(ImGuiMouseCursor_ResizeAll); SetMouseCursor(ImGuiMouseCursor_ResizeAll);
const bool any_y_dragging = const bool any_y_dragging = plot.YAxis[0].Dragging || plot.YAxis[1].Dragging || plot.YAxis[2].Dragging;
plot.YAxis[0].Dragging || plot.YAxis[1].Dragging || plot.YAxis[2].Dragging;
if (IO.MouseDown[0] && !plot.XAxis.Dragging && !any_y_dragging) { if (IO.MouseDown[0] && !plot.XAxis.Dragging && !any_y_dragging) {
plot.DraggingQuery = true; plot.DraggingQuery = true;
} }
@ -933,6 +969,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
// DRAG INPUT ------------------------------------------------------------- // DRAG INPUT -------------------------------------------------------------
// end drags // end drags
if (plot.XAxis.Dragging && (IO.MouseReleased[0] || !IO.MouseDown[0])) { if (plot.XAxis.Dragging && (IO.MouseReleased[0] || !IO.MouseDown[0])) {
plot.XAxis.Dragging = false; plot.XAxis.Dragging = false;
@ -944,11 +981,10 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
G.IO.MouseDragMaxDistanceSqr[0] = 0; G.IO.MouseDragMaxDistanceSqr[0] = 0;
} }
} }
const bool any_y_dragging = plot.YAxis[0].Dragging || plot.YAxis[1].Dragging || plot.YAxis[2].Dragging;
bool drag_in_progress = plot.XAxis.Dragging || any_y_dragging;
// do drag // do drag
const bool any_y_dragging = if (drag_in_progress) {
plot.YAxis[0].Dragging || plot.YAxis[1].Dragging || plot.YAxis[2].Dragging;
if (plot.XAxis.Dragging || any_y_dragging) {
UpdateTransformCache(); UpdateTransformCache();
if (!x.lock && plot.XAxis.Dragging) { if (!x.lock && plot.XAxis.Dragging) {
ImVec2 plot_tl = PixelsToPlot(gp.BB_Grid.Min - IO.MouseDelta, 0); ImVec2 plot_tl = PixelsToPlot(gp.BB_Grid.Min - IO.MouseDelta, 0);
@ -993,7 +1029,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
} }
} }
// start drag // start drag
if (gp.Hov_Frame && IO.MouseDragMaxDistanceSqr[0] > 5 && !plot.Selecting && !hov_legend && !hov_query && !plot.DraggingQuery) { if (!drag_in_progress && gp.Hov_Frame && IO.MouseDragMaxDistanceSqr[0] > 5 && !plot.Selecting && !hov_legend && !hov_query && !plot.DraggingQuery) {
if (hov_x_axis_region) { if (hov_x_axis_region) {
plot.XAxis.Dragging = true; plot.XAxis.Dragging = true;
} }
@ -1051,6 +1087,8 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
if (!x.lock_max && !IO.KeyAlt) if (!x.lock_max && !IO.KeyAlt)
plot.XAxis.Range.Max = ImMax(p1.x, p2.x); plot.XAxis.Range.Max = ImMax(p1.x, p2.x);
for (int i = 0; i < MAX_Y_AXES; i++) { for (int i = 0; i < MAX_Y_AXES; i++) {
p1 = PixelsToPlot(plot.SelectStart, i);
p2 = PixelsToPlot(IO.MousePos, i);
if (!y[i].lock_min && !IO.KeyShift) if (!y[i].lock_min && !IO.KeyShift)
plot.YAxis[i].Range.Min = ImMin(p1.y, p2.y); plot.YAxis[i].Range.Min = ImMin(p1.y, p2.y);
if (!y[i].lock_max && !IO.KeyShift) if (!y[i].lock_max && !IO.KeyShift)
@ -1094,21 +1132,21 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
} }
} }
// begin query // begin query
if ((gp.Hov_Frame && gp.Hov_Grid && IO.MouseClicked[2])) { if (HasFlag(plot.Flags, ImPlotFlags_Query) && (gp.Hov_Frame && gp.Hov_Grid && IO.MouseClicked[2])) {
plot.QueryRect = ImRect(0,0,0,0); plot.QueryRect = ImRect(0,0,0,0);
plot.Querying = true; plot.Querying = true;
plot.Queried = true; plot.Queried = true;
plot.QueryStart = IO.MousePos; plot.QueryStart = IO.MousePos;
} }
// toggle between select/query // toggle between select/query
if (plot.Selecting && IO.KeyCtrl) { if (HasFlag(plot.Flags, ImPlotFlags_Query) && plot.Selecting && IO.KeyCtrl) {
plot.Selecting = false; plot.Selecting = false;
plot.QueryRect = ImRect(0,0,0,0); plot.QueryRect = ImRect(0,0,0,0);
plot.Querying = true; plot.Querying = true;
plot.Queried = true; plot.Queried = true;
plot.QueryStart = plot.SelectStart; plot.QueryStart = plot.SelectStart;
} }
if (plot.Querying && !IO.KeyCtrl && !IO.MouseDown[2]) { if (HasFlag(plot.Flags, ImPlotFlags_Selection) && plot.Querying && !IO.KeyCtrl && !IO.MouseDown[2]) {
plot.Selecting = true; plot.Selecting = true;
plot.Querying = false; plot.Querying = false;
plot.Queried = false; plot.Queried = false;
@ -1203,7 +1241,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
PushClipRect(gp.BB_Frame.Min, gp.BB_Frame.Max, true); PushClipRect(gp.BB_Frame.Min, gp.BB_Frame.Max, true);
for (int i = 0; i < MAX_Y_AXES; i++) { for (int i = 0; i < MAX_Y_AXES; i++) {
if (y[i].present && HasFlag(plot.YAxis[i].Flags, ImAxisFlags_TickLabels)) { if (y[i].present && HasFlag(plot.YAxis[i].Flags, ImAxisFlags_TickLabels)) {
const int x_start = const float x_start =
gp.AxisLabelReference[i] + gp.AxisLabelReference[i] +
((i == 0) ? ((i == 0) ?
(-txt_off - max_label_width[0]) : (-txt_off - max_label_width[0]) :
@ -1301,10 +1339,10 @@ void PlotContextMenu(ImPlot& plot) {
ImGui::EndMenu(); ImGui::EndMenu();
} }
for (int i = 0; i < MAX_Y_AXES; i++) { for (int i = 0; i < MAX_Y_AXES; i++) {
if (i == 1 && !HasFlag(plot.Flags, ImPlotFlags_Y2Axis)) { if (i == 1 && !HasFlag(plot.Flags, ImPlotFlags_YAxis2)) {
continue; continue;
} }
if (i == 2 && !HasFlag(plot.Flags, ImPlotFlags_Y3Axis)) { if (i == 2 && !HasFlag(plot.Flags, ImPlotFlags_YAxis3)) {
continue; continue;
} }
char buf[10] = {}; char buf[10] = {};
@ -1396,13 +1434,13 @@ void EndPlot() {
// AXIS STATES ------------------------------------------------------------ // AXIS STATES ------------------------------------------------------------
AxisState x(plot.XAxis, gp.NextPlotData.HasXBounds, gp.NextPlotData.XBoundsCond, true, 0); AxisState x(plot.XAxis, gp.NextPlotData.HasXRange, gp.NextPlotData.XRangeCond, true, 0);
AxisState y[MAX_Y_AXES]; AxisState y[MAX_Y_AXES];
y[0] = AxisState(plot.YAxis[0], gp.NextPlotData.HasYBounds[0], gp.NextPlotData.YBoundsCond[0], true, 0); y[0] = AxisState(plot.YAxis[0], gp.NextPlotData.HasYRange[0], gp.NextPlotData.YRangeCond[0], true, 0);
y[1] = AxisState(plot.YAxis[1], gp.NextPlotData.HasYBounds[1], gp.NextPlotData.YBoundsCond[1], y[1] = AxisState(plot.YAxis[1], gp.NextPlotData.HasYRange[1], gp.NextPlotData.YRangeCond[1],
HasFlag(plot.Flags, ImPlotFlags_Y2Axis), y[0].present_so_far); HasFlag(plot.Flags, ImPlotFlags_YAxis2), y[0].present_so_far);
y[2] = AxisState(plot.YAxis[2], gp.NextPlotData.HasYBounds[2], gp.NextPlotData.YBoundsCond[2], y[2] = AxisState(plot.YAxis[2], gp.NextPlotData.HasYRange[2], gp.NextPlotData.YRangeCond[2],
HasFlag(plot.Flags, ImPlotFlags_Y3Axis), y[1].present_so_far); HasFlag(plot.Flags, ImPlotFlags_YAxis3), y[1].present_so_far);
const bool lock_plot = x.lock && y[0].lock && y[1].lock && y[2].lock; const bool lock_plot = x.lock && y[0].lock && y[1].lock && y[2].lock;
const bool any_y_locked = y[0].lock || y[1].lock || y[2].lock; const bool any_y_locked = y[0].lock || y[1].lock || y[2].lock;
@ -1413,10 +1451,14 @@ void EndPlot() {
PushClipRect(gp.BB_Grid.Min, gp.BB_Frame.Max, true); PushClipRect(gp.BB_Grid.Min, gp.BB_Frame.Max, true);
// render ticks // render ticks
PushPlotClipRect();
if (HasFlag(plot.XAxis.Flags, ImAxisFlags_TickMarks)) { if (HasFlag(plot.XAxis.Flags, ImAxisFlags_TickMarks)) {
for (ImTick &xt : gp.XTicks) for (ImTick &xt : gp.XTicks)
DrawList.AddLine({xt.PixelPos, gp.BB_Grid.Max.y},{xt.PixelPos, gp.BB_Grid.Max.y - (xt.Major ? 10.0f : 5.0f)}, gp.Col_Border, 1); DrawList.AddLine({xt.PixelPos, gp.BB_Grid.Max.y},{xt.PixelPos, gp.BB_Grid.Max.y - (xt.Major ? 10.0f : 5.0f)}, gp.Col_Border, 1);
} }
PopPlotClipRect();
PushClipRect(gp.BB_Grid.Min, {gp.BB_Frame.Max.x, gp.BB_Grid.Max.y}, true);
int axis_count = 0; int axis_count = 0;
for (int i = 0; i < MAX_Y_AXES; i++) { for (int i = 0; i < MAX_Y_AXES; i++) {
if (!y[i].present) { continue; } if (!y[i].present) { continue; }
@ -1425,7 +1467,7 @@ void EndPlot() {
if (!HasFlag(plot.YAxis[i].Flags, ImAxisFlags_TickMarks)) { continue; } if (!HasFlag(plot.YAxis[i].Flags, ImAxisFlags_TickMarks)) { continue; }
float x_start = gp.AxisLabelReference[i]; float x_start = gp.AxisLabelReference[i];
float direction = (i == 0) ? 1.0 : -1.0; float direction = (i == 0) ? 1.0f : -1.0f;
bool no_major = axis_count >= 3; bool no_major = axis_count >= 3;
for (ImTick &yt : gp.YTicks[i]) { for (ImTick &yt : gp.YTicks[i]) {
@ -1446,6 +1488,9 @@ void EndPlot() {
} }
} }
PopClipRect();
PushPlotClipRect();
// render selection/query // render selection/query
if (plot.Selecting) { if (plot.Selecting) {
ImRect select_bb(ImMin(IO.MousePos, plot.SelectStart), ImMax(IO.MousePos, plot.SelectStart)); ImRect select_bb(ImMin(IO.MousePos, plot.SelectStart), ImMax(IO.MousePos, plot.SelectStart));
@ -1568,10 +1613,10 @@ void EndPlot() {
BufferWriter writer(buffer, sizeof(buffer)); BufferWriter writer(buffer, sizeof(buffer));
writer.Write("%.2f,%.2f", gp.LastMousePos[0].x, gp.LastMousePos[0].y); writer.Write("%.2f,%.2f", gp.LastMousePos[0].x, gp.LastMousePos[0].y);
if (HasFlag(plot.Flags, ImPlotFlags_Y2Axis)) { if (HasFlag(plot.Flags, ImPlotFlags_YAxis2)) {
writer.Write(",(%.2f)", gp.LastMousePos[1].y); writer.Write(",(%.2f)", gp.LastMousePos[1].y);
} }
if (HasFlag(plot.Flags, ImPlotFlags_Y3Axis)) { if (HasFlag(plot.Flags, ImPlotFlags_YAxis3)) {
writer.Write(",(%.2f)", gp.LastMousePos[2].y); writer.Write(",(%.2f)", gp.LastMousePos[2].y);
} }
ImVec2 size = CalcTextSize(buffer); ImVec2 size = CalcTextSize(buffer);
@ -1579,7 +1624,7 @@ void EndPlot() {
DrawList.AddText(pos, gp.Col_Txt, buffer); DrawList.AddText(pos, gp.Col_Txt, buffer);
} }
PopClipRect(); PopPlotClipRect();
// render border // render border
DrawList.AddRect(gp.BB_Grid.Min, gp.BB_Grid.Max, gp.Col_Border); DrawList.AddRect(gp.BB_Grid.Min, gp.BB_Grid.Max, gp.Col_Border);
@ -1630,24 +1675,24 @@ void EndPlot() {
// MISC API // MISC API
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void SetNextPlotBounds(float x_min, float x_max, float y_min, float y_max, ImGuiCond cond) { void SetNextPlotLimits(float x_min, float x_max, float y_min, float y_max, ImGuiCond cond) {
SetNextPlotBoundsX(x_min, x_max, cond); SetNextPlotLimitsX(x_min, x_max, cond);
SetNextPlotBoundsY(y_min, y_max, cond); SetNextPlotLimitsY(y_min, y_max, cond);
} }
void SetNextPlotBoundsX(float x_min, float x_max, ImGuiCond cond) { void SetNextPlotLimitsX(float x_min, float x_max, ImGuiCond cond) {
IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
gp.NextPlotData.HasXBounds = true; gp.NextPlotData.HasXRange = true;
gp.NextPlotData.XBoundsCond = cond; gp.NextPlotData.XRangeCond = cond;
gp.NextPlotData.X.Min = x_min; gp.NextPlotData.X.Min = x_min;
gp.NextPlotData.X.Max = x_max; gp.NextPlotData.X.Max = x_max;
} }
void SetNextPlotBoundsY(float y_min, float y_max, ImGuiCond cond, int y_axis) { void SetNextPlotLimitsY(float y_min, float y_max, ImGuiCond cond, int y_axis) {
IM_ASSERT_USER_ERROR(y_axis >= 0 && y_axis < MAX_Y_AXES, "y_axis Needs to be between 0 and MAX_Y_AXES"); IM_ASSERT_USER_ERROR(y_axis >= 0 && y_axis < MAX_Y_AXES, "y_axis Needs to be between 0 and MAX_Y_AXES");
IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
gp.NextPlotData.HasYBounds[y_axis] = true; gp.NextPlotData.HasYRange[y_axis] = true;
gp.NextPlotData.YBoundsCond[y_axis] = cond; gp.NextPlotData.YRangeCond[y_axis] = cond;
gp.NextPlotData.Y[y_axis].Min = y_min; gp.NextPlotData.Y[y_axis].Min = y_min;
gp.NextPlotData.Y[y_axis].Max = y_max; gp.NextPlotData.Y[y_axis].Max = y_max;
} }
@ -1689,16 +1734,16 @@ ImVec2 GetPlotMousePos(int y_axis_in) {
} }
ImPlotBounds GetPlotBounds(int y_axis_in) { ImPlotLimits GetPlotLimits(int y_axis_in) {
IM_ASSERT_USER_ERROR(y_axis_in >= -1 && y_axis_in < MAX_Y_AXES, "y_axis needs to between -1 and MAX_Y_AXES"); IM_ASSERT_USER_ERROR(y_axis_in >= -1 && y_axis_in < MAX_Y_AXES, "y_axis needs to between -1 and MAX_Y_AXES");
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotBounds() Needs to be called between BeginPlot() and EndPlot()!"); IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotLimits() 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;
ImPlot& plot = *gp.CurrentPlot; ImPlot& plot = *gp.CurrentPlot;
ImPlotBounds bounds; ImPlotLimits limits;
bounds.X = plot.XAxis.Range; limits.X = plot.XAxis.Range;
bounds.Y = plot.YAxis[y_axis].Range; limits.Y = plot.YAxis[y_axis].Range;
return bounds; return limits;
} }
bool IsPlotQueried() { bool IsPlotQueried() {
@ -1706,7 +1751,7 @@ bool IsPlotQueried() {
return gp.CurrentPlot->Queried; return gp.CurrentPlot->Queried;
} }
ImPlotBounds GetPlotQuery(int y_axis_in) { ImPlotLimits GetPlotQuery(int y_axis_in) {
IM_ASSERT_USER_ERROR(y_axis_in >= -1 && y_axis_in < MAX_Y_AXES, "y_axis needs to between -1 and MAX_Y_AXES"); IM_ASSERT_USER_ERROR(y_axis_in >= -1 && y_axis_in < MAX_Y_AXES, "y_axis needs to between -1 and MAX_Y_AXES");
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotQuery() Needs to be called between BeginPlot() and EndPlot()!"); IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotQuery() Needs to be called between BeginPlot() and EndPlot()!");
ImPlot& plot = *gp.CurrentPlot; ImPlot& plot = *gp.CurrentPlot;
@ -1716,12 +1761,11 @@ ImPlotBounds GetPlotQuery(int y_axis_in) {
ImVec2 p1 = PixelsToPlot(plot.QueryRect.Min + gp.BB_Grid.Min, y_axis); ImVec2 p1 = PixelsToPlot(plot.QueryRect.Min + gp.BB_Grid.Min, y_axis);
ImVec2 p2 = PixelsToPlot(plot.QueryRect.Max + gp.BB_Grid.Min, y_axis); ImVec2 p2 = PixelsToPlot(plot.QueryRect.Max + gp.BB_Grid.Min, y_axis);
ImPlotBounds result; ImPlotLimits result;
result.X.Min = ImMin(p1.x, p2.x); result.X.Min = ImMin(p1.x, p2.x);
result.X.Max = ImMax(p1.x, p2.x); result.X.Max = ImMax(p1.x, p2.x);
result.Y.Min = ImMin(p1.y, p2.y); result.Y.Min = ImMin(p1.y, p2.y);
result.Y.Max = ImMax(p1.y, p2.y); result.Y.Max = ImMax(p1.y, p2.y);
return result; return result;
} }
@ -2520,10 +2564,10 @@ inline void PlotDigitalEx(const char* label_id, Getter getter, int count, int of
if (count > 1 && rend_line) { if (count > 1 && rend_line) {
// //
const float mx = (gp.PixelRange[ax].Max.x - gp.PixelRange[ax].Min.x) / gp.CurrentPlot->XAxis.Range.Size(); const float mx = (gp.PixelRange[ax].Max.x - gp.PixelRange[ax].Min.x) / gp.CurrentPlot->XAxis.Range.Size();
int pixY_0 = line_weight; float pixY_0 = line_weight;
int pixY_1 = gp.Style.DigitalBitHeight; float pixY_1 = gp.Style.DigitalBitHeight;
int pixY_Offset = 20;//20 pixel from bottom due to mouse cursor label float pixY_Offset = 20;//20 pixel from bottom due to mouse cursor label
int pixY_chOffset = pixY_1 + 3; //3 pixels between channels float pixY_chOffset = pixY_1 + 3; //3 pixels between channels
ImVec2 pMin, pMax; ImVec2 pMin, pMax;
float y0 = (gp.PixelRange[ax].Min.y) + ((-pixY_chOffset * gp.DigitalPlotItemCnt) - pixY_0 - pixY_Offset); float y0 = (gp.PixelRange[ax].Min.y) + ((-pixY_chOffset * gp.DigitalPlotItemCnt) - pixY_0 - pixY_Offset);
float y1 = (gp.PixelRange[ax].Min.y) + ((-pixY_chOffset * gp.DigitalPlotItemCnt) - pixY_1 - pixY_Offset); float y1 = (gp.PixelRange[ax].Min.y) + ((-pixY_chOffset * gp.DigitalPlotItemCnt) - pixY_1 - pixY_Offset);
@ -2554,7 +2598,7 @@ inline void PlotDigitalEx(const char* label_id, Getter getter, int count, int of
//plot a rectangle that extends up to x2 with y1 height //plot a rectangle that extends up to x2 with y1 height
if ((pMax.x > pMin.x) && (!cull || gp.BB_Grid.Contains(pMin) || gp.BB_Grid.Contains(pMax))) { if ((pMax.x > pMin.x) && (!cull || gp.BB_Grid.Contains(pMin) || gp.BB_Grid.Contains(pMax))) {
ImVec4 colAlpha = item->Color; ImVec4 colAlpha = item->Color;
colAlpha.w = item->Highlight ? 1.0 : 0.9; colAlpha.w = item->Highlight ? 1.0f : 0.9f;
DrawList.AddRectFilled(pMin, pMax, GetColorU32(colAlpha)); DrawList.AddRectFilled(pMin, pMax, GetColorU32(colAlpha));
} }
} }

View File

@ -20,7 +20,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE. // SOFTWARE.
// ImPlot v0.1 WIP // ImPlot v0.2 WIP
#pragma once #pragma once
#include <imgui.h> #include <imgui.h>
@ -41,13 +41,14 @@ enum ImPlotFlags_ {
ImPlotFlags_Legend = 1 << 1, // a legend will be displayed in the top-left ImPlotFlags_Legend = 1 << 1, // a legend will be displayed in the top-left
ImPlotFlags_Highlight = 1 << 2, // plot items will be highlighted when their legend entry is hovered ImPlotFlags_Highlight = 1 << 2, // plot items will be highlighted when their legend entry is hovered
ImPlotFlags_Selection = 1 << 3, // the user will be able to box-select with right-mouse ImPlotFlags_Selection = 1 << 3, // the user will be able to box-select with right-mouse
ImPlotFlags_ContextMenu = 1 << 4, // the user will be able to open a context menu with double-right click ImPlotFlags_Query = 1 << 4, // the user will be able to draw query rects with middle-mouse
ImPlotFlags_Crosshairs = 1 << 5, // the default mouse cursor will be replaced with a crosshair when hovered ImPlotFlags_ContextMenu = 1 << 5, // the user will be able to open a context menu with double-right click
ImPlotFlags_CullData = 1 << 6, // plot data outside the plot area will be culled from rendering ImPlotFlags_Crosshairs = 1 << 6, // the default mouse cursor will be replaced with a crosshair when hovered
ImPlotFlags_AntiAliased = 1 << 7, // lines and fills will be anti-aliased (not recommended) ImPlotFlags_CullData = 1 << 7, // plot data outside the plot area will be culled from rendering
ImPlotFlags_NoChild = 1 << 8, // a child window region will not be used to capture mouse scroll (can boost performance for single ImGui window applications) ImPlotFlags_AntiAliased = 1 << 8, // lines and fills will be anti-aliased (not recommended)
ImPlotFlags_Y2Axis = 1 << 9, // enable a second y axis ImPlotFlags_NoChild = 1 << 9, // a child window region will not be used to capture mouse scroll (can boost performance for single ImGui window applications)
ImPlotFlags_Y3Axis = 1 << 10, // enable a third y axis ImPlotFlags_YAxis2 = 1 << 10, // enable a 2nd y axis
ImPlotFlags_YAxis3 = 1 << 11, // enable a 3rd y axis
ImPlotFlags_Default = ImPlotFlags_MousePos | ImPlotFlags_Legend | ImPlotFlags_Highlight | ImPlotFlags_Selection | ImPlotFlags_ContextMenu | ImPlotFlags_CullData ImPlotFlags_Default = ImPlotFlags_MousePos | ImPlotFlags_Legend | ImPlotFlags_Highlight | ImPlotFlags_Selection | ImPlotFlags_ContextMenu | ImPlotFlags_CullData
}; };
@ -63,7 +64,7 @@ enum ImAxisFlags_ {
ImAxisFlags_LogScale = 1 << 7, // a logartithmic (base 10) axis scale will be used ImAxisFlags_LogScale = 1 << 7, // a logartithmic (base 10) axis scale will be used
ImAxisFlags_Scientific = 1 << 8, // scientific notation will be used for tick labels if displayed (WIP, not very good yet) ImAxisFlags_Scientific = 1 << 8, // scientific notation will be used for tick labels if displayed (WIP, not very good yet)
ImAxisFlags_Default = ImAxisFlags_GridLines | ImAxisFlags_TickMarks | ImAxisFlags_TickLabels | ImAxisFlags_Adaptive, ImAxisFlags_Default = ImAxisFlags_GridLines | ImAxisFlags_TickMarks | ImAxisFlags_TickLabels | ImAxisFlags_Adaptive,
ImAxisFlags_Auxiliary_Default = ImAxisFlags_Default & ~ImAxisFlags_GridLines, ImAxisFlags_Auxiliary = ImAxisFlags_Default & ~ImAxisFlags_GridLines,
}; };
// Plot styling colors // Plot styling colors
@ -76,15 +77,16 @@ enum ImPlotCol_ {
ImPlotCol_FrameBg, // plot frame background color (defaults to ImGuiCol_FrameBg) ImPlotCol_FrameBg, // plot frame background color (defaults to ImGuiCol_FrameBg)
ImPlotCol_PlotBg, // plot area background color (defaults to ImGuiCol_WindowBg) ImPlotCol_PlotBg, // plot area background color (defaults to ImGuiCol_WindowBg)
ImPlotCol_PlotBorder, // plot area border color (defaults to ImGuiCol_Text) ImPlotCol_PlotBorder, // plot area border color (defaults to ImGuiCol_Text)
ImPlotCol_XAxis, // x-axis grid/label color (defaults to ImGuiCol_Text) ImPlotCol_XAxis, // x-axis grid/label color (defaults to 25% ImGuiCol_Text)
ImPlotCol_YAxis, // y-axis grid/label color (defaults to ImGuiCol_Text) ImPlotCol_YAxis, // y-axis grid/label color (defaults to 25% ImGuiCol_Text)
ImPlotCol_Y2Axis, // y2-axis grid/label color (defaults to ImGuiCol_Text) ImPlotCol_YAxis2, // 2nd y-axis grid/label color (defaults to 25% ImGuiCol_Text)
ImPlotCol_Y3Axis, // y3-axis grid/label color (defaults to ImGuiCol_Text) ImPlotCol_YAxis3, // 3rd y-axis grid/label color (defaults to 25% ImGuiCol_Text)
ImPlotCol_Selection, // box-selection color (defaults to yellow) ImPlotCol_Selection, // box-selection color (defaults to yellow)
ImPlotCol_Query, // box-query color (defaults to green) ImPlotCol_Query, // box-query color (defaults to green)
ImPlotCol_COUNT ImPlotCol_COUNT
}; };
// Plot styling variables
enum ImPlotStyleVar_ { enum ImPlotStyleVar_ {
ImPlotStyleVar_LineWeight, // float, line weight in pixels ImPlotStyleVar_LineWeight, // float, line weight in pixels
ImPlotStyleVar_Marker, // int, marker specification ImPlotStyleVar_Marker, // int, marker specification
@ -111,17 +113,18 @@ enum ImMarker_ {
ImMarker_Asterisk = 1 << 10, // a asterisk marker will be rendered at each point (not filled) ImMarker_Asterisk = 1 << 10, // a asterisk marker will be rendered at each point (not filled)
}; };
// A range defined by a min/max value. Used for plot axes ranges.
struct ImPlotRange { struct ImPlotRange {
float Min, Max; float Min, Max;
ImPlotRange(); ImPlotRange();
bool Contains(float) const; bool Contains(float value) const;
float Size() const; float Size() const;
}; };
/// Plot range utility struct // Combination of two ranges for X and Y axes.
struct ImPlotBounds { struct ImPlotLimits {
ImPlotRange X, Y; ImPlotRange X, Y;
ImPlotBounds(); ImPlotLimits();
bool Contains(const ImVec2& p) const; bool Contains(const ImVec2& p) const;
}; };
@ -148,8 +151,7 @@ namespace ImGui {
// be called, e.g. "if (BeginPlot(...)) { ... EndPlot(); }"". #title_id must // be called, e.g. "if (BeginPlot(...)) { ... EndPlot(); }"". #title_id must
// be unique. If you need to avoid ID collisions or don't want to display a // be unique. If you need to avoid ID collisions or don't want to display a
// title in the plot, use double hashes (e.g. "MyPlot##Hidden"). If #x_label // title in the plot, use double hashes (e.g. "MyPlot##Hidden"). If #x_label
// and/or #y_label are provided, axes labels will be displayed. Axis flags are // and/or #y_label are provided, axes labels will be displayed.
// only set ONCE during the first call to BeginPlot.
bool BeginPlot(const char* title_id, bool BeginPlot(const char* title_id,
const char* x_label = NULL, const char* x_label = NULL,
const char* y_label = NULL, const char* y_label = NULL,
@ -157,8 +159,8 @@ bool BeginPlot(const char* title_id,
ImPlotFlags flags = ImPlotFlags_Default, ImPlotFlags flags = ImPlotFlags_Default,
ImAxisFlags x_flags = ImAxisFlags_Default, ImAxisFlags x_flags = ImAxisFlags_Default,
ImAxisFlags y_flags = ImAxisFlags_Default, ImAxisFlags y_flags = ImAxisFlags_Default,
ImAxisFlags y2_flags = ImAxisFlags_Auxiliary_Default, ImAxisFlags y2_flags = ImAxisFlags_Auxiliary,
ImAxisFlags y3_flags = ImAxisFlags_Auxiliary_Default); ImAxisFlags y3_flags = ImAxisFlags_Auxiliary);
// Only call EndPlot() if BeginPlot() returns true! Typically called at the end // Only call EndPlot() if BeginPlot() returns true! Typically called at the end
// of an if statement conditioned on BeginPlot(). // of an if statement conditioned on BeginPlot().
void EndPlot(); void EndPlot();
@ -201,11 +203,11 @@ bool IsPlotHovered();
/// Returns the mouse position in x,y coordinates of the current or most recent plot. A negative y_axis uses the current value of SetPlotYAxis (0 initially). /// Returns the mouse position in x,y coordinates of the current or most recent plot. A negative y_axis uses the current value of SetPlotYAxis (0 initially).
ImVec2 GetPlotMousePos(int y_axis = -1); ImVec2 GetPlotMousePos(int y_axis = -1);
/// Returns the current or most recent plot axis range. A negative y_axis uses the current value of SetPlotYAxis (0 initially). /// Returns the current or most recent plot axis range. A negative y_axis uses the current value of SetPlotYAxis (0 initially).
ImPlotBounds GetPlotBounds(int y_axis = -1); ImPlotLimits GetPlotLimits(int y_axis = -1);
/// Returns true if the current or most recent plot is being queried. /// Returns true if the current or most recent plot is being queried.
bool IsPlotQueried(); bool IsPlotQueried();
/// Returns the current or most recent plot query bounds. /// Returns the current or most recent plot query bounds.
ImPlotBounds GetPlotQuery(int y_axis = -1); ImPlotLimits GetPlotQuery(int y_axis = -1);
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Plot Styling // Plot Styling
@ -237,15 +239,15 @@ void PopPlotStyleVar(int count = 1);
// Plot Utils // Plot Utils
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/// Set the axes ranges of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axes will be locked. /// Set the axes range limits of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axes limits will be locked.
void SetNextPlotBounds(float x_min, float x_max, float y_min, float y_max, ImGuiCond cond = ImGuiCond_Once); void SetNextPlotLimits(float x_min, float x_max, float y_min, float y_max, ImGuiCond cond = ImGuiCond_Once);
/// Set the X axis range of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axis will be locked. /// Set the X axis range limits of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axis limits will be locked.
void SetNextPlotBoundsX(float x_min, float x_max, ImGuiCond cond = ImGuiCond_Once); void SetNextPlotLimitsX(float x_min, float x_max, ImGuiCond cond = ImGuiCond_Once);
/// Set the Y axis range of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axis will be locked. /// Set the Y axis range limits of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axis limits will be locked.
void SetNextPlotBoundsY(float y_min, float y_max, ImGuiCond cond = ImGuiCond_Once, int y_axis = 0); void SetNextPlotLimitsY(float y_min, float y_max, ImGuiCond cond = ImGuiCond_Once, int y_axis = 0);
/// Select which Y axis will be used for subsequent plot elements. The default is '0', or the first Y axis. /// Select which Y axis will be used for subsequent plot elements. The default is '0', or the first Y axis.
void SetPlotYAxis(int); void SetPlotYAxis(int y_axis);
// Get the current Plot position (top-left) in pixels. // Get the current Plot position (top-left) in pixels.
ImVec2 GetPlotPos(); ImVec2 GetPlotPos();

View File

@ -20,7 +20,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE. // SOFTWARE.
// ImPlot v0.1 WIP // ImPlot v0.2 WIP
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
@ -95,7 +95,7 @@ void ShowImPlotDemoWindow(bool* p_open) {
ImGui::SetNextWindowPos(ImVec2(50, 50), ImGuiCond_FirstUseEver); ImGui::SetNextWindowPos(ImVec2(50, 50), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(520, 750), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(520, 750), ImGuiCond_FirstUseEver);
ImGui::Begin("ImPlot Demo", p_open); ImGui::Begin("ImPlot Demo", p_open);
ImGui::Text("ImPlot says hello. (0.1 WIP)"); ImGui::Text("ImPlot says hello. (0.2 WIP)");
if (ImGui::CollapsingHeader("Help")) { if (ImGui::CollapsingHeader("Help")) {
ImGui::Text("USER GUIDE:"); ImGui::Text("USER GUIDE:");
ImGui::BulletText("Left click and drag within the plot area to pan X and Y axes."); ImGui::BulletText("Left click and drag within the plot area to pan X and Y axes.");
@ -112,11 +112,6 @@ void ShowImPlotDemoWindow(bool* p_open) {
ImGui::BulletText("Hold Shift to expand box selection vertically."); ImGui::BulletText("Hold Shift to expand box selection vertically.");
ImGui::BulletText("Left click while box selecting to cancel the selection."); ImGui::BulletText("Left click while box selecting to cancel the selection.");
ImGui::Unindent(); ImGui::Unindent();
ImGui::BulletText("Middle click (or Ctrl + right click) and drag to create a query range.");
ImGui::Indent();
ImGui::BulletText("Hold Alt to expand query horizontally.");
ImGui::BulletText("Hold Shift to expand query vertically.");
ImGui::Unindent();
ImGui::BulletText("Double left click to fit all visible data."); ImGui::BulletText("Double left click to fit all visible data.");
ImGui::Indent(); ImGui::Indent();
ImGui::BulletText("Double left click on an axis to fit the individual axis."); ImGui::BulletText("Double left click on an axis to fit the individual axis.");
@ -176,9 +171,9 @@ void ShowImPlotDemoWindow(bool* p_open) {
static bool horz = false; static bool horz = false;
ImGui::Checkbox("Horizontal",&horz); ImGui::Checkbox("Horizontal",&horz);
if (horz) if (horz)
ImGui::SetNextPlotBounds(0, 110, -0.5f, 9.5f, ImGuiCond_Always); ImGui::SetNextPlotLimits(0, 110, -0.5f, 9.5f, ImGuiCond_Always);
else else
ImGui::SetNextPlotBounds(-0.5f, 9.5f, 0, 110, ImGuiCond_Always); ImGui::SetNextPlotLimits(-0.5f, 9.5f, 0, 110, ImGuiCond_Always);
if (ImGui::BeginPlot("Bar Plot", horz ? "Score": "Student", horz ? "Student" : "Score", {-1, 300})) { if (ImGui::BeginPlot("Bar Plot", horz ? "Score": "Student", horz ? "Student" : "Score", {-1, 300})) {
static float midtm[10] = {83, 67, 23, 89, 83, 78, 91, 82, 85, 90}; static float midtm[10] = {83, 67, 23, 89, 83, 78, 91, 82, 85, 90};
static float final[10] = {80, 62, 56, 99, 55, 78, 88, 78, 90, 100}; static float final[10] = {80, 62, 56, 99, 55, 78, 88, 78, 90, 100};
@ -203,7 +198,7 @@ void ShowImPlotDemoWindow(bool* p_open) {
float bar[5] = {1,2,5,3,4}; float bar[5] = {1,2,5,3,4};
float err1[5] = {0.2f, 0.4f, 0.2f, 0.6f, 0.4f}; float err1[5] = {0.2f, 0.4f, 0.2f, 0.6f, 0.4f};
float err2[5] = {0.4f, 0.2f, 0.4f, 0.8f, 0.6f}; float err2[5] = {0.4f, 0.2f, 0.4f, 0.8f, 0.6f};
ImGui::SetNextPlotBounds(0, 6, 0, 10); ImGui::SetNextPlotLimits(0, 6, 0, 10);
if (ImGui::BeginPlot("##ErrorBars",NULL,NULL,ImVec2(-1,300))) { if (ImGui::BeginPlot("##ErrorBars",NULL,NULL,ImVec2(-1,300))) {
ImGui::PlotBar("Bar", xs, bar, 5, 0.5f); ImGui::PlotBar("Bar", xs, bar, 5, 0.5f);
@ -227,7 +222,7 @@ void ShowImPlotDemoWindow(bool* p_open) {
ImVec2 center(0.5f,0.5f); // in plot units, not pixels ImVec2 center(0.5f,0.5f); // in plot units, not pixels
float radius = 0.4f; // in plot units, not pixels float radius = 0.4f; // in plot units, not pixels
SetNextPlotBounds(0,1,0,1,ImGuiCond_Always); SetNextPlotLimits(0,1,0,1,ImGuiCond_Always);
if (ImGui::BeginPlot("##Pie1", NULL, NULL, ImVec2(250,250), ImPlotFlags_Legend, 0, 0)) { if (ImGui::BeginPlot("##Pie1", NULL, NULL, ImVec2(250,250), ImPlotFlags_Legend, 0, 0)) {
ImGui::PlotPieChart(labels1, pre_normalized, 4, center, radius); ImGui::PlotPieChart(labels1, pre_normalized, 4, center, radius);
ImGui::EndPlot(); ImGui::EndPlot();
@ -242,7 +237,7 @@ void ShowImPlotDemoWindow(bool* p_open) {
{0.7412f, 0.0f, 0.1490f, 1.0f}, {0.7412f, 0.0f, 0.1490f, 1.0f},
}; };
ImGui::SetPlotPalette(YlOrRd, 5); ImGui::SetPlotPalette(YlOrRd, 5);
SetNextPlotBounds(0,1,0,1,ImGuiCond_Always); SetNextPlotLimits(0,1,0,1,ImGuiCond_Always);
static const char* labels2[] = {"One","Two","Three","Four","Five"}; static const char* labels2[] = {"One","Two","Three","Four","Five"};
static float not_normalized[] = {1,2,3,4,5}; static float not_normalized[] = {1,2,3,4,5};
if (ImGui::BeginPlot("##Pie2", NULL, NULL, ImVec2(250,250), ImPlotFlags_Legend, 0, 0)) { if (ImGui::BeginPlot("##Pie2", NULL, NULL, ImVec2(250,250), ImPlotFlags_Legend, 0, 0)) {
@ -268,14 +263,14 @@ void ShowImPlotDemoWindow(bool* p_open) {
sdata2.AddPoint(t, mouse.y * 0.0005f); sdata2.AddPoint(t, mouse.y * 0.0005f);
rdata2.AddPoint(t, mouse.y * 0.0005f); rdata2.AddPoint(t, mouse.y * 0.0005f);
} }
ImGui::SetNextPlotBoundsX(t - 10, t, paused ? ImGuiCond_Once : ImGuiCond_Always); ImGui::SetNextPlotLimitsX(t - 10, t, paused ? ImGuiCond_Once : ImGuiCond_Always);
static int rt_axis = ImAxisFlags_Default & ~ImAxisFlags_TickLabels; static int rt_axis = ImAxisFlags_Default & ~ImAxisFlags_TickLabels;
if (ImGui::BeginPlot("##Scrolling", NULL, NULL, {-1,150}, ImPlotFlags_Default, rt_axis, rt_axis)) { if (ImGui::BeginPlot("##Scrolling", NULL, NULL, {-1,150}, ImPlotFlags_Default, rt_axis, rt_axis)) {
ImGui::Plot("Data 1", &sdata1.Data[0].x, &sdata1.Data[0].y, sdata1.Data.size(), sdata1.Offset, 2 * sizeof(float)); ImGui::Plot("Data 1", &sdata1.Data[0].x, &sdata1.Data[0].y, sdata1.Data.size(), sdata1.Offset, 2 * sizeof(float));
ImGui::Plot("Data 2", &sdata2.Data[0].x, &sdata2.Data[0].y, sdata2.Data.size(), sdata2.Offset, 2 * sizeof(float)); ImGui::Plot("Data 2", &sdata2.Data[0].x, &sdata2.Data[0].y, sdata2.Data.size(), sdata2.Offset, 2 * sizeof(float));
ImGui::EndPlot(); ImGui::EndPlot();
} }
ImGui::SetNextPlotBoundsX(0, 10, ImGuiCond_Always); ImGui::SetNextPlotLimitsX(0, 10, ImGuiCond_Always);
if (ImGui::BeginPlot("##Rolling", NULL, NULL, {-1,150}, ImPlotFlags_Default, rt_axis, rt_axis)) { if (ImGui::BeginPlot("##Rolling", NULL, NULL, {-1,150}, ImPlotFlags_Default, rt_axis, rt_axis)) {
ImGui::Plot("Data 1", &rdata1.Data[0].x, &rdata1.Data[0].y, rdata1.Data.size(), 0, 2 * sizeof(float)); ImGui::Plot("Data 1", &rdata1.Data[0].x, &rdata1.Data[0].y, rdata1.Data.size(), 0, 2 * sizeof(float));
ImGui::Plot("Data 2", &rdata2.Data[0].x, &rdata2.Data[0].y, rdata2.Data.size(), 0, 2 * sizeof(float)); ImGui::Plot("Data 2", &rdata2.Data[0].x, &rdata2.Data[0].y, rdata2.Data.size(), 0, 2 * sizeof(float));
@ -285,7 +280,7 @@ void ShowImPlotDemoWindow(bool* p_open) {
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Markers and Labels")) { if (ImGui::CollapsingHeader("Markers and Labels")) {
ImGui::SetNextPlotBounds(0, 10, 0, 12); ImGui::SetNextPlotLimits(0, 10, 0, 12);
if (ImGui::BeginPlot("##MarkerStyles", NULL, NULL, ImVec2(-1,300), 0, 0, 0)) { if (ImGui::BeginPlot("##MarkerStyles", NULL, NULL, ImVec2(-1,300), 0, 0, 0)) {
float xs[2] = {1,4}; float xs[2] = {1,4};
float ys[2] = {10,11}; float ys[2] = {10,11};
@ -369,7 +364,7 @@ void ShowImPlotDemoWindow(bool* p_open) {
ys2[i] = log(xs[i]); ys2[i] = log(xs[i]);
ys3[i] = pow(10.0f, xs[i]); ys3[i] = pow(10.0f, xs[i]);
} }
ImGui::SetNextPlotBounds(0.1f, 100, 0, 10); ImGui::SetNextPlotLimits(0.1f, 100, 0, 10);
if (ImGui::BeginPlot("Log Plot", NULL, NULL, ImVec2(-1,300), ImPlotFlags_Default, ImAxisFlags_Default | ImAxisFlags_LogScale )) { if (ImGui::BeginPlot("Log Plot", NULL, NULL, ImVec2(-1,300), ImPlotFlags_Default, ImAxisFlags_Default | ImAxisFlags_LogScale )) {
ImGui::Plot("f(x) = x", xs, xs, 1001); ImGui::Plot("f(x) = x", xs, xs, 1001);
ImGui::Plot("f(x) = sin(x)+1", xs, ys1, 1001); ImGui::Plot("f(x) = sin(x)+1", xs, ys1, 1001);
@ -379,25 +374,43 @@ void ShowImPlotDemoWindow(bool* p_open) {
} }
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Multiple Y Axes")) { if (ImGui::CollapsingHeader("Multiple Y-Axes")) {
static ImVec4 txt_col = ImGui::GetStyle().Colors[ImGuiCol_Text];
txt_col.w = 0.25f;
static ImVec4 y1_col = txt_col;
static ImVec4 y2_col = txt_col;
static ImVec4 y3_col = txt_col;
static float xs[1001], xs2[1001], ys1[1001], ys2[1001], ys3[1001]; static float xs[1001], xs2[1001], ys1[1001], ys2[1001], ys3[1001];
static bool y2_axis = true; static bool y2_axis = true;
static bool y3_axis = false; static bool y3_axis = false;
ImGui::Checkbox("Y-Axis 2", &y2_axis);
ImGui::SameLine();
ImGui::Checkbox("Y-Axis 3", &y3_axis);
ImGui::SameLine();
ImGui::ColorEdit4("##Col1", &y1_col.x, ImGuiColorEditFlags_NoInputs);
ImGui::SameLine();
ImGui::ColorEdit4("##Col2", &y2_col.x, ImGuiColorEditFlags_NoInputs);
ImGui::SameLine();
ImGui::ColorEdit4("##Col3", &y3_col.x, ImGuiColorEditFlags_NoInputs);
for (int i = 0; i < 1001; ++i) { for (int i = 0; i < 1001; ++i) {
xs[i] = (float)(i*0.1f); xs[i] = (float)(i*0.1f);
ys1[i] = sin(xs[i]) * 3 + 1; ys1[i] = sin(xs[i]) * 3 + 1;
ys2[i] = cos(xs[i]) * 0.2 + 0.5; ys2[i] = cos(xs[i]) * 0.2f + 0.5f;
ys3[i] = sin(xs[i]+.5) * 100 + 200; ys3[i] = sin(xs[i]+0.5f) * 100 + 200;
xs2[i] = xs[i] + 10.0; xs2[i] = xs[i] + 10.0f;
} }
ImGui::SetNextPlotBounds(0.1f, 100, 0, 10); ImGui::SetNextPlotLimits(0.1f, 100, 0, 10);
ImGui::SetNextPlotBoundsY(0, 1, ImGuiCond_Once, 1); ImGui::SetNextPlotLimitsY(0, 1, ImGuiCond_Once, 1);
ImGui::SetNextPlotBoundsY(0, 300, ImGuiCond_Once, 2); ImGui::SetNextPlotLimitsY(0, 300, ImGuiCond_Once, 2);
ImGui::PushPlotColor(ImPlotCol_YAxis, y1_col);
ImGui::PushPlotColor(ImPlotCol_YAxis2, y2_col);
ImGui::PushPlotColor(ImPlotCol_YAxis3, y3_col);
if (ImGui::BeginPlot("Multi-Axis Plot", NULL, NULL, ImVec2(-1,300), if (ImGui::BeginPlot("Multi-Axis Plot", NULL, NULL, ImVec2(-1,300),
ImPlotFlags_Default | ImPlotFlags_Default |
(y2_axis ? ImPlotFlags_Y2Axis : 0) | (y2_axis ? ImPlotFlags_YAxis2 : 0) |
(y3_axis ? ImPlotFlags_Y3Axis : 0))) { (y3_axis ? ImPlotFlags_YAxis3 : 0))) {
ImGui::Plot("f(x) = x", xs, xs, 1001); ImGui::Plot("f(x) = x", xs, xs, 1001);
ImGui::Plot("f(x) = sin(x)*3+1", xs, ys1, 1001); ImGui::Plot("f(x) = sin(x)*3+1", xs, ys1, 1001);
@ -413,18 +426,20 @@ void ShowImPlotDemoWindow(bool* p_open) {
ImGui::EndPlot(); ImGui::EndPlot();
} }
ImGui::Checkbox("Y2 Axis", &y2_axis); ImGui::PopPlotColor(3);
ImGui::SameLine();
ImGui::Checkbox("Y3 Axis", &y3_axis);
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Querying")) { if (ImGui::CollapsingHeader("Querying")) {
ImGui::BulletText("Ctrl + click in the plot area to draw points."); ImGui::BulletText("Ctrl + click in the plot area to draw points.");
ImGui::BulletText("Middle click (or Ctrl + right click) and drag to query points."); ImGui::BulletText("Middle click (or Ctrl + right click) and drag to create a query rect.");
ImGui::BulletText("Hold the Alt and/or Shift keys to expand the query range."); ImGui::Indent();
ImGui::BulletText("Hold Alt to expand query horizontally.");
ImGui::BulletText("Hold Shift to expand query vertically.");
ImGui::BulletText("The query rect can be dragged after it's created.");
ImGui::Unindent();
static ImVector<ImVec2> data; static ImVector<ImVec2> data;
ImPlotBounds range, query; ImPlotLimits range, query;
if (ImGui::BeginPlot("##Drawing", NULL, NULL, ImVec2(-1,300), ImPlotFlags_Default, ImAxisFlags_GridLines, ImAxisFlags_GridLines)) { if (ImGui::BeginPlot("##Drawing", NULL, NULL, ImVec2(-1,300), ImPlotFlags_Default | ImPlotFlags_Query, ImAxisFlags_GridLines, ImAxisFlags_GridLines)) {
if (ImGui::IsPlotHovered() && ImGui::IsMouseClicked(0) && ImGui::GetIO().KeyCtrl) if (ImGui::IsPlotHovered() && ImGui::IsMouseClicked(0) && ImGui::GetIO().KeyCtrl)
data.push_back(ImGui::GetPlotMousePos()); data.push_back(ImGui::GetPlotMousePos());
ImGui::PushPlotStyleVar(ImPlotStyleVar_LineWeight, 0); ImGui::PushPlotStyleVar(ImPlotStyleVar_LineWeight, 0);
@ -432,7 +447,7 @@ void ShowImPlotDemoWindow(bool* p_open) {
if (data.size() > 0) if (data.size() > 0)
ImGui::Plot("Points", &data[0].x, &data[0].y, data.size(), 0, 2 * sizeof(float)); ImGui::Plot("Points", &data[0].x, &data[0].y, data.size(), 0, 2 * sizeof(float));
if (ImGui::IsPlotQueried() && data.size() > 0) { if (ImGui::IsPlotQueried() && data.size() > 0) {
ImPlotBounds range = ImGui::GetPlotQuery(); ImPlotLimits range = ImGui::GetPlotQuery();
int cnt = 0; int cnt = 0;
ImVec2 avg; ImVec2 avg;
for (int i = 0; i < data.size(); ++i) { for (int i = 0; i < data.size(); ++i) {
@ -449,12 +464,12 @@ void ShowImPlotDemoWindow(bool* p_open) {
} }
} }
ImGui::PopPlotStyleVar(2); ImGui::PopPlotStyleVar(2);
range = ImGui::GetPlotBounds(); range = ImGui::GetPlotLimits();
query = ImGui::GetPlotQuery(); query = ImGui::GetPlotQuery();
ImGui::EndPlot(); ImGui::EndPlot();
} }
ImGui::Text("The current plot range is: [%g,%g,%g,%g]", range.X.Min, range.X.Max, range.Y.Min, range.Y.Max); ImGui::Text("The current plot limits are: [%g,%g,%g,%g]", range.X.Min, range.X.Max, range.Y.Min, range.Y.Max);
ImGui::Text("The current query range is: [%g,%g,%g,%g]", query.X.Min, query.X.Max, query.Y.Min, query.Y.Max); ImGui::Text("The current query limits are: [%g,%g,%g,%g]", query.X.Min, query.X.Max, query.Y.Min, query.Y.Max);
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Views")) { if (ImGui::CollapsingHeader("Views")) {
@ -468,24 +483,23 @@ void ShowImPlotDemoWindow(bool* p_open) {
for (size_t i = 0; i < 512; ++i) { for (size_t i = 0; i < 512; ++i) {
const float t = i / sampling_freq; const float t = i / sampling_freq;
x_data[i] = t; x_data[i] = t;
const float arg = 2 * 3.14 * freq * t; const float arg = 2 * 3.14f * freq * t;
y_data1[i] = sin(arg); y_data1[i] = sin(arg);
y_data2[i] = y_data1[i] * -0.6 + sin(2 * arg) * 0.4; y_data2[i] = y_data1[i] * -0.6f + sin(2 * arg) * 0.4f;
y_data3[i] = y_data2[i] * -0.6 + sin(3 * arg) * 0.4; y_data3[i] = y_data2[i] * -0.6f + sin(3 * arg) * 0.4f;
} }
ImGui::BulletText("Query the first plot to render a subview in the second plot."); ImGui::BulletText("Query the first plot to render a subview in the second plot (see above for controls).");
ImGui::BulletText("Toggle \"Pixel Query\" in the context menu and then pan the plot."); ImGui::SetNextPlotLimits(0,0.01f,-1,1);
ImGui::SetNextPlotBounds(0,0.01f,-1,1);
ImAxisFlags flgs = ImAxisFlags_Default & ~ImAxisFlags_TickLabels; ImAxisFlags flgs = ImAxisFlags_Default & ~ImAxisFlags_TickLabels;
ImPlotBounds query; ImPlotLimits query;
if (ImGui::BeginPlot("##View1",NULL,NULL,ImVec2(-1,150), ImPlotFlags_Default, flgs, flgs)) { if (ImGui::BeginPlot("##View1",NULL,NULL,ImVec2(-1,150), ImPlotFlags_Default | ImPlotFlags_Query, flgs, flgs)) {
ImGui::Plot("Signal 1", x_data, y_data1, 512); ImGui::Plot("Signal 1", x_data, y_data1, 512);
ImGui::Plot("Signal 2", x_data, y_data2, 512); ImGui::Plot("Signal 2", x_data, y_data2, 512);
ImGui::Plot("Signal 3", x_data, y_data3, 512); ImGui::Plot("Signal 3", x_data, y_data3, 512);
query = ImGui::GetPlotQuery(); query = ImGui::GetPlotQuery();
ImGui::EndPlot(); ImGui::EndPlot();
} }
ImGui::SetNextPlotBounds(query.X.Min, query.X.Max, query.Y.Min, query.Y.Max, ImGuiCond_Always); ImGui::SetNextPlotLimits(query.X.Min, query.X.Max, query.Y.Min, query.Y.Max, ImGuiCond_Always);
if (ImGui::BeginPlot("##View2",NULL,NULL,ImVec2(-1,150), 0, 0, 0)) { if (ImGui::BeginPlot("##View2",NULL,NULL,ImVec2(-1,150), 0, 0, 0)) {
ImGui::Plot("Signal 1", x_data, y_data1, 512); ImGui::Plot("Signal 1", x_data, y_data1, 512);
ImGui::Plot("Signal 2", x_data, y_data2, 512); ImGui::Plot("Signal 2", x_data, y_data2, 512);
@ -493,12 +507,9 @@ void ShowImPlotDemoWindow(bool* p_open) {
ImGui::EndPlot(); ImGui::EndPlot();
} }
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Drag and Drop")) { if (ImGui::CollapsingHeader("Drag and Drop")) {
srand(10000000 * ImGui::GetTime()); srand((int)(10000000 * ImGui::GetTime()));
static bool paused = false; static bool paused = false;
static bool init = true; static bool init = true;
static ScrollingData data[10]; static ScrollingData data[10];
@ -543,7 +554,7 @@ void ShowImPlotDemoWindow(bool* p_open) {
data[i].Data.back().y + (0.005f + 0.0002f * (float)rand() / float(RAND_MAX)) * (-1 + 2 * (float)rand() / float(RAND_MAX))); data[i].Data.back().y + (0.005f + 0.0002f * (float)rand() / float(RAND_MAX)) * (-1 + 2 * (float)rand() / float(RAND_MAX)));
} }
} }
ImGui::SetNextPlotBoundsX(t - 10, t, paused ? ImGuiCond_Once : ImGuiCond_Always); ImGui::SetNextPlotLimitsX(t - 10, t, paused ? ImGuiCond_Once : ImGuiCond_Always);
if (ImGui::BeginPlot("##DND", NULL, NULL, ImVec2(-1,300), ImPlotFlags_Default)) { if (ImGui::BeginPlot("##DND", NULL, NULL, ImVec2(-1,300), ImPlotFlags_Default)) {
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
if (show[i]) { if (show[i]) {
@ -644,8 +655,8 @@ void ShowImPlotDemoWindow(bool* p_open) {
if (showAnalog[i]) if (showAnalog[i])
dataAnalog[i].AddPoint(t, sin(2*t) - cos(2*t)); dataAnalog[i].AddPoint(t, sin(2*t) - cos(2*t));
} }
ImGui::SetNextPlotBoundsY(-1, 1); ImGui::SetNextPlotLimitsY(-1, 1);
ImGui::SetNextPlotBoundsX(t - 10.0f, t, paused ? ImGuiCond_Once : ImGuiCond_Always); ImGui::SetNextPlotLimitsX(t - 10.0f, t, paused ? ImGuiCond_Once : ImGuiCond_Always);
if (ImGui::BeginPlot("##Digital", NULL, NULL, ImVec2(-1,300), ImPlotFlags_Default)) { if (ImGui::BeginPlot("##Digital", NULL, NULL, ImVec2(-1,300), ImPlotFlags_Default)) {
for (int i = 0; i < K_PLOT_DIGITAL_CH_COUNT; ++i) { for (int i = 0; i < K_PLOT_DIGITAL_CH_COUNT; ++i) {
if (showDigital[i]) { if (showDigital[i]) {
@ -692,7 +703,7 @@ void ShowImPlotDemoWindow(bool* p_open) {
ImGui::PushPlotColor(ImPlotCol_XAxis, IM_COL32(192, 192, 192, 192)); ImGui::PushPlotColor(ImPlotCol_XAxis, IM_COL32(192, 192, 192, 192));
ImGui::PushPlotColor(ImPlotCol_YAxis, IM_COL32(192, 192, 192, 192)); ImGui::PushPlotColor(ImPlotCol_YAxis, IM_COL32(192, 192, 192, 192));
ImGui::PushPlotStyleVar(ImPlotStyleVar_LineWeight, 2); ImGui::PushPlotStyleVar(ImPlotStyleVar_LineWeight, 2);
ImGui::SetNextPlotBounds(-0.5f, 9.5f, -0.5f, 9.5f); ImGui::SetNextPlotLimits(-0.5f, 9.5f, -0.5f, 9.5f);
if (ImGui::BeginPlot("##Custom", NULL, NULL, {-1,300}, ImPlotFlags_Default & ~ImPlotFlags_Legend, 0)) { if (ImGui::BeginPlot("##Custom", NULL, NULL, {-1,300}, ImPlotFlags_Default & ~ImPlotFlags_Legend, 0)) {
float lin[10] = {8,8,9,7,8,8,8,9,7,8}; float lin[10] = {8,8,9,7,8,8,8,9,7,8};
float bar[10] = {1,2,5,3,4,1,2,5,3,4}; float bar[10] = {1,2,5,3,4,1,2,5,3,4};
@ -727,7 +738,7 @@ void ShowImPlotDemoWindow(bool* p_open) {
static BenchmarkItem items[n_items]; static BenchmarkItem items[n_items];
ImGui::BulletText("Make sure VSync is disabled."); ImGui::BulletText("Make sure VSync is disabled.");
ImGui::BulletText("%d lines with %d points each @ %.3f FPS.",n_items,1000,ImGui::GetIO().Framerate); ImGui::BulletText("%d lines with %d points each @ %.3f FPS.",n_items,1000,ImGui::GetIO().Framerate);
SetNextPlotBounds(0,1,0,1, ImGuiCond_Always); SetNextPlotLimits(0,1,0,1, ImGuiCond_Always);
if (ImGui::BeginPlot("##Bench",NULL,NULL,{-1,300},ImPlotFlags_Default | ImPlotFlags_NoChild)) { if (ImGui::BeginPlot("##Bench",NULL,NULL,{-1,300},ImPlotFlags_Default | ImPlotFlags_NoChild)) {
char buff[16]; char buff[16];
for (int i = 0; i < 100; ++i) { for (int i = 0; i < 100; ++i) {