You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Starting this PR to keep #63 on everyone's radar. Along with #50 and #45 this is one of the major (but mostly internal) changes I am considering for the version 1.0 release.
ProPlot adds "batch" setter methods called format to every Axes subclass. The idea is it's quicker to call 1 method with 10 keyword arguments rather than 10 methods on 10 lines. Interestingly, it looks like the Plots.jl julia package follows a similar philosophy (see the "Lorenz attractor" example).
However:
It seems kind of sloppy / unpythonic to me to have individual settings that can only be modified with a batch setter. It also makes the setter methods really long and difficult to maintain. (no longer valid; see below) I want to encourage batch setting but permit individual one-liner setting if the user so chooses.
One of my goals for version 1 is to incorporate ProPlot internals more closely with matplotlib, and matplotlib apparently has its own batch setter, Artist.set. However nobody uses it, probably because (1) it seldom appears in the online examples and (2) the valid arguments are not explicitly documented, which is confusing for new userss.
With this PR, I'd like to combine the features of Axes.format with Artist.update and Artist.set by overriding the latter for axes artists. I will deprecate format and break up the format tasks into individual setters, but encourage using the batch setters by using them in all of the examples and documenting the acceptable keyword args.
Here is some pseudocode to outline the general idea.
# The batch setters@cbook.deprecated("1.0.0", alternative="Axes.set(...)") # use matplotlib's deprecation system?defformat(self, **kwargs):
_warn_proplot(
'Axes.format() was deprecated in version 1.0.0. Please use `Axes.set()` instead.'
) # or "deprecation" with a simple warningreturnself.set(*args, **kwargs)
defset(self, **kwargs):
# Just like Artist.set(), process aliases here, e.g. `xticklabels` for `xformatter`# May just add `_alias_map` and `_prop_order` attributes to Axes!self._alias_map= ... # make sure these hidden props are stable!self._prop_order= ...
# then filter out rc props here, and maybe we can have some sort of# rcupdate() method that updates *any* rc property that has changedrcprops, kwargs=_process_kwargs(kwargs)
self.applyrc(rcprops)
super().set(**kwargs)
defupdate(self, props):
# *Superset* of internal matplotlib.artist.Artist.update()# Permit passing *keyword arguments* to each setter# Example: If we get `xlim` and `xlim_kw`, call `Axes.set_xlim(xlim, **xlim_kw)`def_update_property(self, k, v, **kwargs):
k=k.lower()
ifkin {'axes'}:
returnsetattr(self, k, v)
else:
func=getattr(self, 'set_'+k, None)
ifnotcallable(func):
raiseAttributeError(
f'{type(self).__name__!r} object has no property {k!r}.')
returnfunc(v)
withcbook._setattr_cm(self, eventson=False):
ret= []
forkey, valuein_kwargs_not_ending_in_kw(kwargs).items():
kw=_kwarg_ending_in_kw(key)
ret.append(_update_property(self, k, v, **kw))
returnret# Helper method that looks for rc setting names passed# to the bulk settersdefapplyrc(self, **kwargs):
# perform various actions currently spread around Axes.format()withplot.rc.context(**kwargs):
# apply "cached" props (i.e. props changed in this block)# plot.rc.fill(props, cached=True)# plot.rc.get(props, cached=True)# etc.pass# The individual setters# These replace features originally coded in Axes.formatdefset_abcstyle(self, style):
ifnotisinstance(style, str) or (style.count('a') !=1andstyle.count('A') !=1):
raiseValueErrorabc=_abc(self.number-1)
if'A'instyle:
abc=abc.upper()
abc=re.sub('[aA]', abc, abcstyle)
self.abc.set_text(abc)
defset_xticks(self, locator, **kwargs):
locator=axistools.Locator(locator, **kwargs)
self.xaxis.set_major_locator(locator)
defset_xminorticks(self, locator, **kwargs):
locator=axistools.Locator(locator, **kwargs)
self.xaxis.set_minor_locator(locator)
defset_xticklabels(self, formatter, **kwargs):
formatter=axistools.Formatter(formatter, **kwargs)
self.xaxis.set_major_formatter(formatter)
...
Then to encourage using the batch setters, we can concatenate docstrings from each individual setter:
# Documentation builderdef_get_setter_docs(self):
# Maybe just retrieve first sentence of each docstring,# and look at `Axes._alias_map` for aliases!
....
Axes.set.__doc__=f"""Bulk update the axes.Parameters-----------{_get_setter_docs(Axes)}"""# Results in the following docstring# (not sure how we can consistently get argument types though)"""Parameters-----------xlim : (float, float), optional Call `~Axes.set_xlim`. Set the x-axis view limits.ylim : (float, float), optional Call `~Axes.set_ylim`. Set the y-axis view limits.... etc ..."""
This PR will still be useful but no longer high priority. On the main branch I have split up the format() tasks into separate _update_xyz utilities, which already makes things much cleaner/easier to maintain. So half of point 1 is no longer valid.
...on second thought I really don't think this is necessary anymore.
Matplotlib has enough setters and getters, and in the latest proplot version, if you use mpl setters set_title, set_xlabel, set_ylabel, the labels still get synced to the appropriate shared axes/panels just as if you called format(). So, for almost all settings, users already have the option of using "individual setters" from the native matplotlib API vs. format().
In the future I might make public some of the currently-private functions used for a handful of proplot-specific features (e.g. suplabels(), set_abc(), and making the GeoAxeslonaxis and lataxis used to control lon/lat ticks public in analogy with xaxis and yaxis). But the broader goal of this PR is probably not worth my time beyond these very specific cases and (possibly) the goal of adding generalized artist "properties" (#168). So, I'm closing this PR.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Starting this PR to keep #63 on everyone's radar. Along with #50 and #45 this is one of the major (but mostly internal) changes I am considering for the version 1.0 release.
ProPlot adds "batch" setter methods called
formatto everyAxessubclass. The idea is it's quicker to call 1 method with 10 keyword arguments rather than 10 methods on 10 lines. Interestingly, it looks like the Plots.jl julia package follows a similar philosophy (see the "Lorenz attractor" example).However:
It also makes the setter methods really long and difficult to maintain.(no longer valid; see below) I want to encourage batch setting but permit individual one-liner setting if the user so chooses.Artist.set. However nobody uses it, probably because (1) it seldom appears in the online examples and (2) the valid arguments are not explicitly documented, which is confusing for new userss.With this PR, I'd like to combine the features of
Axes.formatwithArtist.updateandArtist.setby overriding the latter for axes artists. I will deprecateformatand break up theformattasks into individual setters, but encourage using the batch setters by using them in all of the examples and documenting the acceptable keyword args.Here is some pseudocode to outline the general idea.
Then to encourage using the batch setters, we can concatenate docstrings from each individual setter: