Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement multi-yaxis support #5621

Merged
merged 64 commits into from
Jul 21, 2023
Merged
Show file tree
Hide file tree
Changes from 57 commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
c55f97b
Initial multi-axes implementation
philippjfr Feb 10, 2023
533f5e6
Remove multi_x handling for now
philippjfr Feb 10, 2023
45d3999
Start handling invert_axes
philippjfr Feb 10, 2023
d7a0d98
Applied suggested edit
jlstevens Feb 10, 2023
d84b64e
Correctly update extra_ranges on inverted axes
philippjfr Feb 10, 2023
f5cf609
Further fix for invert_axes range handling
philippjfr Feb 10, 2023
7c6ab2c
Fixed signature of get_extents in GenericElementPlot base class
jlstevens Feb 20, 2023
d799d77
Fixed flakes
jlstevens Jun 14, 2023
b143891
Further flake fixes
jlstevens Jun 14, 2023
bba1265
More flake fixes
jlstevens Jun 14, 2023
c0eefa7
Fixed get_extents signatures
jlstevens Jun 27, 2023
528952c
Fixed clashing unit test names
jlstevens Jun 27, 2023
493795d
Fixes for failing unit tests
jlstevens Jun 27, 2023
8f70867
Removed stray comment
jlstevens Jun 27, 2023
0191d2a
No longer applying invert_axes swap in _init_plot
jlstevens Jun 27, 2023
2230808
Reimplemented shared axis ranges
jlstevens Jun 30, 2023
1bf4600
Work in progress fixes for remaining unit test failures
jlstevens Jun 30, 2023
efa01e6
Fix for cftime_types
jlstevens Jun 30, 2023
08e2a1c
Fix multi distribution extents
philippjfr Jun 30, 2023
f8c727e
Ensure axis_dims are inverted correctly
philippjfr Jun 30, 2023
eee5d57
Allowing autorange parameter to be set to None
jlstevens Jul 5, 2023
3ceae86
Implemented autoranging support for multi axes
jlstevens Jul 5, 2023
14d9e4d
Using zoom_together='none' in wheel zoom by default for bokeh>=3.2
jlstevens Jul 5, 2023
07da43b
Fix invert_axes when not z-dim is defined
philippjfr Jul 5, 2023
a2cf788
Fix extra range lookup when bokeh transform is applied
philippjfr Jul 5, 2023
7ac4d08
Fix import
philippjfr Jul 5, 2023
0c13deb
Simplistic attempt to fix Field import
jlstevens Jul 5, 2023
91f08da
Fixed concatenation issue
jlstevens Jul 5, 2023
171c3c4
More fixes
jlstevens Jul 5, 2023
3004d7b
Using property_to_dict utility
jlstevens Jul 6, 2023
8634d4f
Fix for location of main ranges
jlstevens Jul 6, 2023
e3bb5d4
Renamed confusing extra_range_tags to range_tags_extras
jlstevens Jul 6, 2023
49504ef
Implemented multi-y axis sharing
jlstevens Jul 6, 2023
91b1334
Renamed x and y key in ._shared to avoid dimension name clashes
jlstevens Jul 6, 2023
e8bbff7
Handled log multi-axes in _update_ranges
jlstevens Jul 6, 2023
c1aca40
Added per-axis data autoranging
jlstevens Jul 6, 2023
20d256f
Respecting ylim range on a per-axis basis
jlstevens Jul 7, 2023
28e73e6
Handling None for ylim
jlstevens Jul 7, 2023
88e09a4
Added guard against unhashables
jlstevens Jul 7, 2023
9bfc3de
Cleaned up range_tags_extras by promoting to a dictionary/object
jlstevens Jul 7, 2023
dd4d24e
Readded 'invert_yaxis' to propagated options
jlstevens Jul 7, 2023
d25ed90
Disabling appropriate propagated options when multi_y=True
jlstevens Jul 8, 2023
65995ba
Added per axis support for invert_yaxis
jlstevens Jul 9, 2023
a1e8072
Added initial set of 16 twin axis unit tests
jlstevens Jul 10, 2023
db6b091
Fix to avoid applying global ylim when using multi_y=True
jlstevens Jul 14, 2023
3e14896
Simplified overlay extent fix
jlstevens Jul 14, 2023
79e7eea
Handle current lack of multi_y parameter for non-Bokeh backends
jlstevens Jul 14, 2023
c2afa4b
Added four xfail tests for label position issue
jlstevens Jul 20, 2023
54d4213
Added twin axis section to customizing plots user guide
jlstevens Jul 20, 2023
db0a21c
Broken pre-commit hook
jlstevens Jul 20, 2023
f80e127
Added clarification about streams to docs
jlstevens Jul 21, 2023
ce0d089
Temporary pin of dask
jlstevens Jul 21, 2023
55e6d83
Small refactors
philippjfr Jul 21, 2023
70ca492
Small fixes
philippjfr Jul 21, 2023
ca2052e
Clean up extra axis setup
philippjfr Jul 21, 2023
6ef173c
Ensure extra_x_scales are set
philippjfr Jul 21, 2023
c79e287
Fix lint
philippjfr Jul 21, 2023
7cd3051
Apply suggestions from code review
philippjfr Jul 21, 2023
938eb9e
Move utils
philippjfr Jul 21, 2023
eae0cd2
Fix zoom tool handling
philippjfr Jul 21, 2023
41d09c1
Update holoviews/plotting/bokeh/element.py
philippjfr Jul 21, 2023
a9a2b80
Merge branch 'main' into multi_axes
philippjfr Jul 21, 2023
55d2be3
Removed backwards-compatibility example from docs section
jlstevens Jul 21, 2023
e319a5a
Removed temporary dask pin
jlstevens Jul 21, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 77 additions & 2 deletions examples/user_guide/Customizing_Plots.ipynb
jlstevens marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@
" - [Inverting axes](#inverting-axes): Flipping the x-/y-axes and inverting an axis\n",
" - [Axis labels](#axis-labels): Setting axis labels using dimensions and options\n",
" - [Axis ranges](#axis-ranges): Controlling axes ranges using dimensions, padding and options\n",
" - [Axis ticks](#axis-ticks): Controlling axis tick locations, labels and formatting"
" - [Axis ticks](#axis-ticks): Controlling axis tick locations, labels and formatting\n",
" - [Twin axes](#twin-axes): Enabling twin axes"
]
},
{
Expand Down Expand Up @@ -689,6 +690,80 @@
"source": [
"bars.opts(xrotation=45)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Twin axes\n",
"*(Available in HoloViews > 1.17)*\n",
"\n",
"HoloViews now supports displaying overlays containing two different value dimensions as twin axes for chart elements. To maintain backwards compatibility, this feature is only enabled by setting the `multi_y=True` option on the overlay:\n",
"\n",
"To illustrate, here is an overlay containing three curves with two value dimensions ('A' and 'B'). The following shows the default, backwards compatible behavior:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"overlay = hv.Curve([1, 2, 3], vdims=['A']) * hv.Curve([2, 3, 4], vdims=['A']) * hv.Curve([3, 2, 1], vdims=['B'])\n",
"overlay"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Additional value dimensions do map to additional axes but be aware that support of multi axes beyond twin axes is currently considered experimental.\n",
"\n",
"#### Setting `multi_y=True`\n",
"\n",
"We can now enable twin axes by setting `multi_y=True` on the overlay:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"overlay.opts(multi_y=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The first value dimension is mapped to the left-hand axis and the second value dimension maps to the right axis. Note that the two axes are individually zoomable by hovering over them and using the Bokeh wheelzoom tool.\n",
"\n",
"\n",
"#### Supported `multi_y` options\n",
"\n",
"When `multi_y` is enabled, you can set individual axis options on the elements of the overlay.\n",
"\n",
"In this example, the left axis uses the default options while the right axis is an inverted, autoranged, log axis with a set `ylim`:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"(hv.Curve([1, 2, 3], vdims=['A']) * hv.Curve([2, 3, 4], vdims=['B']).opts(autorange='y', invert_yaxis=True, logy=True, ylim=(1,10))).opts(multi_y=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Supported options for customizing individual axes are `apply_ranges`, `autorange='y'`, `invert_yaxis`, `logy` and `ylim`.\n",
"\n",
"Note that as of HoloViews 1.17.0, `multi_y` does not have streaming plot support and that linked streams are not yet aware of additional y-axes."
]
}
],
"metadata": {
Expand All @@ -698,5 +773,5 @@
}
},
"nbformat": 4,
"nbformat_minor": 2
"nbformat_minor": 4
}
8 changes: 4 additions & 4 deletions holoviews/plotting/bokeh/annotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def get_batched_data(self, element, ranges=None):
data[k].extend(eld)
return data, elmapping, style

