FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

imshow doesn't properly display some images · Issue #10072 · matplotlib/matplotlib · GitHub

Repository navigation

imshow doesn't properly display some images #10072

Description

Bug report

Bug summary
When using imshow with larger images, you lose pixel resolution for low intensity pixels with lots of nearby zeros (not sure if the intensity or nearby zeros are relevant, or just relative isolation of the pixel). It's like they're being interpolated away, even if interpolation is set to nearest. This is new behavior in version 2.1.

Code for reproduction
Use the attached npy file, which is an image referenced in this test script.

import matplotlib.pyplot as plt
import numpy as np

img = np.load('test_image.npy')

#Display full image
plt.imshow(img, interpolation = 'nearest')
plt.clim(0, 5)
plt.show()

#Display part of image
plt.imshow(img[200:400,500:700], interpolation = 'nearest')
plt.clim(0, 5)
plt.show()

Actual outcome
Using matplotlib 2.1.1:
Screenshot from the display of full image (first plot in code above):

Using the zoom tool to zoom in on a region when the full image is plotted:

Plotting roughly the same zoom region initially (second plot in code above):

Expected outcome
It should all look like the third image. Here's the output when the same code is run in version 2.0.2
Screenshot from the display of full image (first plot in code above):

Using the zoom tool to zoom in on a region when the full image is plotted:

Plotting roughly the same zoom region initially (second plot in code above):

Matplotlib version

  • Operating system: macOS 10.12.6
  • Matplotlib version: 2.1.1 (broken) and 2.0.2 (working)
  • Matplotlib backend (print(matplotlib.get_backend())): MacOSX
  • Python version: 2.7.12
  • Other libraries: numpy version 1.13.3

All libraries are installed through conda, using the standard channel. This includes both versions of matplotlib (2.1.1 and 2.0.2).

Numpy file with image data:
test_image.zip

