Skip to content

imshow interpolation generating artifacts #9961

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

Closed
arthur00 opened this issue Dec 8, 2017 · 12 comments
Closed

imshow interpolation generating artifacts #9961

arthur00 opened this issue Dec 8, 2017 · 12 comments

Comments

@arthur00
Copy link

arthur00 commented Dec 8, 2017

Bug report

Bug summary

When interpolating a 2D heatmap on Windows, I get colored artifacts drawn over the 'bad' points. I am using LogNorm for normalization. I suspect it has something to do with the masked values caused by having 0s in a LogNorm. I set then to white with set_bad() function. On Linux, the interpolation looks entirely different (the white areas are not interpolated) and no artifacts can be seen.

I've also tried different interpolating methods, all of them seem to create artifacts, except for nearest.

image

Zooming in creates more artifacts:
image

Zooming in to one of these artifacts, reveals this:
image

Code for reproduction

import matplotlib.pyplot as plt
import matplotlib.colors

heatmap = [[0] * 32 for _ in range(128)]
cnt = 0
last = 1
for lvl in range(127):
    if lvl % 20 < 10:
        for i in range(32):
            heatmap[lvl][i] = 40
    else:
        for i in range(32):
            heatmap[lvl][i] = 0
jet = plt.get_cmap('jet')
jet.set_bad('white', 1)

plt.imshow(heatmap, origin='lower', interpolation='gaussian', aspect='auto', cmap=jet,
                 norm=matplotlib.colors.LogNorm())
plt.show()

Matplotlib version

  • Operating system: Windows
  • Matplotlib version: 2.1.0
  • Matplotlib backend (print(matplotlib.get_backend())): TkAgg
  • Python version: 3.6
  • Jupyter version (if applicable):
  • Other libraries:
@tacaswell tacaswell added this to the v2.2 milestone Dec 8, 2017
@tacaswell
Copy link
Member

Interesting that you do not see the 'fuzz' on linux. This is due to some instability in the interpolation over big constant regions near the clipping limits.

Duplicate of #8947

@jklymak
Copy link
Member

jklymak commented Dec 8, 2017

When you interpolate using "Gaussian" you are probably getting data that is "near" zero, but not quite due to floating point round off, which is different between machines. It doesn't show up as white because its not quite invalid...

I'm not actually sure why imshow has an interpolation keyword as it seems to cause no end of trouble. Having the user do the interpolation themsleves outside of imshow would get rid of a black box that is expected to work magically.

@arthur00
Copy link
Author

arthur00 commented Dec 8, 2017

I've "solved" it by creating a custom colormap that defines 0 as white (which was my intention anyway), and by adding clip=True on the LogNorm. The artifacts are probably still there, but now at least they are the same color.

I am not familiar with the codebase of matplotlib, but I believe @jklymak has a point in that using imshow with interpolation does not give the user any chance to customize interpolation results. Interpolating before would allow fixing rounding errors.

@tacaswell The reason I do not see it in Linux is that the interpolation function does not work on the 'masked' area.

image

@dstansby
Copy link
Member

dstansby commented Apr 5, 2018

Is this still a problem in version 2.2?

@arthur00
Copy link
Author

arthur00 commented Apr 9, 2018

I just checked against 2.2 and the artifacts are gone. There was another curious side-effect: the LogNorm would return 'bad' for value of 0, and now it seems to return a valid value, since my original code now prints an entirely blue squared plot with no white stripes. I reproduced the stripes by writing np.nan instead of 0, and verified artifacts are gone.

If LogNorm for 0 should have returned np.nan (and thus created the white stripes), a bug should be filed for that. But as for this particular bug, it has been resolved. Thanks!

@arthur00 arthur00 closed this as completed Apr 9, 2018
@tacaswell
Copy link
Member

@arthur00 LogNorm returning valid values for 0 seems like a bug, can you open a new issue for that?

The reason imshow needs an interpolation kwarg is that the number and pitch of the pixels in the input image and the number and pitch of the pixels in the output image do not match so there will be interpolation (either up or down sampling). There is not a generic 'right' way to do this, so we expose a way for the user to change it.

@arthur00
Copy link
Author

arthur00 commented Apr 12, 2018

LogNorm seems to be correctly returning 'masked' for 0, however the set_bad('white') does not seem to be working anymore. LogNorm(np.nan) returns 0.0 for some reason - I imagined it would return 'masked'.

Running the snippet of code I wrote at the beginning will create a blue squared block on matplotlib 2.2.0 (Windows) and will create graph with horizontal stripes on matplotlib 2.1.1 (Windows)

@tacaswell
Copy link
Member

what versions of numpy are you using in the two cases?

@tacaswell
Copy link
Member

In [143]: n = LogNorm(vmin=1, vmax=5)

In [144]: n(1)
Out[144]: 0.0

In [145]: n(.5)
Out[145]: -0.43067655807339306

In [146]: n(np.nan)
Out[146]: nan

In [147]: n(0)
Out[147]: masked

In [148]: type(n(0))
Out[148]: numpy.ma.core.MaskedConstant

In [149]: n([1, 2, 5, 12, 0, np.nan])
/home/tcaswell/src/p/matplotlib/lib/matplotlib/colors.py:1031: RuntimeWarning: invalid value encountered in less_equal
  val = np.ma.asarray(value)
Out[149]: 
masked_array(data = [0.0 0.43067655807339306 1.0 1.5439593106327716 -- nan],
             mask = [False False False False  True False],
       fill_value = 1e+20)

In [150]: 

@arthur00
Copy link
Author

I have opened another bug to explore this issue: #11039

@arthur00
Copy link
Author

Ok, I tried rerunning my original code and setting vmin/vmax, and now it worked but the artifacts are back.

image

image

I guess the artifacts dissapeared because np.nan was returning 0.0, not masked. The 'masked' values interpolation seem to be issue here.

Reopening this issue as well, but feel free to close if this is not a relevant bug.

@arthur00 arthur00 reopened this Apr 12, 2018
@timhoffm
Copy link
Member

Cannot reproduce as of v3.3.0. Please reopen if the problem still persists.

@story645 story645 removed this from the future releases milestone Oct 6, 2022
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

No branches or pull requests

6 participants