diff --git a/doc/Tutorials/Columnar_Data.ipynb b/doc/Tutorials/Columnar_Data.ipynb
index b048eee040..5c3b8b8f6e 100644
--- a/doc/Tutorials/Columnar_Data.ipynb
+++ b/doc/Tutorials/Columnar_Data.ipynb
@@ -853,7 +853,7 @@
},
"outputs": [],
"source": [
- "%%opts Scatter [scaling_factor=1.4] (color=Palette('Set3') edgecolors='k')\n",
+ "%%opts Scatter [scaling_method='width' scaling_factor=2] (color=Palette('Set3') edgecolors='k')\n",
"gdp_unem_scatter = macro.to.scatter('Year', ['GDP Growth', 'Unemployment'])\n",
"gdp_unem_scatter.overlay('Country')"
]
@@ -873,7 +873,7 @@
},
"outputs": [],
"source": [
- "%%opts NdOverlay [legend_cols=2] Scatter [size_index=1 scaling_factor=1.3] (color=Palette('Blues'))\n",
+ "%%opts NdOverlay [legend_cols=2] Scatter [size_index=1] (color=Palette('Blues'))\n",
"macro.to.scatter('GDP Growth', 'Unemployment', ['Year']).overlay()"
]
},
diff --git a/doc/Tutorials/Elements.ipynb b/doc/Tutorials/Elements.ipynb
index bca51af95b..8e1fe7733b 100644
--- a/doc/Tutorials/Elements.ipynb
+++ b/doc/Tutorials/Elements.ipynb
@@ -565,7 +565,7 @@
"source": [
"The ``Scatter`` object expresses a dependent relationship between *x* and *y*, making it useful for combining with other similar ``Chart`` types, while the ``Points`` object expresses the relationship of two independent keys *x* and *y* with optional ``vdims`` (zero in this case), which makes ``Points`` objects meaningful to combine with the ``Raster`` types below.\n",
"\n",
- "Of course, the ``vdims`` need not be empty for ``Points``; here is an example with two additional quantities for each point, as ``value_dimension``s *z* and α visualized as the color and size of the dots, respectively:"
+ "Of course, the ``vdims`` need not be empty for ``Points``; here is an example with two additional quantities for each point, as ``value_dimension``s *z* and α visualized as the color and size of the dots, respectively. The point sizes can be tweaked using the option `scaling_factor`, which determines the amount by which each point width or area is scaled, depending on the value of `scaling_method`."
]
},
{
@@ -576,7 +576,7 @@
},
"outputs": [],
"source": [
- "%%opts Points [color_index=2 size_index=3 scaling_factor=50]\n",
+ "%%opts Points [color_index=2 size_index=3 scaling_method=\"width\" scaling_factor=10]\n",
"np.random.seed(10)\n",
"data = np.random.rand(100,4)\n",
"\n",
diff --git a/holoviews/plotting/bokeh/chart.py b/holoviews/plotting/bokeh/chart.py
index a4e485948e..b03f1d379d 100644
--- a/holoviews/plotting/bokeh/chart.py
+++ b/holoviews/plotting/bokeh/chart.py
@@ -13,22 +13,21 @@
class PointPlot(ElementPlot):
- color_index = param.Integer(default=3, doc="""
+ color_index = param.Integer(default=3, allow_None=True, doc="""
Index of the dimension from which the color will the drawn""")
- size_index = param.Integer(default=2, doc="""
+ size_index = param.Integer(default=2, allow_None=True, doc="""
Index of the dimension from which the sizes will the drawn.""")
- radius_index = param.Integer(default=None, doc="""
- Index of the dimension from which the sizes will the drawn.""")
+ scaling_method = param.ObjectSelector(default="area",
+ objects=["width", "area"],
+ doc="""
+ Determines whether the `scaling_factor` should be applied to
+ the width or area of each point (default: "area").""")
scaling_factor = param.Number(default=1, bounds=(1, None), doc="""
- If values are supplied the area of the points is computed relative
- to the marker size. It is then multiplied by scaling_factor to the power
- of the ratio between the smallest point and all other points.
- For values of 1 scaling by the values is disabled, a factor of 2
- allows for linear scaling of the area and a factor of 4 linear
- scaling of the point width.""")
+ Scaling factor which is applied to either the width or area
+ of each point, depending on the value of `scaling_method`.""")
size_fn = param.Callable(default=np.abs, doc="""
Function applied to size values before applying scaling,
@@ -49,7 +48,7 @@ def get_data(self, element, ranges=None, empty=False):
data = {}
cmap = style.get('palette', style.get('cmap', None))
- if self.color_index < len(dims) and cmap:
+ if self.color_index is not None and self.color_index < len(dims) and cmap:
map_key = 'color_' + dims[self.color_index]
mapping['color'] = map_key
if empty:
@@ -59,7 +58,7 @@ def get_data(self, element, ranges=None, empty=False):
colors = element.dimension_values(self.color_index)
crange = ranges.get(dims[self.color_index], None)
data[map_key] = map_colors(colors, crange, cmap)
- if self.size_index < len(dims) and self.scaling_factor != 1:
+ if self.size_index is not None and self.size_index < len(dims):
map_key = 'size_' + dims[self.size_index]
mapping['size'] = map_key
if empty:
@@ -67,8 +66,9 @@ def get_data(self, element, ranges=None, empty=False):
else:
ms = style.get('size', 1)
sizes = element.dimension_values(self.size_index)
- data[map_key] = compute_sizes(sizes, self.size_fn,
- self.scaling_factor, ms)
+ data[map_key] = np.sqrt(compute_sizes(sizes, self.size_fn,
+ self.scaling_factor,
+ self.scaling_method, ms))
data[dims[0]] = [] if empty else element.dimension_values(0)
data[dims[1]] = [] if empty else element.dimension_values(1)
diff --git a/holoviews/plotting/mpl/chart.py b/holoviews/plotting/mpl/chart.py
index 6fcb41c8ea..0b10ae8b95 100644
--- a/holoviews/plotting/mpl/chart.py
+++ b/holoviews/plotting/mpl/chart.py
@@ -542,19 +542,21 @@ class PointPlot(ChartPlot, ColorbarPlot):
how point magnitudes are rendered to different colors.
"""
- color_index = param.Integer(default=3, doc="""
+ color_index = param.Integer(default=3, allow_None=True, doc="""
Index of the dimension from which the color will the drawn""")
- size_index = param.Integer(default=2, doc="""
+ size_index = param.Integer(default=2, allow_None=True, doc="""
Index of the dimension from which the sizes will the drawn.""")
- scaling_factor = param.Number(default=1, bounds=(1, None), doc="""
- If values are supplied the area of the points is computed relative
- to the marker size. It is then multiplied by scaling_factor to the power
- of the ratio between the smallest point and all other points.
- For values of 1 scaling by the values is disabled, a factor of 2
- allows for linear scaling of the area and a factor of 4 linear
- scaling of the point width.""")
+ scaling_method = param.ObjectSelector(default="area",
+ objects=["width", "area"],
+ doc="""
+ Determines whether the `scaling_factor` should be applied to
+ the width or area of each point (default: "area").""")
+
+ scaling_factor = param.Number(default=1, bounds=(0, None), doc="""
+ Scaling factor which is applied to either the width or area
+ of each point, depending on the value of `scaling_method`.""")
show_grid = param.Boolean(default=True, doc="""
Whether to draw grid lines at the tick positions.""")
@@ -584,7 +586,7 @@ def initialize_plot(self, ranges=None):
cs = points.dimension_values(self.color_index)
style = self.style[self.cyclic_index]
- if self.size_index < ndims and self.scaling_factor > 1:
+ if self.size_index is not None and self.size_index < ndims:
style['s'] = self._compute_size(points, style)
color = style.pop('color', None)
@@ -609,7 +611,7 @@ def initialize_plot(self, ranges=None):
def _compute_size(self, element, opts):
sizes = element.dimension_values(self.size_index)
ms = opts.pop('s') if 's' in opts else plt.rcParams['lines.markersize']
- return compute_sizes(sizes, self.size_fn, self.scaling_factor, ms)
+ return compute_sizes(sizes, self.size_fn, self.scaling_factor, self.scaling_method, ms)
def update_handles(self, axis, element, key, ranges=None):
@@ -617,10 +619,10 @@ def update_handles(self, axis, element, key, ranges=None):
paths.set_offsets(element.array(dimensions=[0, 1]))
dims = element.dimensions(label=True)
ndims = len(dims)
- if self.size_index < ndims:
+ if self.size_index is not None and self.size_index < ndims:
opts = self.style[self.cyclic_index]
paths.set_sizes(self._compute_size(element, opts))
- if self.color_index < ndims:
+ if self.color_index is not None and self.color_index < ndims:
cs = element.dimension_values(self.color_index)
val_dim = dims[self.color_index]
paths.set_clim(ranges[val_dim])
diff --git a/holoviews/plotting/util.py b/holoviews/plotting/util.py
index 82f6aa1b5e..420f335592 100644
--- a/holoviews/plotting/util.py
+++ b/holoviews/plotting/util.py
@@ -1,3 +1,4 @@
+import math
import param
from ..core import (HoloMap, DynamicMap, CompositeOverlay, Layout,
@@ -74,14 +75,22 @@ def undisplayable_info(obj, html=False):
['%s' % error, remedy, '%s' % info])))
-def compute_sizes(sizes, size_fn, scaling, base_size):
+def compute_sizes(sizes, size_fn, scaling_factor, scaling_method, base_size):
"""
Scales point sizes according to a scaling factor,
base size and size_fn, which will be applied before
scaling.
"""
+ if scaling_method == 'area':
+ pass
+ elif scaling_method == 'width':
+ scaling_factor = scaling_factor**2
+ else:
+ raise ValueError(
+ 'Invalid value for argument "scaling_method": "{}". '
+ 'Valid values are: "width", "area".'.format(scaling_method))
sizes = size_fn(sizes)
- return (base_size*scaling**sizes)
+ return (base_size*scaling_factor*sizes)
def get_sideplot_ranges(plot, element, main, ranges):