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

Add heatmap plot widget #2246

Closed

Conversation

JohannesProgrammiert
Copy link
Contributor

@JohannesProgrammiert JohannesProgrammiert commented Nov 6, 2022

Add widget for heatmap plot. Takes ImPlot as inspiration.

Preview:

simplescreenrecorder.webm

TODO before ready

Closes emilk/egui_plot#6.

@wlwatkins
Copy link

I see in the commit that you're working on Interpolation between the point, I believe that this is some sort of blueing between pixels. If so, is it going to be optional?

@wlwatkins
Copy link

I tried the implementation, but it gets very laggy when loading relatively large arrays. I tried your example and it works fine, but when loading a 1200x360px the whole ui is unresponsive. Do you think the issue is with egui itself? compared to the example in imgui where we see the high fps white noise, i think there still some work to do...

@voelklmichael
Copy link
Contributor

Hi, I'm working on a heatmap widget for egui.
If you want to take a look:
egui_heatmap

@JohannesProgrammiert
Copy link
Contributor Author

JohannesProgrammiert commented May 27, 2023

I believe that this is some sort of blueing between pixels. If so, is it going to be optional?

I don't understand, sorry.
I map user-defined colors to a user-defined resolution, i.e. a number of color-steps. For example, if a user defines the colors [black, red, white] and specifies RESOLUTION = 5 it is linearly interpolated to [black, dark-red, red, light-red, white]. Then, data values are mapped to one of the 5 colors. If you don't want any interpolation just specify a RESOLUTION that matches your number of colors.

but when loading a 1200x360px the whole ui is unresponsive

Yes, the implementation is very basic, drawing each data point one-by-one, as primitive. For large amounts of data, this becomes inefficient. 1200x360 is basically an image ... maybe we can draw the map in the same way we would draw an actual bitmap image, but it would require some more time and investment.

I think it is a good start to get some inspiration from the imgui source code.

Hi, I'm working on a heatmap widget for egui.

Hi, I tested your examples. Good work, but it is laggy for me, too, and for some reason the UI looks distorted. If you manage to resolve the hickups feel free to replace this MR with yours.

@JohannesProgrammiert
Copy link
Contributor Author

Example added to the demo lib:

heatmap

Copy link
Owner

@emilk emilk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool demo!

impl std::error::Error for HeatmapErr {}

/// A heatmap.
pub struct Heatmap<const RESOLUTION: usize> {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this to its own file (this one is already too long!)

Comment on lines +1600 to +1609
pos: PlotPoint,
/// values to plot
pub(super) values: Vec<f64>,
/// number of columns in heatmap
cols: usize,
/// number of rows in heatmap
rows: usize,
/// minimum value in colormap.
/// Everything smaller will be mapped to palette[0]
min: f64,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find readability increases a lot by adding newlines before docstrings:

Suggested change
pos: PlotPoint,
/// values to plot
pub(super) values: Vec<f64>,
/// number of columns in heatmap
cols: usize,
/// number of rows in heatmap
rows: usize,
/// minimum value in colormap.
/// Everything smaller will be mapped to palette[0]
min: f64,
pos: PlotPoint,
/// values to plot
pub(super) values: Vec<f64>,
/// number of columns in heatmap
cols: usize,
/// number of rows in heatmap
rows: usize,
/// minimum value in colormap.
/// Everything smaller will be mapped to palette[0]
min: f64,

Comment on lines +1665 to +1667
if cols == 0 {
return Err(HeatmapErr::ZeroColumns);
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this an error?

Comment on lines +1680 to +1685
if v < &min {
min = *v;
}
if v > &max {
max = *v;
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if v < &min {
min = *v;
}
if v > &max {
max = *v;
}
min = min.min(v);
max = max.max(v);

Comment on lines +1688 to +1694
// calculate palette
let base_colors = vec![
Color32::BLACK,
Color32::DARK_RED,
Color32::YELLOW,
Color32::BLACK,
];
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be nice to use a standard colormap here, like turbo

@JohannesProgrammiert
Copy link
Contributor Author

Recently, I implemented a polar plot widget for ImGui using GLSL shaders. I needed it to visualize radar spectrum data. It takes a two-dimensional array as input and performs a color mapping and then an (optional) transformation to polar coordinate space. With GPU acceleration, this runs smoothly even for larger arrays.

It could be used here to greatly improve performance.

Is it possible (and reasonable) to use shaders in egui-plot widgets? Or are there some major issues with it?
Interestingly, large realtime heatmap plots is a feature not even available in ImPlot.

@watsaig
Copy link

watsaig commented Jan 24, 2024

@JohannesProgrammiert the heatmap looks great -- is there any reason this PR is still in progress?

@JohannesProgrammiert
Copy link
Contributor Author

Some reasons:

  • It is not rebased on current master
  • I did not yet consider emilk's review (thanks a lot, btw)
  • the performance is not as good as imgui's. It can be greatly improved using shaders but I don't know how complicated that is in terms of integration and compatibility.

But generally, it works and could be merged to provide an "early access" version of this feature.

@wlwatkins
Copy link

i remember trying this out a few months back and it worked good enough for a mvp. Do you have an idea of the timeline? I remember this was the missing widet for me to switch to egui and rust in general for production. I'll clone this and update my code as it seems to conflict with the latest branch, but if you are about to merge it within the next few weeks, i might just wait ;)

@jjimenezroda
Copy link

Not sure if it is covered, but it would be great to be able to set a background image so that you could use a heatmap on top of it to represent different aspects (e.g. a map and on top the heatmap to represent temperatures).

@emilk
Copy link
Owner

emilk commented Jul 15, 2024

egui_plot has recently been moved to its own repository, at https://github.com/emilk/egui_plot

This will hopefully speed up its development by having more reviewers and maintainers.

Please re-open this PR at https://github.com/emilk/egui_plot/pulls

See also:

@emilk emilk closed this Jul 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Heatmap Widget for Plots Axis legends for Plots
6 participants