1

I'd like to update a text input in a pyshiny app each time a marker is clicked in an ipyleaflet map widget using the marker's title value. I have been using the marker.on_click() callback to get the title (station_id in this case) from the clicked marker, but I am struggling to dynamically change the text input box with the title text.

A basic working example that I have tried is shown below. The title of each marker is printed to screen from within the callback() function each time it is clicked. However, I can't figure out how to update the ui.input_text's value. The Reactive.Effect function does not seem to be called at all and I'm not sure why. What do I need to change here to update the value in the text input?

from shiny import App, reactive, run_app, ui
from shinywidgets import output_widget, register_widget
import ipyleaflet as ipyl


app_ui = ui.page_fluid(
    {"class": "p-4"},
    ui.row(
        ui.column(
            4,
            ui.input_text("station_id", "Station ID:", value="Click on a station marker"),
        ),
        ui.column(
            8,
            output_widget("map_widget")
        ),
    ),
)


def get_station_id(_marker):
    def callback(*args, **kwargs):
        print(_marker.title)
        return _marker.title
    return callback


def add_stations_to_map(_map, stations):
    markers = []
    for station in stations:
        marker = ipyl.Marker(location=station[0], draggable=False, title=station[1])
        _map.add(marker)
        markers.append(marker)
    return markers


def server(input, output, session):
    # Initialize and display when the session starts (1)
    _map = ipyl.Map(center=(-33.8, 151), zoom=8, scroll_wheel_zoom=True)
    # Add a distance scale
    _map.add(ipyl.leaflet.ScaleControl(position="bottomleft"))
    register_widget("map_widget", _map)

    # add markers and station id clik function
    stations = [
        [(-33.8, 151), "station_1"],
        [(-33.8, 150), "station_2"],
    ]
    markers = add_stations_to_map(_map, stations)
    clicked_marker = "Click on a station marker"
    for marker in markers:
        clicked_marker = marker.on_click(get_station_id(marker))

    @reactive.Effect
    def _():
        ui.update_text("station_id", value=clicked_marker)


app = App(app_ui, server, debug=True)
run_app(app, launch_browser=True, port=0)
wardj
  • 13
  • 2

1 Answers1

1

You can use a reactive.Value to set your text:

clicked_marker_value = reactive.Value("Click on a station marker")
def get_station_id(_marker):
    def callback(*args, **kwargs):
        print(_marker.title)
        clicked_marker_value.set(_marker.title)
        return _marker.title
    return callback

@reactive.Effect
    def _():
        ui.update_text("station_id", value=clicked_marker_value())
michael
  • 245
  • 2
  • 11
  • Perfect, that works nicely. Thank you so much. I see that in the API now, and probably should have figured that out myself... – wardj Nov 01 '22 at 20:51
  • We're all new to python/shiny and figuring things out. Please accept the answer (and maybe upvote) – michael Nov 02 '22 at 15:08