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

[Bug]: pcolormesh is not responsive in Matplotlib 3.5 · Issue #21917 · matplotlib/matplotlib · GitHub

Repository navigation

[Bug]: pcolormesh is not responsive in Matplotlib 3.5 #21917

Closed

Description

Bug summary

After updating to mpl 3.5.0 my program hangs after plotting with pcolormesh(), no error messages. It works fine witl mpl 3.3.3. When I reduce the nx,ny values in my program it works fine.

Code for reproduction

import numpy as np
    import matplotlib.pyplot as plt
    import cartopy.io.img_tiles as cimgt
    import cartopy.crs as ccrs

    fig, ax1 = plt.subplots(num="TestXX", figsize=(30/2.54, 25/2.54))
    
    #add a map of the Netherlands
    request = cimgt.OSM()
    ax1=plt.axes(projection=request.crs)
    ax1.set_extent([3.25, 7.35, 50.45, 53.55],ccrs.PlateCarree())
    ax1.add_image(request, 10)
    
    #create a rectangular grid a little smaller than the map
    #with cell sizes of 0.01 degree filled with random values
    nx=400
    ny=300
    xedges=np.linspace(3.3, 7.3, nx)
    yedges=np.linspace(50.5, 53.5, ny)
    zvalues=np.random.random((nx, ny))
    
    ax1.pcolormesh(xedges, yedges, zvalues.T ,\
                   alpha=0.3, shading='auto', transform=ccrs.PlateCarree())
        
    plt.show()

Actual outcome

Program hangs. Toolbar doesn't response. Hourglass is visible. No errors.

Expected outcome

Plot has been made. Toolbar works, normal running program.

Additional information

