I am trying to put together an app where user can:
- decide between colormap collections (for example between Matplotlib and Colorcet) using a Select widget
- based on the chosen collection pick a colormap using a second Select widget (for example, having chosen Matplotlib, pick cubehelix)
- have a Matplotlib plot of some data update to reflect the choice of colormap
The following is a “minimal” working example of my current code, up to where I get stuck (somewhere in the middle of part 3 above).
### preliminaries
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as clr
from matplotlib.figure import Figure
import matplotlib.cm as cm
import colorcet as cc
import panel as pn
pn.extension()
The part below is adapted from this example, already adapted from the User Guide.
Colormap collections:
### colormap collections
_colormaps = {
'matplotlib': sorted([
'viridis', 'plasma', 'inferno', 'magma', 'cividis',
'Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds',
'YlOrBr', 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu',
'GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn', 'YlGn',
'binary', 'gist_yarg', 'gist_gray', 'gray', 'bone', 'pink',
'spring', 'summer', 'autumn', 'winter', 'cool', 'Wistia',
'hot', 'afmhot', 'gist_heat', 'copper',
'PiYG', 'PRGn', 'BrBG', 'PuOr', 'RdGy', 'RdBu',
'RdYlBu', 'RdYlGn', 'Spectral', 'coolwarm', 'bwr', 'seismic',
'flag', 'prism', 'ocean', 'gist_earth', 'terrain', 'gist_stern',
'gnuplot', 'CMRmap', 'cubehelix', 'brg','gist_rainbow',
'rainbow', 'jet', 'nipy_spectral', 'gist_ncar'
'viridis_r', 'plasma_r', 'inferno_r', 'magma_r', 'cividis_r',
'Greys_r', 'Purples_r', 'Blues_r', 'Greens_r', 'Oranges_r', 'Reds_r',
'YlOrBr_r', 'YlOrRd_r', 'OrRd_r', 'PuRd_r', 'RdPu_r', 'BuPu_r',
'GnBu_r', 'PuBu_r', 'YlGnBu_r', 'PuBuGn_r', 'BuGn_r', 'YlGn_r',
'binary_r', 'gist_yarg_r', 'gist_gray_r', 'gray_r', 'bone_r', 'pink_r',
'spring_r', 'summer_r', 'autumn_r', 'winter_r', 'cool_r', 'Wistia_r',
'hot_r', 'afmhot_r', 'gist_heat_r', 'copper_r',
'PiYG_r', 'PRGn_r', 'BrBG_r', 'PuOr_r', 'RdGy_r', 'RdBu_r',
'RdYlBu_r', 'RdYlGn_r', 'Spectral_r', 'coolwarm_r', 'bwr_r', 'seismic_r',
'flag_r', 'prism_r', 'ocean_r', 'gist_earth_r', 'terrain_r', 'gist_stern_r',
'gnuplot_r', 'CMRmap_r', 'cubehelix_r', 'brg_r', 'gist_rainbow_r',
'rainbow_r', 'jet_r', 'nipy_spectral_r', 'gist_ncar_r'], key=str.casefold),
'colorcet': sorted([
'cet_bgy', 'cet_bkr', 'cet_bgyw', 'cet_bky', 'cet_kbc', 'cet_coolwarm',
'cet_blues', 'cet_gwv', 'cet_bmw', 'cet_bjy', 'cet_bmy', 'cet_bwy', 'cet_kgy',
'cet_cwr', 'cet_gray', 'cet_dimgray', 'cet_fire', 'kb', 'cet_kg', 'cet_kr',
'cet_colorwheel', 'cet_isolium', 'cet_rainbow', 'cet_bgy_r', 'cet_bkr_r',
'cet_bgyw_r', 'cet_bky_r', 'cet_kbc_r', 'cet_coolwarm_r', 'cet_blues_r',
'cet_gwv_r', 'cet_bmw_r', 'cet_bjy_r', 'cet_bmy_r', 'cet_bwy_r', 'cet_kgy_r',
'cet_cwr_r', 'cet_gray_r', 'cet_dimgray_r', 'cet_fire_r', 'kb_r', 'cet_kg_r',
'cet_kr_r', 'cet_colorwheel_r', 'cet_isolium_r', 'cet_rainbow_r'])
}
Setting up widgets:
### Colormap collection drop-down
collection = pn.widgets.Select(value='matplotlib',
options=['matplotlib', 'colorcet'])
### Colormap drop-down
colormap = pn.widgets.Select(
value=_colormaps[collection.value][0],
options=_colormaps[collection.value])
### depend decorator
@pn.depends(collection.param.value, watch=True)
def _update_colormaps(collection):
colormaps = _colormaps[collection]
colormap.options = colormaps
colormap.value = colormaps[0]
Here I lay out the two widgets in a row:
selection_widget = pn.Row(collection, colormap)
selection_widget
which, as expected, works:
I then wrote this plot function, which works if I pass colormap.value
(or even selection_widget[1].value
) and uses as told the last selected colormap:
But things get really confusing as I want the plot to update live when the colormap is further changed. My first thought was to also wrap the plot
function in a decorator, something like this:
Which does not do anything.
First question:
- if this is a viable solution, what am I doing wrong?
My second thought was to link the colormap
Select widget to the plot. So I went back to the Scipy 2019 tutorial (video here) and started plating with it to see if I at least could get a string pane to update when the colormap is changed. That does not seem to work either.
I am reasonably sure it has to do with what is declared as value
in the link (which seems to not always be clear, at least according to James i nthe video). So it looks like I am stuck.
I have two further questions:
2. Any suggestions (or pointers to existing examples) as to how to move forward with this specific case.
3. Is there any documentation on how to even look for what might be the appropriate “object” for links?
Final question / comment more general:
4. For someone who has a decent experience with functional programming and lots of visualization, but very green with other areas of Python, like making apps, I find it difficult to gage ahead of time (that is without getting oneself in a corner) what might be the right strategy, even with as good documentation ( I refer to this and this). Is it better to start simple and see where one get, or perhaps always aim to go for using param
and get really good at it?
Thank you, all help appreciated.