Conversation
|
I think this should take an ax and a cax argument, just like normal colorbar. For layout we are going to want the option for the colorbar to steal space from a number of axes, not just the axes that holds the mappable (though it's probably fine to default to that) This should also play well with constrained layout. Tight layout won't work with colorbars so that is not a concern. If you need help with that, please ping. However conceptually it should be the same as a normal colorbar, it'll just possibly be much larger. |
|
|
|
Also apparently I didn't read 3 correctly 🤦♀️ but I agree w/ @timhoffm's proposal d) |
3cf2df9 to
701c4b2
Compare
|
This is progressing well, thank you for all the feedback so far. In the draft, I am using self._image = self.ax.imshow(
self.colorizer.cmap.lut,
origin='lower',
extent=(0, 1, 0, 1),
transform=self.ax.transAxes,
interpolation='nearest',
alpha=self.alpha,
)to display the bivariate colorbar. The This can for example be illustrated by: norm = mpl.colors.MultiNorm(['log', 'log'])
ca = mpl.colorizer.Colorizer('BiOrangeBlue', norm)
fig, ax = plt.subplots()
cbar = fig.bivar_colorbar(ca, cax = ax, ticklocations=['left', 'bottom'])
norm.norms[1].vmin = 0.1
norm.norms[1].vmax = 10
cbar.xaxis.set_ticks([1, 10, 100])
print(ca.norm.vmin, ca.norm.vmax, cbar.ax.get_xlim() )
# (None, 0.1), (None, 10.0), (0.1, 100.0)Where the xlim is changed but vmax on the norm is not. My thinking is that any action taken by the user which would change the limits on the axis by operations on the axis, and not by setting the vmin or vmax, should raise an error of the form: raise ValueError("Changing the limits of this axis must be done "
"using the norm attached to the bivariate colorbar.")I can do this by connecting to Does this seem like a reasonable solution to you? When |
701c4b2 to
f19b42c
Compare
|
Wouldn't it make sense to use pcolormesh instead of image so users can change the scale if they want to? |
Thank you for the feedback @jklymak, but I think we can work with imshow in this case. The user should be able to change the scale on the norm, which will change the axis, but the bivariate colormap should render the same. Where the only change is that a LogNorm is used to when visualizing the GDP per capita in the lower plot. I do not think there is a need to set a scale different from that of the norm. (additionally: I would like to avoid pcolormesh if possible, because if saved as an SVG, each tile in the mesh gets stored as a polygon, which makes it almost impossible to edit the svg later. I personally find the pipeline matplotlib→inkscape to be extremely powerful, and would like that to be possible here.) The plots are based on https://trygvrad.github.io//mpl_docs/Bivariate%20colormaps.html |
|
People do ask to set the scale differently from the norm and they will be able to, but will get incorrect scaling of the colors. Pcolormesh can be rasterized, so you can avoid the polygon problem in svg/pdf. Note normal colorbar uses pcolormesh. |
|
@jklymak thank you for the specification, I will see if I can make pcolormesh behave :) |
f19b42c to
22e122d
Compare
|
@jklymak I am looking at what we need for layouts for multivar colorbar. import matplotlib.pyplot as plt
import numpy as np
im_A = np.arange(200)[np.newaxis, :]*np.ones((200, 200))
im_B = np.arange(200)[:, np.newaxis]*np.ones((200, 200))
im_C = 0.9*im_A + 0.9*im_B
im_A = np.sin(im_A**0.5)**2
im_B = np.sin(im_B**0.5)**2
im_C = np.sin(im_C**0.5)**2
fig, axes = plt.subplots(2, 2, figsize = (10, 6))
axes = axes.ravel()
locs = ['left', 'right', 'top', 'bottom']
im = (im_A, im_B, im_C)
for i, loc in enumerate(locs):
cim = axes[i].imshow(im, cmap='3VarAddA')
cb = fig.multivar_colorbar(cim, location=loc, use_gridspec=False, fraction=0.3)
Where In terms of layout, I want the user to have the option to organize the colorbars in a different way: cb = fig.multivar_colorbar(..., n_major=2)
or cb = fig.multivar_colorbar(..., n_major=1)
For the prototype I am basing this on bbox.splitx() and bbox.splity() [gridspec=False]. In the existing code there is make_axes
make_bivar_axes
make_multivar_axes
make_axes_gridspec
make_bivar_axes_gridspec
make_multivar_axes_gridspec [not yet implemented]Because there is a lot of overlap, I have created a number of private helper functions, which (hopefully) avoids duplicate code. @jklymak does this make sense to you in terms of the layout? I have not yet started looking at |
|
I'll need to look at what you are proposing. Ideally I think your colorbars would be encapsulated inside something constrained layout thinks is a "colorbar" that is should put into the colorbar slot in the layout manager. After that the "colorbar" can look as you like. If you want the colorbars to be placed inside of the allotted area by the layout manager I think that will be more difficult Overall I would not suggest making a gridspec version of the colorbars. I suppose those allow a non optimal but still legible layout. I can try and look closer this weekend. If you had some example scripts for me to look at that'd make things easier. Apologies if they are already in this PR |
|
which looks fixable? |
|
This might be the silliest thing but can we maybe flip the names to colorbar_{bi, multi}? I think would be especially easier for auto complete. |
:D
@jklymak This is a good idea, and I will try to make it happen, but I am not super familiar with this part of the code. What kind of object do you think that something should be, because I don't think it should be an axis in an of itself, but it should probably show up in def get_children(self):
"""Get a list of artists contained in the figure."""
return [self.patch,
*self.artists,
*self._localaxes,
*self.lines,
*self.patches,
*self.texts,
*self.images,
*self.legends,
*self.subfigs]
Thanks for checking this, I will fix this and add some tests that cover these cases.
@story645 I think there is significant merit to this argument :) |
|
It's possible it will just work if you give each of the colorbars a If not, if you make a container that has |
|
I'm following maybe 20% of the layout discussion, but looking at those figures, we should probably allow a way for folks to specify nrows/ncols in the independent multivariate case. |






