opengeos/leafmap

Leafmap Legend Not displaying in shiny python

micboat opened this issue · 12 comments

Hi, thanks for an amazing package. its very easy to use. Not sure if this is something you can help with:

Environment Information

  • leafmap version:0.35.2
  • shiny:0.10.2
  • shinywidgets:0.3.2
  • Python version: 3.10.4
  • Operating System: MacOS

mapclassify==2.6.1
ipywidgets==7.8.1

Description

Describe what you were trying to get done.
Am trying to render leafmap within shiny app (python) using the chloropleth example here:
example

What I Did

from ipyleaflet import *
from shiny.express import  ui
from shinywidgets import  render_widget

import leafmap
import geopandas as gpd
data = leafmap.examples.datasets.countries_geojson



ui.page_opts(title="Market Change Profile", 

             )

with ui.sidebar(open="open"):
    ui.h4("Year Filter")
   
ui.nav_spacer()

with ui.nav_panel("Map"):
    with ui.card(full_screen=True):
        ui.card_header(f"Test Map")

        @render_widget
        def map_ui():
            m = leafmap.Map()
            m.add_data(
                data, column="POP_EST", scheme="Quantiles", cmap="Blues", legend_title="Population"
            )
            return m

If there was a crash, please include the traceback here.

HTML(value="<html>\n<body>\n  <div class='my-legend'>\n  <div class='legend-title'>Population</div>\n  <div class='legend-scale'>\n    <ul class='legend-labels'>\n      <li><span style='background:#f7fbff;'></span>[       140,    2484780]</li>\n      <li><span style='background:#c6dbef;'></span>(   2484780,    6229794]</li>\n      <li><span style='background:#6baed6;'></span>(   6229794,   14668522]</li>\n      <li><span style='background:#2171b5;'></span>(  14668522,   38476269]</li>\n      <li><span style='background:#08306b;'></span>(  38476269, 1379302771]</li>\n    </ul>\n  </div>\n  </div>\n\n  <style type='text/css'>\n    .my-legend .legend-title {\n      text-align: left;\n      margin-bottom: 2px;\n      margin-left: 2px;\n      font-weight: bold;\n      font-size: 90%;\n      }\n    .my-legend .legend-scale ul {\n      margin: 0;\n      margin-bottom: 5px;\n      padding: 0;\n      float: left;\n      list-style: none;\n      }\n    .my-legend .legend-scale ul li {\n      font-size: 80%;\n      list-style: none;\n      margin-left: 1px;\n      line-height: 18px;\n      margin-bottom: 2px;\n      }\n    .my-legend ul.legend-labels li span {\n      display: block;\n      float: left;\n      height: 16px;\n      width: 30px;\n      margin-right: 5px;\n      margin-left: 2px;\n      border: 1px solid #999;\n      }\n    .my-legend .legend-source {\n      font-size: 70%;\n      color: #999;\n      clear: both;\n      }\n    .my-legend a {\n      color: #777;\n      }\n  </style>\n</body>\n</html>\n")
INFO:     127.0.0.1:57549 - "GET /jupyter-leaflet.js HTTP/1.1" 404 Not Found
INFO:     127.0.0.1:57545 - "GET /ipyevents.js HTTP/1.1" 404 Not Found
INFO:     127.0.0.1:57547 - "GET /jupyter-leaflet.js HTTP/1.1" 404 Not Found
INFO:     127.0.0.1:57549 - "GET /ipyevents.js HTTP/1.1" 404 Not Found

Sorry, I am not a shiny user. Does not map show up? Or just the legend does not show up?

I cant share the screenshot somehow but just the legend, map is ok INFO: 127.0.0.1:57549 - "GET /jupyter-leaflet.js HTTP/1.1" 404 Not Found INFO: 127.0.0.1:57545 - "GET /ipyevents.js HTTP/1.1" 404 Not Found INFO: 127.0.0.1:57547 - "GET /jupyter-leaflet.js HTTP/1.1" 404 Not Found INFO: 127.0.0.1:57549 - "GET /ipyevents.js HTTP/1.1" 404 Not Found

