Closed kcpevey closed 5 years ago
For problem 1, you're using datashade
, which does not have a cmap
option; cmap
is for rasterize
. You're already coloring by magnitude, so you presumably don't need any colormapping anyway, so you can just remove that argument.
But its in my apply_opts
because I need it for the scalar images. So I can't have both image types use the same apply_opts
callback?
You could simply switch to rasterize
for both.
I don't get how it works at all, given that the magnitude is already mapped to color by vectorfield_to_paths; doesn't that leave no room for colormapping?
@jbednar the issue was that I am reusing the apply_opts function for multiple plot types. vectorfield_to_paths doesn't need it, but scalar plotting does. Switching to rasterize for both works.
As for question 2:
This works:
@param.depends('time','result_label')
def time_mesh(self):
# add this time step's data as a vdim under the provided label
data_points = self.mesh_points.add_dimension(self.result_label, 0,
self.model[self.result_label].sel(times=self.time).data,
vdim=True)
return gv.TriMesh((self.tris[['v0', 'v1', 'v2']], data_points), label=self.result_label, crs=ccrs.GOOGLE_MERCATOR)
def create_animation(self):
""" Method to create holoviews dynamic map meshes (1D data only)"""
if self.mesh_points is None:
self.reproject_points()
meshes = hv.DynamicMap(self.time_mesh, label='scalar')
return meshes
But this doesn't:
@param.depends('time', 'result_label')
def time_mesh_scalar(self):
# add this time step's data as a vdim under the provided label
data_points = self.mesh_points.add_dimension(self.result_label, 0,
self.model[self.result_label].sel(times=self.time).data,
vdim=True)
return gv.TriMesh((self.tris[['v0', 'v1', 'v2']], data_points), label=self.result_label,
crs=ccrs.GOOGLE_MERCATOR)
@param.depends('time', 'result_label')
def time_mesh_vector(self):
vx = self.model[self.result_label].sel(times=self.time).data[:, 0]
vy = self.model[self.result_label].sel(times=self.time).data[:, 1]
xs = self.mesh_points.data['x']
ys = self.mesh_points.data['y']
with np.errstate(divide='ignore', invalid='ignore'):
angle = np.arctan2(vy, vx)
mag = np.sqrt(vx ** 2 + vy ** 2)
return gv.VectorField((xs, ys, angle, mag), vdims=['Angle', 'Magnitude'],
crs=ccrs.GOOGLE_MERCATOR)
def create_animation2(self):
""" Method to create holoviews dynamic map meshes for vector or scalar datasets"""
# check to make sure the mesh points have been set.
if self.mesh_points is None:
self.reproject_points()
if 'BEGSCL' in self.model[self.result_label].attrs.keys():
meshes = hv.DynamicMap(self.time_mesh_scalar, label='scalar')
return meshes
elif 'BEGVEC' in self.model[self.result_label].attrs.keys():
meshes = hv.DynamicMap(self.time_mesh_vector, label='vector')
return meshes
else:
log.error('Data type not recognized. Must be BEGSCL or BEGVEC.')
I also added the param.depends
decorator to the create_animation function but that didn't work either. What am I doing wrong here?
I dont understand how the decorator @param.depends('time','result_label')
correctly triggers a redraw when I have just one time_mesh method, but when I have alternating methods, it doesn't trigger a redraw?
Hi @kcpevey , I am also interested in using Vector/quiver plots and want it to explore using datashader because of large amount of data. Could we talk on what you have done and what approach we can try? Edit: Thanks @philippjfr , Checking out #273
@aeroaks I'm using the latest vectorfield_to_paths
code that @philippjfr developed in #273 . My current dataset is 836k data points and that method works well enough for that. Having to call it in a dynamicMap callback is a little laggy with a dataset of that size, but it does work.
I needed to move my @param.depends
calls around. Working code snippets:
@param.depends('time')
def time_mesh_scalar(self):
# add this time step's data as a vdim under the provided label
data_points = self.mesh_points.add_dimension(self.result_label, 0,
self.model[self.result_label].sel(times=self.time).data,
vdim=True)
# return a trimesh with this data
return gv.TriMesh((self.tris[['v0', 'v1', 'v2']], data_points), label=self.result_label,
crs=ccrs.GOOGLE_MERCATOR)
@param.depends('time')
def time_mesh_vector(self):
vx = self.model[self.result_label].sel(times=self.time).data[:, 0]
vy = self.model[self.result_label].sel(times=self.time).data[:, 1]
xs = self.mesh_points.data['x']
ys = self.mesh_points.data['y']
with np.errstate(divide='ignore', invalid='ignore'):
angle = np.arctan2(vy, vx)
mag = np.sqrt(vx ** 2 + vy ** 2)
return gv.VectorField((xs, ys, angle, mag), vdims=['Angle', 'Magnitude'],
crs=ccrs.GOOGLE_MERCATOR)
@param.depends('result_label')
def create_animation2(self):
""" Method to create holoviews dynamic map meshes for vector or scalar datasets"""
# check to make sure the mesh points have been set.
if self.mesh_points is None:
self.reproject_points()
if 'BEGSCL' in self.model[self.result_label].attrs.keys():
meshes = hv.DynamicMap(self.time_mesh_scalar, label='scalar')
return meshes
elif 'BEGVEC' in self.model[self.result_label].attrs.keys():
meshes = hv.DynamicMap(self.time_mesh_vector, label='vector')
return meshes
else:
log.error('Data type not recognized. Must be BEGSCL or BEGVEC.')
@param.depends('adh_viz.result_label')
def run(self):
# create the meshes for the dynamic map
meshes = self.adh_viz.create_animation2()
# Define function which applies colormap and color_range
def apply_opts(obj, colormap, color_range):
return obj.options(cmap=colormap).redim.range(**{obj.vdims[0].name: color_range}).options(
clipping_colors={'NaN': 'transparent', 'min': 'transparent'})
if meshes.label == 'scalar':
# Apply the colormap and color range dynamically
dynamic = hv.util.Dynamic(rasterize(meshes), operation=apply_opts, streams=[Params(self.cmap_opts), Params(self.display_range)]
).options(colorbar=True, height=600, width=600) * self.wmts_widget.view() * self.annotator.polys * self.annotator.points
elif meshes.label == 'vector':
# Apply the colormap and color range dynamically
dynamic = hv.util.Dynamic(rasterize(vectorfield_to_paths(meshes, color='Magnitude', magnitude='Magnitude', scale=0.05), aggregator='mean', cmap=process_cmap('viridis'), precompute=True), operation=apply_opts, streams=[Params(self.cmap_opts), Params(self.display_range)]).options(colorbar=True, height=600, width=600) * self.wmts_widget.view() * self.annotator.polys * self.annotator.points
I'm working on adapting my code to include vector visualization in way that is seamless to the user and requires as little code duplication as possible. I tested the vector viz outside of this big code base and didn't have any trouble, but now that its integrated, it has issues. Here are the code snippets:
apply_opts
method is throwing an error with the cmap: