Plots.jl: Axes swapped in heatmap

Created on 24 May 2016  Â·  20Comments  Â·  Source: JuliaPlots/Plots.jl

Plots.jl 0.6.2 mirrors the axes for heatmap with the PyPlot backend:

Plots.heatmap(0:0.1:1, 0:0.1:1, (x, y) -> e^-x)

exp-heatmap-mirrored

The bright area should be on the left, not on the bottom. This is a new problem, with the Plots.jl version (sorry, forgot which one) I used before, everything was fine. Interestingly, histogram2d still plots correctly:

# Random numbers distributed according to e^-x:
X = -log(rand(100000))
# Uniform random numbers:
Y = rand(100000)
Plots.histogram2d(X, Y)

exp-histogram2d

discussion help wanted

All 20 comments

This is actually a feature, not a bug. I was convinced to change it to follow conventions in which the y-axis should match the rows of the z-matrix. See: https://github.com/tbreloff/Plots.jl/issues/196#issuecomment-216725551

You can switch the behavior with transpose = true

This is actually a feature, not a bug.

It results in a lot of inconsistency, though, if x and y data have to be passed to heatmap in a different order than for all other plots (including histogram2d, which should be the same, modulo auto-binning of the data). I would imagine that it will surprise many users.

in a different order than for all other plots
Ok maybe not exactly in a different order - it's matrix data, after all. Still, it's confusing when using a generation function, like in my example - so shouldn't x and y be passed in a different order too, then, if z is a function?

I don't disagree... which is why I fought it. Just like anything, there can only be one built-in default, and someone's always going to disagree with the choice. My solution is to tie it to a keyword (transpose is an alias for match_dimensions) so that you can set your own personal default value if you want.

Sure, transpose works. But what I mean is, couldn't Plots.jl just feed x and y into z in a different order if transpose is set to false? I would assume that if z is given as a function, the user would always assume that the x-axis is the first, and the y-axis the second argument. If z is a function, the user will never see the resulting matrix, after all.

It's worth considering, but we'd really have to think that through. If anyone else has an opinion, please chime in!

Thanks for considering it, Tom. I really have a feeling that the average user will be really surprised, otherwise, if he does something like (this time with axis labels)

Plots.heatmap(0:0.1:1, 0:0.1:1, (x, y) -> e^-x, xlabel = "x", ylabel ="y")

out

It's just such a natural thing to do - and if you don't know what the function should look like, you may never notice the plot is wrong this way. Or in other terms, the user will likely never thing in terms of a matrix, he's just plotting a function, in his mind.

I'd prefer if heatmap had axis (x,y) as well; just as proposed in https://github.com/tbreloff/Plots.jl/issues/196#issuecomment-216731678 . At least the way I've ever used a heatmap, it was to draw a flattened 3D plot of a function.

It seems that matplotlib, whose heatmap equivalent is called pcolor, displays the matrix like Plots.jl (one reason why this behaviour was changed recently) but also relabels the axes! The x-axis thus becomes the rows, and the y axis the columns. I had not noticed this issue, because when discussing in issue #196 I was only concerned about the location of the points, not their association to any axis.

See this question on StackExchange and notice that the command to set the x-axis labels labels the vertical axis.

This command by @oschulz

Plots.heatmap(0:0.1:1, 0:0.1:1, (x, y) -> e^-x, xlabel = "x", ylabel ="y")

would thus look the same, except that the xlabel would go on the left instead of at the bottom of the plot, matching the function used.

Plotly currently has the same behaviour as Plots.jl, whereas the x-axis corresponds to columns of the matrix...

Pick your poison!

