plot/heatmap: Remove grid

470 views
Skip to first unread message

davidkl...@gmail.com

unread,
Jul 23, 2020, 6:05:13 AM7/23/20
to gonum-dev
Hi,

I am using gonum/plot to produce heatmaps for a project. When I plot I get a grid on top of the plot. I would like to remove this grid and get a result similar to what one gets with *imshow* in matplotlib. Below is an example where I plot a gaussian 

1) With gonum/plot

demo.png

2) Desired result obtained with imshow in matplotlib
imshow.png

is it possible to remove the grid in the first figure?

For completeness, I attach the code used to produce the figures

==========================================================
package main

import (
"math"

)

// Gaussian represents a gaussian sampled on a "virtual" grid
// of dimension NxN.
type Gaussian struct {
Width float64
N int
}

// X returns the x coordinate corresponding to column c
func (g *Gaussian) X(c int) float64 {
return float64(c) - float64(g.N/2)
}

// Y returns the y coordinate corresponding to row r
func (g *Gaussian) Y(r int) float64 {
return float64(r) - float64(g.N/2)
}

// Z returns the value correspondin
func (g *Gaussian) Z(c, r int) float64 {
rSq := g.X(c)*g.X(c) + g.Y(r)*g.Y(r)
return math.Exp(-rSq / (g.Width * g.Width))
}

// Dims returns the dimension of the "virtual" grid
func (g *Gaussian) Dims() (int, int) {
return g.N, g.N
}

func main() {
data := Gaussian{
Width: 16.0,
N: 64,
}

pal := moreland.SmoothBlueRed().Palette(255)
hm := plotter.NewHeatMap(&data, pal)

plt, _ := plot.New()
plt.Add(hm)
plt.Save(400, 400, "demo.png")
}
==========================================================

Python code:

==========================================================
from matplotlib import pyplot as plt
import numpy as np

w = 16.0
N = 64
x = np.linspace(-N/2, N/2, N)
y = np.linspace(-N/2, N/2, N)
X, Y = np.meshgrid(x, y)
Z = np.exp(-(X**2 + Y**2)/(w*w))

plt.imshow(Z, cmap="coolwarm")
plt.savefig("imshow.png")
==========================================================

Thanks in advance,

David

Dan Kortschak

unread,
Jul 23, 2020, 7:04:34 AM7/23/20
to gonu...@googlegroups.com
This is not something that is done intentionally, but is either a
consequence of the drawing backend or floating point error in the heat
map plotter (or both).

The relevant code is here
https://github.com/gonum/plot/blob/4260761de856821a3e6a37142379d2348fe79b65/plotter/heat.go#L151-L179

If you use a different back end, do you have the same issue? e.g. svg
or pdf.

If you want to investigate the possibility that it's floating point
error you can use the vg/recorder.Canvas and look at the floating point
values of corners to see if they are mismatched. If they are, this is
potentially something we could look at fixing.

Dan

On Thu, 2020-07-23 at 03:05 -0700, davidkl...@gmail.com wrote:
> Hi,
>
> I am using gonum/plot to produce heatmaps for a project. When I plot
> I get a grid on top of the plot. I would like to remove this grid and
> get a result similar to what one gets with *imshow* in matplotlib.
> Below is an example where I plot a gaussian
>
> 1) With gonum/plot
>
>
>
> 2) Desired result obtained with imshow in matplotlib
>
>
> --
> You received this message because you are subscribed to the Google
> Groups "gonum-dev" group.
> To unsubscribe from this group and stop receiving emails from it,
> send an email to gonum-dev+...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/gonum-dev/7b3ce6e7-e701-4a4c-8e0a-5b3b5fd5f780n%40googlegroups.com
> .


davidkl...@gmail.com

unread,
Jul 23, 2020, 9:28:10 AM7/23/20
to gonum-dev
Hi,

I checked svg and pdf and the grid is visible there as well. However, gridlines appear and disappear depending on the zoom level. I did not find any round-off mismatch in the corners (I checked the actions of the recorder as well as manually inspected the svg), but when it is rendered the gridlines appear. However, if one in addition to the fill sets the stroke to the same color the lines are removed (I did this manually in Inkscape) it is less pronounced. I can only vaguely see it when I zoom very far out.

When it comes to pixel-based formats I am not sure what the cause can be. Here is a zoom at the center

screenShotCenter.png

so there is some bright grid line that appears brighter than the rest of the colors. I am happy to investigate this deeper, but I am not yet sure about what causes this behavior. Any suggestions are much appreciated :)

David
demoWithStroke.svg
demo.svg

Sebastien Binet

unread,
Jul 23, 2020, 9:37:58 AM7/23/20
to davidkl...@gmail.com, gonum-dev
David,

‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐
On Thursday, July 23, 2020 3:28 PM, davidkl...@gmail.com <davidkl...@gmail.com> wrote:

> Hi,
>
> I checked svg and pdf and the grid is visible there as well. However, gridlines appear and disappear depending on the zoom level. I did not find any round-off mismatch in the corners (I checked the actions of the recorder as well as manually inspected the svg), but when it is rendered the gridlines appear. However, if one in addition to the fill sets the stroke to the same color the lines are removed (I did this manually in Inkscape) it is less pronounced. I can only vaguely see it when I zoom very far out.
>
> When it comes to pixel-based formats I am not sure what the cause can be. Here is a zoom at the center
>
> so there is some bright grid line that appears brighter than the rest of the colors. I am happy to investigate this deeper, but I am not yet sure about what causes this behavior. Any suggestions are much appreciated :)

