Final improvements to 1D plotting wrappers #258
Merged
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.
Resolves #194 (and #229). This is another one of those big "refactor" PRs. There are already a couple of them in the recent commit history -- I've been trying to make
plot.py
more organized, modular, and, well... less of a clusterf*ck. This will be the final one before the imminent v0.7 release. Here are some notes:The canonical order for 1D plotting wrappers is now switched from
plot_specific_wrapper
-->standardize_1d
--> ... tostandardize_1d
-->plot_specific_wrapper
--> ... . This way I don't have to individually parse positional arguments for eachplot_specific_wrapper
. Now, theplot_specific_wrapper
s are all smaller -- they just add keywords and supportnegpos
"negative-positive" plots. Previously I had to put wrappers beforestandardize
to convert keywords likex
,ymin
, etc. to positional arguments, but now that is handled insidestandardize_1d
.The
standardize_1d
andstandardize_2d
functions now accept adata
argument, just like many (all?) matplotlib commands. ProPlot previously disabled this feature. Now, you can use e.g.ax.plot('x', 'y', data=pandas_dataframe)
or e.g.ax.contourf('z', data=xarray_dataset)
andstandardize
will retrieve arrays from the dict-like containers. This is arguably a cleaner way to work withDataFrame
andDataArray
input.All "auto-formatting" is now done in
_auto_format_1d
and_auto_format_2d
(from d335272 on master). There is no longer "auto-formatting" of legends/colorbars inapply_cmap
andapply_cycle
-- the_auto_format
functions just pass those funcs default keyword args. This also lets me enforce consistent type --_auto_format
always spits out numpy ndarrays or masked ndarrays. Makes the remaining wrappers much simpler. I also caught a few edge case bugs while refactoring this stuff.There are new plotting commands
plotx
andscatterx
. They are the same as respectiveplot
andscatter
but positional input is eithercommand(x)
orcommand(y, x)
and multiple columns of x coordinates are supported. This is analogous tofill_betweenx
/areax
andbarh
. This also permits "horizontal-direction" shading (resolves indicate_error for x direction #194) without adding a bunch of keywords toindicate_error
.Implementing separate
plot
andplotx
functions let me impose "sticky edges" for line plots (a pet peeve of mine). Now, if you don't specify limits, the default limits of the dependent axis (x forplot
, y forplotx
) are drawn right up to the line edge rather than having padding. I find this is what I want 99% of the time. Without a dedicatedplotx
, it would be equally possible to have aplot
where y is intended to be the "dependent" axis, so until now I couldn't implement this.The process of wrapping
barh
is considerably simplified. There are two possible workflows for implementing "horizontal" plotting commands:plot()
, haveplotx()
point to the wrappedplot()
function, and have an undocumentedplot()
method onbase.Axes
(or add something tocycle_changer
) that reverses positional arguments when it gets a keyword likevert=False
.plot()
andplotx()
with the usualstandardize_1d
--> ... chain, make theirplot_extras
wrappers point to a shared function, and have theplotx()
method onbase.Axes
reverse the arguments.Previously I used the former approach for
barh
and latter approach forfill_between
/fill_betweenx
andvlines
/hlines
. Now I use the latter approach for everything -- it's much cleaner.Originally I was thinking I'd need to implement "wrappers" on
base.Axes
for this system to be sustainable (#45). But I actually really like howplot.py
has turned out... Perhaps in #45 (after v0.7) I will simply make the "wrapper" functions hidden and figure out a way to concatenate proplot/matplotlib docstrings onbase.Axes
instances (so that it's easier for users to learn ProPlot). But as far as additional refactoring goes, the current implementation isn't too bad.