Plotting math functions (quadratic functions) in C++11 on Ubuntu using ImGui

I'm trying to plot a math function (specifically a quadratic function) using ImGUI, and was wondering where I should start from?

I'm trying to achieve something like this: https://www.youtube.com/watch?v=F8KpvjdZTMc

I'm using SFML to render the window and the GUI tools from ImGUI.

I'm thinking that I need to understand how the "ImGUI::PlotLines" function works and then simply add the math to its parameters, but I'm unsure what the parameters are for PlotLines. Any ImGUI experts in here?
Last edited on
Hey there, thanks for the response.

So I'm currently here with the code:
1
2
ImGui::PlotLines("", [](void*data, int idx) { return (((0.4f*idx)*(0.4f*idx))+1.2f*idx+0.30f);}, 
NULL, 100, 0, NULL, -10.0f, 10.0f, ImVec2(780, 255));


I'm trying to achieve a parabolic curve, but it seems to give me the following result instead:
https://imgur.com/a/XCugNOm
Last edited on
What is the x value of the left side of your plot? Where is it set in the PlotLines call?
Do you have a link to the manual page for ImGui::PlotLines?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ImGui::PlotLines(
    "",                           // label
    [](void* data, int idx)       // values_getter
    {
        return 0.16f * idx * idx
             + 1.20f * idx
             + 0.30f;
    },
    NULL,                         // data
    100,                          // values_count
    0,                            // values_offset
    NULL,                         // overlay_text
    -10.0f,                       // scale_min (y value)
     10.0f,                       // scale_max (y value)
    ImVec2(780, 255)              // graph_size
);

I'm guessing the scale values are for y because of the python documentation here: https://pyimgui.readthedocs.io/en/latest/reference/imgui.core.html?highlight=plotlines

I found this in the header file (https://github.com/ocornut/imgui/blob/master/imgui.h):

1
2
3
4
5
6
7
8
9
10
11
void
PlotLines(
    const char* label,
    float(*values_getter)(void* data, int idx),
    void* data,
    int values_count,
    int values_offset = 0,
    const char* overlay_text = NULL,
    float scale_min = FLT_MAX,
    float scale_max = FLT_MAX,
    ImVec2 graph_size = ImVec2(0, 0));


Why is the default for scale_min not negative (FLT_MIN)?
Why is there a "data" input and a "values_getter" input? (EDIT: I think I understand this.)
What is the "data" input to the values_getter function for? (EDIT: and this.)

EDIT: Try this for values_getter, keeping all other inputs the same:

1
2
3
4
5
6
7
    [](void* data, int idx)       // values_getter
    {
        float x = idx / 5.0f - 10.0f;  // generate an x value from -10 to 10 from idx's from 0 to 99
        return 0.16f * x * x
             + 1.20f * x
             + 0.30f;
    }


Last edited on
Hey there, thanks for the response.

The values_getter that you mentioned, gives me the following result:
(The first picture)
https://imgur.com/a/XCugNOm

Not sure what x value you're referring to, but the equation I'm returning, is basically a random generated quadratic equation.

I really can't answer the other questions, since I'm no expert in ImGUI, but it seems that you've done some research.
Last edited on
I guess that picture is a little better. It's a horizontally stretched out parabola with the right side going "off the chart", as it were.

Looking at the python documentation, it looks like scale_min and scale_max are only for the y dimension.
So I'm wondering where the same thing is set for the x dimension.

What do you get if you leave off the last parameter, the ImVec2, and let it use the default? Maybe it will set it itself (or maybe you'll get nothing).

You might also try passing ImVec2(-10, 10).
Last edited on
Are you sure you are not just "clipping" at the top?

Increase the maximum y value.
@lastchance, that's not an overall solution, though. Obviously the top is "clipping". But we need to find out how to set the x boundaries.

@emilo, also try ImVec2(500, 500) (i.e., make it square).
Last edited on
@dutch

https://imgur.com/a/XCugNOm
- Third picture = Default ImVec2 settings
- Second Picture = Another quadratic equation, compared to the same quadratic equation but in another software application designed to draw math functions.
- First picture = ImVec2(500, 500)

PS: ImVec2(-10, 10) = no display of line, since the ImVec2 paramter is a positioning parameter.

since the ImVec2 paramter is a positioning parameter

If there is some documentation that you are referencing, give us a link!

Try this (my last guess):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
float data[100];
for (int i = 0; i < 100; ++i)
    data[i] = i / 5.0f - 10.0f;

ImGui::PlotLines(
    "",                           // label
    [](void* data, int i)         // values_getter
    {
        float *vals = static_cast<float*>(data);
        return 0.16f * vals[i] * vals[i]
             + 1.20f * vals[i]
             + 0.30f;
    },
    data,                         // data
    100,                          // values_count
    0,                            // values_offset
    NULL,                         // overlay_text
    -10.0f,                       // scale_min (y value)
     10.0f,                       // scale_max (y value)
    ImVec2(500, 500)              // graph_size
);


Or does that need to be a reinterpret_cast? I didn't test it.

EDIT: Now that I think about it, that's not going to work at all, is it.... oh well.
Some documentation/example would be useful.
Last edited on
I'm technically assuming that ImVec2 is a positioning parameter, since it changes the x/y position of an object that I'm drawing and in the time that I've been playing with ImVec2, it's been doing what I suspected it to do, which was to change the positioning. I don't have any documentation for it though.

Your try produced the following (picture one)
https://imgur.com/a/XCugNOm

but to be honest, I think you actually did fix it, since picture 3 really does produce a quadratic/parabolic curve really similar to the actual curve (possibly the same).

So I'll just try and work out a grid for this and then see what I can do from there.

I really appreciate the help :)
This is all the 'documentation' I've had a look at:
https://github.com/ocornut/imgui/blob/master/imgui_demo.cpp

Ctrl+F ("plotlines")
Definitely try what lastchance said. Increase scale_max to fix the clipping. I would try ImVec2(500, 500) (or other equal values) to see if that makes the window square. Or maybe the window size is set somewhere else? I have no idea how it is choosing the x boundaries. Anyway, I'm done for now. Good luck!
The link to the header file that @dutch gave earlier shows two overloads of procedure PlotLines: the first takes a pre-computed array of values, the second a pointer to a function that will compute those values. You are currently trying to use the second of these, although I believe that you might actually do better pre-computing the values and using the first, because then you could work out what the max and min values of y were.

1
2
3
IMGUI_API void PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float));

