1
0
Fork 0
mirror of https://github.com/gwm17/implot.git synced 2024-11-13 22:48:50 -05:00

finish templetizing API, several optimizations to plotting pipeline, remmove t_float etc from demo

This commit is contained in:
epezent 2020-09-07 16:08:59 -05:00
parent 48cc6e15d6
commit 75e779c931
4 changed files with 458 additions and 400 deletions

View File

@ -31,6 +31,7 @@ Below is a change-log of API breaking changes only. If you are using one of the
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/09/07 (0.8) - Plotting functions which accept a custom getter function pointer have been post-fixed with a G (e.g. PlotLineG)
- 2020/09/06 (0.7) - Several flags under ImPlotFlags and ImPlotAxisFlags were inverted (e.g. ImPlotFlags_Legend -> ImPlotFlags_NoLegend) so that the default flagset
is simply 0. This more closely matches ImGui's style and makes it easier to enable non-default but commonly used flags (e.g. ImPlotAxisFlags_Time).
- 2020/08/28 (0.5) - ImPlotMarker_ can no longer be combined with bitwise OR, |. This features caused unecessary slow-down, and almost no one used it.

View File

@ -301,8 +301,40 @@ void EndPlot();
// Plot Items
//-----------------------------------------------------------------------------
// Supported Types for T*
// The template functions below are explicitly instantiated in implot_items.cpp.
// They are not intended to be used generically with custom types. You will get
// a linker error if you try! All functions support the following scalar types:
//
// float, double, ImS8, ImU8, ImS16, ImU16, ImS32, ImU32, ImS64, ImU64
//
//
// If you need to plot custom or non-homogenous data you have a few options:
//
// 1. If your data is a simple struct/class (e.g. Vector2f), you can use striding.
// This is the most performant option if applicable.
//
// struct Vector2f { float X, Y; };
// ...
// Vector2f data[42];
// ImPlot::PlotLine("line", &data[0].x, &data[0].y, 42, 0, sizeof(Vector2f)); // or sizeof(float)*2
//
// 2. Write a custom getter function or C++ lambda and pass it and your data to
// an ImPlot function post-fixed with a G (e.g. PlotScatterG). This has a
// slight performance cost, but probably not enough to worry about.
//
// ImPlotPoint MyDataGetter(void* data, int idx) {
// MyData* my_data = (MyData*)data;
// ImPlotPoint p;
// p.X = my_data->GetTime(idx);
// p.Y = my_data->GetValue(idx);
// return p
// }
// ...
// MyData my_data;
// ImPlot::PlotScatterG("scatter", MyDataGetter, &my_data, my_data.Size());
//
// NB: All types are converted to double before plotting. You may loose information
// if you try plotting extremely large 64-bit integral types. Proceed with caution!
// Plots a standard 2D line plot.
template <typename T> void PlotLine(const char* label_id, const T* values, int count, int offset = 0, int stride = sizeof(T));
@ -330,41 +362,29 @@ template <typename T> void PlotBarsH(const char* label_id, const T* values, int
template <typename T> void PlotBarsH(const char* label_id, const T* xs, const T* ys, int count, double height, int offset = 0, int stride = sizeof(T));
void PlotBarsHG(const char* label_id, ImPlotPoint (*getter)(void* data, int idx), void* data, int count, double height, int offset = 0);
// TODO ...
// Plots vertical error bar. The label_id should be the same as the label_id of the associated line or bar plot.
void PlotErrorBars(const char* label_id, const float* xs, const float* ys, const float* err, int count, int offset = 0, int stride = sizeof(float));
void PlotErrorBars(const char* label_id, const double* xs, const double* ys, const double* err, int count, int offset = 0, int stride = sizeof(double));
void PlotErrorBars(const char* label_id, const float* xs, const float* ys, const float* neg, const float* pos, int count, int offset = 0, int stride = sizeof(float));
void PlotErrorBars(const char* label_id, const double* xs, const double* ys, const double* neg, const double* pos, int count, int offset = 0, int stride = sizeof(double));
template <typename T> void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* err, int count, int offset = 0, int stride = sizeof(T));
template <typename T> void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* neg, const T* pos, int count, int offset = 0, int stride = sizeof(T));
// Plots horizontal error bars. The label_id should be the same as the label_id of the associated line or bar plot.
void PlotErrorBarsH(const char* label_id, const float* xs, const float* ys, const float* err, int count, int offset = 0, int stride = sizeof(float));
void PlotErrorBarsH(const char* label_id, const double* xs, const double* ys, const double* err, int count, int offset = 0, int stride = sizeof(double));
void PlotErrorBarsH(const char* label_id, const float* xs, const float* ys, const float* neg, const float* pos, int count, int offset = 0, int stride = sizeof(float));
void PlotErrorBarsH(const char* label_id, const double* xs, const double* ys, const double* neg, const double* pos, int count, int offset = 0, int stride = sizeof(double));
template <typename T> void PlotErrorBarsH(const char* label_id, const T* xs, const T* ys, const T* err, int count, int offset = 0, int stride = sizeof(T));
template <typename T> void PlotErrorBarsH(const char* label_id, const T* xs, const T* ys, const T* neg, const T* pos, int count, int offset = 0, int stride = sizeof(T));
/// Plots vertical stems.
void PlotStems(const char* label_id, const float* values, int count, float y_ref = 0, int offset = 0, int stride = sizeof(float));
void PlotStems(const char* label_id, const double* values, int count, double y_ref = 0, int offset = 0, int stride = sizeof(double));
void PlotStems(const char* label_id, const float* xs, const float* ys, int count, float y_ref = 0, int offset = 0, int stride = sizeof(float));
void PlotStems(const char* label_id, const double* xs, const double* ys, int count, double y_ref = 0, int offset = 0, int stride = sizeof(double));
template <typename T> void PlotStems(const char* label_id, const T* values, int count, double y_ref = 0, int offset = 0, int stride = sizeof(T));
template <typename T> 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 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.
void PlotPieChart(const char* const label_ids[], const float* values, int count, float x, float y, float radius, bool normalize = false, const char* label_fmt = "%.1f", float angle0 = 90);
void PlotPieChart(const char* const label_ids[], const double* values, int count, double x, double y, double radius, bool normalize = false, const char* label_fmt = "%.1f", double angle0 = 90);
template <typename T> 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);
// Plots a 2D heatmap chart. Values are expected to be in row-major order. #label_fmt can be set to NULL for no labels.
void PlotHeatmap(const char* label_id, const float* values, int rows, int cols, float scale_min, float scale_max, const char* label_fmt = "%.1f", const ImPlotPoint& bounds_min = ImPlotPoint(0,0), const ImPlotPoint& bounds_max = ImPlotPoint(1,1));
void PlotHeatmap(const char* label_id, const double* values, int rows, int cols, double scale_min, double scale_max, const char* label_fmt = "%.1f", const ImPlotPoint& bounds_min = ImPlotPoint(0,0), const ImPlotPoint& bounds_max = ImPlotPoint(1,1));
template <typename T> void PlotHeatmap(const char* label_id, const T* values, int rows, int cols, double scale_min, double scale_max, const char* label_fmt = "%.1f", const ImPlotPoint& bounds_min = ImPlotPoint(0,0), const ImPlotPoint& bounds_max = ImPlotPoint(1,1));
// Plots digital data. Digital plots do not respond to y drag or zoom, and are always referenced to the bottom of the plot.
void PlotDigital(const char* label_id, const float* xs, const float* ys, int count, int offset = 0, int stride = sizeof(float));
void PlotDigital(const char* label_id, const double* xs, const double* ys, int count, int offset = 0, int stride = sizeof(double));
void PlotDigital(const char* label_id, ImPlotPoint (*getter)(void* data, int idx), void* data, int count, int offset = 0);
template <typename T> void PlotDigital(const char* label_id, const T* xs, const T* ys, int count, int offset = 0, int stride = sizeof(T));
void PlotDigitalG(const char* label_id, ImPlotPoint (*getter)(void* data, int idx), void* data, int count, int offset = 0);
// Plots a centered text label at point x,y with optional pixel offset. Text color can be changed with ImPlot::PushStyleColor(ImPlotCol_InlayText, ...).
void PlotText(const char* text, float x, float y, bool vertical = false, const ImVec2& pixel_offset = ImVec2(0,0));
void PlotText(const char* text, double x, double y, bool vertical = false, const ImVec2& pixel_offset = ImVec2(0,0));
//-----------------------------------------------------------------------------

View File

