Skip to content
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

wrong internal state with title setting and unable to make new figures #348

Closed
syrte opened this issue Mar 11, 2022 · 2 comments
Closed
Labels

Comments

@syrte
Copy link

syrte commented Mar 11, 2022

Description

When I was adjusting the axes titles of a figure, something seemed to break the internal state of proplot. The package does not work anymore, see the error message below. I have no choice but restart the whole python session.

Steps to reproduce

I tried the following code

import proplot as pplt

fig, axs = pplt.subplots(None, 1, 4)
axs[0].format(
    title='title',
    titleloc='c', titlesize=10, titleweight='normal', titlecolor='gray10'
)

It complains "gray10" is not a good color as follows

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
/tmp/ipykernel_125973/2407293224.py in <module>
      2 
      3 fig, axs = pplt.subplots(None, 1, 4)
----> 4 axs[0].format(
      5     title='title',
      6     titleloc='c', titlesize=10, titleweight='normal', titlecolor='gray10'

~/local/conda/envs/nemo/lib/python3.8/site-packages/proplot/axes/cartesian.py in format(self, aspect, xloc, yloc, xspineloc, yspineloc, xoffsetloc, yoffsetloc, xwraprange, ywraprange, xreverse, yreverse, xlim, ylim, xmin, ymin, xmax, ymax, xscale, yscale, xbounds, ybounds, xmargin, ymargin, xrotation, yrotation, xformatter, yformatter, xticklabels, yticklabels, xticks, yticks, xlocator, ylocator, xminorticks, yminorticks, xminorlocator, yminorlocator, xcolor, ycolor, xlinewidth, ylinewidth, xtickloc, ytickloc, fixticks, xtickdir, ytickdir, xtickminor, ytickminor, xtickrange, ytickrange, xtickcolor, ytickcolor, xticklen, yticklen, xticklenratio, yticklenratio, xtickwidth, ytickwidth, xtickwidthratio, ytickwidthratio, xticklabelloc, yticklabelloc, xticklabeldir, yticklabeldir, xticklabelpad, yticklabelpad, xticklabelcolor, yticklabelcolor, xticklabelsize, yticklabelsize, xticklabelweight, yticklabelweight, xlabel, ylabel, xlabelloc, ylabelloc, xlabelpad, ylabelpad, xlabelcolor, ylabelcolor, xlabelsize, ylabelsize, xlabelweight, ylabelweight, xgrid, ygrid, xgridminor, ygridminor, xgridcolor, ygridcolor, xlabel_kw, ylabel_kw, xscale_kw, yscale_kw, xlocator_kw, ylocator_kw, xformatter_kw, yformatter_kw, xminorlocator_kw, yminorlocator_kw, **kwargs)
    987         """
    988         rc_kw, rc_mode = _pop_rc(kwargs)
--> 989         with rc.context(rc_kw, mode=rc_mode):
    990             # No mutable default args
    991             xlabel_kw = xlabel_kw or {}

~/local/conda/envs/nemo/lib/python3.8/site-packages/proplot/config.py in __enter__(self)
    791         rc_old = context.rc_old  # used to re-apply settings without copying whole dict
    792         for key, value in kwargs.items():
--> 793             kw_proplot, kw_matplotlib = self._get_item_dicts(key, value)
    794             for rc_dict, kw_new in zip(
    795                 (rc_proplot, rc_matplotlib),

~/local/conda/envs/nemo/lib/python3.8/site-packages/proplot/config.py in _get_item_dicts(self, key, value, skip_cycle)
    922         # Get validated key, value, and child keys
    923         key, value = self._validate_key(key, value)
--> 924         value = self._validate_value(key, value)
    925         keys = (key,) + rcsetup._rc_children.get(key, ())  # settings to change
    926         contains = lambda *args: any(arg in keys for arg in args)  # noqa: E731

~/local/conda/envs/nemo/lib/python3.8/site-packages/proplot/config.py in _validate_value(key, value)
    884             value = validate_matplotlib[key](value)
    885         elif key in validate_proplot:
--> 886             value = validate_proplot[key](value)
    887         return value
    888 

~/local/conda/envs/nemo/lib/python3.8/site-packages/proplot/internals/rcsetup.py in _validate_color(value, alternative)
    264             or not REGEX_NAMED_COLOR.match(value)
    265         ):
--> 266             raise ValueError(f'{value!r} is not a valid color arg.') from None
    267         return value
    268     except Exception as error:

ValueError: 'gray10' is not a valid color arg.

The problem is that I can not make any new figures since then.
When I start a new figure in a jupyter cell

fig, axs = pplt.subplots(None, 1, 4)

I get the following error

Error in callback <function install_repl_displayhook.<locals>.post_execute at 0x7f705b74adc0> (for post_execute):
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
~/local/conda/envs/nemo/lib/python3.8/site-packages/matplotlib/pyplot.py in post_execute()
    137             def post_execute():
    138                 if matplotlib.is_interactive():
--> 139                     draw_all()
    140 
    141             # IPython >= 2

~/local/conda/envs/nemo/lib/python3.8/site-packages/matplotlib/_pylab_helpers.py in draw_all(cls, force)
    135         for manager in cls.get_all_fig_managers():
    136             if force or manager.canvas.figure.stale:
--> 137                 manager.canvas.draw_idle()
    138 
    139 

~/local/conda/envs/nemo/lib/python3.8/site-packages/matplotlib/backend_bases.py in draw_idle(self, *args, **kwargs)
   2053         if not self._is_idle_drawing:
   2054             with self._idle_draw_cntx():
-> 2055                 self.draw(*args, **kwargs)
   2056 
   2057     def get_width_height(self):

~/local/conda/envs/nemo/lib/python3.8/site-packages/proplot/figure.py in _canvas_preprocess(self, *args, **kwargs)
    461         ctx3 = rc.context(fig._render_context)  # draw with figure-specific setting
    462         with ctx1, ctx2, ctx3:
--> 463             fig.auto_layout()
    464             return func(self, *args, **kwargs)
    465 

~/local/conda/envs/nemo/lib/python3.8/site-packages/proplot/figure.py in auto_layout(self, renderer, aspect, tight, resize)
   1474         _align_content()
   1475         if tight:
-> 1476             gs._auto_layout_tight(renderer)
   1477         _align_content()
   1478 

~/local/conda/envs/nemo/lib/python3.8/site-packages/proplot/gridspec.py in _auto_layout_tight(self, renderer)
    818         pad = self._outerpad
    819         obox = fig.bbox_inches  # original bbox
--> 820         bbox = fig.get_tightbbox(renderer)
    821 
    822         # Calculate new figure margins

~/local/conda/envs/nemo/lib/python3.8/site-packages/matplotlib/figure.py in get_tightbbox(self, renderer, bbox_extra_artists)
   1637 
   1638         for a in artists:
-> 1639             bbox = a.get_tightbbox(renderer)
   1640             if bbox is not None and (bbox.width != 0 or bbox.height != 0):
   1641                 bb.append(bbox)

~/local/conda/envs/nemo/lib/python3.8/site-packages/proplot/axes/cartesian.py in get_tightbbox(self, renderer, *args, **kwargs)
   1310         self._apply_axis_sharing()
   1311         self._update_rotation('x')
-> 1312         return super().get_tightbbox(renderer, *args, **kwargs)
   1313 
   1314 

~/local/conda/envs/nemo/lib/python3.8/site-packages/proplot/axes/base.py in get_tightbbox(self, renderer, *args, **kwargs)
   2610         if self._inset_parent is not None and self._inset_zoom:
   2611             self.indicate_inset_zoom()
-> 2612         self._tight_bbox = super().get_tightbbox(renderer, *args, **kwargs)
   2613         return self._tight_bbox
   2614 

~/local/conda/envs/nemo/lib/python3.8/site-packages/matplotlib/axes/_base.py in get_tightbbox(self, renderer, call_axes_locator, bbox_extra_artists, for_layout_only)
   4444                 if bb_yaxis:
   4445                     bb.append(bb_yaxis)
-> 4446         self._update_title_position(renderer)
   4447         axbbox = self.get_window_extent(renderer)
   4448         bb.append(axbbox)

~/local/conda/envs/nemo/lib/python3.8/site-packages/proplot/axes/base.py in _update_title_position(self, renderer)
   2388         # Sync the title position with the a-b-c label position
   2389         aobj = self._title_dict['abc']
-> 2390         tobj = self._title_dict[self._abc_loc]
   2391         aobj.set_transform(tobj.get_transform())
   2392         aobj.set_position(tobj.get_position())

KeyError: None

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
~/local/conda/envs/nemo/lib/python3.8/site-packages/IPython/core/formatters.py in __call__(self, obj)
    339                 pass
    340             else:
--> 341                 return printer(obj)
    342             # Finally look for special method names
    343             method = get_real_method(obj, self.print_method)

~/local/conda/envs/nemo/lib/python3.8/site-packages/IPython/core/pylabtools.py in retina_figure(fig, base64, **kwargs)
    166         base64 argument
    167     """
--> 168     pngdata = print_figure(fig, fmt="retina", base64=False, **kwargs)
    169     # Make sure that retina_figure acts just like print_figure and returns
    170     # None when the figure is empty.

~/local/conda/envs/nemo/lib/python3.8/site-packages/IPython/core/pylabtools.py in print_figure(fig, fmt, bbox_inches, base64, **kwargs)
    149         FigureCanvasBase(fig)
    150 
--> 151     fig.canvas.print_figure(bytes_io, **kw)
    152     data = bytes_io.getvalue()
    153     if fmt == 'svg':

~/local/conda/envs/nemo/lib/python3.8/site-packages/proplot/figure.py in _canvas_preprocess(self, *args, **kwargs)
    461         ctx3 = rc.context(fig._render_context)  # draw with figure-specific setting
    462         with ctx1, ctx2, ctx3:
--> 463             fig.auto_layout()
    464             return func(self, *args, **kwargs)
    465 

~/local/conda/envs/nemo/lib/python3.8/site-packages/proplot/figure.py in auto_layout(self, renderer, aspect, tight, resize)
   1474         _align_content()
   1475         if tight:
-> 1476             gs._auto_layout_tight(renderer)
   1477         _align_content()
   1478 

~/local/conda/envs/nemo/lib/python3.8/site-packages/proplot/gridspec.py in _auto_layout_tight(self, renderer)
    818         pad = self._outerpad
    819         obox = fig.bbox_inches  # original bbox
--> 820         bbox = fig.get_tightbbox(renderer)
    821 
    822         # Calculate new figure margins

~/local/conda/envs/nemo/lib/python3.8/site-packages/matplotlib/figure.py in get_tightbbox(self, renderer, bbox_extra_artists)
   1637 
   1638         for a in artists:
-> 1639             bbox = a.get_tightbbox(renderer)
   1640             if bbox is not None and (bbox.width != 0 or bbox.height != 0):
   1641                 bb.append(bbox)

~/local/conda/envs/nemo/lib/python3.8/site-packages/proplot/axes/cartesian.py in get_tightbbox(self, renderer, *args, **kwargs)
   1310         self._apply_axis_sharing()
   1311         self._update_rotation('x')
-> 1312         return super().get_tightbbox(renderer, *args, **kwargs)
   1313 
   1314 

~/local/conda/envs/nemo/lib/python3.8/site-packages/proplot/axes/base.py in get_tightbbox(self, renderer, *args, **kwargs)
   2610         if self._inset_parent is not None and self._inset_zoom:
   2611             self.indicate_inset_zoom()
-> 2612         self._tight_bbox = super().get_tightbbox(renderer, *args, **kwargs)
   2613         return self._tight_bbox
   2614 

~/local/conda/envs/nemo/lib/python3.8/site-packages/matplotlib/axes/_base.py in get_tightbbox(self, renderer, call_axes_locator, bbox_extra_artists, for_layout_only)
   4444                 if bb_yaxis:
   4445                     bb.append(bb_yaxis)
-> 4446         self._update_title_position(renderer)
   4447         axbbox = self.get_window_extent(renderer)
   4448         bb.append(axbbox)

~/local/conda/envs/nemo/lib/python3.8/site-packages/proplot/axes/base.py in _update_title_position(self, renderer)
   2388         # Sync the title position with the a-b-c label position
   2389         aobj = self._title_dict['abc']
-> 2390         tobj = self._title_dict[self._abc_loc]
   2391         aobj.set_transform(tobj.get_transform())
   2392         aobj.set_position(tobj.get_position())

KeyError: None

Figure(nrows=1, ncols=4, refwidth=2.5)

Proplot version

Paste the results of import matplotlib; print(matplotlib.__version__); import proplot; print(proplot.version)here.
3.4.3
0.9.5.post284

@syrte syrte changed the title wrong internal state with abc setting and unable to make new figures wrong internal state with title setting and unable to make new figures Mar 11, 2022
@lukelbd lukelbd added the bug label Mar 21, 2022
@lukelbd
Copy link
Collaborator

lukelbd commented Mar 21, 2022

I think I see the problem -- the rc state is not reset by Configurator.__exit__ during the error because the error is triggered inside Configurator.__enter__ rather than inside the with...as block. This leaves rc in a "user-modification" context mode rather than an "initialization" mode, so the initial values for ax._title_loc and ax._abc_loc are unset.

I think the solution is to validate rc values inside of pplt.rc.context rather than inside of pplt.Configurator.__enter__ and simplify the content in __enter__, and/or use a try...except block in __enter__ that calls __exit__ if necessary.

@lukelbd
Copy link
Collaborator

lukelbd commented Mar 29, 2023

This was a very simple fix -- should have done it much sooner. Fixed by c567329 with a simple try-except clause.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants