Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Plotting data #1772

Closed
kenkit opened this issue Apr 24, 2018 · 4 comments
Closed

Plotting data #1772

kenkit opened this issue Apr 24, 2018 · 4 comments

Comments

@kenkit
Copy link

kenkit commented Apr 24, 2018

Hi,
I'm using IMGUI as the default user interface for all my apps since it's easy to use. However I've noticed that there is little information/documentation on the api.
Ok, my current problem is that I have a histogram which is an arrary of floats which is updated every second incrementally, if the value reaches max it resets to 0. The problem is the graph iteself begins repeating while ovewriting the existing values instead of moving the whole thing to one side.
Here is part of my code

  if (diff.total_milliseconds() >= 1000) {
                upload_log[current_ul_log] = graph_rt;//--this is the value I'm plotting
                last_ulspeed = graph_rt;
                current_ul_log++;
            }

 ImGui::PlotHistogram("Log", upload_log, IM_ARRAYSIZE(upload_log),
                current_log, std::string("speed " + std::to_string(upload_speed) + std::string(rate[current_rate].symbol)).c_str(), 0.0f, max_ul_value, ImVec2(0, 80));

So my question is do I have to iterate over the whole array just to make it look like it's moving ?
I didn't see this being done in the examples, I thought of using a vector but I don't know how to do it.
Any help will be greatly appreciated.

@ocornut
Copy link
Owner

ocornut commented Apr 24, 2018

The values_offset parameter serves this purpose.

@kenkit
Copy link
Author

kenkit commented Apr 25, 2018

Oooh, I see my mistake, I have two graphs so I was using the wrong value_offset which should be current_ul_log thanks for your assistance.
Btw is it possible to render imgui to a texture ? , like say I have the window rendered on one face of a cube ?

@ocornut
Copy link
Owner

ocornut commented Apr 25, 2018

Good, closing this.

Btw is it possible to render imgui to a texture ? , like say I have the window rendered on one face of a cube?

Just as anything you render with OpenGL or DirectX can be rendered to a texture, yes. The question doesn't really have anything to do with imgui it's more a graphics API question at this point.

@ocornut ocornut closed this as completed Apr 25, 2018
@ocornut
Copy link
Owner

ocornut commented May 16, 2022

Posting here a copy of an old (2016) wiki page that had an example.
Not sure it's useful anymore but at least it is posted somewhere.

Helper to store values so they can be plotted over time.

Usage

// Call once a frame with current value
ImGui::PlotVar("Speed", current_speed);

capture

.h

// Plot value over time
// Pass FLT_MAX value to draw without adding a new value
void	PlotVar(const char* label, float value, float scale_min = FLT_MAX, float scale_max = FLT_MAX, size_t buffer_size = 120);

// Call this periodically to discard old/unused data
void	PlotVarFlushOldEntries();

.cpp

#include <map>
struct PlotVarData
{
	ImGuiID        ID;
	Vector<float>  Data;
	int            DataInsertIdx;
	int            LastFrame;

	PlotVarData() : ID(0), DataInsertIdx(0), LastFrame(-1) {}
};

typedef std::map<ImGuiID, PlotVarData> PlotVarsMap;
static PlotVarsMap	g_PlotVarsMap;

// Plot value over time
// Call with 'value == FLT_MAX' to draw without adding new value to the buffer
void ImGui::PlotVar(const char* label, float value, float scale_min, float scale_max, size_t buffer_size)
{
	ASSERT(label);
	if (buffer_size == 0)
		buffer_size = 120;

	ImGui::PushID(label);
	ImGuiID id = ImGui::GetID("");

	// Lookup O(log N)
	PlotVarData& pvd = g_PlotVarsMap[id];

	// Setup
	if (pvd.Data.capacity() != buffer_size)
	{
		pvd.Data.resize(buffer_size);
		memset(&pvd.Data[0], 0, sizeof(float) * buffer_size);
		pvd.DataInsertIdx = 0;
		pvd.LastFrame = -1;
	}

	// Insert (avoid unnecessary modulo operator)
	if (pvd.DataInsertIdx == buffer_size)
		pvd.DataInsertIdx = 0;
	int display_idx = pvd.DataInsertIdx;
	if (value != FLT_MAX)
		pvd.Data[pvd.DataInsertIdx++] = value;

	// Draw
	int current_frame = ImGui::GetFrameCount();
	if (pvd.LastFrame != current_frame)
	{
		ImGui::PlotLines("##plot", &pvd.Data[0], buffer_size, pvd.DataInsertIdx, NULL, scale_min, scale_max, ImVec2(0, 40));
		ImGui::SameLine();
		ImGui::Text("%s\n%-3.4f", label, pvd.Data[display_idx]);	// Display last value in buffer
		pvd.LastFrame = current_frame;
	}
	
	ImGui::PopID();
}

void ImGui::PlotVarFlushOldEntries()
{
	int current_frame = ImGui::GetFrameCount();
	for (PlotVarsMap::iterator it = g_PlotVarsMap.begin(); it != g_PlotVarsMap.end(); )
	{
		PlotVarData& pvd = it->second;
		if (pvd.LastFrame < current_frame - MAX(400,(int)pvd.Data.size()))
			it = g_PlotVarsMap.erase(it);
		else
			++it;
	}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants