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

Added datashader regridding operation #1773

Merged
merged 14 commits into from Aug 4, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
37 changes: 30 additions & 7 deletions holoviews/operation/datashader.py
Expand Up @@ -37,7 +37,13 @@ class resample_operation(Operation):

expand = param.Boolean(default=True, doc="""
Whether the x_range and y_range should be allowed to expand
beyond the extent of the data.""")
beyond the extent of the data. Setting this value to True is
useful for the case where you want to ensure a certain size of
output grid, e.g. if you are doing masking or other arithmetic
on the grids. A value of False ensures that the grid is only
just as large as it needs to be to contain the data, which will
be faster and use less memory if the resulting aggregate is
being overlaid on a much larger background.""")

height = param.Integer(default=400, doc="""
The height of the aggregated image in pixels.""")
Copy link
Contributor

@jlstevens jlstevens Aug 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this height parameter used by regrid? I'm not sure it is clear to talk about an 'aggregated' image in that case. Maybe just talk about the 'output' image?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, although in aggregation is still the correct term at least when downsampling. Will fix it anyway.

Expand Down Expand Up @@ -133,7 +139,7 @@ class aggregate(resample_operation):
the x_range and y_range. If x_sampling or y_sampling are supplied
the operation will ensure that a bin is no smaller than the minimum
sampling distance by reducing the width and height when the zoomed
in beyond the minimum sampling distance.
beyond the minimum sampling distance.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when zoomed in beyond


By default, the PlotSize stream is applied when this operation
is used dynamically, which means that the height and width
Expand Down Expand Up @@ -333,20 +339,35 @@ def _process(self, element, key=None):

class regrid(resample_operation):
"""
Regridding allows resampling a HoloViews Image type using specified
up- and downsampling functions.
regrid allows resampling a HoloViews Image type using specified
up- and downsampling functions defined using the aggregator and
interpolation parameters respectively. By default upsampling is
disabled to avoid unnecessarily upscaling an image that has to be
sent to the browser. Also disables expanding the image beyond its
original bounds avoiding unneccessarily padding the output array
with nan values.
"""

aggregator = param.ObjectSelector(default='mean',
objects=['first', 'last', 'mean', 'mode', 'std', 'var', 'min', 'max'], doc="""
Aggregation method.
""")

expand = param.Boolean(default=False, doc="""
Whether the x_range and y_range should be allowed to expand
beyond the extent of the data. Setting this value to True is
useful for the case where you want to ensure a certain size of
output grid, e.g. if you are doing masking or other arithmetic
on the grids. A value of False ensures that the grid is only
just as large as it needs to be to contain the data, which will
be faster and use less memory if the resulting aggregate is
being overlaid on a much larger background.""")

interpolation = param.ObjectSelector(default='nearest',
objects=['linear', 'nearest'], doc="""
Interpolation method""")

upsample = param.Boolean(default=True, doc="""
upsample = param.Boolean(default=False, doc="""
Whether to allow upsampling if the source array is smaller than
the requested array.""")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be False by default since interpolation is nearest by default, and thus the result will be approximately the same whether or not upsampling is done? With linear interpolation the results will be different, but one could say in the docstring for the interpolation parameter that one might want upsample=False for interpolation methods that smooth the data, unlike nearest.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'd agree with that, upsampling is rarely needed I think, again only when you're trying to match a higher resolution target gridding (in which case you should probably downsample the higher resolution grid rather than upsampling the lower resolution one).


Expand Down Expand Up @@ -378,7 +399,7 @@ def _process(self, element, key=None):
# Disable upsampling if requested
(xstart, xend), (ystart, yend) = (x_range, y_range)
xspan, yspan = (xend-xstart), (yend-ystart)
if not self.p.upsample:
if not self.p.upsample and self.p.target is None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't there at least be a warning to say upsampling has been disabled?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh why? It's a parameter.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the parameter should be respected as set, with no warning.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case the docstring needs improvement:

"Whether to allow upsampling if the source array is smaller than the requested array."

What is the behavior if upsample=False? Padding?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, Philipp's now explained it to me. The behavior makes sense though I think there could be a bit more clarification in the docstrings.

(x0, x1), (y0, y1) = element.range(0), element.range(1)
exspan, eyspan = (x1-x0), (y1-y0)
width = min([int((xspan/exspan) * len(coords[0])), width])
Expand Down Expand Up @@ -433,7 +454,9 @@ class shade(Operation):
link_inputs = param.Boolean(default=True, doc="""
By default, the link_inputs parameter is set to True so that
when applying shade, backends that support linked streams
update RangeXY streams on the inputs of the shade operation.""")
update RangeXY streams on the inputs of the shade operation.
Disable when you do not want the resulting plot to be interactive,
e.g. when trying to display an interactive plot a second time.""")

@classmethod
def concatenate(cls, overlay):
Expand Down
8 changes: 4 additions & 4 deletions tests/testdatashader.py
Expand Up @@ -83,7 +83,7 @@ def test_regrid_max(self):

def test_regrid_upsampling(self):
img = Image(([0.5, 1.5], [0.5, 1.5], [[0, 1], [2, 3]]))
regridded = regrid(img, width=4, height=4, dynamic=False)
regridded = regrid(img, width=4, height=4, upsample=True, dynamic=False)
expected = Image(([0.25, 0.75, 1.25, 1.75], [0.25, 0.75, 1.25, 1.75],
[[0, 0, 1, 1],
[0, 0, 1, 1],
Expand All @@ -93,20 +93,20 @@ def test_regrid_upsampling(self):

def test_regrid_upsampling_linear(self):
img = Image(([0.5, 1.5], [0.5, 1.5], [[0, 1], [2, 3]]))
regridded = regrid(img, width=4, height=4, interpolation='linear', dynamic=False)
regridded = regrid(img, width=4, height=4, upsample=True, interpolation='linear', dynamic=False)
expected = Image(([0.25, 0.75, 1.25, 1.75], [0.25, 0.75, 1.25, 1.75],
[[0, 0, 0, 1],
[0, 1, 1, 1],
[1, 1, 2, 2],
[2, 2, 2, 3]]))
self.assertEqual(regridded, expected)

def test_regrid_disable_upsampling(self):
def test_regrid_disabled_upsampling(self):
img = Image(([0.5, 1.5], [0.5, 1.5], [[0, 1], [2, 3]]))
regridded = regrid(img, width=3, height=3, dynamic=False, upsample=False)
self.assertEqual(regridded, img)

def test_regrid_disable_expand(self):
def test_regrid_disabled_expand(self):
img = Image(([0.5, 1.5], [0.5, 1.5], [[0., 1.], [2., 3.]]))
regridded = regrid(img, width=2, height=2, x_range=(-2, 4), y_range=(-2, 4), expand=False,
dynamic=False)
Expand Down