IMGUI_API void PlotLines(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0));


I believe that @dutch's guess was correct. The function takes the integers 0, ..., values_count-1 and returns the value at these points. On this basis, the LHS of the window will correspond to the function returned for idx = 0 and the RHS of the window will correspond to the function returned for idx = values_count - 1.

You appear to have to manually set minimum y and maximum y (which is why a pre-computed array with these limits found might be better). At present, the plotter seems to be clipping at upper (and, presumably, lower) limits; this is relatively unusual behaviour for a plotting routine; I would prefer it to simply stop drawing at this point. Maybe there is some setting in ImGUI to change this. I have no idea what "values_offset" does; I suggest you leave it with the default value 0.

Don't just guess "any old quadratic" - why not construct one for which you know the limits.
1
2
3
4
5
6
7
[](void* data, int idx )       // values_getter
{
    float x = ( idx - 49.5f )/ 49.5f;  // generate an x value from -1 to 1 from idx's from 0 to 99

    // and make sure that its y-limits for this interval are -1 and 1
    return -1.0f + 2.0f * x * x;
}


Now call your function with
values_count = 100;
scale_min = -1.0f;
scale_max = 1.0f;

Let us know how you get on (and preferably show your code).


Last edited on
Hey there @lastchance, thanks for your response!

I tried out your suggestion with the following code:
1
2
3
4
5
6
7
8
    auto values = [](void* data, int idx )
	{
	    float x = ( idx - 49.5f )/ 49.5f; 

	    return -1.0f + 2.0f * x * x;
	};

	ImGui::PlotLines("", values, NULL, 100, 0, NULL, -1.0f, 1.0f, ImVec2(780, 255));


and got the following result:
https://imgur.com/a/1iLBlKJ
Bingo!

I think there are much better GUIs for use with C++ if you are into plotting data rather than positioning widgets, though.
Last edited on
Topic archived. No new replies allowed.