Couldn't this be some transparency effect?
ie: what happens if you play with the alpha channel of the color you set?

hth,
-s

Chris Tessum

unread,
Jul 23, 2020, 1:29:20 PM7/23/20
to gonum-dev
I think this is related to the fact that heatmap plots the grid cells as vector rectangles. We get the same issue here: https://github.com/gonum/plot/blob/master/palette/moreland/testdata/moreland_golden.png, and you can see the same thing in other vector graphics renderers (QGIS is one that comes to mind). A workaround is to put your data in an image and then plot that: https://pkg.go.dev/gonum.org/v1/plot/plotter?tab=doc#Image. The ColorBar plotter is an example of how to do this: https://github.com/gonum/plot/blob/v0.7.0/plotter/colorbar.go#L55

As a more permanent fix would be to have heatmap render a raster image by default. I think this would be easy to implement if we only need heatmap to accept square grid cells. If we want it to be able to handle arbitrary rectangles, warping etc that would be more difficult.

Chris Tessum

unread,
Jul 23, 2020, 1:32:26 PM7/23/20
to gonum-dev
Setting the stroke color to the same as the fill color kind of works but it isn't a robust solution because you can get weird artifacts caused by the overlapping strokes.

Sebastien Binet

unread,
Jul 23, 2020, 1:38:09 PM7/23/20
to Chris Tessum, gonum-dev
I guess it would also be interesting to see how this is handled in, say, mpl.imshow...



‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐
--
You received this message because you are subscribed to the Google Groups "gonum-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to gonum-dev+...@googlegroups.com.

Chris Tessum

unread,
Jul 23, 2020, 1:50:49 PM7/23/20
to gonum-dev
Based on the name `imshow`, I would assume it's raster-based, but it good be worthwhile to confirm.
To unsubscribe from this group and stop receiving emails from it, send an email to gonu...@googlegroups.com.

davidkl...@gmail.com

unread,
Jul 23, 2020, 4:36:26 PM7/23/20
to gonum-dev
Hi,


Thanks for the suggestions. Plotting as a raster image results in an image without a grid.

demoRaster.png

For reference, here is the code

=============================================================
package main

import (
"image"
"math"

)

// Gaussian represents a gaussian sampled on a "virtual" grid
// of dimension NxN.
type Gaussian struct {
Width float64
N int
}

// X returns the x coordinate corresponding to column c
func (g *Gaussian) X(c int) float64 {
return float64(c) - float64(g.N/2)
}

// Y returns the y coordinate corresponding to row r
func (g *Gaussian) Y(r int) float64 {
return float64(r) - float64(g.N/2)
}

// Z returns the value correspondin
func (g *Gaussian) Z(c, r int) float64 {
rSq := g.X(c)*g.X(c) + g.Y(r)*g.Y(r)
return math.Exp(-rSq / (g.Width * g.Width))
}

// Dims returns the dimension of the "virtual" grid
func (g *Gaussian) Dims() (int, int) {
return g.N, g.N
}

func main() {
data := Gaussian{
Width: 16.0,
N: 40,
}

pal := moreland.SmoothBlueRed().Palette(255)

plt, _ := plot.New()
img := fillImage(&data, pal)
pImg := plotter.NewImage(img, 0, 0, float64(data.N), float64(data.N))
plt.Add(pImg)
plt.Save(200, 200, "demoRaster.png")
}

func fillImage(data plotter.GridXYZ, pal palette.Palette) *image.RGBA64 {
n, m := data.Dims()
img := image.NewRGBA64(image.Rectangle{
Min: image.Point{X: 0, Y: 0},
Max: image.Point{X: n, Y: m},
})
colors := pal.Colors()

max := data.Z(0, 0)
min := data.Z(0, 0)
for i := 0; i < n; i++ {
for j := 0; j < m; j++ {
if data.Z(i, j) > max {
max = data.Z(i, j)
}

if data.Z(i, j) < min {
min = data.Z(i, j)
}
}
}

for i := 0; i < n; i++ {
for j := 0; j < m; j++ {
v := data.Z(i, j)
colorIdx := int((v - min) * float64(len(colors)-1) / (max - min))
img.Set(i, j, colors[colorIdx])
}
}

return img
}
====================================================================================

Cheers,
David

Sebastien Binet

unread,
Jul 24, 2020, 3:13:25 AM7/24/20
to davidkl...@gmail.com, gonum-dev
this looks great!
and could probably be integrated into gonum/plot.
(or, failing that, into go-hep/hplot)

do you want to give it a try?
(unless other gonum-devs object?)

-s

‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐
To unsubscribe from this group and stop receiving emails from it, send an email to gonum-dev+...@googlegroups.com.

davidkl...@gmail.com

unread,
Jul 24, 2020, 6:19:49 AM7/24/20
to gonum-dev
Yes, I can give it a try. Is it best to create a new plotter inside heat.go and leave the current heatmap as it is? It could be called RasterHeatmap, PixelHeatmap, or maybe even just Imshow or perhaps there are better names?

David

Reply all
Reply to author
Forward
0 new messages