Activity

  1. jbhopkins commented on Dec 21, 2017

    ContributorAuthor

    One additional note. This doesn't seem to be backend dependent. I first noticed the bug on the wxagg backend. Here's some code for reproducing it there if you want:

    import matplotlib
    matplotlib.rcParams['backend'] = 'WxAgg'
    import numpy as np
    import wx
    from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg
    from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
    
    class ImagePanel(wx.Panel):
    
        def __init__(self, parent, panel_id, name, *args, **kwargs):
    
            wx.Panel.__init__(self, parent, panel_id, *args, name = name, **kwargs)
    
            self.fig = matplotlib.figure.Figure((5,4), 75)
            self.canvas = FigureCanvasWxAgg(self, -1, self.fig)
    
            self.draw_cid = self.canvas.mpl_connect('draw_event', self.safe_draw)
    
            self.toolbar = NavigationToolbar2WxAgg(self.canvas)
            self.toolbar.Realize()
    
            sizer = wx.BoxSizer(wx.VERTICAL)
            sizer.Add(self.canvas, 1, wx.LEFT|wx.TOP|wx.GROW)
            sizer.Add(self.toolbar, 0, wx.GROW)
    
            self.SetSizer(sizer)
    
        def safe_draw(self, event = None):
            '''should allow drawing when the panel resizes'''
            self.canvas.mpl_disconnect(self.draw_cid)
            self.canvas.draw()
            self.draw_cid = self.canvas.mpl_connect('draw_event', self.safe_draw)
    
        def showNewImage(self, img):
            '''Plots a new image'''
            self.img = img
            self.fig.clear()
    
            a = self.fig.gca()
    
            self.imgobj = a.imshow(self.img, interpolation = 'nearest')
    
            a.set_title('My Image Title')
            a.set_xlabel('x (pixels)')
            a.set_ylabel('y (pixels)')
            a.axis('image')
    
            self.imgobj.set_clim(0, 5)
    
            self.canvas.draw()
    
    class ImageFrame(wx.Frame):
        ''' A Frame for testing the image panel '''
    
        def __init__(self, title, frame_id):
            wx.Frame.__init__(self, None, frame_id, title, name = 'MainFrame')
    
            self.SetSize((750,750))
    
            self.background_panel = wx.Panel(self, -1)
            self.image_panel = ImagePanel(self.background_panel, -1, 'ImagePlotPanel')
    
            sizer = wx.BoxSizer()
            sizer.Add(self.image_panel, 1, wx.GROW)
    
            self.background_panel.SetSizer(sizer)
    
            self.loadTestImage()
    
        def loadTestImage(self):
            img = np.load('test_image.npy')
            self.image_panel.showNewImage(img)
    
    
    class ImageTestApp(wx.App):
        ''' A test app '''
    
        def OnInit(self):
    
            frame = ImageFrame('My Image', -1)
            self.SetTopWindow(frame)
            frame.CenterOnScreen()
            frame.Show(True)
            return True
    
    if __name__ == "__main__":
        app = ImageTestApp(0)
        app.MainLoop()
  2. tacaswell commented on Dec 21, 2017

    Member

    What is the datatype of your input data?

    Can you reproduce this with synthetic data?

  3. jbhopkins commented on Dec 21, 2017

    ContributorAuthor

    The datatype of the numpy array is uint32 (just realized that's what you meant, so edited this answer).

    I haven't tried with synthetic data. If I have a chance, I'll try to generate a dataset and test, but I can't promise I'll have time to do that.

  4. tacaswell commented on Dec 21, 2017

    Member

    Does it work if you cast to floats first? My knee-jerk guess is that we have gotten too-careful with preserving input types.

  5. jbhopkins commented on Dec 21, 2017

    ContributorAuthor

    If I cast it as a float it works fine, good guess!

    I don't understand enough about the inner workings of matplotlib to know why that changed things. Is this something you'll fix going forward, or should I just default to casting to float?

  6. added this to the v2.1.2 milestone on Dec 21, 2017
  7. tacaswell commented on Dec 21, 2017

    Member

    Definitely something that should be fixed (hopefully soon!), but as a work around now casting to float will work.

    The root of the issues is we removed a couple of cast-to-float calls (both to save memory and to avoid down-casting float128 values) but apparently now let uint though un cast which means in the normalization step they all end up being 0 or 1 (as it looks like your minimum is 0 and all of the other values are strictly less that the maximum value except the maximum so integer division does it's thing).

  8. jbhopkins commented on Dec 21, 2017

    ContributorAuthor

    Great, thanks! I will look for it in the next release (hopefully). I appreciate the fast response, and all of your hard work, along with the rest of the community.

  9. jklymak commented on Dec 30, 2017

    Member

    Pretty sure it was #8966 around line 382 of image.py

  10. xanfus commented on Mar 2, 2018

  11. jklymak commented on Mar 2, 2018

  12. xanfus commented on Mar 2, 2018

  13. jklymak commented on Mar 2, 2018

  14. jklymak commented on Mar 2, 2018

  15. 6 remaining items

  16. jklymak commented on Apr 13, 2018

    Member

    First, I think its pretty straightforward to do x = np.ma.masked_greater(x, 1e10) or whatever is adequate to catch your bad flag.

    But, I agree that if you specify vmax in imshow that it should do a better job of the scaling.

    @tacaswell the interpolation happens at draw time. Should we not use vmin and vmax to do the scaling if they are set?

  17. jklymak commented on Apr 13, 2018

    Member

    Oh, hold it, we kind of do, but only if you set both vmin and vmax. The bug here is that vmin=None and then our attempt to make things right fails. Your test above works fine if you set vmin=-2

  18. tacaswell commented on Apr 13, 2018

    Member

    For pcolor we are rendering individual rectangle patches w for here as for image we resample the image and then pass that to the renderer. In general imshow will be much faster for large arrays.

    You can not use vmin and vmax for the rescaling limits because you will not get the interpolation correct as you will be clipping any large values to just above / below the limits.

  19. tacaswell commented on Apr 13, 2018

    Member

    ah, that means we just need to make sure the norm has auto-scaled.

  20. mmf1982 commented on Apr 13, 2018

    jklymak, sure I can mask the bad flag, but it's one more step to do and not at all handy if you do not know beforehand what was actually used and you just want to get an impression of the data.
    I realized that, if I do the plotting and then re-size the plotting window, using version 2.2.2, it sets back to ok scaling. The same is not true for 2.1.2.

  21. jklymak commented on Apr 13, 2018

    Member

    See #11047 for the same fix as before, but this time handling if the norms are None.

    @tacaswell, I just used the data min and max rather than relying on a norm autoscaling.

  22. jklymak commented on Apr 13, 2018

    Member

    @mmf1982 OK, thats probably because the autoscaling for the norm gets applied at the first draw, so the second draw has the correct info.

  23. mmf1982 commented on Apr 13, 2018

    There are still problems if the initial dtype is not float64 and the outlier is negative, consider:
    x=np.array([[0.1,0.2],[-1.e18,0.3]]).astype("float32");plt.imshow(x,vmin=0,vmax=0.5)
    I set both vmin and vmax, but still the result does not look as wanted. In fact, this is even more akward,0.1, 0.2 and -1e18 are coloured as min and 0.3 as maximum.
    I still do not see why you "need to do the scaling and unscaling" to the data. If you do not do it, the internal resampling is fine. (?)

  24. tacaswell commented on Apr 13, 2018

    Member
  25. jklymak commented on Apr 13, 2018

    Member

    The dv * 1e7 was too big for float32. Changed to dv * 1e4 seems OK, but that value was just empricallly decided. See change to #11047

  26. mmf1982 commented on Apr 16, 2018

    Thanks @tacaswell for the references and thanks @jklymak for the fix.

  27. modified the milestones: v2.1.2, v2.2.3 on May 15, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions


      Back | FazBrowse Home | New Git URL