Open ahuang11 opened 4 years ago
That code doesn't run for me on master with xarray 0.13 or 0.15; I get AttributeError: 'DataFrame' object has no attribute 'data_vars'
.
I think it works for me with latest master and xarray==0.15
Does this not "just" amount to the fact that bokeh does not permit creating legends/colorbars on its own, i.e. not attached to a particular axis?
Even so, you can still disable the colorbar on all but one plot, which works but is clunky:
import xarray as xr
import hvplot.xarray
ds = xr.tutorial.open_dataset('air_temperature').isel(time=[0, 4, 7, 8])
l = ds.hvplot('lon', 'lat', colorbar=False).layout()
l.values()[-1].opts(colorbar=True)
l.cols(2)
(I got the code to run locally by deleting my ~/.xarray_tutorial_data/air_temperature.nc file, which must have been cached from a long-ago xarray version; the current version xarray downloads works fine.)
It would be nice to have a less-clunky way to do this, and also to ensure that all plots actually do respect that single shared colorbar.
Yes, though it only gets really clunky if you want a colorbar that stretches over, let's say, the entire height of the subplot grid, instead of being attached to only one of the subplots. And I'm not sure it's even doable in current bokeh without creating a fifth panel and then hiding the axes.
To answer this question https://discourse.holoviz.org/t/shared-colorbar-for-all-heatmap-subplots/448/2
With Panel, it's possible with a lot of opts :)
import xarray as xr
import hvplot.xarray
import panel as pn
ds = xr.tutorial.open_dataset('air_temperature').isel(time=[0, 4, 7, 8])
l = ds.hvplot('lon', 'lat', colorbar=False).layout()
plots = l.cols(2)
shared_colorbar = l.values()[0].clone().opts(
colorbar=True,
frame_width=0,
frame_height=500,
show_frame=False,
shared_axes=False,
xaxis=None,
yaxis=None,
toolbar=None,
colorbar_opts={"width": 50, "height": 400, "title": "Temperature (°C)"},
)
# colorbar_opts: background_fill_alpha, background_fill_color, bar_line_alpha, bar_line_cap, bar_line_color, bar_line_dash, bar_line_dash_offset, bar_line_join, bar_line_width, border_line_alpha, border_line_cap, border_line_color, border_line_dash, border_line_dash_offset, border_line_join, border_line_width, color_mapper, context_menu, coordinates, display_high, display_low, elements, formatter, group, height, js_event_callbacks, js_property_callbacks, label_standoff, level, location, major_label_overrides, major_label_policy, major_label_text_align, major_label_text_alpha, major_label_text_baseline, major_label_text_color, major_label_text_font, major_label_text_font_size, major_label_text_font_style, major_label_text_line_height, major_label_text_outline_color, major_tick_in, major_tick_line_alpha, major_tick_line_cap, major_tick_line_color, major_tick_line_dash, major_tick_line_dash_offset, major_tick_line_join, major_tick_line_width, major_tick_out, margin, minor_tick_in, minor_tick_line_alpha, minor_tick_line_cap, minor_tick_line_color, minor_tick_line_dash, minor_tick_line_dash_offset, minor_tick_line_join, minor_tick_line_width, minor_tick_out, name, orientation, padding, propagate_hover, renderers, scale_alpha, subscribed_events, syncable, tags, ticker, title, title_standoff, title_text_align, title_text_alpha, title_text_baseline, title_text_color, title_text_font, title_text_font_size, title_text_font_style, title_text_line_height, title_text_outline_color, visible, width, x_range_name or y_range_name
pn.Row(plots, shared_colorbar, align="center")
To answer this question https://discourse.holoviz.org/t/shared-colorbar-for-all-heatmap-subplots/448/2
With Panel, it's possible with a lot of opts :)
import xarray as xr import hvplot.xarray import panel as pn ds = xr.tutorial.open_dataset('air_temperature').isel(time=[0, 4, 7, 8]) l = ds.hvplot('lon', 'lat', colorbar=False).layout() plots = l.cols(2) shared_colorbar = l.values()[0].clone().opts( colorbar=True, frame_width=0, frame_height=500, show_frame=False, shared_axes=False, xaxis=None, yaxis=None, toolbar=None, colorbar_opts={"width": 50, "height": 400, "title": "Temperature (°C)"}, ) # colorbar_opts: background_fill_alpha, background_fill_color, bar_line_alpha, bar_line_cap, bar_line_color, bar_line_dash, bar_line_dash_offset, bar_line_join, bar_line_width, border_line_alpha, border_line_cap, border_line_color, border_line_dash, border_line_dash_offset, border_line_join, border_line_width, color_mapper, context_menu, coordinates, display_high, display_low, elements, formatter, group, height, js_event_callbacks, js_property_callbacks, label_standoff, level, location, major_label_overrides, major_label_policy, major_label_text_align, major_label_text_alpha, major_label_text_baseline, major_label_text_color, major_label_text_font, major_label_text_font_size, major_label_text_font_style, major_label_text_line_height, major_label_text_outline_color, major_tick_in, major_tick_line_alpha, major_tick_line_cap, major_tick_line_color, major_tick_line_dash, major_tick_line_dash_offset, major_tick_line_join, major_tick_line_width, major_tick_out, margin, minor_tick_in, minor_tick_line_alpha, minor_tick_line_cap, minor_tick_line_color, minor_tick_line_dash, minor_tick_line_dash_offset, minor_tick_line_join, minor_tick_line_width, minor_tick_out, name, orientation, padding, propagate_hover, renderers, scale_alpha, subscribed_events, syncable, tags, ticker, title, title_standoff, title_text_align, title_text_alpha, title_text_baseline, title_text_color, title_text_font, title_text_font_size, title_text_font_style, title_text_line_height, title_text_outline_color, visible, width, x_range_name or y_range_name pn.Row(plots, shared_colorbar, align="center")
What if we have tiles? Is there a way to create a panel for the colorbar instead of copying from the layout?
What tiles? Can you share an example?
Sorry..
I meant
import xarray as xr
import hvplot.xarray
import panel as pn
ds = xr.tutorial.open_dataset('air_temperature').isel(time=[0, 4, 7, 8])
l = ds.hvplot('lon', 'lat', geo=True, tiles="EsriImagery", colorbar=False).layout()
plots = l.cols(2)
plots
creates
but when I do
shared_colorbar = l.values()[0].clone().opts(
colorbar=True,
frame_width=0,
frame_height=500,
show_frame=False,
shared_axes=False,
xaxis=None,
yaxis=None,
toolbar=None,
colorbar_opts={"width": 50, "height": 400, "title": "Temperature (°C)"},
)
pn.Row(plots, shared_colorbar, align="center")
it returns
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[4], line 1
----> 1 shared_colorbar = l.values()[0].clone().opts(
2 colorbar=True,
3 frame_width=0,
4 frame_height=500,
5 show_frame=False,
6 shared_axes=False,
7 xaxis=None,
8 yaxis=None,
9 toolbar=None,
10 colorbar_opts={"width": 50, "height": 400, "title": "Temperature (°C)"},
11 )
12 # colorbar_opts: background_fill_alpha, background_fill_color, bar_line_alpha, bar_line_cap, bar_line_color, bar_line_dash, bar_line_dash_offset, bar_line_join, bar_line_width, border_line_alpha, border_line_cap, border_line_color, border_line_dash, border_line_dash_offset, border_line_join, border_line_width, color_mapper, context_menu, coordinates, display_high, display_low, elements, formatter, group, height, js_event_callbacks, js_property_callbacks, label_standoff, level, location, major_label_overrides, major_label_policy, major_label_text_align, major_label_text_alpha, major_label_text_baseline, major_label_text_color, major_label_text_font, major_label_text_font_size, major_label_text_font_style, major_label_text_line_height, major_label_text_outline_color, major_tick_in, major_tick_line_alpha, major_tick_line_cap, major_tick_line_color, major_tick_line_dash, major_tick_line_dash_offset, major_tick_line_join, major_tick_line_width, major_tick_out, margin, minor_tick_in, minor_tick_line_alpha, minor_tick_line_cap, minor_tick_line_color, minor_tick_line_dash, minor_tick_line_dash_offset, minor_tick_line_join, minor_tick_line_width, minor_tick_out, name, orientation, padding, propagate_hover, renderers, scale_alpha, subscribed_events, syncable, tags, ticker, title, title_standoff, title_text_align, title_text_alpha, title_text_baseline, title_text_color, title_text_font, title_text_font_size, title_text_font_style, title_text_line_height, title_text_outline_color, visible, width, x_range_name or y_range_name
14 pn.Row(plots, shared_colorbar, align="center")
File ~/miniforge3/envs/coringa/lib/python3.9/site-packages/holoviews/core/accessors.py:35, in AccessorPipelineMeta.pipelined.<locals>.pipelined_call(*args, **kwargs)
31 inst = args[0]
33 if not hasattr(inst._obj, '_pipeline'):
34 # Wrapped object doesn't support the pipeline property
---> 35 return __call__(*args, **kwargs)
37 inst_pipeline = copy.copy(inst._obj. _pipeline)
38 in_method = inst._obj._in_method
File ~/miniforge3/envs/coringa/lib/python3.9/site-packages/holoviews/core/accessors.py:568, in Opts.__call__(self, *args, **kwargs)
562 msg = ("Calling the .opts method with options broken down by options "
563 "group (i.e. separate plot, style and norm groups) is deprecated. "
564 "Use the .options method converting to the simplified format "
565 "instead or use hv.opts.apply_groups for backward compatibility.")
566 param.main.param.warning(msg)
--> 568 return self._dispatch_opts( *args, **kwargs)
File ~/miniforge3/envs/coringa/lib/python3.9/site-packages/holoviews/core/accessors.py:572, in Opts._dispatch_opts(self, *args, **kwargs)
570 def _dispatch_opts(self, *args, **kwargs):
571 if self._mode is None:
--> 572 return self._base_opts(*args, **kwargs)
573 elif self._mode == 'holomap':
574 return self._holomap_opts(*args, **kwargs)
File ~/miniforge3/envs/coringa/lib/python3.9/site-packages/holoviews/core/accessors.py:651, in Opts._base_opts(self, *args, **kwargs)
648 return opts.apply_groups(self._obj, **dict(kwargs, **new_kwargs))
650 kwargs['clone'] = False if clone is None else clone
--> 651 return self._obj.options(*new_args, **kwargs)
File ~/miniforge3/envs/coringa/lib/python3.9/site-packages/holoviews/core/dimension.py:1276, in Dimensioned.options(self, clone, *args, **kwargs)
1274 expanded_backends = opts._expand_by_backend(options, backend)
1275 else:
-> 1276 expanded_backends = [(backend, opts._expand_options(options, backend))]
1278 obj = self
1279 for backend, expanded in expanded_backends:
File ~/miniforge3/envs/coringa/lib/python3.9/site-packages/holoviews/util/__init__.py:361, in opts._expand_options(cls, options, backend)
355 else:
356 valid_options = sorted({
357 keyword
358 for group_opts in obj_options.groups.values()
359 for keyword in group_opts.allowed_keywords
360 })
--> 361 cls._options_error(opt, objtype, backend, valid_options)
362 return expanded
File ~/miniforge3/envs/coringa/lib/python3.9/site-packages/holoviews/util/__init__.py:404, in opts._options_error(cls, opt, objtype, backend, valid_options)
401 return
403 if matches:
--> 404 raise ValueError('Unexpected option %r for %s type '
405 'across all extensions. Similar options '
406 'for current extension (%r) are: %s.' %
407 (opt, objtype, current_backend, matches))
408 else:
409 raise ValueError('Unexpected option %r for %s type '
410 'across all extensions. No similar options '
411 'found.' % (opt, objtype))
ValueError: Unexpected option 'colorbar' for Overlay type across all extensions. Similar options for current extension ('bokeh') are: ['bgcolor', 'toolbar'].
Maybe
shared_colorbar = l.values()[0].clone().opts(
"Image",
colorbar=True,
frame_width=0,
frame_height=500,
show_frame=False,
shared_axes=False,
xaxis=None,
yaxis=None,
toolbar=None,
colorbar_opts={"width": 50, "height": 400, "title": "Temperature (°C)"},
)
pn.Row(plots, shared_colorbar, align="center")
shared_colorbar = l.values()[0].clone().opts( "Image", colorbar=True, frame_width=0, frame_height=500, show_frame=False, shared_axes=False, xaxis=None, yaxis=None, toolbar=None, colorbar_opts={"width": 50, "height": 400, "title": "Temperature (°C)"}, )
pn.Row(plots, shared_colorbar, align="center")
It returned something like this
😓
import xarray as xr
import hvplot.xarray
import panel as pn
ds = xr.tutorial.open_dataset('air_temperature').isel(time=[0, 4, 7, 8])
l = ds.hvplot('lon', 'lat', geo=True, tiles="EsriImagery", colorbar=False).layout()
plots = l.cols(2)
shared_colorbar = plots.values()[0].get(1).clone().opts(
"Image",
colorbar=True,
frame_width=1,
frame_height=550,
show_frame=False,
shared_axes=False,
xaxis=None,
yaxis=None,
toolbar=None,
colorbar_opts={"width": 50, "height": 400, "title": "Temperature (°C)"},
)
pn.Row(plots, shared_colorbar, align="center", styles={"background-color": "white"})
How I approached it:
Print out the plots
Get the image
Tweak the opts, specifically width
Is there a way to set a unified colorbar for a layout?