It worked fine with matplotlib 3.3.3. I can then increase nx,ny to 8000,6000.(I didn't try higher values)
It seems that there is a 'problem' with pcolormesh().
It works fine in mpl 3.5.0 with reduced nx,ny values(i.e. 100,75)

Operating system

Windows 10

Matplotlib Version

3.3.3 and 3.5.0

Matplotlib Backend

Qt5Agg

Python version

Python 3.8.12

Jupyter version

No response

Installation

conda

Activity

  1. jklymak commented on Dec 10, 2021

    Member

    Please try

    xedges=np.linspace(3.3, 7.3, nx)
    yedges=np.linspace(50.5, 53.5, ny)
    zvalues=np.random.random((nx-1, ny-1))
    

    3.5 changed the behaviour of pcolormesh when nx and ny were the same size; we used to drop the last row and column. Now we don't do that. In order to get the old behaviour you can drop the last row and column yourself, and user interp='flat'. However, I don't know how that interacts with cartopy.

  2. Hermeij commented on Dec 10, 2021

    Author

    Thnx. Tried your suggestion, but no succes, same behaviour. I think you meant shading='flat' instead of interp='flat'?

  3. jklymak commented on Dec 10, 2021

    Member

    Does the same behaviour happen without cartopy? Perhaps this is a cartopy problem, despite being linked to a Matplotlib version change. You may also make sure you are using the latest cartopy as they made some 3.5-relevant changes.

  4. Hermeij commented on Dec 10, 2021

    Author

    Checked the cartopy version, it is the latest. Removed the map and cartopy imports. So I only plot a 400x300 grid.
    Program doesn't hang anymore, but when I try to use zooming function from the toolbar the zooming window in the plot is very slow and lags with mouse movement. This is not happening in mpl 3.3.3 version. Can there be a memory problem?

  5. greglucas commented on Dec 10, 2021

    Contributor

    I can confirm this with only Matplotlib. There is definitely a massive increase in memory usage (without cursor data it is ~300MB, so 4-5x increase).

    It bisects to implementing the cursor data: #19908
    So, it seems like a better implementation specific to QuadMesh should be considered here because it is a pretty bad interaction with large data right now.

  6. added this to the v3.5.2 milestone on Dec 10, 2021
  7. tacaswell commented on Dec 13, 2021

    Member

    From skimming #19908 nothing obviously jumps out at me as the problem. My knee-jerk guess is that the problem is actually in obj.contains, but the cursor data is just bringing that issue to the front by putting it in a hot loop.

  8. Hermeij commented on Dec 13, 2021

    Author

    I did some more investigation. I added some 'event' code to print mouse coordinates when moving over the figure.
    When the matplotlib toolbar is active the program still hangs itself. But when the toolbar is deactivated, the program continues printing the mouse coordinates and there don't seem to be a problem with pcolormesh().

      import numpy as np
      import matplotlib.pyplot as plt
      import cartopy.io.img_tiles as cimgt
      import cartopy.crs as ccrs
      import matplotlib as mpl
      from matplotlib.backend_bases import  Event
      
      fig, ax1 = plt.subplots(num="TestXX", figsize=(30/2.54, 25/2.54))
      
      def onmove(event):
          x1,y1 = event.xdata, event.ydata
          print(x1,y1)
      
      cn1=ax1.figure.canvas.mpl_connect\
                  ('motion_notify_event', onmove)
      
      mpl.rcParams['toolbar'] = 'None'
            
      #add a map of the Netherlands
      request = cimgt.OSM()
      ax1=plt.axes(projection=request.crs)
      ax1.set_extent([3.25, 7.35, 50.45, 53.55],ccrs.PlateCarree())
      ax1.add_image(request, 10)
      
      #create a rectangular grid a little smaller than the map
      #with cell sizes of 0.01 degree filled with random values
      nx=400
      ny=300
      xedges=np.linspace(3.3, 7.3, nx)
      yedges=np.linspace(50.5, 53.5, ny)
      zvalues=np.random.random((nx, ny))
      
      ax1.pcolormesh(xedges, yedges, zvalues.T ,\
                     alpha=0.3, shading='auto',transform=ccrs.PlateCarree())
      
      plt.show()
    
  9. anntzer commented on Dec 13, 2021

    Contributor

    This occurs because Collection.contains calls _prepare_points, which repeatedly tries to apply the (nonlinear, slow) transform to all paths. This would indeed be necessary if pickradius > 0 (in which case we need to know the paths in screen space to detect points within a certain number of pixels of a path, but in the case of get_cursor_data, we actually use pickradius=0, i.e. we treat the individual paths as filled and just want to know which paths contain the selected point. For that case, it is likely much more efficient to inverse-transform the query point and look for containment in data space? (Alternatively, we could add some kind of caching to _prepare points, but caching is well known to be one of the two hard problems in CS :-))

  10. dstansby commented on Dec 28, 2021

    Member

    Below is a MPL only example. To demonstrate how slow things become uncomment the plt.show() comment. It seems like the time is not spent doing the transform, but in creating an individual Path object for every cell:

    1.494 <module>  test.py:1
    └─ 1.494 contains  matplotlib/collections.py:439
       ├─ 1.134 _prepare_points  matplotlib/collections.py:310
       │  └─ 1.134 get_paths  matplotlib/collections.py:2009
       │     └─ 1.134 set_paths  matplotlib/collections.py:2014
       │        └─ 1.134 _convert_mesh_to_paths  matplotlib/collections.py:2083
       │           ├─ 1.117 <listcomp>  matplotlib/collections.py:2102
       │           │  ├─ 0.973 __init__  matplotlib/path.py:99
       │           │  │  ├─ 0.434 check_shape  matplotlib/_api/__init__.py:132
       │           │  │  │  ├─ 0.314 [self]  
       │           │  │  │  ├─ 0.061 <genexpr>  matplotlib/_api/__init__.py:152
       │           │  │  │  ├─ 0.027 any  <built-in>:0
       │           │  │  │  ├─ 0.017 dict.items  <built-in>:0
       │           │  │  │  └─ 0.015 len  <built-in>:0
       │           │  │  ├─ 0.286 _update_values  matplotlib/path.py:191
       │           │  │  │  ├─ 0.151 __getitem__  matplotlib/__init__.py:651
       │           │  │  │  │  ├─ 0.104 [self]  
       │           │  │  │  │  └─ 0.047 RcParams.__getitem__  <built-in>:0
       │           │  │  │  └─ 0.128 [self]  
       │           │  │  ├─ 0.168 [self]  
       │           │  │  └─ 0.085 _to_unmasked_float_array  matplotlib/cbook/__init__.py:1290
       │           │  │     ├─ 0.056 [self]  
       │           │  │     └─ 0.015 hasattr  <built-in>:0
       │           │  └─ 0.144 [self]  
       │           └─ 0.017 concatenate  <__array_function__ internals>:2
       │              └─ 0.017 implement_array_function  <built-in>:0
       ├─ 0.308 [self]  
       ├─ 0.019 vertices  matplotlib/path.py:200
       └─ 0.015 simplify_threshold  matplotlib/path.py:233

    This suggests that doing an inverse transform on the mouse event display coordinates will not fix the issue, as we will still need to create a path for every cell to determine which cell the event falls into.

    Given this issue prevents use of not-very-large (>~ 400x400 for me) QuadMeshes, I would propose that we disable get_cursor_data as a fairly urgent fix for 3.5.2. We could disable it by default for now, with an option to turn it on that has a performance warning in the docs?

    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib.backend_bases import MouseEvent
    
    fig, ax1 = plt.subplots()
    
    # create a rectangular grid a little smaller than the map
    # with cell sizes of 0.01 degree filled with random values
    nx = 400
    ny = 400
    xedges=np.linspace(3.3, 7.3, nx)
    yedges=np.linspace(50.5, 53.5, ny)
    zvalues=np.random.random((nx, ny))
    
    im = ax1.pcolormesh(xedges, yedges, zvalues.T,
                        alpha=0.3, shading='auto')
    # plt.show()
    
    from pyinstrument import Profiler
    profiler = Profiler()
    profiler.start()
    im.contains(MouseEvent('', fig.canvas, 100, 100))
    profiler.stop()
    profiler.print(show_all=True)
  11. changed the title [-][Bug]: Plotting with matplotlib 3.5.0/cartopy: Program hangs no error message[/-] [+][Bug]: pcolormesh is not responsive in Matplotlib 3.5[/+] on Jan 18, 2022
  12. dstansby commented on Jan 18, 2022

    Member

    I've just updated the title so this is easier to find for users with similar issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions


      Back | FazBrowse Home | New Git URL