Open m7200 opened 1 year ago
Work around
import panel as pn
import param
import logging
log = logging.getLogger('test_logger')
logging.basicConfig(format='%(lineno)d - %(name)s - %(asctime)s - %(levelname)s '
'- %(message)s', level=logging.DEBUG)
log.setLevel(logging.DEBUG)
pn.extension()
class LayerModel(param.Parameterized):
scale_min = param.Number(0, instantiate=True)
tname = param.String(default='none', instantiate=True)
def handle_set_scale_min(self, *events):
for event in events:
if event.name == 'value':
self.scale_min = float(event.obj.value)
log.info('handle_set_scale_min: %s' % self.scale_min)
log.debug(f"(event: {event.name} changed from {event.old} to {event.new})")
self.param.trigger('scale_min')
class LayerListItem(param.Parameterized):
delete = param.Event()
move_layer_up = param.Event()
move_layer_down = param.Event()
def __init__(self, layer_model=None, **kwds):
super().__init__(**kwds)
self.layer_model=layer_model
class LayerList(param.Parameterized):
def add_layer(self, layer_model):
log.info('LayerList.add_layer')
new_item = LayerListItem(
parent=self,
layer_model=layer_model,
)
new_item.param.watch(self._delete_layer, ['delete'])
new_item.param.watch(self._move_layer_up, ['move_layer_up'])
new_item.param.watch(self._move_layer_down, ['move_layer_down'])
self.layer_list.append(new_item)
log.debug(f'New item {new_item}')
self.param.trigger('layer_list')
def _delete_layer(self, *events):
for event in events:
if event.name == 'delete':
list_index = self.layer_list.index(event.obj)
log.debug('DELETE layer at index: %s' % list_index)
layer_item = self.layer_list[list_index]
self.layer_list.remove(event.obj)
self.param.trigger('layer_list')
def _move_layer_up(self, *events):
x = 0
for event in events:
if event.name == 'move_layer_up':
# no move
if len(self.layer_list) == 1:
return
layer_index = self.layer_list.index(event.obj)
if layer_index < len(self.layer_list) - 1:
tmp = self.layer_list[:]
tmp.pop(layer_index)
tmp.insert(layer_index+1, event.obj)
self.layer_list = []
self.layer_list[:] = tmp[:]
# self.layer_list.pop(layer_index)
# self.layer_list.insert(layer_index+1, event.obj)
self.param.trigger('layer_list')
def _move_layer_down(self, *events):
for event in events:
if event.name == 'move_layer_down':
# do move
if len(self.layer_list) == 1:
return
layer_index = self.layer_list.index(event.obj)
if layer_index > 0:
tmp = self.layer_list[:]
tmp.pop(layer_index)
tmp.insert(layer_index-1, event.obj)
self.layer_list = []
self.layer_list[:] = tmp[:]
# self.layer_list.pop(layer_index)
# self.layer_list.insert(layer_index-1, event.obj)
self.param.trigger('layer_list')
layer_list = param.List([], item_type=LayerListItem, instantiate=True)
delete_layer = param.Action(_delete_layer)
move_layer_up = param.Action(_move_layer_up)
move_layer_down = param.Action(_move_layer_down)
class LayerLegendView():
def __init__(self, layer_item):
self.layer_model = layer_item.layer_model
self.title = pn.pane.HTML(
object='Doc ' + self.layer_model.tname,
styles={'font-weight': 'bold'}
)
self.scale_min_input = pn.widgets.FloatInput(
value=self.layer_model.scale_min,
name= self.layer_model.tname + "_min",
max_width=120,
sizing_mode='stretch_width'
)
log.debug(f'Min input {self.scale_min_input}')
test = self.scale_min_input.param.watch(self.layer_model.handle_set_scale_min, 'value')
# log.debug(f'Watcher {test}')
def z_up_button(item):
return pn.Param(
item,
widgets={
'move_layer_up': {
'widget_type': pn.widgets.Button,
'name': '▲',
}})
def z_down_button(item):
return pn.Param(item,
widgets={
'move_layer_down': {
'widget_type': pn.widgets.Button,
'name': '▼',
}}
)
def remove_button(item):
return pn.Param(
item,
widgets={
'delete': {
'widget_type': pn.widgets.Button,
'name': '✖',
}})
self.control_pane = pn.Column(
objects=[
z_up_button(layer_item.param.move_layer_up),
remove_button(layer_item.param.delete),
z_down_button(layer_item.param.move_layer_down),
],
)
legend_margin = (0, 5, 0, 5)
self.legend_pane = pn.Column(
pn.Row(
self.title,
sizing_mode='stretch_width',
margin=(10, 5, 0, 5)
),
pn.Row(
self.scale_min_input,
margin=legend_margin
),
sizing_mode='stretch_width',
styles=dict(border='1px dashed black'),
)
def ui(self):
x = 0
return pn.Row(
self.legend_pane,
self.control_pane, sizing_mode='stretch_width'
)
def ui(layer_list_model):
@pn.depends(layer_list_model.param.layer_list)
def render_list(item_list):
def get_legend(layer_item):
legend = LayerLegendView(layer_item)
return legend.ui()
col = pn.Column(sizing_mode='stretch_width')
for layer_item in reversed(item_list):
col.append(get_legend(layer_item))
log.debug(f'Column {col}')
return col
rv = pn.Column(render_list)#, loading_indicator=True)
# rv = render_list(layer_list_model.param.layer_list)
log.debug(f'Panel {rv}')
return rv
a = LayerModel(tname='A', scale_min=7.9, instantiate=True)
b = LayerModel(tname='B', scale_min=8.0, instantiate=True)
z = LayerList()
z.add_layer(a)
z.add_layer(b)
first_app = pn.Column(ui(z))
first_app.servable()
Problem still appears to be evident in Panel 1.3.0 and Param 2.0.0
ALL software version info
bleach==6.1.0 bokeh==3.2.2 Bottleneck==1.3.7 Cartopy==0.22.0 certifi==2023.7.22 cftime==1.6.3 charset-normalizer==3.3.0 click==8.1.7 cloudpickle==3.0.0 colorama==0.4.6 colorcet==3.0.1 contourpy==1.1.1 cycler==0.12.1 dask==2023.10.0 datashader==0.15.2 datashape==0.5.2 fonttools==4.43.1 fsspec==2023.9.2 geojson==2.5.0 geoviews==1.10.1 holoviews==1.17.1 idna==3.4 importlib-metadata==6.8.0 Jinja2==3.1.2 kiwisolver==1.4.5 linkify-it-py==2.0.2 llvmlite==0.40.1 locket==1.0.0 lz4==4.3.2 Markdown==3.5 markdown-it-py==3.0.0 MarkupSafe==2.1.3 matplotlib==3.7.2 mdit-py-plugins==0.4.0 mdurl==0.1.2 multipledispatch==1.0.0 netCDF4==1.6.4 numba==0.57.1 numpy==1.24.4 packaging==23.2 pandas==2.1.1 panel==1.2.3 param==1.13.0 partd==1.4.1 Pillow==10.1.0 pyarrow==13.0.0 pyct==0.5.0 pyparsing==3.0.9 pyproj==3.6.0 pyshp==2.3.1 python-dateutil==2.8.2 pytz==2023.3.post1 pyviz_comms==3.0.0 PyYAML==6.0.1 requests==2.31.0 scipy==1.9.3 shapely==2.0.1 six==1.16.0 toolz==0.12.0 tornado==6.3.3 tqdm==4.66.1 typing_extensions==4.8.0 tzdata==2023.3 uc-micro-py==1.0.2 urllib3==2.0.7 webencodings==0.5.1 xarray==2023.10.1 xyzservices==2023.10.0 zipp==3.17.0
Description of expected behavior and the observed behavior
I have the following code which works under Panel 0.14.2 and executes under 1.2.3 but does not produce a correct result.
The code under 0.14.2 creates two rows (A and B) with each row having a FloatInput and controls (up and down) which alter the order of the display of the two rows. Up arrow moves the row up, down arrow moves the row down. This works fine under 0.14.2. When Up arrow of layer A is pressed, layer A and its FloatInput move to the top (correct layer A value maintained 7.9). Under 1.2.3 when either using the up or down arrows results in the layer FloatInput values in both layers being modified (swapped).
Complete, minimal, self-contained example code that reproduces the issue
Stack traceback and/or browser JavaScript console output
Screenshots or screencasts of the bug in action