8000 matplotlib 3.5 breaks yt · Issue #20520 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content
matplotlib 3.5 breaks yt #20520
Closed
Closed
@neutrinoceros

Description

@neutrinoceros

Bug report

Bug summary

I found a regression in yt (https://github.com/yt-project/yt) by running our CI against matplotlib's master branch.

Code for reproduction

Here's a "minimal" script using yt's api

from yt.testing import fake_sph_grid_ds
from yt.visualization.plot_window import ProjectionPlot

ds = fake_sph_grid_ds()
plot = ProjectionPlot(ds, "z", ("gas", "density"))
plot.save()

I apologise for not being able to provide a pure mpl minimal example at the moment. The data flow is unfortunately very hard to keep track of on the yt side, but I'm working on it.
I think a better approach might be to go through the diff from the breaking commit and attempt a patch from there. I will attempt this and report here.

Actual outcome

Here's the traceback (using rich)

yt : [INFO     ] 2021-06-25 17:00:25,961 Parameters: current_time              = 0.0
yt : [INFO     ] 2021-06-25 17:00:25,961 Parameters: domain_dimensions         = [1 1 1]
yt : [INFO     ] 2021-06-25 17:00:25,961 Parameters: domain_left_edge          = [0. 0. 0.]
yt : [INFO     ] 2021-06-25 17:00:25,961 Parameters: domain_right_edge         = [3. 3. 3.]
yt : [INFO     ] 2021-06-25 17:00:25,962 Parameters: cosmological_simulation   = 0
yt : [INFO     ] 2021-06-25 17:00:25,962 Allocating for 2.700e+01 particles
yt : [INFO     ] 2021-06-25 17:00:28,828 xlim = 0.000000 3.000000
yt : [INFO     ] 2021-06-25 17:00:28,828 ylim = 0.000000 3.000000
yt : [INFO     ] 2021-06-25 17:00:28,828 xlim = 0.000000 3.000000
yt : [INFO     ] 2021-06-25 17:00:28,828 ylim = 0.000000 3
8000
.000000
yt : [INFO     ] 2021-06-25 17:00:28,836 Making a fixed resolution buffer of (('gas', 'density')) 800 by 800
> /Users/robcleme/dev/yt-project/yt-py310/yt/visualization/plot_window.py(1072)_setup_plots()
   1070             #balise 3
   1071             # THE ISSUE IS HERE
-> 1072             self.plots = WindowPlotMPL(
   1073                 ia,
   1074                 self._field_transform.name,

(Pdbr) c
> /Users/robcleme/dev/yt-project/yt-py310/yt/visualization/base_plot_types.py(238)_init_image()
    236         # tuple colormaps are from palettable (or brewer2mpl)
    237         breakpoint()
--> 238         if isinstance(cmap, tuple):
    239             cmap = get_brewer_cmap(cmap)
    240

(Pdbr) c
> /Users/robcleme/dev/yt-project/yt-py310/yt/visualization/plot_window.py(1072)_setup_plots()
   1070             #balise 3
   1071             # THE ISSUE IS HERE
-> 1072             self.plots = WindowPlotMPL(
   1073                 ia,
   1074                 self._field_transform.name,

(Pdbr) c
> /Users/robcleme/dev/yt-project/yt-py310/yt/visualization/base_plot_types.py(238)_init_image()
    236         # tuple colormaps are from palettable (or brewer2mpl)
    237         breakpoint()
--> 238         if isinstance(cmap, tuple):
    239             cmap = get_brewer_cmap(cmap)
    240

(Pdbr) c
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /Users/robcleme/dev/yt-project/yt-py310/repro_mpl_bug.py:49 in <module>                          │
│                                                                                                  │
│   46 │   return 0                                                                                │
│   47                                                                                             │
│   48 if __name__ == "__main__":                                                                  │
│ ❱ 49 │   sys.exit(main())                                                                        │
│                                                                                                  │
│ /Users/robcleme/dev/yt-project/yt-py310/repro_mpl_bug.py:25 in main                              │
│                                                                                                  │
│   22 │                                                                                           │
│   23 │   ds = fake_sph_grid_ds()                                                                 │
│   24 │   plot = ProjectionPlot(ds, "z", ("gas", "density"))                                      │
│ ❱ 25 │   plot.save()                                                                             │
│   26 │   return 0                                                                                │
│   27                                                                                             │
│   28 def main2() -> int:                                                                         │
│                                                                                                  │
│ /Users/robcleme/dev/yt-project/yt-py310/yt/visualization/plot_container.py:106 in newfunc        │
│                                                                                                  │
│    103 │   │   if not args[0]._plot_valid:                                                       │
│    104 │   │   │   # it is the responsibility of _setup_plots to                                 │
│    105 │   │   │   # call args[0].run_callbacks()                                                │
│ ❱  106 │   │   │   args[0]._setup_plots()                                                        │
│    107 │   │   rv = f(*args, **kwargs)                                                           │
│    108 │   │   return rv                                                                         │
│    109                                                                                           │
│                                                                                                  │
│ /Users/robcleme/dev/yt-project/yt-py310/yt/visualization/plot_window.py:1072 in _setup_plots     │
│                                                                                                  │
│   1069 │   │   │   breakpoint()                                                                  │
│   1070 │   │   │   #balise 3                                                                     │
│   1071 │   │   │   # THE ISSUE IS HERE                                                           │
│ ❱ 1072 │   │   │   self.plots[f] = WindowPlotMPL(                                                │
│   1073 │   │   │   │   ia,                                                                       │
│   1074 │   │   │   │   self._field_transform[f].name,                                            │
│   1075 │   │   │   │   self._field_transform[f].func,                                            │
│                                                                                                  │
│ /Users/robcleme/dev/yt-project/yt-py310/yt/visualization/plot_window.py:2268 in __init__         │
│                                                                                                  │
│   2265 │   │                                                                                     │
│   2266 │   │   super().__init__(size, axrect, caxrect, zlim, figure, axes, cax)                  │
│   2267 │   │                                                                                     │
│ ❱ 2268 │   │   self._init_image(data, cbname, cblinthresh, cmap, extent, aspect)                 │
│   2269 │   │                                                                                     │
│   2270 │   │   # In matplotlib 2.1 and newer we'll be able to do this using                      │
│   2271 │   │   # self.image.axes.ticklabel_format                                                │
│                                                                                                  │
│ /Users/robcleme/dev/yt-project/yt-py310/yt/visualization/base_plot_types.py:327 in _init_image   │
│                                                                                                  │
│   324 │   │   else:                                                                              │
│   325 │   │   │   # this is where it breaks (but only on second pass)                            │
│   326 │   │   │   #breakpoint()                                                                  │
│ ❱ 327 │   │   │   self.cb = self.figure.colorbar(self.image, self.cax)                           │
│   328 │   │   for which in ["major", "minor"]:                                                   │
│   329 │   │   │   self.cax.tick_params(which=which, axis="y", direction="in")                    │
│   330                                                                                            │
│                                                                                                  │
│ /Users/robcleme/dev/yt-project/yt-py310/matplotlib/lib/matplotlib/figure.py:1156 in colorbar     │
│                                                                                                  │
│   1153 │   │   │   │   │   │   │    'panchor']                                                   │
│   1154 │   │   cb_kw = {k: v for k, v in kw.items() if k not in NON_COLORBAR_KEYS}               │
│   1155 │   │                                                                                     │
│ ❱ 1156 │   │   cb = cbar.Colorbar(cax, mappable, **cb_kw)                                        │
│   1157 │   │                                                                                     │
│   1158 │   │   if not kw['userax']:                                                              │
│   1159 │   │   │   self.sca(current_ax)                                                          │
│                                                                                                  │
│ /Users/robcleme/dev/yt-project/yt-py310/matplotlib/lib/matplotlib/colorbar.py:1196 in __init__   │
│                                                                                                  │
│   1193 │   │   │   │   kwargs.setdefault('extend', mappable.cmap.colorbar_extend)                │
│   1194 │   │   │   if isinstance(mappable, martist.Artist):                                      │
│   1195 │   │   │   │   _add_disjoint_kwargs(kwargs, alpha=mappable.get_alpha())                  │
│ ❱ 1196 │   │   │   super().__init__(ax, **kwargs)                                                │
│   1197 │   │                                                                                     │
│   1198 │   │   mappable.colorbar = self                                                          │
│   1199 │   │   mappable.colorbar_cid = mappable.callbacksSM.connect(                             │
│                                                                                                  │
│ /Users/robcleme/dev/yt-project/yt-py310/matplotlib/lib/matplotlib/_api/deprecation.py:489 in     │
│ wrapper                                                                                          │
│                                                                                                  │
│   486 │   │   │   │   "positionally is deprecated since Matplotlib %(since)s; the "              │
│   487 │   │   │   │   "parameter will become keyword-only %(removal)s.",                         │
│   488 │   │   │   │   name=name, obj_type=f"parameter of {func.__name__}()")                     │
│ ❱ 489 │   │   return func(*args, **kwargs)                                                       │
│   490 │                                                                                          │
│   491 │   return wrapper                                                                         │
│   492                                                                                            │
│                                                                                                  │
│ /Users/robcleme/dev/yt-project/yt-py310/matplotlib/lib/matplotlib/colorbar.py:421 in __init__    │
│                                                                                                  │
│    418 │   │   │   ['uniform', 'proportional'], spacing=spacing)                                 │
│    419 │   │                                                                                     │
│    420 │   │   # wrap the axes so that it can be positioned as an inset axes:                    │
│ ❱  421 │   │   ax = ColorbarAxes(ax, userax=userax)                                              │
│    422 │   │   self.ax = ax                                                                      │
│    423 │   │   ax.set(navigate=False)                                                            │
│    424                                                                                           │
│                                                                                                  │
│ /Users/robcleme/dev/yt-project/yt-py310/matplotlib/lib/matplotlib/colorbar.py:260 in __init__    │
│                                                                                                  │
│    257 │   │   │   │   parent._axes.add_child_axes(outer_ax)                                     │
│    258 │   │   │   │   outer_ax._axes.child_axes.remove(parent)                                  │
│    259 │   │   │   else:                                                                         │
│ ❱  260 │   │   │   │   parent.remove()                                                           │
│    261 │   │   else:                                                                             │
│    262 │   │   │   outer_ax = parent                                                             │
│    263                                                                                           │
│                                                                                                  │
│ /Users/robcleme/dev/yt-project/yt-py310/matplotlib/lib/matplotlib/artist.py:163 in remove        │
│                                                                                                  │
│    160 │   │   # protected attribute if Python supported that sort of thing.  The                │
│    161 │   │   # callback has one parameter, which is the child to be removed.                   │
│    162 │   │   if self._remove_method is not None:                                               │
│ ❱  163 │   │   │   self._remove_method(self)                                                     │
│    164 │   │   │   # clear stale callback                                                        │
│    165 │   │   │   self.stale_callback = None                                                    │
│    166 │   │   │   _ax_flag = False                                                              │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
ValueError: list.remove(x): x not in list

A CI log with multiple such failures can be found here https://github.com/yt-project/yt/runs/2899209479?check_suite_focus=true

Expected outcome

The script is supposed to output a file named "ParticleData_Projection_z_density.png".
It works fine with matplotlib 3.4.0, and I was able to identify (git bisect) the breaking commit in matplotilb: 146856b

Matplotlib version

  • Operating system: OsX
  • Matplotlib version (import matplotlib; print(matplotlib.__version__)): 3.4.2.post863+g146856b03
  • Matplotlib backend (print(matplotlib.get_backend())):
  • Python version: I used 3.10.0b2 but I don't believe it is relevant
  • Jupyter version (if applicable):
  • Other libraries: yt (installed from source, main branch, commit c3054df545b51871ae22ef900a4d0e56cf0f2428) https://github.com/yt-project/yt

I installed matplotlib with

pip install git+https://github.com/matplotlib/matplotlib.git

and reinstalled on every iteration of my git bisect run.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0