def get_extents(self, element, ranges=None, range_type='combined'):
def get_extents(self, element, ranges=None, range_type='combined', **kwargs):
return None, None, None, None


Expand Down Expand Up @@ -161,7 +161,7 @@ def _init_glyph(self, plot, mapping, properties):
plot.renderers.append(box)
return None, box

def get_extents(self, element, ranges=None, range_type='combined'):
def get_extents(self, element, ranges=None, range_type='combined', **kwargs):
loc = element.data
if isinstance(element, VLine):
dim = 'x'
Expand Down Expand Up @@ -241,7 +241,7 @@ def _init_glyph(self, plot, mapping, properties):
plot.add_layout(slope)
return None, slope

def get_extents(self, element, ranges=None, range_type='combined'):
def get_extents(self, element, ranges=None, range_type='combined', **kwargs):
return None, None, None, None


Expand Down Expand Up @@ -366,7 +366,7 @@ def _init_glyph(self, plot, mapping, properties, key):
plot.renderers.append(renderer)
return renderer, glyph

def get_extents(self, element, ranges=None, range_type='combined'):
def get_extents(self, element, ranges=None, range_type='combined', **kwargs):
return None, None, None, None


Expand Down
14 changes: 1 addition & 13 deletions holoviews/plotting/bokeh/chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ def get_data(self, element, ranges, style):
self._get_hover_data(data, element)
return (data, mapping, style)

def get_extents(self, element, ranges, range_type='combined'):
def get_extents(self, element, ranges, range_type='combined', **kwargs):
ydim = element.get_dimension(1)
s0, s1 = ranges[ydim.name]['soft']
s0 = min(s0, 0) if isfinite(s0) else 0
Expand Down Expand Up @@ -693,11 +693,6 @@ class SpikesPlot(SpikesMixin, ColorbarPlot):
_nonvectorized_styles = base_properties + ['cmap']
_plot_methods = dict(single='segment')

def _get_axis_dims(self, element):
if 'spike_length' in self.lookup_options(element, 'plot').options:
return [element.dimensions()[0], None, None]
return super()._get_axis_dims(element)

def get_data(self, element, ranges, style):
dims = element.dimensions()

Expand Down Expand Up @@ -815,13 +810,6 @@ def _axis_properties(self, axis, key, plot, dimension=None,
props['group_text_baseline'] = 'middle'
return props

def _get_axis_dims(self, element):
if element.ndims > 1 and not (self.stacked or not self.multi_level):
xdims = element.kdims
else:
xdims = element.kdims[0]
return (xdims, element.vdims[0])

def _get_factors(self, element, ranges):
xvals, gvals = self._get_coords(element, ranges)
if gvals is not None:
Expand Down
Loading