This PR relates to Bivariate and Multivariate Colormapping, specifically #30527 Bivariate and multivariate colorbar.
This draft includes only
BivarColorbar(notMultivarColorbar) but I want to make the PR now so that we can start discussing some of the questions.Note that the first axis is the y-axis and the second is the x-axis when the bivariate colormap is shown, following the implementation in #28454
@story645, @timhoffm, @ksunden
The main questions I have now are:
fig.bivar_colorbar(mappable)rather than branching insidefig.colorbar()bivar_colorbaris slightly awkward because it is not a bar, but more like a stamp. What do you think about this name?Colorbarclass has functions for customizing the ticks. To me the logic here is that a 1D colorbar does not have an x and y axis in the traditional sense, but a single axis, so it makes sense to have another layer of abstraction.BivarColorbaron the other hand has an x-axis and y-axis in the normal sense, and in light of this, how do we want users to customize the ticks?a. Not have functions on
BivarColorbarfor customizing ticks, and instead expect users to useBivarColorbar.ax.set_xticksetc.b. Make it possible to call the ax functions via the
BivarColorbar, i.e.BivarColorbar.set_xticksc. Make functions that reflect the fact that
BivarColorbarhas a first and second axis matching the axes in the input to the mappable, i.eBivarColorbar.set_ticks(axis_0, axis_1)I would really appreciate some feedback on 3. before I start making tests and typing :)
The placement of the bivariate colorbar uses nearly identical code to the normal colorbar. I assume this is what we want. [we will need more complicated placement for
MultivarColorbar]If you want to look at the code, I advise you to look at the commit 3cf2df9, rather than the PR, as this is built on top of #30597 – Multivar imshow.