Dynamic update of one class based on the other

I have the following two classes and I want to update the map view with the parameters selected as country/continent in the parameterized class.

import panel as pn
import param
from panel.viewable import Viewer
pn.extension()

class MapCountry(param.Parameterized):
    continent = param.ObjectSelector(default="Asia", objects=["Africa", "Asia", "Europe"])
    country = param.ObjectSelector(default="China", objects=["China", "Thailand", "Japan"])

    settings_panel = param.Parameter()
    
    _countries = {
        "Africa": ["Ghana", "Togo", "South Africa", "Tanzania"],
        "Asia": ["China", "Thailand", "Japan"],
        "Europe": ["Austria", "Bulgaria", "Greece", "Portugal", "Switzerland"],
    }

    def __init__(self, **params):
        super().__init__(**params)
        self.settings_panel = pn.Param(self, parameters=["continent", "country"])

    @param.depends("continent", watch=True)
    def _update_countries(self):
        countries = self._countries[self.continent]
        self.param["country"].objects = countries
        self.country = countries[0]


class GoogleView(Viewer):
    map_panel = param.Parameter()
    country = param.String()

    def __init__(self, **params):
        super().__init__(**params)        
        self.map_panel = pn.pane.HTML()
        self._update_map()

    @param.depends("country", watch=True)
    def _update_map(self):
        iframe = f"""
        <iframe width="100%" height="100%" src="https://maps.google.com/maps?q={self.country}&z=6&output=embed"
        frameborder="0" scrolling="no" marginheight="0" marginwidth="0"></iframe>
        """
        self.map_panel.object = iframe

map = MapCountry(name="Country Selection")
view = GoogleView(name="Google Map viewer")
app = pn.Column(map.settings_panel,
               view.map_panel)
app.servable()
1 Like

Hi @Besteverandever

If you allow_refs on the GoogleView country parameter, you can use the MapCountry country parameter as a reference: GoogleView(name="Google Map viewer", country=map.param.country).

import panel as pn
import param
from panel.viewable import Viewer
pn.extension()

class MapCountry(param.Parameterized):
    continent = param.ObjectSelector(default="Asia", objects=["Africa", "Asia", "Europe"])
    country = param.ObjectSelector(default="China", objects=["China", "Thailand", "Japan"])

    settings_panel = param.Parameter()
    
    _countries = {
        "Africa": ["Ghana", "Togo", "South Africa", "Tanzania"],
        "Asia": ["China", "Thailand", "Japan"],
        "Europe": ["Austria", "Bulgaria", "Greece", "Portugal", "Switzerland"],
    }

    def __init__(self, **params):
        super().__init__(**params)
        self.settings_panel = pn.Param(self, parameters=["continent", "country"])

    @param.depends("continent", watch=True)
    def _update_countries(self):
        countries = self._countries[self.continent]
        self.param["country"].objects = countries
        self.country = countries[0]


class GoogleView(Viewer):
    map_panel = param.Parameter()
    country = param.String(allow_refs=True)

    def __init__(self, **params):
        super().__init__(**params)        
        self.map_panel = pn.pane.HTML()
        self._update_map()

    @param.depends("country", watch=True)
    def _update_map(self):
        iframe = f"""
        <iframe width="100%" height="100%" src="https://maps.google.com/maps?q={self.country}&z=6&output=embed"
        frameborder="0" scrolling="no" marginheight="0" marginwidth="0"></iframe>
        """
        self.map_panel.object = iframe

map = MapCountry(name="Country Selection")
view = GoogleView(name="Google Map viewer", country=map.param.country)
app = pn.Column(map.settings_panel,
               view.map_panel)
app.servable()

Tips & Tricks

If you need to do more advanced nested selections take a look at the NestedSelect widget.

Here I’m implementing the same app using it.

import panel as pn
import param
from panel.viewable import Viewer

pn.extension()

countries = {
    "Africa": ["Ghana", "Togo", "South Africa", "Tanzania"],
    "Asia": ["China", "Thailand", "Japan"],
    "Europe": ["Austria", "Bulgaria", "Greece", "Portugal", "Switzerland"],
}

country_input = pn.widgets.NestedSelect(options=countries, levels=["Region", "Country"],)

class GoogleView(Viewer):
    map_panel = param.Parameter()
    country = param.String(allow_refs=True)

    def __init__(self, **params):
        super().__init__(**params)        
        self.map_panel = pn.pane.HTML()
        self._update_map()

    @param.depends("country", watch=True)
    def _update_map(self):
        iframe = f"""
        <iframe width="100%" height="100%" src="https://maps.google.com/maps?q={self.country}&z=6&output=embed"
        frameborder="0" scrolling="no" marginheight="0" marginwidth="0"></iframe>
        """
        self.map_panel.object = iframe

country = country_input.param.value.rx()["Country"]

view = GoogleView(name="Google Map viewer", country=country)
app = pn.Column(country_input, view.map_panel)
app.servable()
1 Like

Yes this is working for me now. Thank you so much for your help!!

1 Like

Tips & Tricks

When you inherit from Viewer you should remember to implement the __panel__ method.

Here is an example

image

import panel as pn
import param
from panel.viewable import Viewer

pn.extension()

map_iframe = """
<iframe width="100%" height="100%" src="https://maps.google.com/maps?q={country}&z=6&output=embed"
frameborder="0" scrolling="no" marginheight="0" marginwidth="0"></iframe>
"""

class GoogleMapViewer(Viewer):
    country = param.String(allow_refs=True)

    def __init__(self, **params):
        super().__init__(**params)        
        
        map_iframe_rx = pn.rx(map_iframe).format(country=self.param.country)
        self._layout = pn.pane.HTML(map_iframe_rx)
        
    def __panel__(self):
        return self._layout

country = pn.widgets.Select(options=["Germany", "Nigeria", "Thailand"], name="Country")
view = GoogleMapViewer(name="Google Map viewer", country=country)
pn.Column(country, view).servable()

FYI. I’ve created a PR to add this example to the intermediate tutorials in Add allow_refs example to tutorials.

3 Likes