def _set_aspect_ratio(self, elem): # hack to avoid bug with rasterize + invert_yaxis + aspect='equal' # manually set data_aspect=1 options = elem.opts.get().options frame_w = options.get('frame_width', None) frame_h = options.get('frame_height', None) if frame_w and frame_h: # already set return elem wstart, wstop = elem.dimension_values(0, expanded=False)[[0, -1]] hstart, hstop = elem.dimension_values(1, expanded=False)[[0, -1]] w = wstop - wstart h = hstop - hstart if frame_w: return elem.opts( opts.Image(frame_height=int(round(frame_w / w * h)))) elif frame_h: return elem.opts( opts.Image(frame_width=int(round(frame_h / h * w)))) else: return elem
def swatch(name, bounds=None, array=array, aspect=10, **kwargs): """Show swatch using matplotlib or bokeh via holoviews""" if bounds is None: bounds = (0, 0, 256, 1) plot = hv.Image(array, bounds=bounds, group=name) backends = hv.Store.loaded_backends() if 'bokeh' in backends: frame_height = kwargs.pop('frame_height', 60) plot.opts(opts.Image(backend='bokeh', aspect=aspect, frame_height=frame_height, toolbar='above', default_tools=['xwheel_zoom', 'xpan', 'save', 'reset'], cmap=palette[name])) if 'matplotlib' in backends: def hook(plot, element): plot.handles['axis'].axis('off') plot.handles['axis'].set_title("sample", loc='left', fontfamily='DejaVu Sans', fontsize=14, fontweight='roman',fontstretch='semi-expanded') fig_size = kwargs.pop('fig_size', 300) plot.opts(opts.Image(backend='matplotlib', aspect=aspect, fig_size=fig_size, title="", cmap=cm[name], hooks=[hook])) return plot.opts(opts.Image(xaxis=None, yaxis=None), opts.Image(**kwargs))
def swatch(name, cmap=None, bounds=None, array=array, **kwargs): """Show swatch using matplotlib or bokeh via holoviews""" title = name if cmap else get_aliases(name) if bounds is None: bounds = (0, 0, 256, 1) cmap = list(cmap) if cmap is not None else None plot = hv.Image(array, bounds=bounds, group=title) backends = hv.Store.loaded_backends() if 'bokeh' in backends: width = kwargs.pop('width', 900) height = kwargs.pop('height', 100) plot.opts( opts.Image(backend='bokeh', width=width, height=height, toolbar='above', default_tools=['xwheel_zoom', 'xpan', 'save', 'reset'], cmap=cmap or palette[name])) if 'matplotlib' in backends: aspect = kwargs.pop('aspect', 15) fig_size = kwargs.pop('fig_size', 350) plot.opts( opts.Image(backend='matplotlib', aspect=aspect, fig_size=fig_size, cmap=cmap or cm[name])) return plot.opts(opts.Image(xaxis=None, yaxis=None), opts.Image(**kwargs))
def test_plot_options_object_list(self): im = Image(np.random.rand(10,10)) imopts1 = opts.Image(interpolation='nearest') imopts2 = opts.Image(cmap='summer') styled_im = im.options([imopts1,imopts2]) self.assertEqual(self.lookup_options(im, 'plot').options, {}) self.assertEqual(self.lookup_options(styled_im, 'style').options, dict(cmap='summer', interpolation='nearest'))
def sine_comb(name, cmap=None, **kwargs): """Show sine_comb using matplotlib or bokeh via holoviews""" title = name if cmap else get_aliases(name) plot = hv.Image(sine, group=title) backends = hv.Store.loaded_backends() if 'bokeh' in backends: plot.opts(opts.Image(backend='bokeh', width=400, height=150, toolbar='above', cmap=cmap or palette[name])) if 'matplotlib' in backends: plot.opts(opts.Image(backend='matplotlib', aspect=3, fig_size=200, cmap=cmap or cm[name])) return plot.opts(opts.Image(xaxis=None, yaxis=None), opts.Image(**kwargs))
def panel(self, dmaps): xy, zy, xz = dmaps self._update_dynamic_values(xy, zy, xz) zy.opts( opts.Image(frame_width=self.frame_z_size, frame_height=self.frame_y_size), opts.RGB(frame_width=self.frame_z_size, frame_height=self.frame_y_size), ) if self.add_crosshairs: self.get_crosshair() panel_xy = self.z_viewer.panel( (xy * self.xy_h * self.xy_v).relabel(group='orthoview')) panel_zy = self.x_viewer.panel( (zy * self.zy_h * self.zy_v).relabel(group='orthoview')) panel_xz = self.y_viewer.panel( (xz * self.xz_h * self.xz_v).relabel(group='orthoview')) else: panel_xy = self.z_viewer.panel(xy.relabel(group='orthoview')) panel_zy = self.x_viewer.panel(zy.relabel(group='orthoview')) panel_xz = self.y_viewer.panel(xz.relabel(group='orthoview')) self._link_crosshairs() return pn.Column(pn.Row(panel_xy, panel_zy), pn.Row(panel_xz, self.param.navigaton_on))
def grid_plot( self, step: int, cmap: Optional[Tuple] = None, opts_list: Optional[opts.Image] = None, ): """ Plot the incoming data. Graphical 2D-representation of the given (heigt x width) array. Each site represents an individual speaking either language A, language B, or language AB (bilinguals). Args: step: Integer value representing the iteration step during the grid evolution. cmap: N-Dimensional tuple containing the color palette used to represent the different languages. opts_list: Optional argument. opts.Image list specifying a custom option list. Returns: The functions returns a holoviews image describing the lattice, where each node is represented by the language it speaks. """ data = self.memory[step] opts_list = opts_list if opts_list else opts.Image(**self.return_plot_options(cmap)) return super(MinettWang, self).grid_plot(data=data, plot_option_list=opts_list)
def test_plot_options_one_object(self): im = Image(np.random.rand(10,10)) imopts = opts.Image(interpolation='nearest', cmap='jet') styled_im = im.options(imopts) self.assertEqual(self.lookup_options(im, 'plot').options, {}) self.assertEqual(self.lookup_options(styled_im, 'style').options, dict(cmap='jet', interpolation='nearest'))
def __post_init__(self): """ :return: """ data = self.spectral_cube.data self.ds = hv.Dataset((np.arange(data.shape[2]), np.arange( data.shape[1]), np.arange(data.shape[0]), data), [self.spectral_axis_name, 'x', 'y'], 'Cube') # maybe PolyEdit as well # polys = hv.Polygons([hv.Box(int(self.image_width / 2), int(self.image_height / 2), int(self.image_height / 2))]) # self.box_stream = streams.PolyEdit(source=polys) polys = hv.Polygons([]) self.box_stream = streams.BoxEdit(source=polys) hlines = hv.HoloMap({i: hv.VLine(i) for i in range(data.shape[2])}, 'wavelengths') dmap = hv.DynamicMap(self.roi_curves, streams=[self.box_stream]) im = self.ds.to(hv.Image, ['x', 'y'], dynamic=True) self.layout = (im * polys + dmap * hlines).opts( opts.Image(cmap=self.color_map, width=self.image_width, height=self.image_height), opts.Curve(width=650, height=450, framewise=True), opts.Polygons(fill_alpha=0.2, line_color='white'), opts.VLine(color='black'))
def test_opts_method_with_utility(self): im = Image(np.random.rand(10,10)) imopts = opts.Image(cmap='Blues') styled_im = im.opts(imopts) assert styled_im is im self.assertEqual(self.lookup_options(im, 'style').options, {'cmap': 'Blues', 'interpolation': 'nearest'})
def swatch(name, cmap=None, bounds=None, array=array, **kwargs): """Show a color swatch for a colormap using matplotlib or bokeh via holoviews. Colormaps can be selected by `name`, including those in Colorcet along with any standard Bokeh palette or named Matplotlib colormap. Custom colormaps can be visualized by passing an explicit list of colors (for Bokeh) or the colormap object (for Matplotlib) to `cmap`. HoloViews options for either backend can be passed in as kwargs, so that you can customize the width, height, etc. of the swatch. The `bounds` and `array` arguments allow you to customize the portion of the colormap to show and how many samples to take from it; see the source code and hv.Image documentation for details. """ title = name if cmap else get_aliases(name) if bounds is None: bounds = (0, 0, 256, 1) if type(cmap) is tuple: cmap = list(cmap) plot = hv.Image(array, bounds=bounds, group=title) backends = hv.Store.loaded_backends() if 'bokeh' in backends: width = kwargs.pop('width', 900) height = kwargs.pop('height', 100) plot.opts( opts.Image(backend='bokeh', width=width, height=height, toolbar='above', default_tools=['xwheel_zoom', 'xpan', 'save', 'reset'], cmap=cmap or palette[name])) if 'matplotlib' in backends: aspect = kwargs.pop('aspect', 15) fig_size = kwargs.pop('fig_size', 350) plot.opts( opts.Image(backend='matplotlib', aspect=aspect, fig_size=fig_size, cmap=cmap or cm[name])) return plot.opts(opts.Image(xaxis=None, yaxis=None), opts.Image(**kwargs))
def _plot_overlay(elevation, shadows): ''' ''' shadows = hv.Dataset( (np.arange(shadows.shape[2]), np.arange( shadows.shape[0]), np.arange(shadows.shape[1]), shadows), ['Time', 'x', 'y'], 'Shadows') elevation = hv.Dataset((np.arange( elevation.shape[0]), np.arange(elevation.shape[1]), elevation), ['x', 'y'], 'Elevation') opts.defaults( opts.Image('elevation', cmap='viridis', invert_yaxis=True), opts.Image('shadows', cmap='binary', invert_yaxis=True, alpha=0.7), opts.Overlay(show_legend=False)) elevation = elevation.to(hv.Image, ['x', 'y'], group='elevation') shadows = shadows.to(hv.Image, ['x', 'y'], group='shadows') return elevation * shadows
def __init__(self, adh_mod, **params): super(InterpolateMesh, self).__init__(adh_mod=adh_mod, **params) # set defaults for initialized example self.display_range.param.color_range.bounds = (10, 90) self.display_range.color_range = (10, 90) self.cmap_opts.colormap = cc.rainbow self.scatter_projection.set_crs(ccrs.GOOGLE_MERCATOR) self.adh_mod.wmts.source = gv.tile_sources.EsriImagery # print(self.projection.param.UTM_zone_hemi.constant, self.projection.crs_label) self.opts = (opts.Curve(height=self.map_height, width=self.map_width, xaxis=None, line_width=1.50, color='red', tools=['hover']), opts.Path(height=self.map_height, width=self.map_width, line_width=3, color='black'), opts.Image(height=self.map_height, width=self.map_width, cmap=self.cmap_opts.param.colormap, clim=self.display_range.param.color_range, colorbar=True, clipping_colors={ 'NaN': 'transparent', 'min': 'transparent' }, axiswise=True), opts.RGB(height=self.map_height, width=self.map_width), opts.Points(height=self.map_height, width=self.map_width, color_index='z', cmap=self.cmap_opts.param.colormap, clim=self.display_range.param.color_range, size=10, tools=['hover'], padding=(0.1, 0.1), colorbar=True), opts.TriMesh(height=self.map_height, width=self.map_width, color_index='z', cmap=self.cmap_opts.param.colormap, clim=self.display_range.param.color_range, tools=['hover'], padding=(0.1, 0.1), colorbar=True), opts.VLine(color='black'))
def view(self): data = self.data xmin, xmax = np.min(data), np.max(data) x1_dim = hv.Dimension('x₁', range=(xmin, xmax)) x2_dim = hv.Dimension('x₂', range=(xmin, xmax)) samples_map = self.maps["samples"] samples_map = samples_map.opts(width=600, height=350, show_grid=True, padding=(0, 0.1), toolbar=None) samples_map = samples_map.opts(opts.Path(color=blue, framewise=True)) samples_map = samples_map.redim.label(y="f(x)", x="x") control_vline_map = self.maps["vlines_control"] control_vline_map = control_vline_map.redim(x=x1_dim, y=x2_dim) control_vline_map = control_vline_map.opts(show_grid=True) control_vline_map = control_vline_map.opts( opts.HLine(line_width=2), opts.VLine(line_width=2), opts.Points(color="white", marker="s", size=8), opts.Image(cmap="viridis")) vlines_map = self.maps["vlines"] vlines_map = vlines_map.opts(toolbar=None) vlines_map = vlines_map.opts(opts.VLine(line_width=2), opts.Points(size=6)) scatter_map = self.maps["scatter"] scatter_map = scatter_map.redim.label(y="f(x₂)", x="f(x₁)") scatter_map = scatter_map.opts(padding=(0.5, 0.5), show_grid=True, toolbar=None) scatter_map = scatter_map.opts( opts.Scatter(size=7, framewise=True, fill_color=orange1, line_color=orange2)) title = pn.pane.Markdown("## GP samples visualization", max_height=25) descr = pn.pane.Markdown( "_For moving x₁ and x₂ bars: 1. turn off **pan** tool, 2. click and move the orange squared point on the covariance matrix_" ) row0 = pn.Row(pn.Spacer(width=25), self.kernels_controller.view()) row1 = samples_map * vlines_map row2 = pn.Row(control_vline_map, scatter_map) return pn.Column(title, descr, row0, row1, row2)
def __post_init__(self): """ :return: """ self._pca_transform() (shape_x, shape_y, n_component) = self.scores_cube.shape self.ds = hv.Dataset((np.arange(n_component), np.arange(shape_y), np.arange(shape_x), self.scores_cube), ['Principal Component', 'x', 'y'], 'Cube') im = self.ds.to(hv.Image, ['x', 'y'], dynamic=True) self.layout = im.opts( opts.Image(cmap=self.color_map, width=self.image_width, height=self.image_height))
def view_map(self): # print('view_map method') if self.adh_mod.mesh.elevation_toggle: elevation = rasterize(self.adh_mod.mesh.tri_mesh, aggregator=ds.mean('z'), precompute=True).apply.opts( opts.Image( cmap=self.cmap_opts.colormap, clim=self.display_range.color_range, height=self.map_height, width=self.map_width)) else: elevation = Curve([]).opts(height=self.map_height, width=self.map_width) # return self.adh_mod.mesh.view_bathy() * self.adh_mod.mesh.view_elements(line_color='yellow') * base_map * self.view_scatter() return elevation * self.adh_mod.mesh.view_elements( line_color='yellow') * hv.DynamicMap( self.adh_mod.wmts.view) * self.view_scatter()
# In[ ] import holoviews as hv, datashader as ds from holoviews import opts import dask.dataframe as dd from holoviews.operation.datashader import rasterize hv.extension('bokeh') # In[ ] path = './nyc_taxi_wide.parq' df = dd.read_parquet(path).persist() points = hv.Points(df, ['dropoff_x', 'dropoff_y'], ['dropoff_hour', 'pickup_hour']) # In[ ] options = opts.Image(data_aspect=1, responsive=True, logz=True, tools=['hover'], colorbar=True) rasterize(points).options(options) # In[ ] import panel panel.panel(rasterize(points).options(options))
# -*- coding: utf-8 -*- """Tools to work with images. """ import circle_fit as cf import holoviews as hv import numpy as np import pandas as pd from astropy.io import fits from holoviews import opts from skimage.exposure import equalize_adapthist as equalize from skimage.exposure import rescale_intensity hv.extension("bokeh") opts.defaults( opts.Image(tools=["hover"], cmap="gray"), opts.Points(color="red", marker="x", size=20), ) class Image: def __init__(self, path): self.path = path self.data, self.header = fits.getdata(path, header=True) @property def name(self): return self.path.name @property def wavelength(self): return self.header["FILTER"]
import panel as pn from skimage.exposure import rescale_intensity from holoviews import opts from holoviews.operation.datashader import rasterize from inter_view.color import available_cmaps from inter_view.utils import blend_overlay # defines default options for all viewers opts.defaults( opts.Image('channel', frame_width=600, invert_yaxis=True, xaxis='bare', yaxis='bare', bgcolor='black', active_tools=['pan', 'wheel_zoom'], show_title=False), opts.RGB('composite', frame_width=600, invert_yaxis=True, xaxis='bare', yaxis='bare', bgcolor='black', active_tools=['pan', 'wheel_zoom'], show_title=False), opts.HLine('orthoview', line_dash='dashed', line_width=1, line_color='white'),
def _plot(self) -> pn.panel: """ Represent the initial and final state of the lattice. Graphical representation of the lattice. The image shows the initial and final state of the grid (in order to compare how the network has evolved), as well as the number of speakers as a function of time. self.track = True is needed to call this method. """ grid_flat = self.memory.reshape(self.memory.shape[0], -1) speakers_a = (grid_flat == 1).sum(1) speakers_b = (grid_flat == -1).sum(1) speakers_ab = (grid_flat == 0).sum(1) total = speakers_a + speakers_b + speakers_ab == (self.width * self.height) * np.ones( len(self.memory), ) if not np.all(total): raise ValueError( "The total number of speakers does not correspond to the lattice size!", ) # Plots colors = ["navy", "white", "red"] data_start = self.memory[0] data_end = self.grid.data grid_start = { "xdata": np.arange(1, data_start.shape[1] + 1), "ydata": np.arange(1, data_start.shape[0] + 1), "zdata": data_start, } grid_end = { "xdata": np.arange(1, data_end.shape[1] + 1), "ydata": np.arange(1, data_end.shape[0] + 1), "zdata": data_end, } plot_start = hv.Image( grid_start, kdims=["xdata", "ydata"], vdims=hv.Dimension("zdata", range=(-1, 1)), label="Initial grid", ) plot_end = hv.Image( grid_end, kdims=["xdata", "ydata"], vdims=hv.Dimension("zdata", range=(-1, 1)), label="Final grid", ) plot_curvea = hv.Curve(speakers_a, label="Speakers A").opts(color="red") plot_curveb = hv.Curve(speakers_b, label="Speakers B").opts(color="navy") plot_curveab = hv.Curve(speakers_ab, label="Speakers AB").opts(color="gray") # Compositions grids = plot_start + plot_end lines = plot_curvea * plot_curveb * plot_curveab layout = grids + lines # Options layout.opts( opts.Image( invert_yaxis=True, cmap=colors, colorbar=True, width=350, labelled=[], colorbar_opts={ "title": "Languages", "title_text_align": "left", "major_label_overrides": {-1: "B", 0: "AB", 1: "A"}, "ticker": FixedTicker(ticks=[-1, 0, 1]), "major_label_text_align": "right", }, ), opts.Curve(xlabel="Iterations", ylabel="Number of speakers", width=700), ) return display(pn.Column(pn.Row(plot_start, plot_end), lines))
def plot_cubes(cube, mode='slider', backend='matplotlib', dpi=100, figtype='png', vmin=None, vmax=None, size=100, width=360, height=360, cmap=None, colorbar=True, dynamic=True, anim_path=None, data_step_range=None, label=None, label_step_range=None, delay=50, anim_format='gif', delete_anim_cache=True, **kwargs): """ Plot multi-dimensional high-contrast imaging datacubes (3d and 4d ``numpy`` arrays). It allows to visualize in-memory ``numpy`` arrays on ``Jupyterlab`` by leveraging the ``HoloViews`` library. It can also generate and save animations from a 3d ``numpy`` array with ``matplotlib``. Parameters ---------- cube : np.ndarray Input 3d or 4d cube. mode : {'slider', 'animation'}, str optional Whether to plot the 3d array as a widget with a slider or to save an animation of the 3d array. The animation is saved to disk using ImageMagick's convert command (it must be installed otherwise a ``FileNotFoundError`` will be raised). backend : {'matplotlib', 'bokeh'}, str optional Selects the backend used to display the plots. ``Bokeh`` plots are interactive, allowing the used to zoom, pan, inspect pixel values, etc. ``Matplotlib`` can lead to some flickering when using the slider and ``dynamic`` is True. dpi : int, optional [backend='matplotlib'] The rendered dpi of the figure. figtype : {'png', 'svg'}, str optional [backend='matplotlib'] Type of output. vmin : None, float or int, optional For defining the data range that the colormap covers. When set to None, the colormap covers the complete value range of the supplied data. vmax : None, float or int, optional For defining the data range that the colormap covers. When set to None, the colormap covers the complete value range of the supplied data. size : int, optional [backend='matplotlib'] Sets the size of the plot. width : int, optional [backend='bokeh'] Sets the width of the plot. height : int, optional [backend='bokeh'] Sets the height of the plot. cmap : None or str, optional Colormap. When None, the value of the global variable ``default_cmap`` will be used. colorbar : bool, optional If True, a colorbar is shown. dynamic : bool, optional [mode='slider'] When False, a ``HoloViews.HoloMap`` is created (slower and will take up a lot of RAM for large datasets). If True, a ``HoloViews.DynamicMap`` is created instead. anim_path : str, optional [mode='animation'] The animation path/filename. If None then the animation will be called ``animation``.``anim_format`` and will be saved in the current directory. data_step_range : tuple, optional [mode='animation'] Tuple of 1, 2 or 3 values that creates a range for slicing the ``data`` cube. label : str, optional [mode='animation'] Label to be overlaid on top of each frame of the animation. If None, then ``frame <#>`` will be used. label_step_range : tuple, optional [mode='animation'] Tuple of 1, 2 or 3 values that creates a range for customizing the label overlaid on top of each frame of the animation. delay : int, optional [mode='animation'] Delay for displaying the frames in the animation sequence. anim_format : str, optional [mode='animation'] Format of the saved animation. By default 'gif' is used. Other formats supported by ImageMagick are valid, such as 'mp4'. delete_anim_cache : str, optional [mode='animation'] If True, the cache folder is deleted once the animation file is saved to disk. **kwargs : dictionary, optional [mode='animation'] Arguments to be passed to ``plot_frames`` to customize each frame of the animation (adding markers, using a log scale, etc). Notes ----- http://holoviews.org/getting_started/Gridded_Datasets.html http://holoviews.org/user_guide/Gridded_Datasets.html http://holoviews.org/user_guide/Applying_Customizations.html """ hv.extension(backend) if not isinstance(cube, np.ndarray): raise TypeError('`cube` must be a numpy.ndarray') if cmap is None: cmap = default_cmap if mode == 'slider': if cube.ndim not in (3, 4): raise ValueError('`cube` must be a 3 or 4 array when `mode` set to ' 'slider') if cube.ndim == 3: # Dataset((X, Y, Z), Data), where # X is a 1D array of shape M , # Y is a 1D array of shape N and # Z is a 1D array of shape O # Data is a ND array of shape NxMxO ds = hv.Dataset((range(cube.shape[2]), range(cube.shape[1]), range(cube.shape[0]), cube), ['x', 'y', 'time'], 'flux') max_frames = cube.shape[0] elif cube.ndim == 4: # adding a lambda dimension ds = hv.Dataset((range(cube.shape[3]), range(cube.shape[2]), range(cube.shape[1]), range(cube.shape[0]), cube), ['x', 'y', 'time', 'lambda'], 'flux') max_frames = cube.shape[0] * cube.shape[1] # Matplotlib takes None but not Bokeh. We take global min & max instead if vmin is None: vmin = cube.min() if vmax is None: vmax = cube.max() print(ds) print(":Cube_shape\t{}".format(list(cube.shape[::-1]))) # not working for bokeh: dpi image_stack = ds.to(hv.Image, kdims=['x', 'y'], dynamic=dynamic) hv.output(backend=backend, size=size, dpi=dpi, fig=figtype, max_frames=max_frames) if backend == 'matplotlib': # keywords in the currently active 'matplotlib' renderer are: # 'alpha', 'clims', 'cmap', 'filterrad', 'interpolation', 'norm', # 'visible' #options = "Image (cmap='" + cmap + "', interpolation='nearest'," #options += " clims=("+str(vmin)+','+str(vmax)+")"+")" #opts(options, image_stack) return image_stack.opts(opts.Image(colorbar=colorbar, cmap=cmap, clim=(vmin, vmax))) # hv.save(image_stack, 'holomap.gif', fps=5) elif backend == 'bokeh': #options = "Image (cmap='" + cmap + "')" #opts(options, image_stack) # Compensating the width to accommodate the colorbar if colorbar: cb_wid = 15 cb_pad = 3 tick_len = len(str(int(cube.max()))) if tick_len < 4: cb_tick = 25 elif tick_len == 4: cb_tick = 35 elif tick_len > 4: cb_tick = 45 width_ = width + cb_pad + cb_wid + cb_tick else: width_ = width return image_stack.opts(opts.Image(colorbar=colorbar, colorbar_opts={'width': 15, 'padding': 3}, width=width_, height=height, clim=(vmin, vmax), cmap=cmap, tools=['hover'])) elif mode == 'animation': if cube.ndim != 3: raise ValueError('`cube` must be a 3 array when `mode` set to ' 'animation') if backend == 'bokeh': print('Creating animations works with the matplotlib backend') dir_path = './animation_temp/' if anim_path is None: anim_path = './animation' if data_step_range is None: data_step_range = range(0, cube.shape[0], 1) else: if not isinstance(data_step_range, tuple): msg = '`data_step_range` must be a tuple with 1, 2 or 3 values' raise ValueError(msg) if len(data_step_range) == 1: data_step_range = range(data_step_range) elif len(data_step_range) == 2: data_step_range = range(data_step_range[0], data_step_range[1]) elif len(data_step_range) == 3: data_step_range = range(data_step_range[0], data_step_range[1], data_step_range[2]) if label_step_range is None: label_step_range = data_step_range else: if not isinstance(label_step_range, tuple): msg = '`label_step_range` must be a tuple with 1, 2 or 3 values' raise ValueError(msg) if len(label_step_range) == 1: label_step_range = range(label_step_range) elif len(label_step_range) == 2: label_step_range = range(label_step_range[0], label_step_range[1]) elif len(label_step_range) == 3: label_step_range = range(label_step_range[0], label_step_range[1], label_step_range[2]) if os.path.exists(dir_path): shutil.rmtree(dir_path) print('Replacing ' + dir_path) os.mkdir(dir_path) print('Producing each animation frame...') for i, labstep in zip(data_step_range, list(label_step_range)): if label is None: label = 'frame ' savelabel = dir_path + label + str(i + 100) plot_frames(cube[i], backend='matplotlib', mode='mosaic', save=savelabel, dpi=dpi, vmin=vmin, vmax=vmax, colorbar=colorbar, cmap=cmap, label=[label + str(labstep + 1)], **kwargs) try: filename = anim_path + '.' + anim_format call(['convert', '-delay', str(delay), dir_path + '*.png', filename]) if os.path.exists(filename): print('Animation successfully saved to disk as ' + filename) if delete_anim_cache: shutil.rmtree(dir_path) print('Temp directory deleted ' + dir_path) except FileNotFoundError: print('ImageMagick `convert` command could not be found') else: raise ValueError("`mode` is not recognized")
def get_fractal(x_range, y_range): (x0, x1), (y0, y1) = x_range, y_range image = np.zeros((600, 600), dtype=np.uint8) return hv.Image(create_fractal(x0, x1, -y1, -y0, image, 200), bounds=(x0, y0, x1, y1)) # Define stream linked to axis XY-range range_stream = RangeXY(x_range=(-1., 1.), y_range=(-1., 1.)) # Create DynamicMap to compute fractal per zoom range and # adjoin a logarithmic histogram dmap = hv.DynamicMap(get_fractal, label='Manderbrot Explorer', streams=[range_stream]).hist(log=True) # Apply options dmap.opts( opts.Histogram(framewise=True, logy=True, width=200), opts.Image(cmap='fire', logz=True, height=600, width=600, xaxis=None, yaxis=None)) doc = renderer.server_doc(dmap) doc.title = 'Mandelbrot Explorer'
def __call__(self, dset, **params): self.p = ParamOverrides(self, params) if self.p.vdim is None: vdim = dset.vdims[0].name else: vdim = self.p.vdim ra_range = (ra0, ra1) = dset.range("ra") if self.p.ra_sampling: xsampling = (ra1 - ra0) / self.p.ra_sampling else: xsampling = None dec_range = (dec0, dec1) = dset.range("dec") if self.p.dec_sampling: ysampling = (dec1 - dec0) / self.p.dec_sampling else: ysampling = None if self.p.aggregator == "mean": aggregator = ds.mean(vdim) elif self.p.aggregator == "std": aggregator = ds.std(vdim) elif self.p.aggregator == "count": aggregator = ds.count() sky_range = RangeXY() if self.p.range_stream: def redim(dset, x_range, y_range): ranges = {} if x_range and all(isfinite(v) for v in x_range): ranges["ra"] = x_range if y_range and all(isfinite(v) for v in x_range): ranges["dec"] = y_range return dset.redim.range(**ranges) if ranges else dset dset = dset.apply(redim, streams=[self.p.range_stream]) link_streams(self.p.range_stream, sky_range) streams = [sky_range, PlotSize()] pts = dset.apply(skypoints, streams=[self.p.filter_stream]) reset = PlotReset(source=pts) reset.add_subscriber(partial(reset_stream, None, [self.p.range_stream])) rasterize_inst = rasterize.instance(aggregator=aggregator, streams=streams, x_sampling=xsampling, y_sampling=ysampling) raster_pts = apply_when( pts, operation=rasterize_inst, predicate=lambda pts: len(pts) > self.p.max_points) return raster_pts.opts( opts.Image( bgcolor="black", colorbar=True, cmap=self.p.cmap, min_height=100, responsive=True, tools=["hover"], symmetric=True, ), opts.Points( color=vdim, cmap=self.p.cmap, framewise=True, size=self.p.decimate_size, tools=["hover"], symmetric=True, ), opts.Overlay(hooks=[ partial(reset_hook, x_range=ra_range, y_range=dec_range) ]), )
def __call__(self, dset, **params): self.p = ParamOverrides(self, params) if self.p.xdim not in dset.dimensions(): raise ValueError("{} not in Dataset.".format(self.p.xdim)) if self.p.ydim not in dset.dimensions(): raise ValueError("{} not in Dataset.".format(self.p.ydim)) if ("ra" not in dset.dimensions()) or ("dec" not in dset.dimensions()): raise ValueError("ra and/or dec not in Dataset.") # Compute sampling ra_range = (ra0, ra1) = dset.range("ra") if self.p.ra_sampling: ra_sampling = (ra1 - ra0) / self.p.x_sampling else: ra_sampling = None dec_range = (dec0, dec1) = dset.range("dec") if self.p.dec_sampling: dec_sampling = (dec1 - dec0) / self.p.y_sampling else: dec_sampling = None x_range = (x0, x1) = dset.range(self.p.xdim) if self.p.x_sampling: x_sampling = (x1 - x0) / self.p.x_sampling else: x_sampling = None y_range = (y0, y1) = dset.range(self.p.ydim) if self.p.y_sampling: y_sampling = (y1 - y0) / self.p.y_sampling else: y_sampling = None # Set up scatter plot scatter_range = RangeXY() if self.p.scatter_range_stream: def redim_scatter(dset, x_range, y_range): ranges = {} if x_range and all(isfinite(v) for v in x_range): ranges[self.p.xdim] = x_range if y_range and all(isfinite(v) for v in x_range): ranges[self.p.ydim] = y_range return dset.redim.range(**ranges) if ranges else dset dset_scatter = dset.apply(redim_scatter, streams=[self.p.scatter_range_stream]) link_streams(self.p.scatter_range_stream, scatter_range) else: dset_scatter = dset scatter_pts = dset_scatter.apply(filterpoints, streams=[self.p.filter_stream], xdim=self.p.xdim, ydim=self.p.ydim) scatter_streams = [scatter_range, PlotSize()] scatter_rasterize = rasterize.instance(streams=scatter_streams, x_sampling=x_sampling, y_sampling=y_sampling) cmap = (process_cmap(self.p.scatter_cmap)[:250] if self.p.scatter_cmap == "fire" else self.p.scatter_cmap) scatter_rasterized = apply_when( scatter_pts, operation=scatter_rasterize, predicate=lambda pts: len(pts) > self.p.max_points ).opts( opts.Image(clim=(1, np.nan), clipping_colors={"min": "transparent"}, cmap=cmap), opts.Points(clim=(1, np.nan), clipping_colors={"min": "transparent"}, cmap=cmap), opts.Overlay( hooks=[partial(reset_hook, x_range=x_range, y_range=y_range)]), ) # Set up sky plot sky_range = RangeXY() if self.p.sky_range_stream: def redim_sky(dset, x_range, y_range): ranges = {} if x_range and all(isfinite(v) for v in x_range): ranges["ra"] = x_range if y_range and all(isfinite(v) for v in x_range): ranges["dec"] = y_range return dset.redim.range(**ranges) if ranges else dset dset_sky = dset.apply(redim_sky, streams=[self.p.sky_range_stream]) link_streams(self.p.sky_range_stream, sky_range) else: dset_sky = dset sky_pts = dset_sky.apply(filterpoints, xdim="ra", ydim="dec", set_title=False, streams=[self.p.filter_stream]) skyplot_streams = [sky_range, PlotSize()] sky_rasterize = rasterize.instance( aggregator=ds.mean(self.p.ydim), streams=skyplot_streams, x_sampling=ra_sampling, y_sampling=dec_sampling, ) sky_rasterized = apply_when( sky_pts, operation=sky_rasterize, predicate=lambda pts: len(pts) > self.p.max_points).opts( opts.Image(bgcolor="black", cmap=self.p.sky_cmap, symmetric=True), opts.Points(bgcolor="black", cmap=self.p.sky_cmap, symmetric=True), opts.Overlay(hooks=[ partial(reset_hook, x_range=ra_range, y_range=dec_range) ]), ) # Set up BoundsXY streams to listen to box_select events and notify FilterStream scatter_select = BoundsXY(source=scatter_pts) scatter_notifier = partial(notify_stream, filter_stream=self.p.filter_stream, xdim=self.p.xdim, ydim=self.p.ydim) scatter_select.add_subscriber(scatter_notifier) sky_select = BoundsXY(source=sky_pts) sky_notifier = partial(notify_stream, filter_stream=self.p.filter_stream, xdim="ra", ydim="dec") sky_select.add_subscriber(sky_notifier) # Reset reset = PlotReset(source=sky_pts) reset.add_subscriber( partial(reset_stream, self.p.filter_stream, [self.p.sky_range_stream, self.p.scatter_range_stream])) raw_scatterpts = filterpoints(dset, xdim=self.p.xdim, ydim=self.p.ydim) raw_scatter = datashade( raw_scatterpts, cmap=list(Greys9[::-1][:5]), streams=scatter_streams, x_sampling=x_sampling, y_sampling=y_sampling, ) scatter_p = raw_scatter * scatter_rasterized if self.p.show_rawsky: raw_skypts = filterpoints(dset, xdim=self.p.xdim, ydim=self.p.ydim) raw_sky = datashade( rawskypts, cmap=list(Greys9[::-1][:5]), streams=skyplot_streams, x_sampling=ra_sampling, y_sampling=dec_sampling, ) sky_p = raw_sky * sky_rasterized else: sky_p = sky_rasterized if self.p.show_table: table = dset.apply(summary_table, ydim=self.p.ydim, streams=[self.p.filter_stream]) table = table.opts() layout = table + scatter_p + sky_p else: layout = (scatter_p + sky_p).opts(sizing_mode="stretch_width") return layout.opts( opts.Image(colorbar=True, responsive=True, tools=["box_select", "hover"]), opts.Layout(sizing_mode="stretch_width"), opts.Points(color=self.p.ydim, tools=["hover"]), opts.RGB(alpha=0.5), opts.Table(width=200), )
img.data = step(img.data) return hv.Image(img) # Set up plot which advances on counter and adds pattern on tap title = 'Game of Life - Tap to place pattern, Doubletap to clear' img = hv.Image(np.zeros((100, 200), dtype=np.uint8)) counter, tap = Counter(transient=True), Tap(transient=True), pattern_dim = hv.Dimension('Pattern', values=sorted(shapes.keys())) dmap = hv.DynamicMap(update, kdims=[pattern_dim], streams=[counter, tap]) plot = dmap.opts( opts.Image(cmap='gray', clim=(0, 1), toolbar=None, responsive=True, min_height=800, title=title, xaxis=None, yaxis=None)) # Add callback to clear on double tap def reset_data(x, y): img.data[:] = 0 reset = DoubleTap(transient=True, source=plot) reset.add_subscriber(reset_data) # Set up Panel app and periodic callback panel = pn.pane.HoloViews(plot, center=True, widget_location='right')
config = yaml.load(fd.read()) # configure logging logging.config.dictConfig(config["logging"]) # load bokeh hv.extension("bokeh") pn.extension(sizing_mode="scale_width") # Set some defaults for the visualization of the graphs hvopts.defaults( hvopts.Image( # pylint: disable=no-member # Don't set both height and width, or the UI will not be responsive! height=600, # width=800, responsive=True, show_title=True, tools=["hover"], active_tools=["pan", "wheel_zoom"], align="end", ), hvopts.Layout(toolbar="right"), # pylint: disable=no-member ) ui = thalassa.ThalassaUI( display_variables=True, display_stations=True, ) # https://panel.holoviz.org/reference/templates/Bootstrap.html bootstrap = pn.template.BootstrapTemplate( site="example.com",
def view(self, plane='axial', three_planes=False, image_size=300, dynamic=True, cmap='gray'): # imopts = {'tools': ['hover'], 'width': 400, 'height': 400, 'cmap': 'gray'} # imopts = {'tools': ['hover'], 'cmap': 'gray'} opts.defaults( opts.GridSpace( shared_xaxis=False, shared_yaxis=False, fontsize={ 'title': 16, 'labels': 16, 'xticks': 12, 'yticks': 12 }, ), # opts.Image(cmap='gray', tools=['hover'], xaxis=None, # yaxis=None, shared_axes=False), # opts.Overlay(tools=['hover']), # opts.NdOverlay(tools=['hover']), opts.Image(cmap=cmap, xaxis=None, yaxis=None, shared_axes=False), ) self.is2d = False if 'z' not in self.ds.dims: self.is2d = True self.set_size(image_size) if self.is2d: plane == '2d' a1, a2 = 'x', 'y' pane_width = self.pane_width pane_height = self.pane_height else: if plane == 'axial': a1, a2, a3 = 'x', 'y', 'z' # invert = True pane_width = self.axial_width pane_height = self.axial_height elif plane == 'coronal': a1, a2, a3 = 'x', 'z', 'y' pane_width = self.coronal_width pane_height = self.coronal_height # invert = False elif plane == 'sagittal': a1, a2, a3 = 'y', 'z', 'x' # invert = False pane_width = self.sagittal_width pane_height = self.sagittal_height contrast_start_min = np.asscalar( self.ds.isel(subject_id=0, ).image.quantile(0.01).values) - 1e-6 contrast_start_max = np.asscalar( self.ds.isel(subject_id=0, ).image.quantile(0.99).values) + 1e-6 contrast_min = np.asscalar( self.ds.isel(subject_id=0).image.min().values) contrast_max = np.asscalar( self.ds.isel(subject_id=0).image.max().values) ctotal = contrast_max - contrast_min contrast_min -= ctotal * 0.1 contrast_max += ctotal * 0.1 cslider = pn.widgets.RangeSlider(start=contrast_min, end=contrast_max, value=(contrast_start_min, contrast_start_max), name='contrast') if 'overlay' in self.ds.data_vars: hv_ds_image = hv.Dataset(self.ds[['image', 'overlay']]) # hv_ds_image = hv.Dataset(self.ds['image']) if self.verbose: print(hv_ds_image) hv_ds_overlay = hv.Dataset(self.ds['overlay']) if self.verbose: print(hv_ds_overlay) # tooltips = [ # ('(x,y)', '($x, $y)'), # ('image', '@image'), # ('overlay', '@overlay') # ] # hover = HoverTool(tooltips=tooltips) if self.verbose: print('overlay_max_calc') if self.is2d: first_subj_max = self.ds.isel(subject_id=0).overlay.max( dim=['x', 'y', 'label']).compute() first_subj_min = self.ds.isel(subject_id=0).overlay.min( dim=['x', 'y', 'label']).compute() else: first_subj_max = self.ds.isel(subject_id=0).overlay.max( dim=['x', 'y', 'z', 'label']).compute() first_subj_min = self.ds.isel(subject_id=0).overlay.min( dim=['x', 'y', 'z', 'label']).compute() if self.verbose: print('overlay_max_calc ready') print(first_subj_max) overlay_max = first_subj_max.max() alpha_slider = pn.widgets.FloatSlider(start=0, end=1, value=0.7, name='overlay transparency') cmap_select = pn.widgets.Select(name='Overlay Colormap', options=['Discrete', 'Continuous']) if self.verbose: print('max thresh calc') print(first_subj_max.max()) max_thresholds = first_subj_max.values if max_thresholds.size != 1: max_thresholds = sorted(set(max_thresholds)) else: max_thresholds = [np.asscalar(max_thresholds)] # max_thresholds = sorted(list(set([first_subj.overlay.sel(overlay_label=i).values.max() # for i in first_subj.overlay_label]))) if self.verbose: print('min thresh calc') min_thresholds = first_subj_min.values + 1e-6 if min_thresholds.size != 1: min_thresholds = sorted(set(min_thresholds)) else: min_thresholds = [np.asscalar(min_thresholds)] # min_thresholds = sorted(list(set(first_subj_min.min()))) # min_thresholds = sorted(list(set([first_subj.sel(overlay_label=i).min()+1e-6 for i in # first_subj.overlay_label]))) # ocslider = pn.widgets.DiscreteSlider(name='overlay max threshold', # options=max_thresholds, # value=max_thresholds[-1]) if len(min_thresholds) == 1 and len(max_thresholds) == 1: thresh_toggle = 0 oclim = (min_thresholds[0], max_thresholds[0]) elif len(min_thresholds) > 1 and len(max_thresholds) == 1: thresh_toggle = 1 ocslider_min = pn.widgets.DiscreteSlider( name='overlay min threshold', options=min_thresholds, value=min_thresholds[-1]) @pn.depends(ocslider_min) def oclim(value): return (value, max_thresholds[0]) elif len(min_thresholds) == 1 and len(max_thresholds) > 1: thresh_toggle = 2 ocslider_max = pn.widgets.DiscreteSlider( name='overlay max threshold', options=max_thresholds, value=max_thresholds[-1]) @pn.depends(ocslider_max) def oclim(value): return (min_thresholds[0], value) else: thresh_toggle = 3 ocslider_min = pn.widgets.DiscreteSlider( name='overlay min threshold', options=min_thresholds, value=min_thresholds[-1]) ocslider_max = pn.widgets.DiscreteSlider( name='overlay max threshold', options=max_thresholds, value=max_thresholds[-1]) @pn.depends(ocslider_min, ocslider_max) def oclim(value_min, value_max): return (value_min, value_max) if self.verbose: print(thresh_toggle) @pn.depends(cmap_select) def cmap_dict(value): d = {'Discrete': 'glasbey_hv', 'Continuous': 'viridis'} return d[value] # subj_viewer = SubjectViewer(ds=self.ds, # subject_id_sel=list(self.ds.subject_id.values)) if self.is2d: gridspace = hv_ds_image.to( hv.Image, [a1, a2], vdims=['image', 'overlay'], dynamic=dynamic).opts( frame_width=pane_width, frame_height=pane_height, tools=['hover'], ).apply.opts(clim=cslider.param.value) if self.verbose: print(gridspace) gridspace *= hv_ds_overlay.to( hv.Image, [a1, a2], vdims='overlay', dynamic=dynamic).opts( cmap='glasbey_hv', clipping_colors={ 'min': 'transparent', 'NaN': 'transparent' }, ).redim.range(overlay=(1e-6, overlay_max)).apply.opts( alpha=alpha_slider.param.value, cmap=cmap_dict, clim=oclim) # print(gridspace) # print(gridspace) # gridspace = hv.DynamicMap(subj_viewer.load_subject).grid('label') gridspace = gridspace.layout('label') elif three_planes: # squish_height = int(max(image_size*(len(self.ds.z)/len(self.ds.x)), image_size/2)) # gridspace = hv.GridSpace(kdims=['plane', 'label'], label=f'{self.subject_id}') gridspace = hv.GridSpace(kdims=['plane', 'label']) for mod in self.ds.label.values: gridspace['axial', mod] = hv_ds_image.select(label=mod).to( hv.Image, ['x', 'y'], groupby=['subject_id', 'z'], vdims='image', dynamic=dynamic).opts( frame_width=self.axial_width, frame_height=self.axial_height).apply.opts( clim=cslider.param.value) gridspace['coronal', mod] = hv_ds_image.select( label=mod).to( hv.Image, ['x', 'z'], groupby=['subject_id', 'y'], vdims='image', dynamic=dynamic).opts( frame_width=self.coronal_width, frame_height=self.coronal_height).apply.opts( clim=cslider.param.value) gridspace['sagittal', mod] = hv_ds_image.select( label=mod).to( hv.Image, ['y', 'z'], groupby=['subject_id', 'x'], vdims='image', dynamic=dynamic).opts( frame_width=self.sagittal_width, frame_height=self.sagittal_height).apply.opts( clim=cslider.param.value) gridspace['axial', mod] *= hv_ds_overlay.select(label=mod).to( hv.Image, ['x', 'y'], groupby=['subject_id', 'z', 'overlay_label'], vdims='overlay', dynamic=dynamic).opts( cmap='glasbey_hv', clipping_colors={ 'min': 'transparent', 'NaN': 'transparent' }, ).redim.range( overlay=(0.1, overlay_max)).apply.opts( alpha=alpha_slider.param.value, cmap=cmap_dict, clim=oclim) gridspace['coronal', mod] *= hv_ds_overlay.select(label=mod).to( hv.Image, ['x', 'z'], groupby=['subject_id', 'y', 'overlay_label'], vdims='overlay', dynamic=dynamic).opts( cmap='glasbey_hv', clipping_colors={ 'min': 'transparent', 'NaN': 'transparent' }, ).redim.range( overlay=(0.1, overlay_max)).apply.opts( alpha=alpha_slider.param.value, cmap=cmap_dict, clim=oclim) gridspace['sagittal', mod] *= hv_ds_overlay.select(label=mod).to( hv.Image, ['y', 'z'], groupby=['subject_id', 'x', 'overlay_label'], vdims='overlay', dynamic=dynamic).opts( cmap='glasbey_hv', clipping_colors={ 'min': 'transparent', 'NaN': 'transparent' }, ).redim.range( overlay=(0.1, overlay_max)).apply.opts( alpha=alpha_slider.param.value, cmap=cmap_dict, clim=oclim) else: # squish_height = int(max(image_size*(len(self.ds.z)/len(self.ds.x)), image_size/2)) # gridspace = hv.GridSpace(kdims=['label'], label=f'{self.subject_id}') if self.verbose: print('init gridspace') # gridspace = hv.GridSpace(kdims=['label']) # for mod in self.ds.label: # gridspace[mod] = hv_ds_image.select(label=mod).to( # hv.Image, [a1, a2], groupby=[a3], vdims='image', # dynamic=dynamic).opts(frame_width=image_size, frame_height=image_size, # ).apply.opts(clim=cslider.param.value) # gridspace[mod] *= hv_ds_overlay.select(label=mod).to( # hv.Image, [a1, a2], groupby=[a3, 'overlay_label'], vdims='overlay', # dynamic=dynamic).opts( # cmap='glasbey_hv', clipping_colors={'min': 'transparent'}, # ).redim.range(overlay=(1e-6, overlay_max)).apply.opts( # alpha=alpha_slider.param.value, cmap=cmap_dict, clim=oclim) # gridspace[mod] = gridspace[mod].opts(tools=['hover']) # print(gridspace[mod]) gridspace = hv_ds_image.to( hv.Image, [a1, a2], vdims=['image', 'overlay'], dynamic=dynamic).opts( frame_width=pane_width, frame_height=pane_height, tools=['hover'], ).apply.opts(clim=cslider.param.value) if self.verbose: print(gridspace) gridspace *= hv_ds_overlay.to( hv.Image, [a1, a2], vdims='overlay', dynamic=dynamic).opts( cmap='glasbey_hv', clipping_colors={ 'min': 'transparent', 'NaN': 'transparent' }, ).redim.range(overlay=(1e-6, overlay_max)).apply.opts( alpha=alpha_slider.param.value, cmap=cmap_dict, clim=oclim) # print(gridspace) # print(gridspace) # gridspace = hv.DynamicMap(subj_viewer.load_subject).grid('label') gridspace = gridspace.layout('label') else: tooltips = [ ('(x,y)', '($x, $y)'), ('image', '@image'), ] hover = HoverTool(tooltips=tooltips) hv_ds = hv.Dataset(self.ds['image']) if self.is2d: gridspace = hv.GridSpace(kdims=['label']) for mod in self.ds.label.values: gridspace[mod] = hv_ds.select(label=mod).to( hv.Image, [a1, a2], groupby=['subject_id'], vdims='image', dynamic=dynamic).opts( frame_width=pane_width, frame_height=pane_height, shared_axes=False, tools=[hover], axiswise=True, # ).apply.opts(clim=cslider.param.value) ) elif three_planes: # squish_height = int(max(image_size*(len(self.ds.z)/len(self.ds.x)), image_size/2)) # gridspace = hv.GridSpace(kdims=['plane', 'label'], label=f'{self.subject_id}') gridspace = hv.GridSpace(kdims=['plane', 'label']) for mod in self.ds.label.values: gridspace['axial', mod] = hv_ds.select(label=mod).to( hv.Image, ['x', 'y'], groupby=['subject_id', 'z'], vdims='image', dynamic=dynamic).opts(frame_width=self.axial_width, frame_height=self.axial_height, invert_yaxis=False).apply.opts( clim=cslider.param.value) gridspace['coronal', mod] = hv_ds.select(label=mod).to( hv.Image, ['x', 'z'], groupby=['subject_id', 'y'], vdims='image', dynamic=dynamic).opts( frame_width=self.coronal_width, frame_height=self.coronal_height).apply.opts( clim=cslider.param.value) gridspace['sagittal', mod] = hv_ds.select(label=mod).to( hv.Image, ['y', 'z'], groupby=['subject_id', 'x'], vdims='image', dynamic=dynamic).opts( frame_width=self.sagittal_width, frame_height=self.sagittal_height).apply.opts( clim=cslider.param.value) else: # squish_height = int(max(image_size*(len(self.ds.z)/len(self.ds.x)), image_size/2)) # gridspace = hv.GridSpace(kdims=['label'], label=f'{self.subject_id}') gridspace = hv.GridSpace(kdims=['label']) for mod in self.ds.label.values: gridspace[mod] = hv_ds.select(label=mod).to( hv.Image, [a1, a2], groupby=['subject_id', a3], vdims='image', dynamic=dynamic).opts( frame_width=pane_width, frame_height=pane_height, shared_axes=False, tools=[hover], ).apply.opts(clim=cslider.param.value) pn_layout = pn.pane.HoloViews(gridspace) wb = pn_layout.widget_box wb.append(cslider) if 'overlay' in self.ds.data_vars: wb.append(alpha_slider) wb.append(cmap_select) if thresh_toggle in [2, 3]: wb.append(ocslider_max) if thresh_toggle in [1, 3]: wb.append(ocslider_min) return pn.Row(wb, pn_layout)
DEFAULT_RADIUS = 1.0 DEFAULT_BOUNDS = (-DEFAULT_RADIUS, -DEFAULT_RADIUS, DEFAULT_RADIUS, DEFAULT_RADIUS) DEFAULT_MIN_N = 100 DEFAULT_MAX_N = 100000 DEFAULT_N_PER_PI_CALC = DEFAULT_MIN_N DEFAULT_PLOT_SIZE = 1200 DEFAULT_IMAGE_SIZE = round(DEFAULT_PLOT_SIZE / 2) DEFAULT_CMAP = 'Spectral' DEFAULT_IMAGE_COLOR_IDX = 2 DEFAULT_POINT_COLOR_IDX = 125 DEFAULT_PI_UPDATE_FORMAT = 'Pi ~= {:8.7f}\nerror = {:6.3f}%\nn = {:d}\n(N ~ {:d})' img_opts = opts.Image(cmap=DEFAULT_CMAP, toolbar=None, height=DEFAULT_PLOT_SIZE, width=DEFAULT_PLOT_SIZE, xaxis=None, yaxis=None) def make_circle(radius=DEFAULT_RADIUS): def circle(t): return (radius * np.sin(t), radius * np.cos(t), t) lin = np.linspace(-np.pi, np.pi, 200) return hv.Path([circle(lin)]).opts(img_opts).opts(line_width=2, color='red') def make_rect(bounds=DEFAULT_BOUNDS, color='blue'): minX, minY, maxX, maxY = bounds
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'
renderer = hv.renderer('bokeh') # Set plot and style options opts.defaults( opts.Curve(xaxis=None, yaxis=None, show_grid=False, show_frame=False, color='orangered', framewise=True, width=100), opts.Image(width=800, height=400, shared_axes=False, logz=True, xaxis=None, yaxis=None, axiswise=True), opts.HLine(color='white', line_width=1), opts.Layout(shared_axes=False), opts.VLine(color='white', line_width=1)) # Read the parquet file df = dd.read_parquet('./data/nyc_taxi_wide.parq').persist() # Declare points points = hv.Points(df, kdims=['pickup_x', 'pickup_y'], vdims=[]) # Use datashader to rasterize and linked streams for interactivity agg = aggregate(points, link_inputs=True, x_sampling=0.0001, y_sampling=0.0001) pointerx = hv.streams.PointerX(x=np.mean(points.range('pickup_x')), source=points)