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.pymore 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_wrappers are all smaller -- they just add keywords and supportnegpos"negative-positive" plots. Previously I had to put wrappers beforestandardizeto convert keywords likex,ymin, etc. to positional arguments, but now that is handled insidestandardize_1d.The
standardize_1dandstandardize_2dfunctions now accept adataargument, 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)andstandardizewill retrieve arrays from the dict-like containers. This is arguably a cleaner way to work withDataFrameandDataArrayinput.All "auto-formatting" is now done in
_auto_format_1dand_auto_format_2d(from d335272 on master). There is no longer "auto-formatting" of legends/colorbars inapply_cmapandapply_cycle-- the_auto_formatfunctions just pass those funcs default keyword args. This also lets me enforce consistent type --_auto_formatalways 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
plotxandscatterx. They are the same as respectiveplotandscatterbut positional input is eithercommand(x)orcommand(y, x)and multiple columns of x coordinates are supported. This is analogous tofill_betweenx/areaxandbarh. This also permits "horizontal-direction" shading (resolves indicate_error for x direction #194) without adding a bunch of keywords toindicate_error.Implementing separate
plotandplotxfunctions 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 aplotwhere y is intended to be the "dependent" axis, so until now I couldn't implement this.The process of wrapping
barhis 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_extraswrappers point to a shared function, and have theplotx()method onbase.Axesreverse the arguments.Previously I used the former approach for
barhand latter approach forfill_between/fill_betweenxandvlines/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.Axesfor this system to be sustainable (#45). But I actually really like howplot.pyhas 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.Axesinstances (so that it's easier for users to learn ProPlot). But as far as additional refactoring goes, the current implementation isn't too bad.