The legend is an ipywidget HTML widget. Can you try if shiny can display an HTML widget without leafmap?
https://ipywidgets.readthedocs.io/en/latest/examples/Widget%20List.html#html

widgets.HTML(
    value="Hello <b>World</b>",
    placeholder='Some HTML',
    description='Some HTML',
)

Yes widgets work ok, this code displays the text as specified. Also the code commented out show an interactive widget:

from shiny.express import  ui
from shinywidgets import  render_widget
import ipywidgets as widgets

import leafmap
import geopandas as gpd
#data = leafmap.examples.datasets.countries_geojson
data =  gpd.read_file('/Users/boatenmi/Downloads/countries.geojson')


ui.page_opts(title="Market Change Profile", 

             )

with ui.sidebar(open="open"):
    ui.h4("Year Filter")
   
ui.nav_spacer()

with ui.nav_panel("Map"):
    with ui.card(full_screen=True):
        ui.card_header(f"Test Map")

        @render_widget
        def map_ui():
            m = leafmap.Map()
            m.add_data(
                data, column="POP_EST", scheme="Quantiles", cmap="Blues", legend_title="Population"
            )
            return m
        

with ui.nav_panel("Widget"):
    with ui.card(full_screen=True):
        ui.card_header(f"TestWidget")
        @render_widget
        def widgets_ui():
            k= widgets.HTML(
            value="Hello <b>World</b>",
            placeholder='Some HTML',
            description='Some HTML',
        )
        #    k= widgets.IntSlider(
        #     value=7,
        #     min=0,
        #     max=10,
        #     step=1,
        #     description='Test:',
        #     disabled=False,
        #     continuous_update=False,
        #     orientation='horizontal',
        #     readout=True,
        #     readout_format='d'
        # )
            return k```

How about this HTML? This is the template used by the legend.
https://github.com/opengeos/leafmap/blob/master/leafmap/data/template/legend.html

Yes that works as well. It generates a legend with the colors and corresponding values

Then the issue is probably related to the ipywidget Output widget. The legend widget is an Output widget, which displays the HTML widget. I guess shiny does not render the Output widget properly

https://ipywidgets.readthedocs.io/en/latest/examples/Output%20Widget.html

Thanks. I will try to ask the question on the shiny platform. I think the newer versions of this package doesnt work at all, so there may be some major compactibility issues. I cant use ipywidgets >= version 8.

Yeah. I guess this is an upstream issue, either ipywidgets or shiny.

Interesting because if I use ipyleaflet directly, it works. like this:

from ipyleaflet import *
from shiny.express import  ui
from shinywidgets import  render_widget
import ipywidgets as widgets

from ipyleaflet import Map, LegendControl
import leafmap
#import leafmap.foliumap as leafmap
import geopandas as gpd
#data = leafmap.examples.datasets.countries_geojson

ui.page_opts(title="Market Change Profile", 

             )

with ui.sidebar(open="open"):
    ui.h4("Year Filter")
   
ui.nav_spacer()

with ui.nav_panel("Map"):
    with ui.card(full_screen=True):
        ui.card_header(f"Test Map") 
            
        @render_widget
        def map_ui():
            mymap = Map(center=(-10, -45), zoom=4)
            a_legend = LegendControl(
            {"low": "#FAA", "medium": "#A55", "High": "#500"},
            title="Legend",
            position="bottomright")
            mymap.add(a_legend)
            return mymap
``` Wondering if the legend can be added manully to the map generated from leafmap

It is different. Leafmap does not use ipyleaflet's built-in LegendControl. It is a custom widget: an ipywidget Output widget with an HMTL widget displayed in it. If shiny can't render the Output widget, then it will not work.

Closing this issue for now as it has been reported upstream.