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

Feature request: heatmap that can handle irregular rectilinear grids #675

Closed
briochemc opened this issue Aug 4, 2020 · 9 comments
Closed
Labels
Makie Backend independent issues (Makie core)

Comments

@briochemc
Copy link
Contributor

MWE:

x = tan.(atan(-3):0.1:atan(3))
y = -2.5:0.1:2.5
peaks(x,y) = 3*(1-x)^2 * exp(-(x^2) - (y+1)^2) - 10*(x/5 - x^3 - y^5) * exp(-x^2-y^2) - 1/3*exp(-(x+1)^2 - y^2)
z = [peaks(x,y) for x in x, y in y]

using AbstractPlotting
using AbstractPlotting.MakieLayout
using GLMakie
scene, layout = layoutscene()
display(scene)
ax = layout[1,1] = LAxis(scene)
heatmap!(ax,x,y,z)

outputs

Screen Shot 2020-08-04 at 12 05 38 pm

The issue is that the irregular grid is replaced with a regular one. (You can see that the boxes in the x direction are regularly spaced, but they should not, since x = tan.(atan(-3):0.1:atan(3)).) I think the bug is that somewhere in the pipeline, x is converted to a range (a (min, max) tuple I think) and the irregularly spaced x values are lost. It seems surface can handle these, so I'm hoping there is not too much work required to allow irregular grids with heatmap, too! 🙂

@jkrumbiegel jkrumbiegel added the Makie Backend independent issues (Makie core) label Aug 9, 2020
@briochemc
Copy link
Contributor Author

Gentle bump!

@SimonDanisch
Copy link
Member

Right now your best bet is surface(x,y,z, shading=false, interpolation=false)

@ffreyer
Copy link
Collaborator

ffreyer commented Oct 9, 2020

Here's a solution using meshscatter:

using GeometryBasics

xs = tan.(atan(-3):0.1:atan(3))
ys = -2.5:0.1:2.5 |> collect
peaks(x,y) = 3*(1-x)^2 * exp(-(x^2) - (y+1)^2) - 10*(x/5 - x^3 - y^5) * exp(-x^2-y^2) - 1/3*exp(-(x+1)^2 - y^2)
zs = [peaks(x,y) for x in xs, y in ys]

# Needs to be a mesh to not get centered?
m = Rect2D(Point2f0(0.0), Vec2f0(1)) |> normal_mesh
# midpoints
midxs = 0.5(xs[1:end-1] .+ xs[2:end])
midys = 0.5(ys[1:end-1] .+ ys[2:end])
# Padding for outer rectangles
midxs = [2xs[1] - midxs[1]; midxs; 2xs[end] - midxs[end]]
midys = [2ys[1] - midys[1]; midys; 2ys[end] - midys[end]]

# rectangle position & size
pos = [Point2f0(x, y) for x in midxs[1:end-1] for y in midys[1:end-1]]
sizes = [Vec2f0(midxs[i+1] - midxs[i], midys[j+1] - midys[j]) for i in eachindex(xs) for j in eachindex(ys)]

# zs need transpose to match previous result
s = meshscatter(pos, markersize=sizes, marker=m, color=zs'[:], shading=false)
display(s)

Screenshot from 2020-10-09 18-28-31

Btw, while making this I noticed that surface(xs, ys, zs) doesn't match up with wireframe(xs, ys, zs) and the above unless you input xs and ys as matrices.

@briochemc
Copy link
Contributor Author

Maybe I can try to contribute, but I have no idea where I should start... Could you point me to where I could edit heatmap to allow irregularly spaced x and y?

@ffreyer
Copy link
Collaborator

ffreyer commented Oct 31, 2020

The "low effort" change would be to change the heatmap recipe here to be the meshscatter thing.

The "high effort" change would be to adjust how GLMakie handles heatmaps (and I guess other backends as well). For that you probably need to change the draw_atomic function, add new _default methods similar to the surface ones and add another shader similar to the surface shader which keeps pos.z = 0.

@briochemc
Copy link
Contributor Author

Ha! I guess it's way more complicated than I anticipated. So the issue is in the backends, e.g., GLMakie, which applies to_range to the x and y vectors. Well I have to admit I only now appreciate what the name "AbstractPlotting" stands for... 😅

Anyway, I am personally more interested in CairoMakie (to save to vectorized PDF) and I am hoping that maybe there is less work with it than with GLMakie. Please let me know if I'm wrong, but it seems like this draw_atomic is the only culprit for the CairoMakie backend because it sets the location and size of each tiny "rectangle" of the heatmap. So that editing only this function to place those rectangles on the irregular grid could be the solution?

@ffreyer
Copy link
Collaborator

ffreyer commented Nov 1, 2020

Yea, draw_atomic is probably the only thing you'd need to change there. (Image plots should still be handled the same.) There may also need to be some adjustments to conversion in AbstractPlotting, not sure.

I can look into making the changes in GLMakie.

@ffreyer
Copy link
Collaborator

ffreyer commented Nov 1, 2020

Oh yea - shouldn't the tiles of a heatmap be centered around their respective coordinates? I did this in the meshscatter version, but it's not the case in the for just heatmap.

@SimonDanisch
Copy link
Member

fixed in JuliaPlots/GLMakie.jl#137

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Makie Backend independent issues (Makie core)
Projects
None yet
Development

No branches or pull requests

4 participants