diff --git a/examples/user_guide/01-Annotating_Data.ipynb b/examples/user_guide/01-Annotating_Data.ipynb index 21892cfcb2..11a55bec84 100644 --- a/examples/user_guide/01-Annotating_Data.ipynb +++ b/examples/user_guide/01-Annotating_Data.ipynb @@ -137,12 +137,12 @@ "source": [ "### Dimension parameters\n", "\n", - "``Dimensions`` are not just names, they are rich objects with numerous parameters that can be used to describe the space in which the data resides. Only two of these are considered *core* parameters that uniquely identify the dimension object; the rest are auxiliary metadata. The most important parameters are:\n", + "``Dimensions`` are not just names, they are rich objects with numerous parameters that can be used to describe the space in which the data resides. Only two of these are considered *core* parameters the dimension object; the rest are auxiliary metadata. The most important parameters are:\n", "\n", "
\n", "
\n", - "
name
(core) A concise name for the dimension, which for convenient usage as a keyword argument should usually be a legal Python identifier.
\n", - "
label
(core) A optional longer description of the dimension, which is convenient if you want the displayed label to contain arbitrary spaces, symbols, or unicode.
\n", + "
name
(core) A concise name for the dimension, which for convenient usage as a keyword argument should usually be a legal Python identifier. The name also corresponds to the name of the variable in the underlying data, e.g. when providing a dictionary of columns or a DataFrame.
\n", + "
label
(core) A optional longer description of the dimension, which is convenient if you want the displayed label to contain arbitrary spaces, symbols, or unicode. By default this is identical to the name but if provided this value uniquely identifies the dimension.
\n", "
range
The minimum and maximum allowable values for the dimension, for error checking and generating widgets when needed.
\n", "
soft_range
Suggested minimum and maximum values within the allowed range, used to specify a useful portion of the range for widgets and animations.
\n", "
step
Suggested interval for sampling a continuous range, if needed for a widget or animation.
\n", @@ -167,7 +167,7 @@ " ('height','Height above sea level'))\n", "\n", "distance = hv.Dimension('distance', label='Horizontal distance', unit='m')\n", - "height = hv.Dimension(('height','Height above sea level'), unit='m')\n", + "height = hv.Dimension(('height', 'Height above sea level'), unit='m')\n", "with_unit = hv.Curve((xs, ys), distance, height)\n", "\n", "# (using + to compose elements is described in the next guide)\n", @@ -254,5 +254,5 @@ } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } diff --git a/examples/user_guide/08-Tabular_Datasets.ipynb b/examples/user_guide/08-Tabular_Datasets.ipynb index 2ee138585f..87aa7b63e4 100644 --- a/examples/user_guide/08-Tabular_Datasets.ipynb +++ b/examples/user_guide/08-Tabular_Datasets.ipynb @@ -264,6 +264,32 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "This is particularly useful when you're working with wide data where you have one column (or index) representing the shared x-values and multiple columns measuring some quantity, e.g. a set of stocks indexed by date. By providing a name and label for the value dimension of our `Curve` we can correctly label the dimension as the stock `Price` while referring to the underlying equity by name:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "stocks = pd.DataFrame({\n", + " 'AAPL': np.random.randn(100).cumsum() + 20,\n", + " 'MSFT': np.random.randn(100).cumsum() + 25,\n", + " 'IBM': np.random.randn(100).cumsum() + 10,\n", + "}, index=pd.date_range('2024-01-01', '2024-04-09'))\n", + "\n", + "hv.NdOverlay(\n", + " {col: hv.Curve(stocks, 'index', (col, 'Price')) for col in stocks.columns}, 'Ticker'\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Each Element merely provides a view into the underlying data.\n", + "\n", "For columnar data, this approach is much more efficient than creating copies of the data for each Element, and allows for some advanced features like linked brushing in the [Bokeh backend](./Plotting_with_Bokeh.ipynb)." ] }, @@ -591,5 +617,5 @@ } }, "nbformat": 4, - "nbformat_minor": 1 + "nbformat_minor": 4 } diff --git a/holoviews/core/dimension.py b/holoviews/core/dimension.py index 3da9ac4898..56b348a637 100644 --- a/holoviews/core/dimension.py +++ b/holoviews/core/dimension.py @@ -347,7 +347,7 @@ def __eq__(self, other): "Implements equals operator including sanitized comparison." if isinstance(other, Dimension): - return self.spec == other.spec + return self.label == other.label # For comparison to strings. Name may be sanitized. return other in [self.name, self.label, util.dimension_sanitizer(self.name)] diff --git a/holoviews/core/pprint.py b/holoviews/core/pprint.py index 958aa3882c..f3b070d3ee 100644 --- a/holoviews/core/pprint.py +++ b/holoviews/core/pprint.py @@ -355,7 +355,7 @@ def element_info(cls_or_slf, node, siblings, level, value_dims): if len(node.kdims) >= 1: info += cls_or_slf.tab + f"[{','.join(d.name for d in node.kdims)}]" if value_dims and len(node.vdims) >= 1: - info += cls_or_slf.tab + f"({','.join(d.name for d in node.vdims)})" + info += cls_or_slf.tab + f"({','.join(d.label for d in node.vdims)})" return level, [(level, info)] @bothmethod diff --git a/holoviews/plotting/bokeh/chart.py b/holoviews/plotting/bokeh/chart.py index fdd7cd97a7..9bb55b1e7f 100644 --- a/holoviews/plotting/bokeh/chart.py +++ b/holoviews/plotting/bokeh/chart.py @@ -435,10 +435,10 @@ def get_data(self, element, ranges, style): def get_extents(self, element, ranges, range_type='combined', **kwargs): ydim = element.get_dimension(1) - s0, s1 = ranges[ydim.name]['soft'] + s0, s1 = ranges[ydim.label]['soft'] s0 = min(s0, 0) if isfinite(s0) else 0 s1 = max(s1, 0) if isfinite(s1) else 0 - ranges[ydim.name]['soft'] = (s0, s1) + ranges[ydim.label]['soft'] = (s0, s1) return super().get_extents(element, ranges, range_type) @@ -876,8 +876,8 @@ def get_data(self, element, ranges, style): stack_dim = element.get_dimension(1) if stack_dim.values: stack_order = stack_dim.values - elif stack_dim in ranges and ranges[stack_dim.name].get('factors'): - stack_order = ranges[stack_dim]['factors'] + elif stack_dim in ranges and ranges[stack_dim.label].get('factors'): + stack_order = ranges[stack_dim.label]['factors'] else: stack_order = element.dimension_values(1, False) stack_order = list(stack_order) @@ -892,7 +892,7 @@ def get_data(self, element, ranges, style): color_index = (group_dim or stack_dim) if no_cidx else self.color_index color_dim = element.get_dimension(color_index) if color_dim: - self.color_index = color_dim.name + self.color_index = color_dim.label # Define style information width = style.get('bar_width', style.get('width', 1)) @@ -923,7 +923,7 @@ def get_data(self, element, ranges, style): datatype=['dataframe', 'dictionary']) width = abs(width) - y0, y1 = ranges.get(ydim.name, {'combined': (None, None)})['combined'] + y0, y1 = ranges.get(ydim.label, {'combined': (None, None)})['combined'] if self.logy: bottom = (ydim.range[0] or (0.01 if y1 > 0.01 else 10**(np.log10(y1)-2))) else: diff --git a/holoviews/plotting/bokeh/element.py b/holoviews/plotting/bokeh/element.py index 48138bfa64..770035c639 100644 --- a/holoviews/plotting/bokeh/element.py +++ b/holoviews/plotting/bokeh/element.py @@ -651,7 +651,7 @@ def _axis_props(self, plots, subplots, element, ranges, pos, *, dim=None, dims = [dim] v0, v1 = dim.range axis_label = str(dim) - specs = ((dim.name, dim.label, dim.unit),) + specs = ((dim.label, dim.unit),) # For y-axes check if we explicitly passed in a dimension. # This is used by certain plot types to create an axis from # a synthetic dimension and exclusively supported for y-axes. @@ -662,7 +662,7 @@ def _axis_props(self, plots, subplots, element, ranges, pos, *, dim=None, for elrange in ranges.values() ]) axis_label = str(dim) - specs = ((dim.name, dim.label, dim.unit),) + specs = ((dim.label, dim.unit),) else: try: l, b, r, t = self.get_extents(range_el, ranges, dimension=dim) @@ -694,7 +694,7 @@ def _axis_props(self, plots, subplots, element, ranges, pos, *, dim=None, if dims: if not isinstance(dims, list): dims = [dims] - specs = tuple((d.name, d.label, d.unit) for d in dims) + specs = tuple((d.label, d.unit) for d in dims) else: specs = None @@ -711,7 +711,7 @@ def _axis_props(self, plots, subplots, element, ranges, pos, *, dim=None, categorical = any(self.traverse(lambda plot: plot._categorical)) if self.subcoordinate_y: categorical = False - elif dims is not None and any(dim.name in ranges and 'factors' in ranges[dim.name] for dim in dims): + elif dims is not None and any(dim.label in ranges and 'factors' in ranges[dim.label] for dim in dims): categorical = True else: categorical = any(isinstance(v, (str, bytes)) for v in (v0, v1)) @@ -1601,8 +1601,8 @@ def get_aspect(self, xspan, yspan): def _get_dimension_factors(self, element, ranges, dimension): if dimension.values: values = dimension.values - elif 'factors' in ranges.get(dimension.name, {}): - values = ranges[dimension.name]['factors'] + elif 'factors' in ranges.get(dimension.label, {}): + values = ranges[dimension.label]['factors'] else: values = element.dimension_values(dimension, False) values = np.asarray(values) diff --git a/holoviews/plotting/bokeh/graphs.py b/holoviews/plotting/bokeh/graphs.py index c9201d6560..5c95d6d6bf 100644 --- a/holoviews/plotting/bokeh/graphs.py +++ b/holoviews/plotting/bokeh/graphs.py @@ -164,8 +164,8 @@ def _get_edge_paths(self, element, ranges): "Expected %d, found %d paths." % (len(element), len(edges))) elif self.directed: xdim, ydim = element.nodes.kdims[:2] - x_range = ranges[xdim.name]['combined'] - y_range = ranges[ydim.name]['combined'] + x_range = ranges[xdim.label]['combined'] + y_range = ranges[ydim.label]['combined'] arrow_len = np.hypot(y_range[1]-y_range[0], x_range[1]-x_range[0])*self.arrowhead_length arrows = get_directed_graph_paths(element, arrow_len) path_data['xs'] = [arr[:, 0] for arr in arrows] diff --git a/holoviews/plotting/bokeh/hex_tiles.py b/holoviews/plotting/bokeh/hex_tiles.py index adcb473c25..1538f9686d 100644 --- a/holoviews/plotting/bokeh/hex_tiles.py +++ b/holoviews/plotting/bokeh/hex_tiles.py @@ -150,16 +150,16 @@ class HexTilesPlot(ColorbarPlot): def get_extents(self, element, ranges, range_type='combined', **kwargs): xdim, ydim = element.kdims[:2] - ranges[xdim.name]['data'] = xdim.range - ranges[ydim.name]['data'] = ydim.range + ranges[xdim.label]['data'] = xdim.range + ranges[ydim.label]['data'] = ydim.range xd = element.cdims.get(xdim.name) - if xd and xdim.name in ranges: - ranges[xdim.name]['hard'] = xd.range - ranges[xdim.name]['soft'] = max_range([xd.soft_range, ranges[xdim.name]['soft']]) + if xd and xdim.label in ranges: + ranges[xdim.label]['hard'] = xd.range + ranges[xdim.label]['soft'] = max_range([xd.soft_range, ranges[xdim.label]['soft']]) yd = element.cdims.get(ydim.name) - if yd and ydim.name in ranges: - ranges[ydim.name]['hard'] = yd.range - ranges[ydim.name]['hard'] = max_range([yd.soft_range, ranges[ydim.name]['soft']]) + if yd and ydim.label in ranges: + ranges[ydim.label]['hard'] = yd.range + ranges[ydim.label]['hard'] = max_range([yd.soft_range, ranges[ydim.label]['soft']]) return super().get_extents(element, ranges, range_type) def _hover_opts(self, element): diff --git a/holoviews/plotting/bokeh/path.py b/holoviews/plotting/bokeh/path.py index d331d3dc7b..74c7a8c68f 100644 --- a/holoviews/plotting/bokeh/path.py +++ b/holoviews/plotting/bokeh/path.py @@ -268,8 +268,8 @@ def get_data(self, element, ranges, style): data[dim_name] = values factors = None - if cdim.name in ranges and 'factors' in ranges[cdim.name]: - factors = ranges[cdim.name]['factors'] + if cdim.label in ranges and 'factors' in ranges[cdim.label]: + factors = ranges[cdim.label]['factors'] elif values.dtype.kind in 'SUO' and len(values): if isinstance(values[0], np.ndarray): values = np.concatenate(values) diff --git a/holoviews/plotting/bokeh/sankey.py b/holoviews/plotting/bokeh/sankey.py index 7a0d76ac53..8115ca1a21 100644 --- a/holoviews/plotting/bokeh/sankey.py +++ b/holoviews/plotting/bokeh/sankey.py @@ -233,8 +233,8 @@ def get_extents(self, element, ranges, range_type='combined', **kwargs): return element.nodes.extents xdim, ydim = element.nodes.kdims[:2] xpad = .05 if self.label_index is None else 0.25 - x0, x1 = ranges[xdim.name][range_type] - y0, y1 = ranges[ydim.name][range_type] + x0, x1 = ranges[xdim.label][range_type] + y0, y1 = ranges[ydim.label][range_type] xdiff = (x1-x0) ydiff = (y1-y0) diff --git a/holoviews/plotting/bokeh/stats.py b/holoviews/plotting/bokeh/stats.py index cc2adcccbb..25d31d4f92 100644 --- a/holoviews/plotting/bokeh/stats.py +++ b/holoviews/plotting/bokeh/stats.py @@ -509,7 +509,7 @@ def get_data(self, element, ranges, style): groups = dict([((element.label,), element)]) if split_dim: - split_name = split_dim.dimension.name + split_name = split_dim.dimension.label if split_name in ranges and not split_dim.ops and 'factors' in ranges[split_name]: split_cats = ranges[split_name].get('factors') elif split_dim: diff --git a/holoviews/plotting/mixins.py b/holoviews/plotting/mixins.py index db3d2d75aa..524308a1c7 100644 --- a/holoviews/plotting/mixins.py +++ b/holoviews/plotting/mixins.py @@ -16,8 +16,8 @@ def get_extents(self, element, ranges, range_type='combined', **kwargs): kdims = element.kdims # loop over start and end points of segments # simultaneously in each dimension - for kdim0, kdim1 in zip([kdims[i].name for i in range(2)], - [kdims[i].name for i in range(2,4)]): + for kdim0, kdim1 in zip([kdims[i].label for i in range(2)], + [kdims[i].label for i in range(2,4)]): new_range = {} for kdim in [kdim0, kdim1]: # for good measure, update ranges for both start and end kdim @@ -85,10 +85,10 @@ def get_extents(self, element, ranges, range_type='combined', **kwargs): opts = self.lookup_options(element, 'plot').options if len(element.dimensions()) > 1 and 'spike_length' not in opts: ydim = element.get_dimension(1) - s0, s1 = ranges[ydim.name]['soft'] + s0, s1 = ranges[ydim.label]['soft'] s0 = min(s0, 0) if util.isfinite(s0) else 0 s1 = max(s1, 0) if util.isfinite(s1) else 0 - ranges[ydim.name]['soft'] = (s0, s1) + ranges[ydim.label]['soft'] = (s0, s1) proxy_dim = None if 'spike_length' in opts or len(element.dimensions()) == 1: proxy_dim = Dimension('proxy_dim') @@ -118,12 +118,12 @@ class AreaMixin: def get_extents(self, element, ranges, range_type='combined', **kwargs): vdims = element.vdims[:2] - vdim = vdims[0].name + vdim = vdims[0].label if len(vdims) > 1: new_range = {} for r in ranges[vdim]: if r != 'values': - new_range[r] = util.max_range([ranges[vd.name][r] for vd in vdims]) + new_range[r] = util.max_range([ranges[vd.label][r] for vd in vdims]) ranges[vdim] = new_range else: s0, s1 = ranges[vdim]['soft'] @@ -153,9 +153,9 @@ def get_extents(self, element, ranges, range_type='combined', **kwargs): element = Bars(overlay.table(), kdims=element.kdims+overlay.kdims, vdims=element.vdims) for kd in overlay.kdims: - ranges[kd.name]['combined'] = overlay.range(kd) + ranges[kd.label]['combined'] = overlay.range(kd) - vdim = element.vdims[0].name + vdim = element.vdims[0].label s0, s1 = ranges[vdim]['soft'] s0 = min(s0, 0) if util.isfinite(s0) else 0 s1 = max(s1, 0) if util.isfinite(s1) else 0 @@ -209,15 +209,15 @@ def _get_coords(self, element, ranges, as_string=True): else: if gdim.values: gvals = gdim.values - elif ranges.get(gdim.name, {}).get('factors') is not None: - gvals = ranges[gdim.name]['factors'] + elif ranges.get(gdim.label, {}).get('factors') is not None: + gvals = ranges[gdim.label]['factors'] else: gvals = element.dimension_values(gdim, False) gvals = np.asarray(gvals) if xvals: pass - elif ranges.get(xdim.name, {}).get('factors') is not None: - xvals = ranges[xdim.name]['factors'] + elif ranges.get(xdim.label, {}).get('factors') is not None: + xvals = ranges[xdim.label]['factors'] else: xvals = element.dimension_values(0, False) xvals = np.asarray(xvals) @@ -229,8 +229,8 @@ def _get_coords(self, element, ranges, as_string=True): else: if xvals: pass - elif ranges.get(xdim.name, {}).get('factors') is not None: - xvals = ranges[xdim.name]['factors'] + elif ranges.get(xdim.label, {}).get('factors') is not None: + xvals = ranges[xdim.label]['factors'] else: xvals = element.dimension_values(0, False) xvals = np.asarray(xvals) diff --git a/holoviews/plotting/mpl/chart.py b/holoviews/plotting/mpl/chart.py index 05dba48efd..879fd260e6 100644 --- a/holoviews/plotting/mpl/chart.py +++ b/holoviews/plotting/mpl/chart.py @@ -6,7 +6,7 @@ from matplotlib.dates import DateFormatter, date2num from packaging.version import Version -from ...core.dimension import Dimension, dimension_name +from ...core.dimension import Dimension from ...core.options import Store, abbreviated_exception from ...core.util import ( dt64_to_dt, @@ -23,7 +23,7 @@ from ...util.transform import dim from ..mixins import AreaMixin, BarsMixin, SpikesMixin from ..plot import PlotSelector -from ..util import compute_sizes, get_min_distance, get_sideplot_ranges +from ..util import compute_sizes, dim_range_key, get_min_distance, get_sideplot_ranges from .element import ColorbarPlot, ElementPlot, LegendPlot from .path import PathPlot from .plot import AdjoinedPlot, mpl_rc_context @@ -396,10 +396,10 @@ def _compute_ticks(self, element, edges, widths, lims): def get_extents(self, element, ranges, range_type='combined', **kwargs): ydim = element.get_dimension(1) - s0, s1 = ranges[ydim.name]['soft'] + s0, s1 = ranges[ydim.label]['soft'] s0 = min(s0, 0) if isfinite(s0) else 0 s1 = max(s1, 0) if isfinite(s1) else 0 - ranges[ydim.name]['soft'] = (s0, s1) + ranges[ydim.label]['soft'] = (s0, s1) return super().get_extents(element, ranges, range_type) def _process_axsettings(self, hist, lims, ticks): @@ -644,11 +644,11 @@ def update_handles(self, key, axis, element, ranges, style): paths = self.handles['artist'] (xs, ys), style, _ = self.get_data(element, ranges, style) xdim, ydim = element.dimensions()[:2] - if 'factors' in ranges.get(xdim.name, {}): - factors = list(ranges[xdim.name]['factors']) + if 'factors' in ranges.get(xdim.label, {}): + factors = list(ranges[xdim.label]['factors']) xs = [factors.index(x) for x in xs if x in factors] - if 'factors' in ranges.get(ydim.name, {}): - factors = list(ranges[ydim.name]['factors']) + if 'factors' in ranges.get(ydim.label, {}): + factors = list(ranges[ydim.label]['factors']) ys = [factors.index(y) for y in ys if y in factors] paths.set_offsets(np.column_stack([xs, ys])) if 's' in style: @@ -752,7 +752,7 @@ def _get_magnitudes(self, element, style, ranges): magnitudes = mag_dim.apply(element, flat=True) else: magnitudes = element.dimension_values(mag_dim) - _, max_magnitude = ranges[dimension_name(mag_dim)]['combined'] + _, max_magnitude = ranges[dim_range_key(mag_dim)]['combined'] if self.normalize_lengths and max_magnitude != 0: magnitudes = magnitudes / max_magnitude else: @@ -873,8 +873,8 @@ def _get_values(self, element, ranges): dimensions = [kdims[0], None, stack_dim] if stack_dim.values: stack_order = stack_dim.values - elif stack_dim in ranges and ranges[stack_dim.name].get('factors'): - stack_order = ranges[stack_dim]['factors'] + elif stack_dim in ranges and ranges[stack_dim.label].get('factors'): + stack_order = ranges[stack_dim.label]['factors'] else: stack_order = element.dimension_values(1, False) stack_order = list(stack_order) @@ -1042,7 +1042,7 @@ def _create_bars(self, axis, element, ranges, style): legend_opts.update(**leg_spec) axis.legend(title=title, **legend_opts) - x_range = ranges[gdim.name]["data"] + x_range = ranges[gdim.label]["data"] if continuous and not is_dt: if style.get('align', 'center') == 'center': left_multiplier = 0.5 @@ -1050,7 +1050,7 @@ def _create_bars(self, axis, element, ranges, style): else: left_multiplier = 0 right_multiplier = 1 - ranges[gdim.name]["data"] = ( + ranges[gdim.label]["data"] = ( x_range[0] - width * left_multiplier, x_range[1] + width * right_multiplier ) diff --git a/holoviews/plotting/mpl/graphs.py b/holoviews/plotting/mpl/graphs.py index c16a800eb0..6279018aef 100644 --- a/holoviews/plotting/mpl/graphs.py +++ b/holoviews/plotting/mpl/graphs.py @@ -131,8 +131,8 @@ def get_data(self, element, ranges, style): if self.directed: xdim, ydim = element.nodes.kdims[:2] - x_range = ranges[xdim.name]['combined'] - y_range = ranges[ydim.name]['combined'] + x_range = ranges[xdim.label]['combined'] + y_range = ranges[ydim.label]['combined'] arrow_len = np.hypot(y_range[1]-y_range[0], x_range[1]-x_range[0])*self.arrowhead_length paths = get_directed_graph_paths(element, arrow_len) else: diff --git a/holoviews/plotting/mpl/heatmap.py b/holoviews/plotting/mpl/heatmap.py index 67cf98fb61..273abea9c8 100644 --- a/holoviews/plotting/mpl/heatmap.py +++ b/holoviews/plotting/mpl/heatmap.py @@ -173,8 +173,8 @@ def get_data(self, element, ranges, style): yvals = aggregate.dimension_values(ydim, expanded=False) yvals = GridInterface._infer_interval_breaks(yvals) - xfactors = list(ranges.get(xdim.name, {}).get('factors', [])) - yfactors = list(ranges.get(ydim.name, {}).get('factors', [])) + xfactors = list(ranges.get(xdim.label, {}).get('factors', [])) + yfactors = list(ranges.get(ydim.label, {}).get('factors', [])) xticks, yticks = self._compute_ticks(element, xvals, yvals, xfactors, yfactors) style['xfactors'] = xfactors diff --git a/holoviews/plotting/mpl/raster.py b/holoviews/plotting/mpl/raster.py index 890d41d7f5..6c35279903 100644 --- a/holoviews/plotting/mpl/raster.py +++ b/holoviews/plotting/mpl/raster.py @@ -330,7 +330,7 @@ def initialize_plot(self, ranges=None): ranges = self.compute_ranges(vmap, key, ranges) opts = self.lookup_options(pane, 'style')[self.cyclic_index] plot = self.handles['axis'].imshow(data, extent=(x,x+w, y, y+h), **opts) - cdim = pane.vdims[0].name + cdim = pane.vdims[0].label valrange = match_spec(pane, ranges).get(cdim, pane.range(cdim))['combined'] plot.set_clim(valrange) if data is None: diff --git a/holoviews/plotting/mpl/sankey.py b/holoviews/plotting/mpl/sankey.py index 40fe39f3e4..606f960af4 100644 --- a/holoviews/plotting/mpl/sankey.py +++ b/holoviews/plotting/mpl/sankey.py @@ -54,8 +54,8 @@ def get_extents(self, element, ranges, range_type='combined', **kwargs): return element.nodes.extents xdim, ydim = element.nodes.kdims[:2] xpad = .05 if self.label_index is None else 0.25 - x0, x1 = ranges[xdim.name][range_type] - y0, y1 = ranges[ydim.name][range_type] + x0, x1 = ranges[xdim.label][range_type] + y0, y1 = ranges[ydim.label][range_type] xdiff = (x1-x0) ydiff = (y1-y0) if self.label_position == 'right': diff --git a/holoviews/plotting/plot.py b/holoviews/plotting/plot.py index cc9bdbc489..03aea004f4 100644 --- a/holoviews/plotting/plot.py +++ b/holoviews/plotting/plot.py @@ -788,7 +788,7 @@ def _compute_group_range(cls, group, elements, ranges, framewise, # Compute dimension normalization for el_dim in el.dimensions('ranges'): - dim_name = el_dim.name + dim_name = el_dim.label if dim_name in prev_ranges and not framewise: continue data_range = data_ranges[(el, el_dim)] diff --git a/holoviews/plotting/plotly/chart.py b/holoviews/plotting/plotly/chart.py index b44b109ded..fcb2235588 100644 --- a/holoviews/plotting/plotly/chart.py +++ b/holoviews/plotting/plotly/chart.py @@ -231,8 +231,8 @@ def get_data(self, element, ranges, style, **kwargs): stack_dim = element.get_dimension(1) if stack_dim.values: svals = stack_dim.values - elif stack_dim in ranges and ranges[stack_dim.name].get('factors'): - svals = ranges[stack_dim]['factors'] + elif stack_dim in ranges and ranges[stack_dim.label].get('factors'): + svals = ranges[stack_dim.label]['factors'] else: svals = element.dimension_values(1, False) else: diff --git a/holoviews/plotting/util.py b/holoviews/plotting/util.py index 4cb3fc26da..27b035ab81 100644 --- a/holoviews/plotting/util.py +++ b/holoviews/plotting/util.py @@ -407,10 +407,10 @@ def get_range(element, ranges, dimension): an element and a dictionary of ranges. """ if dimension and dimension != 'categorical': - if ranges and dimension.name in ranges: - drange = ranges[dimension.name]['data'] - srange = ranges[dimension.name]['soft'] - hrange = ranges[dimension.name]['hard'] + if ranges and dimension.label in ranges: + drange = ranges[dimension.label]['data'] + srange = ranges[dimension.label]['soft'] + hrange = ranges[dimension.label]['hard'] else: drange = element.range(dimension, dimension_range=False) srange = dimension.soft_range @@ -439,8 +439,8 @@ def get_sideplot_ranges(plot, element, main, ranges): range_item = HoloMap({0: main}, kdims=['Frame']) ranges = match_spec(range_item.last, ranges) - if dim.name in ranges: - main_range = ranges[dim.name]['combined'] + if dim.label in ranges: + main_range = ranges[dim.label]['combined'] else: framewise = plot.lookup_options(range_item.last, 'norm').options.get('framewise') if framewise and range_item.get(key, False): @@ -1116,7 +1116,7 @@ def dim_range_key(eldim): if dim_name.startswith("dim('") and dim_name.endswith("')"): dim_name = dim_name[5:-2] else: - dim_name = eldim.name + dim_name = eldim.label return dim_name diff --git a/holoviews/tests/plotting/bokeh/test_layoutplot.py b/holoviews/tests/plotting/bokeh/test_layoutplot.py index 80f90571a0..97757a39ba 100644 --- a/holoviews/tests/plotting/bokeh/test_layoutplot.py +++ b/holoviews/tests/plotting/bokeh/test_layoutplot.py @@ -296,13 +296,26 @@ def test_layout_shared_source_synced_update(self): self.assertEqual(data['D'], np.full_like(hmap1[1].dimension_values(0), np.nan)) def test_shared_axes(self): - curve = Curve(range(10)) + curve = Curve(range(10), ) img = Image(np.random.rand(10,10)) plot = bokeh_renderer.get_plot(curve+img) - plot = plot.subplots[(0, 1)].subplots['main'] - x_range, y_range = plot.handles['x_range'], plot.handles['y_range'] - self.assertEqual((x_range.start, x_range.end), (-.5, 9)) - self.assertEqual((y_range.start, y_range.end), (-.5, 9)) + plot1 = plot.subplots[(0, 0)].subplots['main'] + plot2 = plot.subplots[(0, 1)].subplots['main'] + x_range1, y_range1 = plot1.handles['x_range'], plot1.handles['y_range'] + x_range2, y_range2 = plot2.handles['x_range'], plot2.handles['y_range'] + assert x_range1 is x_range2 + assert y_range1 is y_range2 + + def test_shared_axes_different_dimension_names(self): + curve = Curve(range(10), ('x1', 'foo'), ('y1', 'bar')) + img = Image(np.random.rand(10,10), [('x2', 'foo'), ('y2', 'bar')]) + plot = bokeh_renderer.get_plot(curve+img) + plot1 = plot.subplots[(0, 0)].subplots['main'] + plot2 = plot.subplots[(0, 1)].subplots['main'] + x_range1, y_range1 = plot1.handles['x_range'], plot1.handles['y_range'] + x_range2, y_range2 = plot2.handles['x_range'], plot2.handles['y_range'] + assert x_range1 is x_range2 + assert y_range1 is y_range2 def test_shared_axes_disable(self): curve = Curve(range(10)) @@ -356,8 +369,8 @@ def test_layout_axis_link_matching_name_label(self): p1, p2 = (sp.subplots['main'] for sp in plot.subplots.values()) self.assertIs(p1.handles['y_range'], p2.handles['y_range']) - def test_layout_axis_not_linked_mismatching_name(self): - layout = Curve([1, 2, 3], vdims=('b', 'A')) + Curve([1, 2, 3], vdims=('a', 'A')) + def test_layout_axis_not_linked_mismatching_label(self): + layout = Curve([1, 2, 3], vdims=('a', 'A')) + Curve([1, 2, 3], vdims=('a', 'B')) plot = bokeh_renderer.get_plot(layout) p1, p2 = (sp.subplots['main'] for sp in plot.subplots.values()) self.assertIsNot(p1.handles['y_range'], p2.handles['y_range'])