@ -32,9 +32,16 @@
#define sprintf sprintf_s
#endif
// Encapsulates examples for customizing ImPlot.
namespace MyImPlot {
// Examples for passing custom function pointers to ImPlot in Custom Getters section.
// Example for Custom Data and Getters section.
struct Vector2f {
Vector2f(float _x, float _y) { x = _x; y = _y; }
float x, y;
};
// Example for Custom Data and Getters section.
struct WaveData {
double X, Amp, Freq, Offset;
WaveData(double x, double amp, double freq, double offset) { X = x; Amp = amp; Freq = freq; Offset = offset; }
@ -42,44 +49,25 @@ struct WaveData {
ImPlotPoint SineWave(void* wave_data, int idx);
ImPlotPoint SawWave(void* wave_data, int idx);
ImPlotPoint Spiral(void*, int idx);
// Example for Tables section. Generates a quick and simple shaded line plot. See implementation at bottom.
// Example for Tables section.
void Sparkline(const char* id, const float* values, int count, float min_v, float max_v, int offset, const ImVec4& col, const ImVec2& size);
// Example for Custom Plotters and Tooltips section. Plots a candlestick chart for financial data. See implementation at bottom.
// Example for Custom Plotters and Tooltips section.
void PlotCandlestick(const char* label_id, const double* xs, const double* opens, const double* closes, const double* lows, const double* highs, int count, bool tooltip = true, float width_percent = 0.25f, ImVec4 bullCol = ImVec4(0,1,0,1), ImVec4 bearCol = ImVec4(1,0,0,1));
// Sets style to mimic Seaborn
// Example for Custom Styles section.
void StyleSeaborn();
} // namespace MyImPlot
namespace ImPlot {
/// Choose whether the demo uses double or float versions of the ImPlot API.
/// NB: You don't ever need to typdef of define values for ImPlot. This
/// is only being done here for the sake of demoing both precision types.
// #define IMPLOT_DEMO_USE_DOUBLE
#ifdef IMPLOT_DEMO_USE_DOUBLE
typedef double t_float;
typedef ImPlotPoint t_float2;
#define Sin sin
#define Cos cos
#define Pow pow
#define Log log
#define Fmod fmod
#else
typedef float t_float;
typedef ImVec2 t_float2;
#define Sin sinf
#define Cos cosf
#define Pow powf
#define Log logf
#define Fmod fmodf
#endif
void ShowBenchmarkTool();
inline t_float RandomRange(t_float min, t_float max) {
t_float scale = rand() / (t_float) RAND_MAX;
template <typename T>
inline T RandomRange(T min, T max) {
T scale = rand() / (T) RAND_MAX;
return min + scale * ( max - min );
}
@ -87,17 +75,17 @@ inline t_float RandomRange(t_float min, t_float max) {
struct ScrollingBuffer {
int MaxSize;
int Offset;
ImVector<t_float2> Data;
ImVector<ImVec2> Data;
ScrollingBuffer() {
MaxSize = 2000;
Offset = 0;
Data.reserve(MaxSize);
}
void AddPoint(t_float x, t_float y) {
void AddPoint(float x, float y) {
if (Data.size() < MaxSize)
Data.push_back(t_float2(x,y));
Data.push_back(ImVec2(x,y));
else {
Data[Offset] = t_float2(x,y);
Data[Offset] = ImVec2(x,y);
Offset = (Offset + 1) % MaxSize;
}
}
@ -111,17 +99,17 @@ struct ScrollingBuffer {
// utility structure for realtime plot
struct RollingBuffer {
t_float Span;
ImVector<t_float2> Data;
float Span;
ImVector<ImVec2> Data;
RollingBuffer() {
Span = 10.0f;
Data.reserve(2000);
}
void AddPoint(t_float x, t_float y) {
t_float xmod = Fmod(x, Span);
void AddPoint(float x, float y) {
float xmod = fmodf(x, Span);
if (!Data.empty() && xmod < Data.back().x)
Data.shrink(0);
Data.push_back(t_float2(xmod, y));
Data.push_back(ImVec2(xmod, y));
}
};
@ -145,7 +133,7 @@ struct HugeTimeData {
};
void ShowDemoWindow(bool* p_open) {
t_float DEMO_TIME = (t_float)ImGui::GetTime();
double DEMO_TIME = ImGui::GetTime();
static bool show_imgui_metrics = false;
static bool show_imgui_style_editor = false;
static bool show_implot_style_editor = false;
@ -249,7 +237,7 @@ void ShowDemoWindow(bool* p_open) {
static float xs1[1001], ys1[1001];
for (int i = 0; i < 1001; ++i) {
xs1[i] = i * 0.001f;
ys1[i] = 0.5f + 0.5f * sinf(50 * (xs1[i] + DEMO_TIME / 10));
ys1[i] = 0.5f + 0.5f * sinf(50 * (xs1[i] + (float)DEMO_TIME / 10));
}
static double xs2[11], ys2[11];
for (int i = 0; i < 11; ++i) {
@ -266,13 +254,13 @@ void ShowDemoWindow(bool* p_open) {
}
//-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Filled Line Plots")) {
static t_float xs1[101], ys1[101], ys2[101], ys3[101];
static double xs1[101], ys1[101], ys2[101], ys3[101];
srand(0);
for (int i = 0; i < 101; ++i) {
xs1[i] = (float)i;
ys1[i] = RandomRange(400,450);
ys2[i] = RandomRange(275,350);
ys3[i] = RandomRange(150,225);
ys1[i] = RandomRange(400.0,450.0);
ys2[i] = RandomRange(275.0,350.0);
ys3[i] = RandomRange(150.0,225.0);
}
static bool show_lines = true;
static bool show_fills = true;
@ -300,15 +288,15 @@ void ShowDemoWindow(bool* p_open) {
}
//-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Shaded Plots")) {
static t_float xs[1001], ys[1001], ys1[1001], ys2[1001], ys3[1001], ys4[1001];
static float xs[1001], ys[1001], ys1[1001], ys2[1001], ys3[1001], ys4[1001];
srand(0);
for (int i = 0; i < 1001; ++i) {
xs[i] = i * 0.001f;
ys[i] = 0.25f + 0.25f * Sin(25 * xs[i]) * Sin(5 * xs[i]) + RandomRange(-0.01f, 0.01f);
ys[i] = 0.25f + 0.25f * sinf(25 * xs[i]) * sinf(5 * xs[i]) + RandomRange(-0.01f, 0.01f);
ys1[i] = ys[i] + RandomRange(0.1f, 0.12f);
ys2[i] = ys[i] - RandomRange(0.1f, 0.12f);
ys3[i] = 0.75f + 0.2f * Sin(25 * xs[i]);
ys4[i] = 0.75f + 0.1f * Cos(25 * xs[i]);
ys3[i] = 0.75f + 0.2f * sinf(25 * xs[i]);
ys4[i] = 0.75f + 0.1f * cosf(25 * xs[i]);
}
static float alpha = 0.25f;
ImGui::DragFloat("Alpha",&alpha,0.01f,0,1);
@ -327,15 +315,15 @@ void ShowDemoWindow(bool* p_open) {
//-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Scatter Plots")) {
srand(0);
static t_float xs1[100], ys1[100];
static float xs1[100], ys1[100];
for (int i = 0; i < 100; ++i) {
xs1[i] = i * 0.01f;
ys1[i] = xs1[i] + 0.1f * ((t_float)rand() / (t_float)RAND_MAX);
ys1[i] = xs1[i] + 0.1f * ((float)rand() / (float)RAND_MAX);
}
static t_float xs2[50], ys2[50];
static float xs2[50], ys2[50];
for (int i = 0; i < 50; i++) {
xs2[i] = 0.25f + 0.2f * ((t_float)rand() / (t_float)RAND_MAX);
ys2[i] = 0.75f + 0.2f * ((t_float)rand() / (t_float)RAND_MAX);
xs2[i] = 0.25f + 0.2f * ((float)rand() / (float)RAND_MAX);
ys2[i] = 0.75f + 0.2f * ((float)rand() / (float)RAND_MAX);
}
if (ImPlot::BeginPlot("Scatter Plot", NULL, NULL)) {
@ -386,14 +374,14 @@ void ShowDemoWindow(bool* p_open) {
}
//-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Error Bars")) {
static t_float xs[5] = {1,2,3,4,5};
static t_float bar[5] = {1,2,5,3,4};
static t_float lin1[5] = {8,8,9,7,8};
static t_float lin2[5] = {6,7,6,9,6};
static t_float err1[5] = {0.2f, 0.4f, 0.2f, 0.6f, 0.4f};
static t_float err2[5] = {0.4f, 0.2f, 0.4f, 0.8f, 0.6f};
static t_float err3[5] = {0.09f, 0.14f, 0.09f, 0.12f, 0.16f};
static t_float err4[5] = {0.02f, 0.08f, 0.15f, 0.05f, 0.2f};
static float xs[5] = {1,2,3,4,5};
static float bar[5] = {1,2,5,3,4};
static float lin1[5] = {8,8,9,7,8};
static float lin2[5] = {6,7,6,9,6};
static float err1[5] = {0.2f, 0.4f, 0.2f, 0.6f, 0.4f};
static float err2[5] = {0.4f, 0.2f, 0.4f, 0.8f, 0.6f};
static float err3[5] = {0.09f, 0.14f, 0.09f, 0.12f, 0.16f};
static float err4[5] = {0.02f, 0.08f, 0.15f, 0.05f, 0.2f};
ImPlot::SetNextPlotLimits(0, 6, 0, 10);
@ -417,11 +405,11 @@ void ShowDemoWindow(bool* p_open) {
}
}
if (ImGui::CollapsingHeader("Stem Plots")) {
static t_float xs[51], ys1[51], ys2[51];
static double xs[51], ys1[51], ys2[51];
for (int i = 0; i < 51; ++i) {
xs[i] = i * 0.02f;
ys1[i] = 1.0f + 0.5f * Sin(25*xs[i])*Cos(2*xs[i]);
ys2[i] = 0.5f + 0.25f * Sin(10*xs[i]) * Sin(xs[i]);
xs[i] = i * 0.02;
ys1[i] = 1.0 + 0.5 * sin(25*xs[i])*cos(2*xs[i]);
ys2[i] = 0.5 + 0.25 * sin(10*xs[i]) * sin(xs[i]);
}
ImPlot::SetNextPlotLimits(0,1,0,1.6);
if (ImPlot::BeginPlot("Stem Plots")) {
@ -449,38 +437,34 @@ void ShowDemoWindow(bool* p_open) {
ImPlot::SetNextPlotLimits(0,1,0,1,ImGuiCond_Always);
if (ImPlot::BeginPlot("##Pie1", NULL, NULL, ImVec2(250,250), ImPlotFlags_NoMousePos, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations)) {
ImPlot::PlotPieChart(labels1, data1, 4, 0.5f, 0.5f, 0.4f, normalize, "%.2f");
ImPlot::PlotPieChart(labels1, data1, 4, 0.5, 0.5, 0.4, normalize, "%.2f");
ImPlot::EndPlot();
}
ImGui::SameLine();
static const char* labels2[] = {"A","B","C","D","E"};
static t_float data2[] = {1,1,2,3,5};
static int data2[] = {1,1,2,3,5};
ImPlot::PushColormap(ImPlotColormap_Pastel);
ImPlot::SetNextPlotLimits(0,1,0,1,ImGuiCond_Always);
if (ImPlot::BeginPlot("##Pie2", NULL, NULL, ImVec2(250,250), ImPlotFlags_NoMousePos, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations)) {
ImPlot::PlotPieChart(labels2, data2, 5, 0.5f, 0.5f, 0.4f, true, "%.0f", 180);
ImPlot::PlotPieChart(labels2, data2, 5, 0.5, 0.5, 0.4, true, "%.0f", 180);
ImPlot::EndPlot();
}
ImPlot::PopColormap();
}
//-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Heatmaps")) {
static t_float values1[7][7] = {{0.8f, 2.4f, 2.5f, 3.9f, 0.0f, 4.0f, 0.0f},
{2.4f, 0.0f, 4.0f, 1.0f, 2.7f, 0.0f, 0.0f},
{1.1f, 2.4f, 0.8f, 4.3f, 1.9f, 4.4f, 0.0f},
{0.6f, 0.0f, 0.3f, 0.0f, 3.1f, 0.0f, 0.0f},
{0.7f, 1.7f, 0.6f, 2.6f, 2.2f, 6.2f, 0.0f},
{1.3f, 1.2f, 0.0f, 0.0f, 0.0f, 3.2f, 5.1f},
{0.1f, 2.0f, 0.0f, 1.4f, 0.0f, 1.9f, 6.3f}};
static float scale_min = 0;
static float scale_max = 6.3f;
static t_float values2[100*100];
srand((unsigned int)(DEMO_TIME*1000000));
for (int i = 0; i < 100*100; ++i)
values2[i] = RandomRange(0,1);
static float values1[7][7] = {{0.8f, 2.4f, 2.5f, 3.9f, 0.0f, 4.0f, 0.0f},
{2.4f, 0.0f, 4.0f, 1.0f, 2.7f, 0.0f, 0.0f},
{1.1f, 2.4f, 0.8f, 4.3f, 1.9f, 4.4f, 0.0f},
{0.6f, 0.0f, 0.3f, 0.0f, 3.1f, 0.0f, 0.0f},
{0.7f, 1.7f, 0.6f, 2.6f, 2.2f, 6.2f, 0.0f},
{1.3f, 1.2f, 0.0f, 0.0f, 0.0f, 3.2f, 5.1f},
{0.1f, 2.0f, 0.0f, 1.4f, 0.0f, 1.9f, 6.3f}};
static float scale_min = 0;
static float scale_max = 6.3f;
static const char* xlabels[] = {"C1","C2","C3","C4","C5","C6","C7"};
static const char* ylabels[] = {"R1","R2","R3","R4","R5","R6","R7"};
@ -507,6 +491,11 @@ void ShowDemoWindow(bool* p_open) {
ImGui::SameLine();
static double values2[100*100];
srand((unsigned int)(DEMO_TIME*1000000));
for (int i = 0; i < 100*100; ++i)
values2[i] = RandomRange(0.0,1.0);
static ImVec4 gray[2] = {ImVec4(0,0,0,1), ImVec4(1,1,1,1)};
ImPlot::PushColormap(gray, 2);
ImPlot::SetNextPlotLimits(-1,1,-1,1);
@ -524,7 +513,7 @@ void ShowDemoWindow(bool* p_open) {
static ScrollingBuffer sdata1, sdata2;
static RollingBuffer rdata1, rdata2;
ImVec2 mouse = ImGui::GetMousePos();
static t_float t = 0;
static float t = 0;
t += ImGui::GetIO().DeltaTime;
sdata1.AddPoint(t, mouse.x * 0.0005f);
rdata1.AddPoint(t, mouse.x * 0.0005f);
@ -539,7 +528,7 @@ void ShowDemoWindow(bool* p_open) {
static ImPlotAxisFlags rt_axis = ImPlotAxisFlags_NoTickLabels;
ImPlot::SetNextPlotLimitsX(t - history, t, ImGuiCond_Always);
if (ImPlot::BeginPlot("##Scrolling", NULL, NULL, ImVec2(-1,150), 0, rt_axis, rt_axis | ImPlotAxisFlags_LockMin)) {
ImPlot::PlotShaded("Data 1", &sdata1.Data[0].x, &sdata1.Data[0].y, sdata1.Data.size(), 0, sdata1.Offset, 2 * sizeof(t_float));
ImPlot::PlotShaded("Data 1", &sdata1.Data[0].x, &sdata1.Data[0].y, sdata1.Data.size(), 0, sdata1.Offset, 2 * sizeof(float));
ImPlot::PlotLine("Data 2", &sdata2.Data[0], sdata2.Data.size(), sdata2.Offset);
ImPlot::EndPlot();
}
@ -549,7 +538,7 @@ void ShowDemoWindow(bool* p_open) {
// as ImVec2* (or ImPlot*):
ImPlot::PlotLine("Data 1", &rdata1.Data[0], rdata1.Data.size());
// as float*, float* (or double*, double*) with stride of 2 * sizeof
ImPlot::PlotLine("Data 2", &rdata2.Data[0].x, &rdata2.Data[0].y, rdata2.Data.size(), 0, 2 * sizeof(t_float));
ImPlot::PlotLine("Data 2", &rdata2.Data[0].x, &rdata2.Data[0].y, rdata2.Data.size(), 0, 2 * sizeof(float));
ImPlot::EndPlot();
}
}
@ -562,8 +551,8 @@ void ShowDemoWindow(bool* p_open) {
ImPlot::SetNextPlotLimits(0, 10, 0, 12);
if (ImPlot::BeginPlot("##MarkerStyles", NULL, NULL, ImVec2(-1,0), ImPlotFlags_CanvasOnly, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations)) {
t_float xs[2] = {1,4};
t_float ys[2] = {10,11};
ImS8 xs[2] = {1,4};
ImS8 ys[2] = {10,11};
// filled markers
for (int m = 1; m < ImPlotMarker_COUNT; ++m) {
@ -595,12 +584,12 @@ void ShowDemoWindow(bool* p_open) {
}
//-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Log Scale")) {
static t_float xs[1001], ys1[1001], ys2[1001], ys3[1001];
static double xs[1001], ys1[1001], ys2[1001], ys3[1001];
for (int i = 0; i < 1001; ++i) {
xs[i] = i*0.1f;
ys1[i] = Sin(xs[i]) + 1;
ys2[i] = Log(xs[i]);
ys3[i] = Pow(10.0f, xs[i]);
ys1[i] = sin(xs[i]) + 1;
ys2[i] = log(xs[i]);
ys3[i] = pow(10.0, xs[i]);
}
ImGui::BulletText("Open the plot context menu (double right click) to change scales.");
@ -655,12 +644,12 @@ void ShowDemoWindow(bool* p_open) {
}
//-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Multiple Y-Axes")) {
static t_float xs[1001], xs2[1001], ys1[1001], ys2[1001], ys3[1001];
static float xs[1001], xs2[1001], ys1[1001], ys2[1001], ys3[1001];
for (int i = 0; i < 1001; ++i) {
xs[i] = (i*0.1f);
ys1[i] = Sin(xs[i]) * 3 + 1;
ys2[i] = Cos(xs[i]) * 0.2f + 0.5f;
ys3[i] = Sin(xs[i]+0.5f) * 100 + 200;
ys1[i] = sinf(xs[i]) * 3 + 1;
ys2[i] = cosf(xs[i]) * 0.2f + 0.5f;
ys3[i] = sinf(xs[i]+0.5f) * 100 + 200;
xs2[i] = xs[i] + 10.0f;
}
static bool y2_axis = true;
@ -699,7 +688,7 @@ void ShowDemoWindow(bool* p_open) {
if (ImGui::CollapsingHeader("Linked Axes")) {
static double xmin = 0, xmax = 1, ymin = 0, ymax = 1;
static bool linkx = true, linky = true;
t_float data[2] = {0,1};
int data[2] = {0,1};
ImGui::Checkbox("Link X", &linkx);
ImGui::SameLine();
ImGui::Checkbox("Link Y", &linky);
@ -716,7 +705,7 @@ void ShowDemoWindow(bool* p_open) {
}
//-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Querying")) {
static ImVector<t_float2> data;
static ImVector<ImPlotPoint> data;
static ImPlotLimits range, query;
ImGui::BulletText("Ctrl + click in the plot area to draw points.");
@ -730,14 +719,14 @@ void ShowDemoWindow(bool* p_open) {
if (ImPlot::BeginPlot("##Drawing", NULL, NULL, ImVec2(-1,0), ImPlotFlags_Query, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations)) {
if (ImPlot::IsPlotHovered() && ImGui::IsMouseClicked(0) && ImGui::GetIO().KeyCtrl) {
ImPlotPoint pt = ImPlot::GetPlotMousePos();
data.push_back(t_float2((t_float)pt.x, (t_float)pt.y));
data.push_back(pt);
}
if (data.size() > 0)
ImPlot::PlotScatter("Points", &data[0].x, &data[0].y, data.size(), 0, 2 * sizeof(t_float));
ImPlot::PlotScatter("Points", &data[0].x, &data[0].y, data.size(), 0, 2 * sizeof(double));
if (ImPlot::IsPlotQueried() && data.size() > 0) {
ImPlotLimits range2 = ImPlot::GetPlotQuery();
int cnt = 0;
t_float2 avg;
ImPlotPoint avg;
for (int i = 0; i < data.size(); ++i) {
if (range2.Contains(data[i].x, data[i].y)) {
avg.x += data[i].x;
@ -762,19 +751,19 @@ void ShowDemoWindow(bool* p_open) {
//-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Views")) {
// mimic's soulthread's imgui_plot demo
static t_float x_data[512];
static t_float y_data1[512];
static t_float y_data2[512];
static t_float y_data3[512];
static t_float sampling_freq = 44100;
static t_float freq = 500;
static float x_data[512];
static float y_data1[512];
static float y_data2[512];
static float y_data3[512];
static float sampling_freq = 44100;
static float freq = 500;
for (size_t i = 0; i < 512; ++i) {
const t_float t = i / sampling_freq;
const float t = i / sampling_freq;
x_data[i] = t;
const t_float arg = 2 * 3.14f * freq * t;
y_data1[i] = Sin(arg);
y_data2[i] = y_data1[i] * -0.6f + Sin(2 * arg) * 0.4f;
y_data3[i] = y_data2[i] * -0.6f + Sin(3 * arg) * 0.4f;
const float arg = 2 * 3.14f * freq * t;
y_data1[i] = sinf(arg);
y_data2[i] = y_data1[i] * -0.6f + sinf(2 * arg) * 0.4f;
y_data3[i] = y_data2[i] * -0.6f + sinf(3 * arg) * 0.4f;
}
ImGui::BulletText("Query the first plot to render a subview in the second plot (see above for controls).");
ImPlot::SetNextPlotLimits(0,0.01,-1,1);
@ -836,7 +825,7 @@ void ShowDemoWindow(bool* p_open) {
ImGui::EndGroup();
ImGui::SameLine();
srand((unsigned int)DEMO_TIME*10000000);
static t_float t = 0;
static float t = 0;
if (!paused) {
t += ImGui::GetIO().DeltaTime;
for (int i = 0; i < K_CHANNELS; ++i) {
@ -851,7 +840,7 @@ void ShowDemoWindow(bool* p_open) {
char label[K_CHANNELS];
sprintf(label, "data_%d", i);
ImPlot::SetPlotYAxis(yAxis[i]);
ImPlot::PlotLine(label, &data[i].Data[0].x, &data[i].Data[0].y, data[i].Data.size(), data[i].Offset, 2 * sizeof(t_float));
ImPlot::PlotLine(label, &data[i].Data[0].x, &data[i].Data[0].y, data[i].Data.size(), data[i].Offset, 2 * sizeof(float));
// allow legend labels to be dragged and dropped
if (ImPlot::BeginLegendDragDropSource(label)) {
ImGui::SetDragDropPayload("DND_PLOT", &i, sizeof(int));
@ -923,35 +912,35 @@ void ShowDemoWindow(bool* p_open) {
}
ImGui::EndGroup();
ImGui::SameLine();
static t_float t = 0;
static float t = 0;
if (!paused) {
t += ImGui::GetIO().DeltaTime;
//digital signal values
int i = 0;
if (showDigital[i])
dataDigital[i].AddPoint(t, Sin(2*t) > 0.45);
dataDigital[i].AddPoint(t, sinf(2*t) > 0.45);
i++;
if (showDigital[i])
dataDigital[i].AddPoint(t, Sin(2*t) < 0.45);
dataDigital[i].AddPoint(t, sinf(2*t) < 0.45);
i++;
if (showDigital[i])
dataDigital[i].AddPoint(t, Fmod(t,5.0f));
dataDigital[i].AddPoint(t, fmodf(t,5.0f));
i++;
if (showDigital[i])
dataDigital[i].AddPoint(t, Sin(2*t) < 0.17);
dataDigital[i].AddPoint(t, sinf(2*t) < 0.17);
//Analog signal values
i = 0;
if (showAnalog[i])
dataAnalog[i].AddPoint(t, Sin(2*t));
dataAnalog[i].AddPoint(t, sinf(2*t));
i++;
if (showAnalog[i])
dataAnalog[i].AddPoint(t, Cos(2*t));
dataAnalog[i].AddPoint(t, cosf(2*t));
i++;
if (showAnalog[i])
dataAnalog[i].AddPoint(t, Sin(2*t) * Cos(2*t));
dataAnalog[i].AddPoint(t, sinf(2*t) * cosf(2*t));
i++;
if (showAnalog[i])
dataAnalog[i].AddPoint(t, Sin(2*t) - Cos(2*t));
dataAnalog[i].AddPoint(t, sinf(2*t) - cosf(2*t));
}
ImPlot::SetNextPlotLimitsY(-1, 1);
ImPlot::SetNextPlotLimitsX(t - 10.0, t, paused ? ImGuiCond_Once : ImGuiCond_Always);
@ -960,7 +949,7 @@ void ShowDemoWindow(bool* p_open) {
if (showDigital[i] && dataDigital[i].Data.size() > 0) {
char label[32];
sprintf(label, "digital_%d", i);
ImPlot::PlotDigital(label, &dataDigital[i].Data[0].x, &dataDigital[i].Data[0].y, dataDigital[i].Data.size(), dataDigital[i].Offset, 2 * sizeof(t_float));
ImPlot::PlotDigital(label, &dataDigital[i].Data[0].x, &dataDigital[i].Data[0].y, dataDigital[i].Data.size(), dataDigital[i].Offset, 2 * sizeof(float));
}
}
for (int i = 0; i < K_PLOT_ANALOG_CH_COUNT; ++i) {
@ -968,7 +957,7 @@ void ShowDemoWindow(bool* p_open) {
char label[32];
sprintf(label, "analog_%d", i);
if (dataAnalog[i].Data.size() > 0)
ImPlot::PlotLine(label, &dataAnalog[i].Data[0].x, &dataAnalog[i].Data[0].y, dataAnalog[i].Data.size(), dataAnalog[i].Offset, 2 * sizeof(t_float));
ImPlot::PlotLine(label, &dataAnalog[i].Data[0].x, &dataAnalog[i].Data[0].y, dataAnalog[i].Data.size(), dataAnalog[i].Offset, 2 * sizeof(float));
}
}
ImPlot::EndPlot();
@ -1010,7 +999,7 @@ void ShowDemoWindow(bool* p_open) {
static float data[100];
srand(row);
for (int i = 0; i < 100; ++i)
data[i] = (float)RandomRange(0,10);
data[i] = RandomRange(0.0f,10.0f);
ImGui::TableSetColumnIndex(0);
ImGui::Text("EMG %d", row);
ImGui::TableSetColumnIndex(1);
@ -1032,12 +1021,12 @@ void ShowDemoWindow(bool* p_open) {
static const int k_circles = 11;
static const int k_points_per = 50;
static const int k_size = 2 * k_points_per * k_circles;
static t_float interleaved_data[k_size];
static double interleaved_data[k_size];
for (int p = 0; p < k_points_per; ++p) {
for (int c = 0; c < k_circles; ++c) {
t_float r = (t_float)c / (k_circles - 1) * 0.2f + 0.2f;
interleaved_data[p*2*k_circles + 2*c + 0] = 0.5f + r * Cos((t_float)p/k_points_per * 6.28f);
interleaved_data[p*2*k_circles + 2*c + 1] = 0.5f + r * Sin((t_float)p/k_points_per * 6.28f);
double r = (double)c / (k_circles - 1) * 0.2 + 0.2;
interleaved_data[p*2*k_circles + 2*c + 0] = 0.5 + r * cos((double)p/k_points_per * 6.28);
interleaved_data[p*2*k_circles + 2*c + 1] = 0.5 + r * sin((double)p/k_points_per * 6.28);
}
}
static int offset = 0;
@ -1053,7 +1042,7 @@ void ShowDemoWindow(bool* p_open) {
char buff[16];
for (int c = 0; c < k_circles; ++c) {
sprintf(buff, "Circle %d", c);
ImPlot::PlotLine(buff, &interleaved_data[c*2 + 0], &interleaved_data[c*2 + 1], k_points_per, offset, 2*k_circles*sizeof(t_float));
ImPlot::PlotLine(buff, &interleaved_data[c*2 + 0], &interleaved_data[c*2 + 1], k_points_per, offset, 2*k_circles*sizeof(double));
}
ImPlot::EndPlot();
ImPlot::PopColormap();
@ -1061,12 +1050,25 @@ void ShowDemoWindow(bool* p_open) {
// offset++; uncomment for animation!
}
//-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Custom Getters")) {
ImGui::BulletText("Most plotters can be passed a function pointer for getting data.");
ImGui::BulletText("You can optionally pass user data to be given to your getter.");
ImGui::BulletText("C++ lambdas can be passed as function pointers as well.");
if (ImPlot::BeginPlot("##Custom Getters")) {
if (ImGui::CollapsingHeader("Custom Data and Getters")) {
ImGui::BulletText("You can plot custom structs using the stride feature.");
ImGui::BulletText("Most plotters can also be passed a function pointer for getting data.");
ImGui::Indent();
ImGui::BulletText("You can optionally pass user data to be given to your getter function.");
ImGui::BulletText("C++ lambdas can be passed as function pointers as well!");
ImGui::Unindent();
MyImPlot::Vector2f vec2_data[2] = { MyImPlot::Vector2f(0,0), MyImPlot::Vector2f(1,1) };
if (ImPlot::BeginPlot("##Custom Data")) {
// custom structs using stride example:
ImPlot::PlotLine("Vector2f", &vec2_data[0].x, &vec2_data[0].y, 2, 0, sizeof(MyImPlot::Vector2f) /* or sizeof(float) * 2 */);
// custom getter example 1:
ImPlot::PlotLineG("Spiral", MyImPlot::Spiral, NULL, 1000);
// custom getter example 2:
static MyImPlot::WaveData data1(0.001, 0.2, 2, 0.75);
static MyImPlot::WaveData data2(0.001, 0.2, 4, 0.25);
ImPlot::PlotLineG("Waves", MyImPlot::SineWave, &data1, 1000);
@ -1074,9 +1076,11 @@ void ShowDemoWindow(bool* p_open) {
ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, 0.25f);
ImPlot::PlotShadedG("Waves", MyImPlot::SineWave, &data1, MyImPlot::SawWave, &data2, 1000);
ImPlot::PopStyleVar();
// you can also pass C++ lambdas:
// auto lamda = [](void* data, int idx) { ... return ImPlotPoint(x,y); };
// ImPlot::PlotLine("My Lambda", lambda, data, 1000);
ImPlot::EndPlot();
}
}
@ -1115,9 +1119,9 @@ void ShowDemoWindow(bool* p_open) {
MyImPlot::StyleSeaborn();
ImPlot::SetNextPlotLimits(-0.5f, 9.5f, 0, 10);
if (ImPlot::BeginPlot("seaborn style", "x-axis", "y-axis")) {
t_float lin[10] = {8,8,9,7,8,8,8,9,7,8};
t_float bar[10] = {1,2,5,3,4,1,2,5,3,4};
t_float dot[10] = {7,6,6,7,8,5,6,5,8,7};
unsigned int lin[10] = {8,8,9,7,8,8,8,9,7,8};
unsigned int bar[10] = {1,2,5,3,4,1,2,5,3,4};
unsigned int dot[10] = {7,6,6,7,8,5,6,5,8,7};
ImPlot::PlotBars("Bars", bar, 10, 0.5f);
ImPlot::PlotLine("Line", lin, 10);
ImPlot::NextColormapColor(); // skip green
@ -1154,9 +1158,9 @@ void ShowDemoWindow(bool* p_open) {
static bool markers = false;
static bool shaded = false;
static t_float vals[101];
static float vals[101];
for (int i = 0; i < 101; ++i)
vals[i] = amplitude * Sin(frequency * i);
vals[i] = amplitude * sinf(frequency * i);
ImPlot::SetNextPlotLimits(0,100,-1,1);
if (ImPlot::BeginPlot("Right Click the Legend")) {
@ -1240,8 +1244,8 @@ ImPlotPoint Spiral(void*, int idx) {
float n = (r - a) / b; // number of revolutions
double th = 2 * n * 3.14; // angle
float Th = float(th * idx / (1000 - 1));
return ImPlotPoint(0.5f+(a + b*Th / (2.0f * (float) 3.14))*Cos(Th),
0.5f + (a + b*Th / (2.0f * (float)3.14))*Sin(Th));
return ImPlotPoint(0.5f+(a + b*Th / (2.0f * (float) 3.14))*cos(Th),
0.5f + (a + b*Th / (2.0f * (float)3.14))*sin(Th));
}
// Example for Tables section. Generates a quick and simple shaded line plot. See implementation at bottom.
@ -1412,12 +1416,12 @@ namespace ImPlot {
struct BenchData {
BenchData() {
float y = (float)RandomRange(0,1);
float y = RandomRange(0.0f,1.0f);
Data = new float[1000];
for (int i = 0; i < 1000; ++i) {
Data[i] = y + (float)RandomRange(-0.01f,0.01f);
Data[i] = y + RandomRange(-0.01f,0.01f);
}
Col = ImVec4((float)RandomRange(0,1),(float)RandomRange(0,1),(float)RandomRange(0,1),1);
Col = ImVec4(RandomRange(0.0f,1.0f),RandomRange(0.0f,1.0f),RandomRange(0.0f,1.0f),0.5f);
}
~BenchData() { delete[] Data; }
float* Data;

View File

@ -95,6 +95,34 @@ ImPlotItem* GetCurrentItem() {
return gp.CurrentItem;
}
void SetNextLineStyle(const ImVec4& col, float weight) {
ImPlotContext& gp = *GImPlot;
gp.NextItemStyle.Colors[ImPlotCol_Line] = col;
gp.NextItemStyle.LineWeight = weight;
}
void SetNextFillStyle(const ImVec4& col, float alpha) {
ImPlotContext& gp = *GImPlot;
gp.NextItemStyle.Colors[ImPlotCol_Fill] = col;
gp.NextItemStyle.FillAlpha = alpha;
}
void SetNextMarkerStyle(ImPlotMarker marker, float size, const ImVec4& fill, float weight, const ImVec4& outline) {
ImPlotContext& gp = *GImPlot;
gp.NextItemStyle.Marker = marker;
gp.NextItemStyle.Colors[ImPlotCol_MarkerFill] = fill;
gp.NextItemStyle.MarkerSize = size;
gp.NextItemStyle.Colors[ImPlotCol_MarkerOutline] = outline;
gp.NextItemStyle.MarkerWeight = weight;
}
void SetNextErrorBarStyle(const ImVec4& col, float size, float weight) {
ImPlotContext& gp = *GImPlot;
gp.NextItemStyle.Colors[ImPlotCol_ErrorBar] = col;
gp.NextItemStyle.ErrorBarSize = size;
gp.NextItemStyle.ErrorBarWeight = weight;
}
void BustItemCache() {
ImPlotContext& gp = *GImPlot;
for (int p = 0; p < gp.Plots.GetSize(); ++p) {
@ -104,6 +132,10 @@ void BustItemCache() {
}
}
//-----------------------------------------------------------------------------
// Begin/EndItem
//-----------------------------------------------------------------------------
// Begins a new item. Returns false if the item should not be plotted.
bool BeginItem(const char* label_id, ImPlotCol recolor_from) {
ImPlotContext& gp = *GImPlot;
@ -172,35 +204,6 @@ void EndItem() {
gp.CurrentItem = NULL;
}
void SetNextLineStyle(const ImVec4& col, float weight) {
ImPlotContext& gp = *GImPlot;
gp.NextItemStyle.Colors[ImPlotCol_Line] = col;
gp.NextItemStyle.LineWeight = weight;
}
void SetNextFillStyle(const ImVec4& col, float alpha) {
ImPlotContext& gp = *GImPlot;
gp.NextItemStyle.Colors[ImPlotCol_Fill] = col;
gp.NextItemStyle.FillAlpha = alpha;
}
void SetNextMarkerStyle(ImPlotMarker marker, float size, const ImVec4& fill, float weight, const ImVec4& outline) {
ImPlotContext& gp = *GImPlot;
gp.NextItemStyle.Marker = marker;
gp.NextItemStyle.Colors[ImPlotCol_MarkerFill] = fill;
gp.NextItemStyle.MarkerSize = size;
gp.NextItemStyle.Colors[ImPlotCol_MarkerOutline] = outline;
gp.NextItemStyle.MarkerWeight = weight;
}
void SetNextErrorBarStyle(const ImVec4& col, float size, float weight) {
ImPlotContext& gp = *GImPlot;
gp.NextItemStyle.Colors[ImPlotCol_ErrorBar] = col;
gp.NextItemStyle.ErrorBarSize = size;
gp.NextItemStyle.ErrorBarWeight = weight;
}
//-----------------------------------------------------------------------------
// GETTERS
//-----------------------------------------------------------------------------
@ -208,6 +211,8 @@ void SetNextErrorBarStyle(const ImVec4& col, float size, float weight) {
// Getters can be thought of as iterators that convert user data (e.g. raw arrays)
// to ImPlotPoints
// TODO: Make members const
// Interprets an array of Y points as ImPlotPoints where the X value is the index
template <typename T>
struct GetterYs {
@ -221,7 +226,7 @@ struct GetterYs {
int Count;
int Offset;
int Stride;
inline ImPlotPoint operator()(int idx) {
inline ImPlotPoint operator()(int idx) const {
return ImPlotPoint((double)idx, (double)OffsetAndStride(Ys, idx, Count, Offset, Stride));
}
};
@ -240,7 +245,7 @@ struct GetterXsYs {
int Count;
int Offset;
int Stride;
inline ImPlotPoint operator()(int idx) {
inline ImPlotPoint operator()(int idx) const {
return ImPlotPoint((double)OffsetAndStride(Xs, idx, Count, Offset, Stride), (double)OffsetAndStride(Ys, idx, Count, Offset, Stride));
}
};
@ -249,7 +254,7 @@ struct GetterXsYs {
template <typename T>
struct GetterYRef {
GetterYRef(T y_ref, int count) { YRef = y_ref; Count = count; }
inline ImPlotPoint operator()(int idx) {
inline ImPlotPoint operator()(int idx) const {
return ImPlotPoint((double)idx, (double)YRef);
}
T YRef;
@ -271,7 +276,7 @@ struct GetterXsYRef {
int Count;
int Offset;
int Stride;
inline ImPlotPoint operator()(int idx) {
inline ImPlotPoint operator()(int idx) const {
return ImPlotPoint((double)OffsetAndStride(Xs, idx, Count, Offset, Stride), (double)YRef);
}
};
@ -283,7 +288,7 @@ struct GetterImVec2 {
Count = count;
Offset = count ? ImPosMod(offset, count) : 0;
}
inline ImPlotPoint operator()(int idx) {
inline ImPlotPoint operator()(int idx) const {
idx = ImPosMod(Offset + idx, Count);
return ImPlotPoint((double)Data[idx].x, (double)Data[idx].y);
}
@ -299,7 +304,7 @@ struct GetterImPlotPoint {
Count = count;
Offset = count ? ImPosMod(offset, count) : 0;
}
inline ImPlotPoint operator()(int idx) {
inline ImPlotPoint operator()(int idx) const {
idx = ImPosMod(Offset + idx, Count);
return Data[idx];
}
@ -316,7 +321,7 @@ struct GetterFuncPtrImPlotPoint {
Count = count;
Offset = count ? ImPosMod(offset, count) : 0;
}
inline ImPlotPoint operator()(int idx) {
inline ImPlotPoint operator()(int idx) const {
idx = ImPosMod(Offset + idx, Count);
return getter(Data, idx);
}
@ -330,14 +335,14 @@ template <typename T>
struct GetterBarV {
const T* Ys; double XShift; int Count; int Offset; int Stride;
GetterBarV(const T* ys, double xshift, int count, int offset, int stride) { Ys = ys; XShift = xshift; Count = count; Offset = offset; Stride = stride; }
inline ImPlotPoint operator()(int idx) { return ImPlotPoint((double)idx + (double)XShift, (double)OffsetAndStride(Ys, idx, Count, Offset, Stride)); }
inline ImPlotPoint operator()(int idx) const { return ImPlotPoint((double)idx + (double)XShift, (double)OffsetAndStride(Ys, idx, Count, Offset, Stride)); }
};
template <typename T>
struct GetterBarH {
const T* Xs; double YShift; int Count; int Offset; int Stride;
GetterBarH(const T* xs, double yshift, int count, int offset, int stride) { Xs = xs; YShift = yshift; Count = count; Offset = offset; Stride = stride; }
inline ImPlotPoint operator()(int idx) { return ImPlotPoint((double)OffsetAndStride(Xs, idx, Count, Offset, Stride), (double)idx + (double)YShift); }
inline ImPlotPoint operator()(int idx) const { return ImPlotPoint((double)OffsetAndStride(Xs, idx, Count, Offset, Stride), (double)idx + (double)YShift); }
};
template <typename T>
@ -346,7 +351,7 @@ struct GetterError {
GetterError(const T* xs, const T* ys, const T* neg, const T* pos, int count, int offset, int stride) {
Xs = xs; Ys = ys; Neg = neg; Pos = pos; Count = count; Offset = offset; Stride = stride;
}
ImPlotPointError operator()(int idx) {
ImPlotPointError operator()(int idx) const {
return ImPlotPointError((double)OffsetAndStride(Xs, idx, Count, Offset, Stride),
(double)OffsetAndStride(Ys, idx, Count, Offset, Stride),
(double)OffsetAndStride(Neg, idx, Count, Offset, Stride),
@ -363,62 +368,54 @@ struct GetterError {
// Transforms points for linear x and linear y space
struct TransformerLinLin {
TransformerLinLin() : YAxis(GetCurrentYAxis()) {}
inline ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); }
inline ImVec2 operator()(double x, double y) {
// inline ImVec2 operator()(const ImPlotPoint& plt) const { return (*this)(plt.x, plt.y); }
inline ImVec2 operator()(const ImPlotPoint& plt) const {
ImPlotContext& gp = *GImPlot;
return ImVec2( (float)(gp.PixelRange[YAxis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)),
(float)(gp.PixelRange[YAxis].Min.y + gp.My[YAxis] * (y - gp.CurrentPlot->YAxis[YAxis].Range.Min)) );
return ImVec2( (float)(gp.PixelRange[YAxis].Min.x + gp.Mx * (plt.x - gp.CurrentPlot->XAxis.Range.Min)),
(float)(gp.PixelRange[YAxis].Min.y + gp.My[YAxis] * (plt.y - gp.CurrentPlot->YAxis[YAxis].Range.Min)) );
}
int YAxis;
const int YAxis;
};
// Transforms points for log x and linear y space
struct TransformerLogLin {
TransformerLogLin() : YAxis(GetCurrentYAxis()) {}
inline ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); }
inline ImVec2 operator()(double x, double y) {
inline ImVec2 operator()(const ImPlotPoint& plt) const {
ImPlotContext& gp = *GImPlot;
double t = ImLog10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX;
x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, (float)t);
double t = ImLog10(plt.x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX;
double x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, (float)t);
return ImVec2( (float)(gp.PixelRange[YAxis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)),
(float)(gp.PixelRange[YAxis].Min.y + gp.My[YAxis] * (y - gp.CurrentPlot->YAxis[YAxis].Range.Min)) );
(float)(gp.PixelRange[YAxis].Min.y + gp.My[YAxis] * (plt.y - gp.CurrentPlot->YAxis[YAxis].Range.Min)) );
}
int YAxis;
const int YAxis;
};
// Transforms points for linear x and log y space
struct TransformerLinLog {
TransformerLinLog() : YAxis(GetCurrentYAxis()) {}
inline ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); }
inline ImVec2 operator()(double x, double y) {
inline ImVec2 operator()(const ImPlotPoint& plt) const {
ImPlotContext& gp = *GImPlot;
double t = ImLog10(y / gp.CurrentPlot->YAxis[YAxis].Range.Min) / gp.LogDenY[YAxis];
y = ImLerp(gp.CurrentPlot->YAxis[YAxis].Range.Min, gp.CurrentPlot->YAxis[YAxis].Range.Max, (float)t);
return ImVec2( (float)(gp.PixelRange[YAxis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)),
double t = ImLog10(plt.y / gp.CurrentPlot->YAxis[YAxis].Range.Min) / gp.LogDenY[YAxis];
double y = ImLerp(gp.CurrentPlot->YAxis[YAxis].Range.Min, gp.CurrentPlot->YAxis[YAxis].Range.Max, (float)t);
return ImVec2( (float)(gp.PixelRange[YAxis].Min.x + gp.Mx * (plt.x - gp.CurrentPlot->XAxis.Range.Min)),
(float)(gp.PixelRange[YAxis].Min.y + gp.My[YAxis] * (y - gp.CurrentPlot->YAxis[YAxis].Range.Min)) );
}
int YAxis;
const int YAxis;
};
// Transforms points for log x and log y space
struct TransformerLogLog {
TransformerLogLog() : YAxis(GetCurrentYAxis()) {}
inline ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); }
inline ImVec2 operator()(double x, double y) {
inline ImVec2 operator()(const ImPlotPoint& plt) const {
ImPlotContext& gp = *GImPlot;
double t = ImLog10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX;
x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, (float)t);
t = ImLog10(y / gp.CurrentPlot->YAxis[YAxis].Range.Min) / gp.LogDenY[YAxis];
y = ImLerp(gp.CurrentPlot->YAxis[YAxis].Range.Min, gp.CurrentPlot->YAxis[YAxis].Range.Max, (float)t);
double t = ImLog10(plt.x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX;
double x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, (float)t);
t = ImLog10(plt.y / gp.CurrentPlot->YAxis[YAxis].Range.Min) / gp.LogDenY[YAxis];
double y = ImLerp(gp.CurrentPlot->YAxis[YAxis].Range.Min, gp.CurrentPlot->YAxis[YAxis].Range.Max, (float)t);
return ImVec2( (float)(gp.PixelRange[YAxis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)),
(float)(gp.PixelRange[YAxis].Min.y + gp.My[YAxis] * (y - gp.CurrentPlot->YAxis[YAxis].Range.Min)) );
}
int YAxis;
const int YAxis;
};
//-----------------------------------------------------------------------------
@ -460,16 +457,16 @@ inline void AddLine(const ImVec2& P1, const ImVec2& P2, float weight, ImU32 col,
template <typename TGetter, typename TTransformer>
struct LineStripRenderer {
inline LineStripRenderer(TGetter getter, TTransformer transformer, ImU32 col, float weight) :
inline LineStripRenderer(const TGetter& getter, const TTransformer& transformer, ImU32 col, float weight) :
Getter(getter),
Transformer(transformer)
{
Prims = Getter.Count - 1;
Col = col;
Weight = weight;
Transformer(transformer),
Prims(Getter.Count - 1),
Col(col),
Weight(weight)
{
P1 = Transformer(Getter(0));
}
inline bool operator()(ImDrawList& DrawList, const ImRect& cull_rect, const ImVec2& uv, int prim) {
inline bool operator()(ImDrawList& DrawList, const ImRect& cull_rect, const ImVec2& uv, int prim) const {
ImVec2 P2 = Transformer(Getter(prim + 1));
if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) {
P1 = P2;
@ -479,29 +476,27 @@ struct LineStripRenderer {
P1 = P2;
return true;
}
TGetter Getter;
TTransformer Transformer;
int Prims;
ImU32 Col;
float Weight;
ImVec2 P1;
const TGetter& Getter;
const TTransformer& Transformer;
const int Prims;
const ImU32 Col;
const float Weight;
mutable ImVec2 P1;
static const int IdxConsumed = 6;
static const int VtxConsumed = 4;
};
template <typename TGetter1, typename TGetter2, typename TTransformer>
struct LineSegmentsRenderer {
inline LineSegmentsRenderer(TGetter1 getter1, TGetter2 getter2, TTransformer transformer, ImU32 col, float weight) :
inline LineSegmentsRenderer(const TGetter1& getter1, const TGetter2& getter2, const TTransformer& transformer, ImU32 col, float weight) :
Getter1(getter1),
Getter2(getter2),
Transformer(transformer)
{
Prims = ImMin(Getter1.Count, Getter2.Count);
Col = col;
Weight = weight;
}
inline bool operator()(ImDrawList& DrawList, const ImRect& cull_rect, const ImVec2& uv, int prim) {
Transformer(transformer),
Prims(ImMin(Getter1.Count, Getter2.Count)),
Col(col),
Weight(weight)
{}
inline bool operator()(ImDrawList& DrawList, const ImRect& cull_rect, const ImVec2& uv, int prim) const {
ImVec2 P1 = Transformer(Getter1(prim));
ImVec2 P2 = Transformer(Getter2(prim));
if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2))))
@ -509,30 +504,30 @@ struct LineSegmentsRenderer {
AddLine(P1,P2,Weight,Col,DrawList,uv);
return true;
}
TGetter1 Getter1;
TGetter2 Getter2;
TTransformer Transformer;
int Prims;
ImU32 Col;
float Weight;
const TGetter1& Getter1;
const TGetter2& Getter2;
const TTransformer& Transformer;
const int Prims;
const ImU32 Col;
const float Weight;
static const int IdxConsumed = 6;
static const int VtxConsumed = 4;
};
template <typename TGetter1, typename TGetter2, typename TTransformer>
struct ShadedRenderer {
ShadedRenderer(TGetter1 getter1, TGetter2 getter2, TTransformer transformer, ImU32 col) :
ShadedRenderer(const TGetter1& getter1, const TGetter2& getter2, const TTransformer& transformer, ImU32 col) :
Getter1(getter1),
Getter2(getter2),
Transformer(transformer),
Prims(ImMin(Getter1.Count, Getter2.Count) - 1),
Col(col)
{
Prims = ImMin(Getter1.Count, Getter2.Count) - 1;
P11 = Transformer(Getter1(0));
P12 = Transformer(Getter2(0));
}
inline bool operator()(ImDrawList& DrawList, const ImRect& /*cull_rect*/, const ImVec2& uv, int prim) {
inline bool operator()(ImDrawList& DrawList, const ImRect& /*cull_rect*/, const ImVec2& uv, int prim) const {
// TODO: Culling
ImVec2 P21 = Transformer(Getter1(prim+1));
ImVec2 P22 = Transformer(Getter2(prim+1));
@ -566,26 +561,26 @@ struct ShadedRenderer {
P12 = P22;
return true;
}
TGetter1 Getter1;
TGetter2 Getter2;
TTransformer Transformer;
int Prims;
ImU32 Col;
ImVec2 P11, P12;
const TGetter1& Getter1;
const TGetter2& Getter2;
const TTransformer& Transformer;
const int Prims;
const ImU32 Col;
mutable ImVec2 P11;
mutable ImVec2 P12;
static const int IdxConsumed = 6;
static const int VtxConsumed = 5;
};
template <typename TGetter, typename TTransformer>
struct RectRenderer {
inline RectRenderer(TGetter getter, TTransformer transformer, ImU32 col) :
inline RectRenderer(const TGetter& getter, const TTransformer& transformer, ImU32 col) :
Getter(getter),
Transformer(transformer)
{
Prims = Getter.Count / 2;
Col = col;
}
inline bool operator()(ImDrawList& DrawList, const ImRect& /*cull_rect*/, const ImVec2& uv, int prim) {
Transformer(transformer),
Prims(Getter.Count / 2),
Col(col)
{}
inline bool operator()(ImDrawList& DrawList, const ImRect& /*cull_rect*/, const ImVec2& uv, int prim) const {
// TODO: Culling
ImVec2 P1 = Transformer(Getter(2*prim));
ImVec2 P2 = Transformer(Getter(2*prim+1));
@ -614,10 +609,10 @@ struct RectRenderer {
DrawList._VtxCurrentIdx += 4;
return true;
}
TGetter Getter;
TTransformer Transformer;
int Prims;
ImU32 Col;
const TGetter& Getter;
const TTransformer& Transformer;
const int Prims;
const ImU32 Col;
static const int IdxConsumed = 6;
static const int VtxConsumed = 4;
};
@ -630,7 +625,7 @@ template <> const unsigned int MaxIdx<unsigned int>::Value = 4294967295;
/// Renders primitive shapes in bulk as efficiently as possible.
template <typename Renderer>
inline void RenderPrimitives(Renderer renderer, ImDrawList& DrawList, const ImRect& cull_rect) {
inline void RenderPrimitives(const Renderer& renderer, ImDrawList& DrawList, const ImRect& cull_rect) {
unsigned int prims = renderer.Prims;
unsigned int prims_culled = 0;
unsigned int idx = 0;
@ -667,7 +662,7 @@ inline void RenderPrimitives(Renderer renderer, ImDrawList& DrawList, const ImRe
}
template <typename Getter, typename Transformer>
inline void RenderLineStrip(Getter getter, Transformer transformer, ImDrawList& DrawList, float line_weight, ImU32 col) {
inline void RenderLineStrip(const Getter& getter, const Transformer& transformer, ImDrawList& DrawList, float line_weight, ImU32 col) {
ImPlotContext& gp = *GImPlot;
if (ImHasFlag(gp.CurrentPlot->Flags, ImPlotFlags_AntiAliased) || gp.Style.AntiAliasedLines) {
ImVec2 p1 = transformer(getter(0));
@ -684,7 +679,7 @@ inline void RenderLineStrip(Getter getter, Transformer transformer, ImDrawList&
}
template <typename Getter1, typename Getter2, typename Transformer>
inline void RenderLineSegments(Getter1 getter1, Getter2 getter2, Transformer transformer, ImDrawList& DrawList, float line_weight, ImU32 col) {
inline void RenderLineSegments(const Getter1& getter1, const Getter2& getter2, const Transformer& transformer, ImDrawList& DrawList, float line_weight, ImU32 col) {
ImPlotContext& gp = *GImPlot;
if (ImHasFlag(gp.CurrentPlot->Flags, ImPlotFlags_AntiAliased) || gp.Style.AntiAliasedLines) {
int I = ImMin(getter1.Count, getter2.Count);
@ -810,11 +805,11 @@ inline void RenderMarkers(Getter getter, Transformer transformer, ImDrawList& Dr
}
//-----------------------------------------------------------------------------
// PLOT LINES
// PLOT LINE
//-----------------------------------------------------------------------------
template <typename Getter>
inline void PlotLineEx(const char* label_id, Getter getter) {
inline void PlotLineEx(const char* label_id, const Getter& getter) {
if (BeginItem(label_id, ImPlotCol_Line)) {
if (FitThisFrame()) {
for (int i = 0; i < getter.Count; ++i) {
@ -906,7 +901,7 @@ void PlotLineG(const char* label_id, ImPlotPoint (*getter_func)(void* data, int
//-----------------------------------------------------------------------------
template <typename Getter>
inline void PlotScatterEx(const char* label_id, Getter getter) {
inline void PlotScatterEx(const char* label_id, const Getter& getter) {
if (BeginItem(label_id, ImPlotCol_MarkerOutline)) {
if (FitThisFrame()) {
for (int i = 0; i < getter.Count; ++i) {
@ -990,7 +985,7 @@ void PlotScatterG(const char* label_id, ImPlotPoint (*getter_func)(void* data, i
//-----------------------------------------------------------------------------
template <typename Getter1, typename Getter2>
inline void PlotShadedEx(const char* label_id, Getter1 getter1, Getter2 getter2) {
inline void PlotShadedEx(const char* label_id, const Getter1& getter1, const Getter2& getter2) {
if (BeginItem(label_id, ImPlotCol_Fill)) {
if (FitThisFrame()) {
for (int i = 0; i < ImMin(getter1.Count, getter2.Count); ++i) {
@ -1082,10 +1077,10 @@ void PlotShadedG(const char* label_id, ImPlotPoint (*g1)(void* data, int idx), v
// TODO: Migrate to RenderPrimitives
template <typename Getter, typename TWidth>
void PlotBarsEx(const char* label_id, Getter getter, TWidth width) {
template <typename Getter>
void PlotBarsEx(const char* label_id, const Getter& getter, double width) {
if (BeginItem(label_id, ImPlotCol_Fill)) {
const TWidth half_width = width / 2;
const double half_width = width / 2;
if (FitThisFrame()) {
for (int i = 0; i < getter.Count; ++i) {
ImPlotPoint p = getter(i);
@ -1162,7 +1157,7 @@ void PlotBarsG(const char* label_id, ImPlotPoint (*getter_func)(void* data, int
// TODO: Migrate to RenderPrimitives
template <typename Getter, typename THeight>
void PlotBarsHEx(const char* label_id, Getter getter, THeight height) {
void PlotBarsHEx(const char* label_id, const Getter& getter, THeight height) {
if (BeginItem(label_id, ImPlotCol_Fill)) {
const THeight half_height = height / 2;
if (FitThisFrame()) {
@ -1239,7 +1234,7 @@ void PlotBarsHG(const char* label_id, ImPlotPoint (*getter_func)(void* data, int
//-----------------------------------------------------------------------------
template <typename Getter>
void PlotErrorBarsEx(const char* label_id, Getter getter) {
void PlotErrorBarsEx(const char* label_id, const Getter& getter) {
if (BeginItem(label_id)) {
if (FitThisFrame()) {
for (int i = 0; i < getter.Count; ++i) {
@ -1267,34 +1262,45 @@ void PlotErrorBarsEx(const char* label_id, Getter getter) {
}
}
// float
void PlotErrorBars(const char* label_id, const float* xs, const float* ys, const float* err, int count, int offset, int stride) {
GetterError<float> getter(xs, ys, err, err, count, offset, stride);
template <typename T>
void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* err, int count, int offset, int stride) {
GetterError<T> getter(xs, ys, err, err, count, offset, stride);
PlotErrorBarsEx(label_id, getter);
}
void PlotErrorBars(const char* label_id, const float* xs, const float* ys, const float* neg, const float* pos, int count, int offset, int stride) {
GetterError<float> getter(xs, ys, neg, pos, count, offset, stride);
PlotErrorBarsEx(label_id, getter);
}
template void PlotErrorBars<ImS8>(const char* label_id, const ImS8* xs, const ImS8* ys, const ImS8* err, int count, int offset, int stride);
template void PlotErrorBars<ImU8>(const char* label_id, const ImU8* xs, const ImU8* ys, const ImU8* err, int count, int offset, int stride);
template void PlotErrorBars<ImS16>(const char* label_id, const ImS16* xs, const ImS16* ys, const ImS16* err, int count, int offset, int stride);
template void PlotErrorBars<ImU16>(const char* label_id, const ImU16* xs, const ImU16* ys, const ImU16* err, int count, int offset, int stride);
template void PlotErrorBars<ImS32>(const char* label_id, const ImS32* xs, const ImS32* ys, const ImS32* err, int count, int offset, int stride);
template void PlotErrorBars<ImU32>(const char* label_id, const ImU32* xs, const ImU32* ys, const ImU32* err, int count, int offset, int stride);
template void PlotErrorBars<ImS64>(const char* label_id, const ImS64* xs, const ImS64* ys, const ImS64* err, int count, int offset, int stride);
template void PlotErrorBars<ImU64>(const char* label_id, const ImU64* xs, const ImU64* ys, const ImU64* err, int count, int offset, int stride);
template void PlotErrorBars<float>(const char* label_id, const float* xs, const float* ys, const float* err, int count, int offset, int stride);
template void PlotErrorBars<double>(const char* label_id, const double* xs, const double* ys, const double* err, int count, int offset, int stride);
// double
void PlotErrorBars(const char* label_id, const double* xs, const double* ys, const double* err, int count, int offset, int stride) {
GetterError<double> getter(xs, ys, err, err, count, offset, stride);
PlotErrorBarsEx(label_id, getter);
}
void PlotErrorBars(const char* label_id, const double* xs, const double* ys, const double* neg, const double* pos, int count, int offset, int stride) {
GetterError<double> getter(xs, ys, neg, pos, count, offset, stride);
template <typename T>
void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* neg, const T* pos, int count, int offset, int stride) {
GetterError<T> getter(xs, ys, neg, pos, count, offset, stride);
PlotErrorBarsEx(label_id, getter);
}
template void PlotErrorBars<ImS8>(const char* label_id, const ImS8* xs, const ImS8* ys, const ImS8* neg, const ImS8* pos, int count, int offset, int stride);
template void PlotErrorBars<ImU8>(const char* label_id, const ImU8* xs, const ImU8* ys, const ImU8* neg, const ImU8* pos, int count, int offset, int stride);
template void PlotErrorBars<ImS16>(const char* label_id, const ImS16* xs, const ImS16* ys, const ImS16* neg, const ImS16* pos, int count, int offset, int stride);
template void PlotErrorBars<ImU16>(const char* label_id, const ImU16* xs, const ImU16* ys, const ImU16* neg, const ImU16* pos, int count, int offset, int stride);
template void PlotErrorBars<ImS32>(const char* label_id, const ImS32* xs, const ImS32* ys, const ImS32* neg, const ImS32* pos, int count, int offset, int stride);
template void PlotErrorBars<ImU32>(const char* label_id, const ImU32* xs, const ImU32* ys, const ImU32* neg, const ImU32* pos, int count, int offset, int stride);
template void PlotErrorBars<ImS64>(const char* label_id, const ImS64* xs, const ImS64* ys, const ImS64* neg, const ImS64* pos, int count, int offset, int stride);
template void PlotErrorBars<ImU64>(const char* label_id, const ImU64* xs, const ImU64* ys, const ImU64* neg, const ImU64* pos, int count, int offset, int stride);
template void PlotErrorBars<float>(const char* label_id, const float* xs, const float* ys, const float* neg, const float* pos, int count, int offset, int stride);
template void PlotErrorBars<double>(const char* label_id, const double* xs, const double* ys, const double* neg, const double* pos, int count, int offset, int stride);
//-----------------------------------------------------------------------------
// PLOT ERROR BARS H
//-----------------------------------------------------------------------------
template <typename Getter>
void PlotErrorBarsHEx(const char* label_id, Getter getter) {
void PlotErrorBarsHEx(const char* label_id, const Getter& getter) {
if (BeginItem(label_id)) {
if (FitThisFrame()) {
for (int i = 0; i < getter.Count; ++i) {
@ -1322,34 +1328,46 @@ void PlotErrorBarsHEx(const char* label_id, Getter getter) {
}
}
// float
void PlotErrorBarsH(const char* label_id, const float* xs, const float* ys, const float* err, int count, int offset, int stride) {
GetterError<float> getter(xs, ys, err, err, count, offset, stride);
template <typename T>
void PlotErrorBarsH(const char* label_id, const T* xs, const T* ys, const T* err, int count, int offset, int stride) {
GetterError<T> getter(xs, ys, err, err, count, offset, stride);
PlotErrorBarsHEx(label_id, getter);
}
void PlotErrorBarsH(const char* label_id, const float* xs, const float* ys, const float* neg, const float* pos, int count, int offset, int stride) {
GetterError<float> getter(xs, ys, neg, pos, count, offset, stride);
template void PlotErrorBarsH<ImS8>(const char* label_id, const ImS8* xs, const ImS8* ys, const ImS8* err, int count, int offset, int stride);
template void PlotErrorBarsH<ImU8>(const char* label_id, const ImU8* xs, const ImU8* ys, const ImU8* err, int count, int offset, int stride);
template void PlotErrorBarsH<ImS16>(const char* label_id, const ImS16* xs, const ImS16* ys, const ImS16* err, int count, int offset, int stride);
template void PlotErrorBarsH<ImU16>(const char* label_id, const ImU16* xs, const ImU16* ys, const ImU16* err, int count, int offset, int stride);
template void PlotErrorBarsH<ImS32>(const char* label_id, const ImS32* xs, const ImS32* ys, const ImS32* err, int count, int offset, int stride);
template void PlotErrorBarsH<ImU32>(const char* label_id, const ImU32* xs, const ImU32* ys, const ImU32* err, int count, int offset, int stride);
template void PlotErrorBarsH<ImS64>(const char* label_id, const ImS64* xs, const ImS64* ys, const ImS64* err, int count, int offset, int stride);
template void PlotErrorBarsH<ImU64>(const char* label_id, const ImU64* xs, const ImU64* ys, const ImU64* err, int count, int offset, int stride);
template void PlotErrorBarsH<float>(const char* label_id, const float* xs, const float* ys, const float* err, int count, int offset, int stride);
template void PlotErrorBarsH<double>(const char* label_id, const double* xs, const double* ys, const double* err, int count, int offset, int stride);
template <typename T>
void PlotErrorBarsH(const char* label_id, const T* xs, const T* ys, const T* neg, const T* pos, int count, int offset, int stride) {
GetterError<T> getter(xs, ys, neg, pos, count, offset, stride);
PlotErrorBarsHEx(label_id, getter);
}
// double
void PlotErrorBarsH(const char* label_id, const double* xs, const double* ys, const double* err, int count, int offset, int stride) {
GetterError<double> getter(xs, ys, err, err, count, offset, stride);
PlotErrorBarsHEx(label_id, getter);
}
void PlotErrorBarsH(const char* label_id, const double* xs, const double* ys, const double* neg, const double* pos, int count, int offset, int stride) {
GetterError<double> getter(xs, ys, neg, pos, count, offset, stride);
PlotErrorBarsHEx(label_id, getter);
}
template void PlotErrorBarsH<ImS8>(const char* label_id, const ImS8* xs, const ImS8* ys, const ImS8* neg, const ImS8* pos, int count, int offset, int stride);
template void PlotErrorBarsH<ImU8>(const char* label_id, const ImU8* xs, const ImU8* ys, const ImU8* neg, const ImU8* pos, int count, int offset, int stride);
template void PlotErrorBarsH<ImS16>(const char* label_id, const ImS16* xs, const ImS16* ys, const ImS16* neg, const ImS16* pos, int count, int offset, int stride);
template void PlotErrorBarsH<ImU16>(const char* label_id, const ImU16* xs, const ImU16* ys, const ImU16* neg, const ImU16* pos, int count, int offset, int stride);
template void PlotErrorBarsH<ImS32>(const char* label_id, const ImS32* xs, const ImS32* ys, const ImS32* neg, const ImS32* pos, int count, int offset, int stride);
template void PlotErrorBarsH<ImU32>(const char* label_id, const ImU32* xs, const ImU32* ys, const ImU32* neg, const ImU32* pos, int count, int offset, int stride);
template void PlotErrorBarsH<ImS64>(const char* label_id, const ImS64* xs, const ImS64* ys, const ImS64* neg, const ImS64* pos, int count, int offset, int stride);
template void PlotErrorBarsH<ImU64>(const char* label_id, const ImU64* xs, const ImU64* ys, const ImU64* neg, const ImU64* pos, int count, int offset, int stride);
template void PlotErrorBarsH<float>(const char* label_id, const float* xs, const float* ys, const float* neg, const float* pos, int count, int offset, int stride);
template void PlotErrorBarsH<double>(const char* label_id, const double* xs, const double* ys, const double* neg, const double* pos, int count, int offset, int stride);
//-----------------------------------------------------------------------------
// PLOT STEMS
//-----------------------------------------------------------------------------
template <typename GetterM, typename GetterB>
inline void PlotStemsEx(const char* label_id, GetterM get_mark, GetterB get_base) {
inline void PlotStemsEx(const char* label_id, const GetterM& get_mark, const GetterB& get_base) {
if (BeginItem(label_id, ImPlotCol_Line)) {
if (FitThisFrame()) {
for (int i = 0; i < get_base.Count; ++i) {
@ -1385,29 +1403,41 @@ inline void PlotStemsEx(const char* label_id, GetterM get_mark, GetterB get_base
}
}
void PlotStems(const char* label_id, const float* values, int count, float y_ref, int offset, int stride) {
GetterYs<float> get_mark(values,count,offset,stride);
GetterYRef<float> get_base(y_ref,count);
PlotStemsEx(label_id, get_mark, get_base);
}
void PlotStems(const char* label_id, const double* values, int count, double y_ref, int offset, int stride) {
GetterYs<double> get_mark(values,count,offset,stride);
template <typename T>
void PlotStems(const char* label_id, const T* values, int count, double y_ref, int offset, int stride) {
GetterYs<T> get_mark(values,count,offset,stride);
GetterYRef<double> get_base(y_ref,count);
PlotStemsEx(label_id, get_mark, get_base);
}
void PlotStems(const char* label_id, const float* xs, const float* ys, int count, float y_ref, int offset, int stride) {
GetterXsYs<float> get_mark(xs,ys,count,offset,stride);
GetterXsYRef<float,float> get_base(xs,y_ref,count,offset,stride);
template void PlotStems<ImS8>(const char* label_id, const ImS8* values, int count, double y_ref, int offset, int stride);
template void PlotStems<ImU8>(const char* label_id, const ImU8* values, int count, double y_ref, int offset, int stride);
template void PlotStems<ImS16>(const char* label_id, const ImS16* values, int count, double y_ref, int offset, int stride);
template void PlotStems<ImU16>(const char* label_id, const ImU16* values, int count, double y_ref, int offset, int stride);
template void PlotStems<ImS32>(const char* label_id, const ImS32* values, int count, double y_ref, int offset, int stride);
template void PlotStems<ImU32>(const char* label_id, const ImU32* values, int count, double y_ref, int offset, int stride);
template void PlotStems<ImS64>(const char* label_id, const ImS64* values, int count, double y_ref, int offset, int stride);
template void PlotStems<ImU64>(const char* label_id, const ImU64* values, int count, double y_ref, int offset, int stride);
template void PlotStems<float>(const char* label_id, const float* values, int count, double y_ref, int offset, int stride);
template void PlotStems<double>(const char* label_id, const double* values, int count, double y_ref, int offset, int stride);
template <typename T>
void PlotStems(const char* label_id, const T* xs, const T* ys, int count, double y_ref, int offset, int stride) {
GetterXsYs<T> get_mark(xs,ys,count,offset,stride);
GetterXsYRef<T,double> get_base(xs,y_ref,count,offset,stride);
PlotStemsEx(label_id, get_mark, get_base);
}
void PlotStems(const char* label_id, const double* xs, const double* ys, int count, double y_ref, int offset, int stride) {
GetterXsYs<double> get_mark(xs,ys,count,offset,stride);
GetterXsYRef<double,double> get_base(xs,y_ref,count,offset,stride);
PlotStemsEx(label_id, get_mark, get_base);
}
template void PlotStems<ImS8>(const char* label_id, const ImS8* xs, const ImS8* ys, int count, double y_ref, int offset, int stride);
template void PlotStems<ImU8>(const char* label_id, const ImU8* xs, const ImU8* ys, int count, double y_ref, int offset, int stride);
template void PlotStems<ImS16>(const char* label_id, const ImS16* xs, const ImS16* ys, int count, double y_ref, int offset, int stride);
template void PlotStems<ImU16>(const char* label_id, const ImU16* xs, const ImU16* ys, int count, double y_ref, int offset, int stride);
template void PlotStems<ImS32>(const char* label_id, const ImS32* xs, const ImS32* ys, int count, double y_ref, int offset, int stride);
template void PlotStems<ImU32>(const char* label_id, const ImU32* xs, const ImU32* ys, int count, double y_ref, int offset, int stride);
template void PlotStems<ImS64>(const char* label_id, const ImS64* xs, const ImS64* ys, int count, double y_ref, int offset, int stride);
template void PlotStems<ImU64>(const char* label_id, const ImU64* xs, const ImU64* ys, int count, double y_ref, int offset, int stride);
template void PlotStems<float>(const char* label_id, const float* xs, const float* ys, int count, double y_ref, int offset, int stride);
template void PlotStems<double>(const char* label_id, const double* xs, const double* ys, int count, double y_ref, int offset, int stride);
//-----------------------------------------------------------------------------
// PLOT PIE CHART
@ -1427,19 +1457,19 @@ inline void RenderPieSlice(ImDrawList& DrawList, const ImPlotPoint& center, doub
}
template <typename T>
void PlotPieChartEx(const char* const label_ids[], const T* values, int count, T x, T y, T radius, bool normalize, const char* fmt, T angle0) {
void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, bool normalize, const char* fmt, double angle0) {
IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL, "PlotPieChart() needs to be called between BeginPlot() and EndPlot()!");
ImDrawList & DrawList = *GetPlotDrawList();
T sum = 0;
double sum = 0;
for (int i = 0; i < count; ++i)
sum += values[i];
normalize = normalize || sum > 1.0f;
sum += (double)values[i];
normalize = normalize || sum > 1.0;
ImPlotPoint center(x,y);
PushPlotClipRect();
T a0 = angle0 * 2 * IM_PI / 360.0f;
T a1 = angle0 * 2 * IM_PI / 360.0f;
double a0 = angle0 * 2 * IM_PI / 360.0;
double a1 = angle0 * 2 * IM_PI / 360.0;
for (int i = 0; i < count; ++i) {
T percent = normalize ? values[i] / sum : values[i];
double percent = normalize ? (double)values[i] / sum : (double)values[i];
a1 = a0 + 2 * IM_PI * percent;
if (BeginItem(label_ids[i])) {
ImU32 col = ImGui::GetColorU32(GetCurrentItem()->Color);
@ -1447,26 +1477,26 @@ void PlotPieChartEx(const char* const label_ids[], const T* values, int count, T
RenderPieSlice(DrawList, center, radius, a0, a1, col);
}
else {
RenderPieSlice(DrawList, center, radius, a0, a0 + (a1 - a0) * 0.5f, col);
RenderPieSlice(DrawList, center, radius, a0 + (a1 - a0) * 0.5f, a1, col);
RenderPieSlice(DrawList, center, radius, a0, a0 + (a1 - a0) * 0.5, col);
RenderPieSlice(DrawList, center, radius, a0 + (a1 - a0) * 0.5, a1, col);
}
EndItem();
}
a0 = a1;
}
if (fmt != NULL) {
a0 = angle0 * 2 * IM_PI / 360.0f;
a1 = angle0 * 2 * IM_PI / 360.0f;
a0 = angle0 * 2 * IM_PI / 360.0;
a1 = angle0 * 2 * IM_PI / 360.0;
char buffer[32];
for (int i = 0; i < count; ++i) {
ImPlotItem* item = GetItem(label_ids[i]);
T percent = normalize ? values[i] / sum : values[i];
double percent = normalize ? (double)values[i] / sum : (double)values[i];
a1 = a0 + 2 * IM_PI * percent;
if (item->Show) {
sprintf(buffer, fmt, values[i]);
sprintf(buffer, fmt, (double)values[i]);
ImVec2 size = ImGui::CalcTextSize(buffer);
T angle = a0 + (a1 - a0) * 0.5f;
ImVec2 pos = PlotToPixels(center.x + 0.5f * radius * cos(angle), center.y + 0.5f * radius * sin(angle));
double angle = a0 + (a1 - a0) * 0.5;
ImVec2 pos = PlotToPixels(center.x + 0.5 * radius * cos(angle), center.y + 0.5 * radius * sin(angle));
ImU32 col = CalcTextColor(item->Color);
DrawList.AddText(pos - size * 0.5f, col, buffer);
}
@ -1476,22 +1506,23 @@ void PlotPieChartEx(const char* const label_ids[], const T* values, int count, T
PopPlotClipRect();
}
// float
void PlotPieChart(const char* const label_ids[], const float* values, int count, float x, float y, float radius, bool normalize, const char* fmt, float angle0) {
return PlotPieChartEx(label_ids, values, count, x, y, radius, normalize, fmt, angle0);
}
// double
void PlotPieChart(const char* const label_ids[], const double* values, int count, double x, double y, double radius, bool normalize, const char* fmt, double angle0) {
return PlotPieChartEx(label_ids, values, count, x, y, radius, normalize, fmt, angle0);
}
template void PlotPieChart<ImS8>(const char* const label_ids[], const ImS8* values, int count, double x, double y, double radius, bool normalize, const char* fmt, double angle0);
template void PlotPieChart<ImU8>(const char* const label_ids[], const ImU8* values, int count, double x, double y, double radius, bool normalize, const char* fmt, double angle0);
template void PlotPieChart<ImS16>(const char* const label_ids[], const ImS16* values, int count, double x, double y, double radius, bool normalize, const char* fmt, double angle0);
template void PlotPieChart<ImU16>(const char* const label_ids[], const ImU16* values, int count, double x, double y, double radius, bool normalize, const char* fmt, double angle0);
template void PlotPieChart<ImS32>(const char* const label_ids[], const ImS32* values, int count, double x, double y, double radius, bool normalize, const char* fmt, double angle0);
template void PlotPieChart<ImU32>(const char* const label_ids[], const ImU32* values, int count, double x, double y, double radius, bool normalize, const char* fmt, double angle0);
template void PlotPieChart<ImS64>(const char* const label_ids[], const ImS64* values, int count, double x, double y, double radius, bool normalize, const char* fmt, double angle0);
template void PlotPieChart<ImU64>(const char* const label_ids[], const ImU64* values, int count, double x, double y, double radius, bool normalize, const char* fmt, double angle0);
template void PlotPieChart<float>(const char* const label_ids[], const float* values, int count, double x, double y, double radius, bool normalize, const char* fmt, double angle0);
template void PlotPieChart<double>(const char* const label_ids[], const double* values, int count, double x, double y, double radius, bool normalize, const char* fmt, double angle0);
//-----------------------------------------------------------------------------
// PLOT HEATMAP
//-----------------------------------------------------------------------------
template <typename T, typename Transformer>
void RenderHeatmap(Transformer transformer, ImDrawList& DrawList, const T* values, int rows, int cols, T scale_min, T scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max) {
void RenderHeatmap(Transformer transformer, ImDrawList& DrawList, const T* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max) {
ImPlotContext& gp = *GImPlot;
const double w = (bounds_max.x - bounds_min.x) / cols;
const double h = (bounds_max.y - bounds_min.y) / rows;
@ -1502,10 +1533,10 @@ void RenderHeatmap(Transformer transformer, ImDrawList& DrawList, const T* value
ImPlotPoint p;
p.x = bounds_min.x + 0.5*w + c*w;
p.y = bounds_max.y - (0.5*h + r*h);
ImVec2 a = transformer(p.x - half_size.x, p.y - half_size.y);
ImVec2 b = transformer(p.x + half_size.x, p.y + half_size.y);
float t = (float)ImRemap(values[i], scale_min, scale_max, T(0), T(1));
ImVec4 color = LerpColormap(t);
ImVec2 a = transformer(ImPlotPoint(p.x - half_size.x, p.y - half_size.y));
ImVec2 b = transformer(ImPlotPoint(p.x + half_size.x, p.y + half_size.y));
double t = ImRemap((double)values[i], scale_min, scale_max, 0.0, 1.0);
ImVec4 color = LerpColormap((float)t);
color.w *= gp.Style.FillAlpha;
ImU32 col = ImGui::GetColorU32(color);
DrawList.AddRectFilled(a, b, col);
@ -1523,8 +1554,8 @@ void RenderHeatmap(Transformer transformer, ImDrawList& DrawList, const T* value
char buff[32];
sprintf(buff, fmt, values[i]);
ImVec2 size = ImGui::CalcTextSize(buff);
float t = (float)ImRemap(values[i], scale_min, scale_max, T(0), T(1));
ImVec4 color = LerpColormap(t);
double t = ImRemap((double)values[i], scale_min, scale_max, 0.0, 1.0);
ImVec4 color = LerpColormap((float)t);
ImU32 col = CalcTextColor(color);
DrawList.AddText(px - size * 0.5f, col, buff);
i++;
@ -1534,7 +1565,7 @@ void RenderHeatmap(Transformer transformer, ImDrawList& DrawList, const T* value
}
template <typename T>
void PlotHeatmapEx(const char* label_id, const T* values, int rows, int cols, T scale_min, T scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max) {
void PlotHeatmap(const char* label_id, const T* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max) {
IM_ASSERT_USER_ERROR(scale_min != scale_max, "Scale values must be different!");
if (BeginItem(label_id)) {
if (FitThisFrame()) {
@ -1552,21 +1583,22 @@ void PlotHeatmapEx(const char* label_id, const T* values, int rows, int cols, T
}
}
// float
void PlotHeatmap(const char* label_id, const float* values, int rows, int cols, float scale_min, float scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max) {
return PlotHeatmapEx(label_id, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max);
}
// double
void PlotHeatmap(const char* label_id, const double* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max) {
return PlotHeatmapEx(label_id, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max);
}
template void PlotHeatmap<ImS8>(const char* label_id, const ImS8* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max);
template void PlotHeatmap<ImU8>(const char* label_id, const ImU8* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max);
template void PlotHeatmap<ImS16>(const char* label_id, const ImS16* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max);
template void PlotHeatmap<ImU16>(const char* label_id, const ImU16* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max);
template void PlotHeatmap<ImS32>(const char* label_id, const ImS32* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max);
template void PlotHeatmap<ImU32>(const char* label_id, const ImU32* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max);
template void PlotHeatmap<ImS64>(const char* label_id, const ImS64* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max);
template void PlotHeatmap<ImU64>(const char* label_id, const ImU64* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max);
template void PlotHeatmap<float>(const char* label_id, const float* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max);
template void PlotHeatmap<double>(const char* label_id, const double* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max);
//-----------------------------------------------------------------------------
// PLOT DIGITAL
//-----------------------------------------------------------------------------
// TODO: Make this behave like all the other plot types
// TODO: Make this behave like all the other plot types (.e. not fixed in y axis)
template <typename Getter>
inline void PlotDigitalEx(const char* label_id, Getter getter) {
@ -1624,20 +1656,26 @@ inline void PlotDigitalEx(const char* label_id, Getter getter) {
}
}
// float
void PlotDigital(const char* label_id, const float* xs, const float* ys, int count, int offset, int stride) {
GetterXsYs<float> getter(xs,ys,count,offset,stride);
template <typename T>
void PlotDigital(const char* label_id, const T* xs, const T* ys, int count, int offset, int stride) {
GetterXsYs<T> getter(xs,ys,count,offset,stride);
return PlotDigitalEx(label_id, getter);
}
// double
void PlotDigital(const char* label_id, const double* xs, const double* ys, int count, int offset, int stride) {
GetterXsYs<double> getter(xs,ys,count,offset,stride);
return PlotDigitalEx(label_id, getter);
}
template void PlotDigital<ImS8>(const char* label_id, const ImS8* xs, const ImS8* ys, int count, int offset, int stride);
template void PlotDigital<ImU8>(const char* label_id, const ImU8* xs, const ImU8* ys, int count, int offset, int stride);
template void PlotDigital<ImS16>(const char* label_id, const ImS16* xs, const ImS16* ys, int count, int offset, int stride);
template void PlotDigital<ImU16>(const char* label_id, const ImU16* xs, const ImU16* ys, int count, int offset, int stride);
template void PlotDigital<ImS32>(const char* label_id, const ImS32* xs, const ImS32* ys, int count, int offset, int stride);
template void PlotDigital<ImU32>(const char* label_id, const ImU32* xs, const ImU32* ys, int count, int offset, int stride);
template void PlotDigital<ImS64>(const char* label_id, const ImS64* xs, const ImS64* ys, int count, int offset, int stride);
template void PlotDigital<ImU64>(const char* label_id, const ImU64* xs, const ImU64* ys, int count, int offset, int stride);
template void PlotDigital<float>(const char* label_id, const float* xs, const float* ys, int count, int offset, int stride);
template void PlotDigital<double>(const char* label_id, const double* xs, const double* ys, int count, int offset, int stride);
// custom
void PlotDigital(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, int offset) {
void PlotDigitalG(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, int offset) {
GetterFuncPtrImPlotPoint getter(getter_func,data,count,offset);
return PlotDigitalEx(label_id, getter);
}
@ -1646,7 +1684,7 @@ void PlotDigital(const char* label_id, ImPlotPoint (*getter_func)(void* data, in
// PLOT RECTS
//-----------------------------------------------------------------------------
template <typename Getter>
void PlotRectsEx(const char* label_id, Getter getter) {
void PlotRectsEx(const char* label_id, const Getter& getter) {
if (BeginItem(label_id, ImPlotCol_Fill)) {
if (FitThisFrame()) {
for (int i = 0; i < getter.Count; ++i) {
@ -1691,11 +1729,6 @@ void PlotRects(const char* label_id, ImPlotPoint (*getter_func)(void* data, int
// PLOT TEXT
//-----------------------------------------------------------------------------
// float
void PlotText(const char* text, float x, float y, bool vertical, const ImVec2& pixel_offset) {
return PlotText(text, (double)x, (double)y, vertical, pixel_offset);
}
// double
void PlotText(const char* text, double x, double y, bool vertical, const ImVec2& pixel_offset) {
IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL, "PlotText() needs to be called between BeginPlot() and EndPlot()!");