Hi all, I’m working on a little app to show galaxy images. I have made it so that when a particular pixel in a hvplot Bokeh instance is clicked on, this is detected by stream.Tap, which calls a bound function to record which pixel was clicked. When I replace the hvplot object with an alternative plot, using a RadioButton to replace it via the .object attribute, the stream/bound function appears to stop working. I’ve tried to recreate this using minimal code whilst maintaing the functions/structure of the project, which is below. The idea for the demo is if you click on a point in the lefthand plot, it will display a number on the righthand plot. If you switch from option 1 to option 2 in the menu, this no longer works. I try to explicitly set stream.source = bin_map.object when I replace the plot, but it doesn’t seem to help. Any ideas are much appreciated!
import panel as pn
import numpy as np
from panel.layout.gridstack import GridStack
from matplotlib.figure import Figure
import matplotlib as mpl
import xarray as xr
import holoviews as hv
import hvplot.xarray
import matplotlib.cm as cm
import matplotlib.pyplot as plt
import sys
#sns.set_context("paper")
#plt.style.use('paper.mplstyle')
ACCENT = "goldenrod"
# panel serve ResolvedSEDApp.py --autoreload
pn.extension(sizing_mode="stretch_width", design='material')
pn.extension('gridstack')
facecolor = '#f7f7f7'
stream = hv.streams.Tap()
def plot_sed(x, y, cmap, shown_bins):
skip = False
if x == None or y == None:
skip = True
if not skip:
random_array = np.random.uniform(size=(64, 64))
bin = random_array[int(np.ceil(y)), int(np.ceil(x))]
if bin not in shown_bins:
shown_bins.append(bin)
fig, ax = plt.subplots(figsize=(6, 3), constrained_layout=True, facecolor=facecolor)
for bin in shown_bins:
ax.text(0.5, 0.5, f"SED bin: {bin}", fontsize=20, ha='center', va='center', color='red')
return pn.pane.Matplotlib(fig, dpi=144, tight=True, format="svg", sizing_mode="stretch_width")
#return False
def update_image(value):
# Problem is here? The plot_sed function which is bound to the stream is not being called after the plot is updated
global shown_bins
shown_bins = []
bin_plot = plot_bins(value, 'viridis')
bin_map.object = bin_plot
stream.source = bin_map.object
def update_sidebar(active_tab, sidebar):
settings_sidebar = pn.Column(pn.layout.Divider(), "### Settings", name='settings_sidebar')
which_map = pn.widgets.RadioButtonGroup(options=['option 1', 'option 2'], value='option 1', name='Pixel Binning')
settings_sidebar.append('#### Pixel Binning')
settings_sidebar.append(which_map)
pn.bind(update_image, which_map.param.value, watch=True)
if active_tab == 0:
sidebar.append(settings_sidebar)
else:
# Check if already in sidebar
for item in sidebar:
if item.name == 'settings_sidebar':
sidebar.remove(item)
def plot_bins(bin_type, cmap):
array = np.random.uniform(size=(64, 64))
dimensions = np.linspace(0, 64, 64)
im_array = xr.DataArray(array, dims=['y', 'x'], name=f'{bin_type} bins', coords={'x': dimensions, 'y': dimensions})
hvplot = im_array.hvplot('x','y').opts(cmap=cmap, xaxis=None, yaxis=None, clabel=f'{bin_type} Bin')
return hvplot
def main(components):
global shown_bins
global bin_map
global stream
global sed_results_grid
global cmap
sidebar, tabs = components
sed_results_grid = GridStack(sizing_mode='stretch_both', allow_resize=True,
allow_drag=True, min_height=400, mode='override', nrows=1, ncols=4)
cmap = 'viridis'
hvplot_bins = plot_bins('type 1', cmap)
bin_map = pn.pane.HoloViews(hvplot_bins, sizing_mode='stretch_height')
stream.source = bin_map.object
shown_bins = []
obj = pn.bind(plot_sed, stream.param.x, stream.param.y, cmap, shown_bins, watch=False)
sed_results_grid[0, :2] = bin_map
sed_results_grid[0, 2:] = obj
galaxy_tabs = pn.Tabs()
galaxy_tabs.append(('Galaxy 1', sed_results_grid))
update_sidebar(0, sidebar)
tabs.append(('Galaxy 1', galaxy_tabs))
def resolved_sed_interface():
tabs = pn.Tabs(closable=True, dynamic=True)
sidebar = pn.Column("### Upload .h5")
components = [sidebar, tabs]
main(components)
return pn.template.FastListTemplate(
title="Resolved SED Viewer", sidebar=[sidebar], main=[tabs], accent=ACCENT
)
resolved_sed_interface().servable()