@jebej yes both PyPlot and Plotly do it this way, which was why I decided to follow suit. The open question is whether functions should be called f(y,x) instead of f(x,y)... I'm really torn on this issue. There's no right answer :(

except that the xlabel would go on the left instead of at the bottom of the plot

I don't think that would be a good solution - having the x-axis on the left, different from all other plots, would be a huge inconsitency - esp. compared to histogram2d.

whether functions should be called f(y,x) instead of f(x,y)

I wouldn't say we'd call f(y, x) - I'd put it differently: For

Plots.heatmap(0:0.1:1, 0:0.2:2, (x, y) -> e^-x, xlabel = "x", ylabel ="y")

we should _always_ call f(x,y), with x in 0:0.1:1 and y in 0:0.2:2, _never_ f(y, x). The question is rather how the results should be mapped to a matrix, and we have free choice there. However, I would choose to do it just like the matrix display works now: Since the change in behaviour (which I like, in principle), matrices are displayed with i on the y-axis and j on the x-axis (and with transpose = true, the other way round).

So I'd say we should simply map the output of f(x, y) to the matrix to be plotted (let's call it A) the same way:

    if (transpose == false)
        A[i, j] = f(x[j], y[i])
    else
        A[i, j] = f(x[i], y[j])
    end

After all, why should be map x/y to i/j differently for matrix generation and matrix display?

So this way, the function will always be displayed correctly, with the x-axis corresponding to the first function argument, and the y-axis corresponding to the second function argument - which I believe is a pretty universal convention and will be every user's intuitive assumption.

That sounds like a good solution @oschulz , the user does not need to know about how the 2D function is internally converted into a matrix for display.

This would also mean that we would keep the x-axis on the horizontal, like Plotly is doing, but unlike matplotlib. I think that is fine since the function used to make heatmaps in matplotlib is not called heatmap anyway.

tmp

Hi @tbreloff

I found some inconsistency in the heatmap() for different engines:

using Plots
z = [2.0*x*y for x=1:5, y=1:8]
heatmap(z)
gr()
heatmap(z)
plotly()
heatmap(z)

The gr version (top-left) does not have a legend, and is inverted compared to the other two versions.

heatmaps

The cbar drawing is a known issue, but I'm surprised about the transpose.
What version of Plots?

On Monday, November 14, 2016, Stephen Eglen [email protected]
wrote:

Hi @tbreloff https://github.com/tbreloff

I found some inconsistency in the heatmap() for different engines:

using Plots
z = [2.0_x_y for x=1:5, y=1:8]
heatmap(z)
gr()
heatmap(z)
plotly()
heatmap(z)

The gr version (top-left) does not have a legend, and is inverted compared
to the other two versions.

[image: heatmaps]
https://cloud.githubusercontent.com/assets/1095067/20259664/fd2ef03a-aa4d-11e6-9c03-1708f8753f65.png

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/tbreloff/Plots.jl/issues/273#issuecomment-260289253,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AA492liNVR_tKOaN0mRt3RNxZxdYzLxNks5q-CwHgaJpZM4IlQ0t
.

Thanks. NEWS.md reports this as version 0.9.4, and git says:

~/.julia/v0.5/Plots $ git log| head -10
commit 81302c1e9dad35ae1c713268f5fe39452819fa12
Author: Thomas Breloff <[email protected]>
Date:   Tue Oct 11 12:43:38 2016 -0400

    NEWS; bump version

Check out Plots and PlotUtils and try again.

On Monday, November 14, 2016, Stephen Eglen [email protected]
wrote:

Thanks. NEWS.md reports this as version 0.9.4, and git says:

~/.julia/v0.5/Plots $ git log| head -10
commit 81302c1e9dad35ae1c713268f5fe39452819fa12
Author: Thomas Breloff <[email protected] Date: Tue Oct 11 12:43:38 2016 -0400

NEWS; bump version

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/tbreloff/Plots.jl/issues/273#issuecomment-260337704,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AA492rPuyR55SNb0Nu7_XTYCKYGQYBFfks5q-GXVgaJpZM4IlQ0t
.

Thanks, update flipped the gr() to match the other two.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mkborregaard picture mkborregaard  Â·  3Comments

Cody-G picture Cody-G  Â·  4Comments

cortner picture cortner  Â·  4Comments

jebej picture jebej  Â·  4Comments

Cody-G picture Cody-G  Â·  3Comments