def test_regrid_zero_range(self): ls = np.linspace(0, 10, 200) xx, yy = np.meshgrid(ls, ls) img = Image(np.sin(xx)*np.cos(yy), bounds=(0, 0, 1, 1)) regridded = regrid(img, x_range=(-1, -0.5), y_range=(-1, -0.5), dynamic=False) expected = Image(np.zeros((0, 0)), bounds=(0, 0, 0, 0), xdensity=1, ydensity=1) self.assertEqual(regridded, expected)
def test_regrid_mean_xarray_transposed(self): img = Image((range(10), range(5), np.arange(10) * np.arange(5)[np.newaxis].T), datatype=['xarray']) img.data = img.data.transpose() regridded = regrid(img, width=2, height=2, dynamic=False) expected = Image(([2., 7.], [0.75, 3.25], [[1, 5], [6, 22]])) self.assertEqual(regridded, expected)
def test_regrid_rgb_mean(self): arr = (np.arange(10) * np.arange(5)[np.newaxis].T).astype('f') rgb = RGB((range(10), range(5), arr, arr*2, arr*2)) regridded = regrid(rgb, width=2, height=2, dynamic=False) new_arr = np.array([[1.6, 5.6], [6.4, 22.4]]) expected = RGB(([2., 7.], [0.75, 3.25], new_arr, new_arr*2, new_arr*2), datatype=['xarray']) self.assertEqual(regridded, expected)
def plotMap(self, dArray, name, width=500, height=250, cmap="gist_earth_r", dataShader=True, alpha=0.5): """ plot the DataArray onto the map. Args: dArray (xarray.DataArray): DataArray of your output. name (str): name of your data width (int): width of the output image height (int): height of the output image cmap (str): colormap alpha (float): alpha value Returns: bokeh image object """ dataset = gv.Dataset(dArray) img = dataset.to(gv.Image, ["lon", "lat"], name) if dataShader: img = datashader.regrid(img) img_out = img.opts(width=width, height=height, alpha=alpha, colorbar=True, cmap=cmap, tools=["hover"]) * self.mapTiles return img_out
def view(self): options = dict(width=self.width, height=self.height, xaxis=None, yaxis=None, projection=self.image.crs) dmap = hv.DynamicMap(self.extract_foreground, streams=[self]) dmap = hv.util.Dynamic(dmap, operation=self.filter_contours, streams=[self.filter_stream]) return (regrid(self.image).options(**options) * self.bg_paths * self.fg_paths + dmap.options(**options)).options(merge_tools=False, clone=False)
def plot_decode_image(self, time=None, plt_range=None, x_range=None, y_range=None): if time is None: time = self.posteriors.get_time_start() if plt_range is None: plt_range = self.posteriors.get_time_total() if x_range is None: x_range = (time, time + plt_range) if y_range is None: y_range = self.posteriors.get_pos_range() self.post_img.extents = (x_range[0], 0, x_range[1], self.enc_settings.pos_bins[-1]) self.post_img.relabel('posteriors') rgb = shade(regrid(self.post_img, aggregator='mean', dynamic=False, x_range=x_range, y_range=y_range, precompute=True), cmap=plt.get_cmap('hot'), normalization='linear', dynamic=False) rgb.extents = (x_range[0], 0, x_range[1], self.enc_settings.pos_bins[-1]) return rgb
def test_regrid_zero_range(self): ls = np.linspace(0, 10, 200) xx, yy = np.meshgrid(ls, ls) img = Image(np.sin(xx)*np.cos(yy), bounds=(0, 0, 1, 1)) regridded = regrid(img, x_range=(-1, -0.5), y_range=(-1, -0.5), dynamic=False) expected = Image(np.zeros((0, 0)), bounds=(0, 0, 0, 0), xdensity=1, ydensity=1) self.assertEqual(regridded, expected)
def view( self, ch_to_display, scalebar_size, rescale_factor, show_legend=True, legend_position="bottom_left", ): w = self.data.sizes["x"] h = self.data.sizes["y"] self.prepare_data(ch_to_display) self.combine_ch_colors() self.prepare_texts(ch_to_display) self.rangexy = hv.streams.RangeXY(source=self.rendered_image) self.scalebar_size = scalebar_size self.regridded_image = ( regrid(self.rendered_image, streams=[self.rangexy]) .options(framewise=True) .opts(width=int(w / rescale_factor), height=int(h / rescale_factor)) ) self.scalebar_image = self.regridded_image * hv.DynamicMap( self.scalebar, streams=[self.rangexy] ) self.overlay_image = hv.Overlay([self.scalebar_image] + self.captions_legend) self.final_image = self.overlay_image.collate().opts( show_legend=show_legend, legend_position=legend_position ) return self.final_image
def extract_foreground(self, **kwargs): img = self.image if self._initialized: bg, fg = self.draw_bg.element, self.draw_fg.element else: self._initialized = True bg, fg = self.bg_paths, self.fg_paths bg, fg = (gv.project(g, projection=img.crs) for g in (bg, fg)) if not len(bg) or not len(fg): return gv.Path([], img.kdims, crs=img.crs) if self.downsample != 1: kwargs = {'dynamic': False} h, w = img.interface.shape(img, gridded=True) kwargs['width'] = int(w * self.downsample) kwargs['height'] = int(h * self.downsample) img = regrid(img, **kwargs) foreground = extract_foreground(img, background=bg, foreground=fg, iterations=self.iterations) with warnings.catch_warnings(): warnings.filterwarnings('ignore') foreground = gv.Path( [contours(foreground, filled=True, levels=1).split()[0].data], kdims=foreground.kdims, crs=foreground.crs) self.result = gv.project(foreground, projection=self.crs) return foreground
def test_regrid_mean_xarray_transposed(self): img = Image((range(10), range(5), np.arange(10) * np.arange(5)[np.newaxis].T), datatype=['xarray']) img.data = img.data.transpose() regridded = regrid(img, width=2, height=2, dynamic=False) expected = Image(([2., 7.], [0.75, 3.25], [[1, 5], [6, 22]])) self.assertEqual(regridded, expected)
def test_regrid_rgb_mean(self): arr = (np.arange(10) * np.arange(5)[np.newaxis].T).astype('f') rgb = RGB((range(10), range(5), arr, arr*2, arr*2)) regridded = regrid(rgb, width=2, height=2, dynamic=False) new_arr = np.array([[1.6, 5.6], [6.4, 22.4]]) expected = RGB(([2., 7.], [0.75, 3.25], new_arr, new_arr*2, new_arr*2), datatype=['xarray']) self.assertEqual(regridded, expected)
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 mainview(self): image = hv.DynamicMap(self.get_image, streams=[self.pipe, self.range_xy]) if self.buffer: res = regrid(image) else: res = hd.regrid(image) return res
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, 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], [2, 2, 3, 3], [2, 2, 3, 3]])) self.assertEqual(regridded, expected)
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, 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_max(self): img = Image( (range(10), range(5), np.arange(10) * np.arange(5)[np.newaxis].T)) regridded = regrid(img, aggregator='max', width=2, height=2, dynamic=False) expected = Image(([2., 7.], [0.75, 3.25], [[8, 18], [16, 36]])) self.assertEqual(regridded, expected)
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) self.assertEqual(regridded, img)
def test_rasterize_image_string_aggregator(self): img = Image( (range(10), range(5), np.arange(10) * np.arange(5)[np.newaxis].T)) regridded = regrid(img, width=2, height=2, dynamic=False, aggregator='mean') expected = Image(([2., 7.], [0.75, 3.25], [[1, 5], [6, 22]])) self.assertEqual(regridded, expected)
def test_regrid_upsampling_linear(self): ### This test causes a numba error using 0.35.0 - temporarily disabled ### return img = Image(([0.5, 1.5], [0.5, 1.5], [[0, 1], [2, 3]])) 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_upsampling_linear(self): ### This test causes a numba error using 0.35.0 - temporarily disabled ### return img = Image(([0.5, 1.5], [0.5, 1.5], [[0, 1], [2, 3]])) 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 view(self): height = self.height if height is None: h, w = self.image.dimension_values(2, flat=False).shape[:2] height = int(self.width*(h/w)) options = dict(width=self.width, height=height, xaxis=None, yaxis=None, projection=self.image.crs) dmap = hv.DynamicMap(self.extract_foreground) dmap = hv.util.Dynamic(dmap, operation=self._filter_contours) dmap = hv.util.Dynamic(dmap, operation=self._simplify_contours) return (regrid(self.image).options(**options) * self.bg_paths * self.fg_paths + dmap.options(**options))
def one_band(band, time): xs, ys = dataset[band].sel(time=time)[dims[0]], dataset[band].sel( time=time)[dims[1]] b = ds.utils.orient_array(dataset[band].sel(time=time)) a = (np.where(np.logical_or(np.isnan(b), b <= nodata), 0, 255)).astype(np.uint8) return shade(regrid( hv.RGB((xs, ys[::-1], b, b, b, a), vdims=list('RGBA'))), cmap=cmap, clims=clims, normalization=norm).redim(x=dims[0], y=dims[1]).opts(width=width, height=height)
def plot_decode_image(self, time, x_range=None, y_range=None, plt_range=10): sel_range = [time, time + plt_range] if (x_range is None): x_range = [time, time + plt_range] if (y_range is None): y_range = [0, self.enc_settings.pos_bins[-1]] x_range = list(x_range) #x_range[0] -= plt_range #x_range[1] += plt_range x_range[0] = max(x_range[0], self.posteriors.get_time_start()) x_range[1] = min(x_range[1], self.posteriors.get_time_end()) # post_time = self.posteriors.index.get_level_values('time') # img_sel = self.posteriors.get_distribution_view().query("(time > @x_range[0]) & (time < @x_range[1])").values.T # img_sel = np.flip(img_sel, axis=0) # img = hv.Image(img_sel, bounds=(x_range[0], self.enc_settings.pos_bins[0], # x_range[1], # self.enc_settings.pos_bins[-1]), # kdims=['time (sec)', 'linpos (cm)'], vdims=['probability'],) # img = img.redim(probability={'range': (0, 0.3)}) # img.extents = (sel_range[0], 0, sel_range[1], self.enc_settings.pos_bins[-1]) self.post_img.extents = (sel_range[0], 0, sel_range[1], self.enc_settings.pos_bins[-1]) self.post_img.relabel('posteriors') rgb = shade(regrid(self.post_img, aggregator='max', dynamic=False, x_range=x_range, y_range=y_range), cmap=plt.get_cmap('magma'), normalization='linear', dynamic=False) # rgb = shade(regrid(self.post_img, aggregator='mean', dynamic=False, # x_range=x_range, y_range=y_range, y_sampling=1, x_sampling=0.001), # cmap=plt.get_cmap('hot'), normalization='linear', dynamic=False) rgb.extents = (sel_range[0], 0, sel_range[1], self.enc_settings.pos_bins[-1]) return rgb
def view(self): with TiffImage(self.data_dir / self.imgtype / self.zslice) as im: image = im.asarray() img = image[self.channel] xsize, ysize = img.shape img = hv.Image(img, bounds=(0, 0, ysize, xsize), vdims='Intensity') img = zscale_filter(img) return regrid(img).opts( plot={ 'Image': dict(frame_height=self.height, colorbar=self.colorbar, toolbar=self.toolbar, xaxis=self.xaxis, yaxis=self.yaxis, aspect='equal') })
def combine_bands(): xs, ys = dataset[bands[0]].sel( time=timestep)[dims[0]], dataset[bands[0]].sel( time=timestep)[dims[1]] r, g, b = [ ds.utils.orient_array(img) for img in (dataset[bands[0]].sel(time=timestep), dataset[bands[1]].sel(time=timestep), dataset[bands[2]].sel(time=timestep)) ] a = (np.where(np.logical_or(np.isnan(r), r <= nodata), 0, 255)).astype(np.uint8) r = (normalize_data(r)).astype(np.uint8) g = (normalize_data(g)).astype(np.uint8) b = (normalize_data(b)).astype(np.uint8) return regrid(hv.RGB((xs, ys[::-1], r, g, b, a), vdims=list('RGBA'))).redim(x=dims[0], y=dims[1])
def combine_bands(r, g, b, time): xs, ys = dataset[r].sel(time=time)[dims[0]], dataset[r].sel( time=time)[dims[1]] r, g, b = [ ds.utils.orient_array(img) for img in ( dataset[r].sel(time=time), dataset[g].sel(time=time), dataset[b].sel(time=time), ) ] a = (np.where(np.logical_or(np.isnan(r), r <= nodata), 0, 255)).astype(np.uint8) r = (normalize_data(r)).astype(np.uint8) g = (normalize_data(g)).astype(np.uint8) b = (normalize_data(b)).astype(np.uint8) return (regrid(hv.RGB( (xs, ys[::-1], r, g, b, a), vdims=list("RGBA"))).redim(x=dims[0], y=dims[1]).opts(width=width, height=height))
def extract_foreground(self, **kwargs): img = self.image bg, fg = self.bg_path_view(), self.fg_path_view() self._initialized = True if not len(bg) or not len(fg): return gv.Path([], img.kdims, crs=img.crs) if self.downsample != 1: kwargs = {'dynamic': False} h, w = img.interface.shape(img, gridded=True) kwargs['width'] = int(w*self.downsample) kwargs['height'] = int(h*self.downsample) img = regrid(img, **kwargs) foreground = extract_foreground(img, background=bg, foreground=fg, iterations=self.iterations) foreground = gv.Path([contours(foreground, filled=True, levels=1).split()[0].data], kdims=foreground.kdims, crs=foreground.crs) self.result = gv.project(foreground, projection=self.crs) return foreground
def display(self): # Define DynamicMap with z-dimension to slide through image_stack = hv.DynamicMap(self.load_image, kdims=['plane', 'channel', 'cycle', 'fov']) # Apply regridding in case data is large and set a global Intensity range regridded = regrid(image_stack).redim.range( plane=(0, self.arr.attrs['planes'] - 1), channel=(0, 2), cycle=(0, self.arr.attrs['cycles'] - 1), fov=(0, self.arr.attrs['fov'] - 1)) #+ hist_stack.redim.range(z=(0,3), c=(0,3)) display_obj = regridded.opts( plot={ 'Image': dict(width=700, height=700, colorbar=False, xaxis=None, yaxis=None, aspect='equal') }) return display_obj
def interactive_plot(cube, cmap='viridis', kdims=['longitude', 'latitude'], coastlines=False, coastline_color='white', projection=ccrs.PlateCarree, tools=['hover'], min_height=600, **opts): # Generate an interactive Bokeh image of a cube with various plotting options # Convert cube to GeoViews dataset dataset = gv.Dataset(cube, [coord.name() for coord in cube.dim_coords], label=cube.name()) # Generate an image object which will dynamically render as the interactive view changes image = regrid(dataset.to(gv.Image, kdims, dynamic=True)) # Options for plotting options = { 'cmap': cmap, 'responsive': True, 'projection': projection(), 'colorbar': True, 'min_height': min_height, 'aspect': 2, 'tools': tools } # Include coastlines if needed if coastlines: return gv.feature.ocean * gv.feature.land * image.opts( **options, ** opts) * gv.feature.coastline.opts(line_color=coastline_color) else: return image.opts(**options, **opts)
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_mean(self): img = Image((range(10), range(5), np.arange(10) * np.arange(5)[np.newaxis].T)) regridded = regrid(img, width=2, height=2, dynamic=False) expected = Image(([2., 7.], [0.75, 3.25], [[1, 5], [6, 22]])) self.assertEqual(regridded, expected)
def view( self, *, channels, rscale=None, gscale=None, bscale=None, percentile=98, show_miniview=True, height=600, resolution=900, ): self.channels = channels self.resolution = resolution self.rscale = rscale or self.ds.display_interval( channels[0], percentile) self.gscale = gscale or self.ds.display_interval( channels[1], percentile) self.bscale = bscale or self.ds.display_interval( channels[2], percentile) self.setup_streams() self.setup_controller(channels=channels) self.setup_template(height=height) tooltips = [ ("x", "$x{(0)}"), ("y", "$y{(0)}"), ] hover = HoverTool(tooltips=tooltips) self.main = self.mainview().opts( clone=True, responsive=True, hooks=[remove_bokeh_logo], default_tools=[hover], title=f"Sample: {self.name}", ) boxes = hv.Rectangles([]) self.box_stream = streams.BoxEdit( source=boxes, styles={"fill_color": ["yellow", "red", "green", "blue", "cyan"]}, ) boxes = boxes.opts(hv.opts.Rectangles(active_tools=[], fill_alpha=0.5)) overlay = hd.regrid(hv.Image([]), streams=[self.pointer]) if show_miniview: mini = (self.miniview().clone(link=False).opts( width=200, height=200, xaxis=None, yaxis=None, default_tools=[], shared_axes=False, hooks=[remove_bokeh_logo], )) zoom = self.zoomview().opts( width=200, height=200, xaxis=None, yaxis=None, default_tools=[], shared_axes=False, hooks=[remove_bokeh_logo], ) RangeToolLink(mini, self.main, axes=["x", "y"]) self.tmpl.add_panel( "A", pn.Row( pn.panel(self.main * overlay * boxes), pn.Column(pn.panel(mini), pn.panel(zoom)), width=400, height=280, sizing_mode="scale_both", ), ) else: self.tmpl.add_panel("A", pn.Row(pn.panel(self.main))) self.tmpl.add_panel("C", self.controller) return self.tmpl
cur_cents_nm = cur_uid_nm.merge(cents) A_ma_dict = dict() A_nm_dict = dict() for igrp, grp_ma in cur_uid_ma.groupby(group_dim + ['session']): cur_keys = {d: k for d, k in zip(group_dim + ['session'], igrp)} A_sub = A_shifted.sel(**cur_keys) A_ma = A_sub.sel(unit_id=grp_ma['unit_id'].values) grp_nm = cur_uid_nm.query(" and ".join(["==".join((d, "'{}'".format(k))) for d, k in cur_keys.items()])) A_nm = A_sub.sel(unit_id=grp_nm['unit_id'].values) A_ma_dict[igrp] = hv.Image(A_ma.sum('unit_id').compute(), kdims=['width', 'height']) A_nm_dict[igrp] = hv.Image(A_nm.sum('unit_id').compute(), kdims=['width', 'height']) hv_A_ma = hv.HoloMap(A_ma_dict, kdims=group_dim + ['session']) hv_A_nm = hv.HoloMap(A_nm_dict, kdims=group_dim + ['session']) hv_cent_ma = hv.Dataset(cur_cents_ma).to(hv.Points, kdims=['width', 'height']) hv_cent_nm = hv.Dataset(cur_cents_nm).to(hv.Points, kdims=['width', 'height']) hv_A = hv.HoloMap(dict(match=hv_A_ma, nonmatch=hv_A_nm), kdims=['matching']).collate() hv_cent = hv.HoloMap(dict(match=hv_cent_ma, nonmatch=hv_cent_nm), kdims=['matching']).collate() A_dict[cur_ss] = hv_A cent_dict[cur_ss] = hv_cent hv_A = hv.HoloMap(A_dict, kdims=['session']).collate() hv_cent = hv.HoloMap(cent_dict, kdims=['session']).collate() # In[ ]: from holoviews.operation.datashader import regrid (regrid(hv_A).opts(plot=dict(width=752, height=480), style=dict(cmap='Viridis'))).layout(['animal', 'matching']).cols(2) # In[ ]:
def explore( cyclonic=None, anticyclonic=None, hover_info=["segment", "track"], tiles=None, background_func=None, dynamic=False, date_widget="calendar", ): """explore NetworkObservations of cyclonic and/or anticyclonic :param cyclonic: cyclonic dataset, defaults to None :type cyclonic: :py:class:`~py_eddy_tracker.observations.network.NetworkObservations`, optional :param anticyclonic: anticyclonic dataset, defaults to None :type anticyclonic: :py:class:`~py_eddy_tracker.observations.network.NetworkObservations`, optional :param hover_info: list of data to show on hover, defaults to ["segment", "track"] :type hover_info: list, optional :param tiles: if specified, plot data over web tiles. like :py:class:`geoviews.source_tiles.EsriImagery`, defaults to None :type tiles: :py:class:`geoviews.element.geo.WMTS`, optional :param background_func: python function, takes as param a date and return a `xr.Dataset`, defaults to None :type background_func: callable, optional :param dynamic: if True, use :py:class:`~holoviews.operation.datashader.regrid` to delay plot of `background_func`, defaults to False :type dynamic: bool, optional :param date_widget: widget for date. if not calendar, it will be a radio, defaults to "calendar" :type date_widget: str, optional :return: bokeh plot .. note:: the param `background_func` should return a :py:class :`~xarray.Dataset` with variables "lon", "lat" and "Grid_0001" for the data. The name of data should be on attribute "long_name" of Grid_0001, and "units" if wanted example of function : .. code-block:: python def date2dataset(date): fichier = f"/tmp/global_{date.strftime('%Y%m%d')}.nc" with xr.open_dataset(fichier) as ds: ds = ds.rename({"longitude": "lon", "latitude": "lat", "adt": "Grid_0001"}) ds.Grid_0001.attrs["long_name"] = "adt ds['lon'] = np.where(ds.lon > 180, ds.lon - 360, ds.lon) ds = ds.sortby("lon").load() return ds """ if cyclonic is None and anticyclonic is None: raise NotImplementedError("please specify cyclonic or anticyclonic") # if cyclonic or anticyclonic is not declared, only use one datasets = [(d, color) for d, color in [(cyclonic, "deepskyblue"), (anticyclonic, "red")] if d is not None] # compute every date with data datasets_unique = [np.unique(d.time) for d, _ in datasets] unique = np.unique(np.concatenate(datasets_unique)) if date_widget == "calendar": now = datetime.date(1950, 1, 1) + datetime.timedelta(int(unique[0])) pn_date = pn.widgets.DatePicker( name="date", value=now, width=200, enabled_dates=(np.datetime64("1950-01-01") + unique.astype("timedelta64[D]")).tolist(), ) widget_date = pn_date else: pn_date = pn.widgets.DiscretePlayer(name="date", options=unique.tolist(), value=unique[0]) @pn.depends(pn_date_value=pn_date.param.value) def plot_date(pn_date_value): return pn.pane.HTML( f"<h1>date = {np.datetime64('1950-01-01')+np.timedelta64(pn_date_value)}</h1>" ) widget_date = pn.Row(pn_date, plot_date) @pn.depends(pn_date_value=pn_date.param.value) def update_all(pn_date_value): if isinstance(pn_date_value, datetime.date): # si on a choisi le widget DatePicker pn_date_value = (pn_date_value - datetime.date(1950, 1, 1)).days hv_polygons = [] hv_exterieur = [] for (d, color), d_unique in zip(datasets, datasets_unique): mask = d.time == pn_date_value sub_lon = ((d.contour_lon_s[mask] + 180) % 360) - 180 sub_lat = d.contour_lat_s[mask] sub_data = np.moveaxis(np.array([sub_lon, sub_lat]), [0], [2]) polygons = [Polygon(poly) for poly in sub_data] dct_data = {name: d[name][mask] for name in hover_info} dct_data["geometry"] = polygons gpd = geopandas.GeoDataFrame(dct_data) opts_common = dict(responsive=True) hv_polygons.append( gv.Polygons(gpd, vdims=hover_info).opts(line_color=color, **opts_common)) sub_lon = ((d.contour_lon_e[mask] + 180) % 360) - 180 sub_lat = d.contour_lat_e[mask] _lon = flatten_line_matrix(sub_lon) _lat = flatten_line_matrix(sub_lat) hv_exterieur.append( gv.Path([np.array([_lon, _lat]).T]).opts(color=color, alpha=0.70, line_dash="dashed", **opts_common)) return gv.Overlay([*hv_polygons, *hv_exterieur]).opts(responsive=True, tools=["hover"]) if background_func is not None: @pn.depends(pn_date_value=pn_date.param.value) def update_fond(pn_date_value): if isinstance(pn_date_value, datetime.date): # si on a choisi le widget DatePicker date = pn_date_value else: date = datetime.datetime( 1950, 1, 1) + datetime.timedelta(days=int(pn_date_value)) ds = background_func(date) info = ds.Grid_0001.units if hasattr(ds.Grid_0001, "units") else "" return gv.Image( (ds.lon, ds.lat, ds.Grid_0001.T), kdims=["lon", "lat"], vdims=[ds.Grid_0001.long_name], ).opts(responsive=True, tools=["hover"], clabel=info) if dynamic: fond = regrid(hv.DynamicMap(update_fond)).opts(height=500, responsive=True) else: fond = hv.DynamicMap(update_fond).opts(responsive=True) if tiles is not None: visu = gv.Overlay([ tiles, fond, gv.DynamicMap(update_all), ]).collate() else: visu = gv.Overlay([ fond, gv.feature.land(scale="50m").opts( responsive=True, line_color="black", fill_color="darkgray"), # , data_aspect=0.7), gv.DynamicMap(update_all), ]).collate() return pn.Column(widget_date, visu, sizing_mode="stretch_both", min_height=600, min_width=400) else: if tiles is not None: visu = gv.Overlay([tiles, gv.DynamicMap(update_all)]).collate() else: visu = gv.Overlay([ gv.feature.land(scale="50m").opts( responsive=True, line_color="black", fill_color="darkgray", data_aspect=1, ), gv.DynamicMap(update_all), ]).collate() return pn.Column(widget_date, visu, sizing_mode="stretch_both", min_height=600, min_width=400)
print("time %s, p %s" % (time, p)) data = dataset[p][3] if not sea_data: data = data[0] img = gv.operation.project_image(gv.Image(data)) return img # image_stack = hv.DynamicMap(load_image, kdims=['time', 'p'], streams=[Param()]) #plot = regrid(image_stack)# * gf.coastline(plot=dict(scale='10m')) #.redim.range(time=(0,3)) gf.coastline.set_param("extents", (90, -18, 154, 30)) coastline = gf.coastline(plot=dict(scale='50m')) #regridded_map = regrid(load_image(0, params[0])) data_map = hv.DynamicMap(load_image, streams=[Param()]) regridded_map = regrid(data_map) print("coastline: %s, regridded_map %s" % (coastline, regridded_map)) plot = regridded_map * coastline print("plot: %s" % (plot)) print(plot.id) def select_param(param=params[0]): data_map.event(p=param) def select_param_handler(index): select_param(params[index])
def test_regrid_mean(self): img = Image((range(10), range(5), np.arange(10) * np.arange(5)[np.newaxis].T)) regridded = regrid(img, width=2, height=2, dynamic=False) expected = Image(([2., 7.], [0.75, 3.25], [[1, 5], [6, 22]])) self.assertEqual(regridded, expected)
def create_doc(doc, data_dir): def get_spectrogram(s0=None, s1=None, size=1024, overlap=1. / 8, zfill=1, mode='psd'): s_size = np.dtype(np.complex64).itemsize if s1 is None and s0 is None: ds = None elif s1 is None: ds = None elif s0 is None: ds = np.abs(s1) else: ds = np.abs(s1 - s0) if ds is not None and s0 is not None: flen = getsize(join(data_dir, file)) print("file size: {} bytes".format(flen)) if (ds + s0) * s_size > flen: ds = flen - s0 * s_size samples = np.memmap(join(data_dir, file), dtype='complex64', mode='r', offset=s0 * s_size, shape=(ds, ) if ds else None) if ds is None: ds = len(samples) if ds / size > (res + 0.5) * height: noverlap = -int(float(size) * float(ds) / size / height / res) else: noverlap = size // (1. / overlap) f, t, S = signal.spectrogram(samples, samp_rate, nperseg=size, nfft=int( next_power_of_2(size) * int(zfill)), noverlap=noverlap, return_onesided=False, scaling='density', mode=mode) # f = fftshift(f) S = fftshift(S, axes=(0, )) if mode == 'psd': S = 10 * np.log10(S) return f, t, S, samples def get_spectrogram_img(z_min, z_max, tf_r, zfill, overlap, show_realfreq, freq_unit, x_range, y_range): lock.acquire() show_realfreq = bool(show_realfreq) hv_image = None try: print("y_range:", y_range, type(y_range)) if type(y_range[0]) != float: if np.issubdtype(y_range[0], np.datetime64) and time is not None: y_range = [ (y - np.datetime64(time) ).astype('timedelta64[us]').astype('float') / 1e6 for y in y_range ] #elif np.issubdtype(y0, np.timedelta64): # y0, y1 = [y.astype('timedelta64[s]').astype('float') for y in [y0,y1]] # tranform back to relative frequency if required print(doc.session_context.show_realfreq, x_range) last_freq_unit = doc.session_context.freq_unit x_range = [x * freq_units_names[last_freq_unit] for x in x_range] if doc.session_context.show_realfreq: x_range = [(x - freq) for x in x_range] print(doc.session_context.show_realfreq, "after transform", x_range) (x0, x1), (y0, y1) = x_range, y_range #print("y0 dtype:", y0.dtype) s0, s1 = sorted([ min(max(int(yr * samp_rate), 0), total_samples) for yr in [y0, y1] ]) scale = samp_rate / np.abs(x_range[1] - x_range[0]) size = int(width * scale) # required freq resolution to fulfill zoom level ds = np.abs( s1 - s0) # number of samples covered at the current zoom level if ds / size < height: size = int(np.sqrt(ds * scale * 10**tf_r)) f, t, S, samples = get_spectrogram( s0, s1, size=size, overlap=overlap, mode=mode, zfill=zfill if size < res * width else 1) t += max(min(y0, y1), 0) f_range = (x0 <= f) & (f <= x1) image = S[f_range, :] f = f[f_range] #if ds / size > height: # image = signal.resample(image, height*2, axis=0) print(image.shape) if intp_enabled: ratio = np.array(image.shape, dtype=np.float) / np.array( (height * res, width * res)) if np.min(ratio) < 1: scale = np.max( np.abs(image) ) # normalization factor for image because rescale needs that image = rescale(image / scale, 1. / np.min(ratio), order=1) * scale f = signal.resample(f, image.shape[0]) t = signal.resample(t, image.shape[1]) print("after resampling: ", image.shape) del samples #image = hv.Image(image, bounds=(x0, y0, x1, y1)).redim.range(z=(z_min, z_max)) # TODO get exact values in bounds if show_realtime and time is not None: t = np.datetime64(time) + np.array( t * 1e6).astype('timedelta64[us]') #else: # t = (t*1e6) #.astype('timedelta64[us]') if show_realfreq: f += freq f /= freq_units_names[freq_unit] #image = image.astype('float16') # trying to reduce network bandwidth... print("image dtype:", image.dtype) #hv_image = hv.Image(np.flip(image, axis=1), bounds=(min(f), max(t), max(f), min(t))) \ hv_image = hv.Image(xr.DataArray(image, coords=[f,t], dims=['f','t'], name='z'), ['f','t'], 'z') \ .options( xlabel="Frequency [{}]".format(freq_unit), ylabel="Time " + '[s]' if not show_realtime else '') \ .redim.range(z=(z_min, z_max)) if doc.session_context.show_realfreq != show_realfreq or doc.session_context.freq_unit != freq_unit: hv_image = hv_image \ .redim.range(f=(min(f), max(f))) \ .redim.range(t=(min(t), max(t))) print("redimming axis range") doc.session_context.show_realfreq = show_realfreq doc.session_context.freq_unit = freq_unit except Exception as e: print("Exception in image generation:", e) print(traceback.format_exc()) lock.release() return hv_image def get_param(name, default, t=str): try: args = doc.session_context.request.arguments if t == str: p = str(args.get(name)[0], 'utf-8') else: p = t(args.get(name)[0]) except: p = default return p time = None freq = 0 file = basename(get_param('file', '', str)) skip = get_param('skip', 0, int) keep = get_param('keep', None, int) # low resolution for raspberry width, height = get_param('width', 600, int), get_param('height', 500, int) res = get_param('res', 1.5, float) ds_enabled = get_param('ds', None, str) # datashade option (default: avg) intp_enabled = get_param('intp', 0, int) # interpolation enable flap show_realtime = bool(get_param('rt', 0, int)) # show real time on vertical axis mode = get_param('mode', 'psd', str) t_range = get_param('t', None, str) f_range = get_param('f', None, str) if t_range is not None: try: parts = t_range.split(",") if len(parts) == 2: t_range = list(map(float, parts)) except: pass if f_range is not None: try: parts = f_range.split(",") if len(parts) == 2: f_range = list(map(float, parts)) elif len(parts) == 1: _f = abs(float(parts[0])) f_range = (-_f, _f) except: pass if file.endswith(".meta"): config = ConfigParser() config.read(join(data_dir, file)) file = splitext(file)[0] + ".raw" samp_rate = int(config['main']['samp_rate']) freq = float(config['main']['freq']) time = datetime.fromtimestamp(float(config['main']['time'])) else: samp_rate = get_param('samp_rate', 128000, int) f, t, S, samples = get_spectrogram(s0=skip * samp_rate, s1=keep * samp_rate if keep else None, size=width, mode=mode) total_samples = len(samples) del samples # default is True if show_realtime and time is not None: t = np.datetime64(time) + np.array(t).astype('timedelta64[s]') doc.session_context.show_realfreq = False doc.session_context.freq_unit = freq_units[1000] range_stream = RangeXY(x_range=tuple( x / freq_units_names[doc.session_context.freq_unit] for x in ((min(f_range), max(f_range)) if f_range else (min(f), max(f)))), y_range=(max(t_range), min(t_range)) if t_range else (max(t), min(t))) # transient=True z_range = (np.min(S), np.max(S)) z_init = np.percentile(S, (50, 100)) dmap = hv.DynamicMap( get_spectrogram_img, streams=[range_stream], kdims=[ hv.Dimension('z_min', range=z_range, default=z_init[0]), hv.Dimension('z_max', range=z_range, default=z_init[1]), hv.Dimension('tf_r', label='Time-Frequency pixel ratio', range=(-10., 10.), default=0.), hv.Dimension('zfill', label='Zero-filling factor', range=(1, 10), default=2), hv.Dimension('overlap', label='Overlap factor', range=(-1., 1.), default=1. / 8), #hv.Dimension('show_realtime', label='Show real time on vertical axis', range=(0,1), default=0), hv.Dimension('show_realfreq', label='Show real frequency', range=(0, 1), default=int(doc.session_context.show_realfreq)), hv.Dimension('freq_unit', label='Frequency unit', values=list( map(lambda x: freq_units[x], sorted(freq_units.keys()))), default=doc.session_context.freq_unit), #hv.Dimension('mode', label='Spectrogram mode', values=['psd', 'angle', 'phase', 'magnitude'], default='psd') ]).options( framewise=True, # ??? ) #.redim.range(z=z_init) #dmap = dmap.opts(opts.Image(height=height, width=width)) if ds_enabled != None: print("datashade enabled: yes") if ds_enabled == "" or ds_enabled == "mean": ds_enabled = dsr.mean elif ds_enabled == "max": ds_enabled = dsr.max else: print( "warning: invalid option for datashade. using default value: mean" ) ds_enabled = dsr.mean dmap = regrid(dmap, aggregator=ds_enabled, interpolation='linear', upsample=True, height=height * 2, width=width * 2) # aggregation=dsr.max #dmap = dmap.hist(num_bins=150, normed=False) dmap = dmap.opts( opts.Image( cmap='viridis', framewise=True, colorbar=True, height=height, width=width, tools=['hover'], title='{}, {} {} sps'.format( time.strftime('%Y-%m-%d %H:%M:%S') if time else 'Time unknown', format_freq(freq), samp_rate)), opts.Histogram(framewise=False, width=150)) #plot = renderer.get_plot(hist, doc).state #widget = renderer.get_widget(hist, None, position='right').state #hvobj = layout([plot, widget]) #plot = layout([renderer.get_plot(hist, doc).state]) #doc.add_root(plot) doc = renderer.server_doc(dmap, doc=doc) doc.title = 'Waterfall Viewer'
def test_regrid_max(self): img = Image((range(10), range(5), np.arange(10) * np.arange(5)[np.newaxis].T)) regridded = regrid(img, aggregator='max', width=2, height=2, dynamic=False) expected = Image(([2., 7.], [0.75, 3.25], [[8, 18], [16, 36]])) self.assertEqual(regridded, expected)
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) self.assertEqual(regridded, img)
def test_rasterize_image_string_aggregator(self): img = Image((range(10), range(5), np.arange(10) * np.arange(5)[np.newaxis].T)) regridded = regrid(img, width=2, height=2, dynamic=False, aggregator='mean') expected = Image(([2., 7.], [0.75, 3.25], [[1, 5], [6, 22]])) self.assertEqual(regridded, expected)