How to use `heatmap` in GR.jl

Why does this not work?

julia> using GR

julia> heatmap([1 2], [3 4], [5 6; 7 8])
ERROR: AssertionError: length(x) == dimx + 1 && length(y) == dimy + 1
Stacktrace:
 [1] nonuniformcellarray(::Array{Int64,2}, ::Array{Int64,2}, ::Int64, ::Int64, ::Array{Int64,2}) at C:\Users\aaron\.julia\packages\GR\8mv9N\src\GR.jl:754
 [2] plot_data(::Bool) at C:\Users\aaron\.julia\packages\GR\8mv9N\src\jlgr.jl:1306
 [3] plot_data at C:\Users\aaron\.julia\packages\GR\8mv9N\src\jlgr.jl:1074 [inlined]
 [4] heatmap(::Array{Int64,2}, ::Array{Int64,2}, ::Array{Int64,2}; kv::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}) at C:\Users\aaron\.julia\packages\GR\8mv9N\src\jlgr.jl:2052
 [5] heatmap at C:\Users\aaron\.julia\packages\GR\8mv9N\src\jlgr.jl:2047 [inlined]
 [6] #heatmap#17 at C:\Users\aaron\.julia\packages\GR\8mv9N\src\GR.jl:3419 [inlined]
 [7] heatmap(::Array{Int64,2}, ::Array{Int64,2}, ::Array{Int64,2}) at C:\Users\aaron\.julia\packages\GR\8mv9N\src\GR.jl:3419
 [8] top-level scope at REPL[2]:1

I’m pretty sure people are going to recommend using Plots.jl but I’m trying to select a plotting package to use in my package development, and Plots takes waaaaaaaaaaaaay too long to precompile and ttfp just does my head in.

Should I open an issue on GitHub?

No idea why the GR code wouldn’t work, but on the Plots issue: are you referring to Plots being too slow while you develop your package (i.e. in an iterative workflow where you just use Plots to visualise things every now and then) or Plots being too slow to precompile to integrate into your package as a dependency?

If it’s the former, are you using Revise for development? That should largely obviate the need to re-start your Julia session, so you only pay compilation cost once. If for some reasons you still have to re-start frequently you might want to consider having Plots in a custom sysimage using PackageCompiler.jl

If the latter, have you looked at Recipes? They’re made so you don’t have to depend on Plots in your package, but just on RecipesBase, and users will then using Plots separately if they want to plot.

Finally just so I give at least some info related to your actual question, have you tried GRUtils.jl? I don’t really know anything about it, but it seems that the GR developers recommend using this if one wants to work with GR directly (without the Plots wrapper).

2 Likes

Yes, I use Revise. My current development involves redefining a lot of structs, which requires restarting Julia.

I’m not sure what that means, but I’ll look into that, thanks!

For the output data I’m working on, there are a lot of features involved to look at, so I’ve produced a support niche plotting function that I can just pass the output data/struct instantiations to which will do all the steps of plotting for me. Super nice and convenient – in theory, if I can get along well with the plotting package.

Yep! I’m actually using it, but it’s just a little finicky and has a few bugs (which is not a surprise, it’s still in development), so I decided to check out other options, but I may stick with GRUtils for now since GR can’t even (supposedly) plot a heatmap.

I love the API of Plots.jl, but bloody heck it takes so long to load.

Again slightly off-topic, but for your development workflow consider:

  • Renaming rather than redefining structs - so work with MyStruct_1, when that doesn’t pan out to a find/replace MyStruct_1 => MyStruct_2 etc to avoid having to restart
  • Working with NamedTuples rather than structs

Also I think it should be possible to have quite complex plots with different features using RecipeBase

[ 1 2 ] and [ 3 4 ] are matrices with one row and two columns, while heatmap is expecting a vector (one column and two rows):

julia> heatmap([ 1, 2], [ 3, 4], [ 5 6; 7 8 ])

plot

julia> [ 3 4 ]
1×2 Array{Int64,2}:
 3  4

julia> [3,4]
2-element Array{Int64,1}:
 3
 4

GAH why didn’t I think of that.

Good catch thanks.

I’ve only been learning Julia recently, and NamedTuples is new to me. I’ll check it out, thank you!

Does Julia optimize with NamedTuples well?

Couldn’t that be a strategy for Revise to deal with the struct changes? It could add a marker like _2 while loading the code, and perhaps warn the user of that, so that possible error messages are clear.

1 Like
2 Likes

Back to the original topic, even your MWE response isn’t working for me.

julia> using GR

julia> heatmap([1, 2], [3, 4], [5 6; 7 8])
ERROR: AssertionError: length(x) == dimx + 1 && length(y) == dimy + 1
Stacktrace:
 [1] nonuniformcellarray(::Array{Int64,1}, ::Array{Int64,1}, ::Int64, ::Int64, ::Array{Int64,2}) at C:\Users\aaron\.julia\packages\GR\8mv9N\src\GR.jl:754
 [2] plot_data(::Bool) at C:\Users\aaron\.julia\packages\GR\8mv9N\src\jlgr.jl:1306
 [3] plot_data at C:\Users\aaron\.julia\packages\GR\8mv9N\src\jlgr.jl:1074 [inlined]
 [4] heatmap(::Array{Int64,1}, ::Array{Int64,1}, ::Array{Int64,2}; kv::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}) at C:\Users\aaron\.julia\packages\GR\8mv9N\src\jlgr.jl:2052
 [5] heatmap at C:\Users\aaron\.julia\packages\GR\8mv9N\src\jlgr.jl:2047 [inlined]
 [6] #heatmap#17 at C:\Users\aaron\.julia\packages\GR\8mv9N\src\GR.jl:3419 [inlined]
 [7] heatmap(::Array{Int64,1}, ::Array{Int64,1}, ::Array{Int64,2}) at C:\Users\aaron\.julia\packages\GR\8mv9N\src\GR.jl:3419
 [8] top-level scope at REPL[2]:1

It’s checking that the length of the input range vectors are one element longer than their dimensions?

Sorry, I tested it here with Plots with the gr backend:

julia> using Plots

julia> gr()  # default anyway
Plots.GRBackend()

julia> heatmap([1, 2], [3, 4], [5 6; 7 8])
qt5ct: using qt5ct plugin

Cool, but I’m wondering if I can use GR.jl directly. Plots.jl takes too long to load, and if I can access all the functionality I want with just one of the backends, then I’ll do just that.

In the GR docs they use LinRange to generate the x and y:

https://gr-framework.org/julia-jlgr.html#heatmap-849ebfcad83c4c0251a8873748f01036

So apparently this works

julia> heatmap(z)

but this doesn’t work

julia> heatmap(x, y, z)

Why it doesn’t work is beyond me. I don’t understand the difference in functionality between the two in terms of, why wouldn’t the second one work? Is it still in development?

They even have a little function declaration box saying it should work?

image

Have you tried the example as it is posted in the manual? It does not work?

Yes I did try the example and it works.

However, the example given does not take in x and y as the first two inputs. It only takes in z.

Passing x, y, and z doesn’t work.

The doc mentions something about changing the limits of the heatmap plot, so I might check that out instead.

I might read as much of the doc as is relevant, and if I don’t find an explanation for why heatmap(x, y, z) doesn’t work, then I’ll open an issue on GitHub.

1 Like

It looks like maybe GR expects x and y to be the edges of the heatmap grid. Could you try

heatmap([0.5, 1.5, 2.5], [2.5, 3.5, 4.5], [5 6; 7 8])

instead?

3 Likes

Dang it, I feel stupid.

Yep, it works. Thanks!

1 Like