Replace "panels" with EdgeStack, permit working directly with add_subplot/GridSpec #110
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.
This PR replaces #50 in order to clean up its history.
Subplots
This will allowFigure.add_subplot
to be used by ProPlot users. Basic idea will be that, because we want one single gridspec for the whole axes, the user can generate a naked figure withfig = plot.figure()
, then the first call tofig.add_subplot
will set the geometry, and subsequent calls have to match that geometry. This workflow may be more readable when users want (1) complex combinations of projections, or (2) prefer to make highly complex grids with theadd_subplot(121)
notation orGridSpec
objects rather than passing arrays toplot.subplots
. I think it also makes more sense to implement projection handling inadd_subplot
rather thansubplots
.This was implemented by 51967ce for v0.8.0.
User-accessible GridSpec
If users can now useplot.Figure.add_subplot
, they should be able to useplot.GridSpec
too. This meansGridSpec
must acceptleft
,right
,wspace
, etc. in physical units rather than makingsubplots
do the work. This can be done simply by overridingGridSpec.get_grid_positions()
, which carries out 100% of the math used to calculate subplot positions.This was implemented in 2050234 for v0.8.0.
GeometrySolver class
The above changes mean we have to let users pass gridspec spacing values before the gridspec is necessarily created. Matplotlib specifies default subplot spacing on the figure (Figure.subplots_adjust
andmatplotlib.figure.SubplotParams
) then appliesFigure
spacing values to the unsetGridSpec
values whenver the gridspec is updated. I can mimick this approach with aGeometrySolver
class that acts as the interface between theFigure
and theGridSpec
. This class will parsesubplots
/figure
spacing arguments, carry out the tight layout algorithm, and perform figure-resizing and gridspec-updating tasks. This has the added benefit of cleaning up the internals and removing a bunch of hidden methods fromFigure
.This was not implemented; instead, the functionality was added directly to
GridSpec
2050234 for v0.8.0.EdgeStack class
Currently, when colorbars, legends, and axes panels are created, they secretly "insert a new column or row" by destroying the existing gridspec and create a new one. This means if users keep using the
GridSpec
object after adding a figure panel or something, its geometry is different from the figureGridSpec
, and weird stuff will happen. I considered two approaches to fixing this:GridSpec.__getitem__
obfuscate underlying gridspec dimensions and things generally get messy.Stop drawing panels inside the GridSpec. Instead manage arbitrary artists along the "edge" of individual subplots (or contiguous subplots) with a specialEdgeStack
class. This requires redesigning the "tight layout" algorithm to work with artists in theEdgeStack
, figuring out how to lock them to the main axes (probably similar to how "inset" axes are locked), and figuring out how to lock their physical widths.In the end I decided to pursue # 2. It's sad that that I spent so much time working with "panels" instead of doing this overhaul... but I think it's the right move, given the following benefits:Panels in the same row or column no longer have to be the same width, which can be a problem when you have legends + colorbars alongisde each other.It allows drawing legends + colorbars along the sides of arbitrary contiguous subplots rather than just along the figure edge.Legends no longer have to belong to an empty, dummy axes -- we can just lock the legend position.Colorbars no longer have to belong to empty, dummy axes to extend them along <100% of the axes -- we just adjust the parent-relative long axis coordinates.It will remove all references toGridSpecFromSubplotSpec
, which proplot'sGridSpec
tries to render obsolete.We can implementrowlabels
andcollabels
with the same API, allow "stacking" arbitrary outer text objects just like legends, colorbars, and panels.Also, for permitting colorbars, legends, and text along arbitrary contiguous axes, I can write a helper function that accepts lists of subplots and makes sure their right/left/top/bottom edges are in alignment. When you call e.g.axes_grid([...]).colorbar(...)
, it will pass the axes in the container to a helper function. When you call e.g.Figure.colorbar(...)
, it will select the subplots lying along the figure edge and pass them to the helper function.I decided to use approach # 1 after all, adding the "panel" obfuscation directly onto the
GridSpec
object in 2050234. I use_total
and_panel
attributes to improve this obfuscation. See below notes for details.