Skip to content

Allow users to add new Control classes without implementing a plugin #2122

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 22, 2025

Conversation

hansthen
Copy link
Collaborator

@hansthen hansthen commented Apr 6, 2025

@Conengmo

This is a new, smaller implementation of the Control class I implemented earlier. For this PR I focused only on the user's ability to load a new control in user space, without having to write a new plugin. It is not difficult to write a plugin, but it does require knowledge of Jinja. Also, there is quite some boilerplate code involved.

With this Control clas I was able to implement the minimap and ruler plugins, using just a few lines of code.

import folium
import streamlit as st
from folium import Control, TileLayer

from streamlit_folium import st_folium

st.set_page_config(
    page_title="minimap",
    layout="wide"
)

m = folium.Map(
    location=[39.949610, -75.150282],
    zoom_start=5,
    zoom_control=False
)
tiles = TileLayer(
    tiles="OpenStreetMap",
    show=False,
    control=False,
)
tiles.add_to(m)

minimap = Control("MiniMap", tiles)
minimap.add_js_link(
    "minimap_js",
    "https://cdnjs.cloudflare.com/ajax/libs/leaflet-minimap/3.6.1/Control.MiniMap.min.js"
)
minimap.add_css_link(
    "minimap_css",
    "https://cdnjs.cloudflare.com/ajax/libs/leaflet-minimap/3.6.1/Control.MiniMap.css"
)
minimap.add_to(m)

ruler = Control("Ruler", tiles)
ruler.add_js_link(
    "ruler_js",
    "https://cdn.rawgit.com/gokertanrisever/leaflet-ruler/master/src/leaflet-ruler.js",
)
ruler.add_css_link(
    "ruler_css",
    "https://cdn.rawgit.com/gokertanrisever/leaflet-ruler/master/src/leaflet-ruler.css",
)
ruler.add_to(m)

st_folium(m, width=1600, height=600)

@hansthen hansthen requested a review from Conengmo April 6, 2025 19:39
@hansthen hansthen changed the title Add leaflet control Allow users to add new Control classes without implementing a plugin Apr 18, 2025
@hansthen
Copy link
Collaborator Author

hansthen commented Apr 18, 2025

Closes #1992

This was linked to issues Apr 18, 2025
@hansthen hansthen requested a review from ocefpaf April 19, 2025 05:30
@hansthen
Copy link
Collaborator Author

@ocefpaf can you have a look?

control: str
The javascript class name of the control to be rendered.
position: str
One of "bottomright", "bottomleft", "topright", "topleft"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One problem that we have in folium templates are the silent erros when passing keywords to it. For example, if someone types bottonright instead of bottomright, it will take user a while to figure out what is wrong.

Maybe we should check for this 4 valid kw? I know this doesn't solve it for all templates, but in this case it may be small enough that it is worth it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean as a static typing check or as an assert?

Copy link
Member

@ocefpaf ocefpaf Apr 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should avoid assert use outside of tests.

I'm old school but here is what I would do:

  1. make position a kw argument, not an arg;
  2. Sanitize it with a position.lower() to validate names copied from leaflet JS docs;
  3. Check if the sanitized positions is in a valid list with those 4 names and raise a ValueError if not.

What do you think?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see we have been inconsistent in banning assert :-)

@hansthen hansthen requested a review from ocefpaf April 22, 2025 13:14

if position is not None:
position = position.lower() # type: ignore
if position not in (args := get_args(TypePosition)):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I was a Fortran programmer in my early days, type checking is not my forte. (Heck, I moved to Python to get away from this ;-p)

My crude review tells me that this is equivalent to what I described in my review comment, right? If so, merge away!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wrote my first program for money in RPG :-) which is a fairly obscure language almost as old as Fortran. Whitespace is significant to a fault.

     C* PARAMETER LIST
     C           *ENTRY    PLIST
     C                     PARM           DATEIN  80
     C* PROGRAM START
     C           DATEIN    DIV  100       DATEIN
     C                     MVR            DAY     20
     C           DATEIN    DIV  100       DATEIN
     C                     MVR            MONTH   20
     C                     Z-ADDDATEIN    YEAR    40
     C* SHOW RESULTS
     C           YEAR      DSPLY
     C           MONTH     DSPLY
     C           DAY       DSPLY
     C                     SETON                         LR
     C* EXECUTION EXAMPLE
     C* CALL SEPDATE PARM(X'019960531F')

I added one more test.

@hansthen hansthen merged commit c1210ce into python-visualization:main Apr 22, 2025
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add Leaflet-Ruler plugin Create Scale control class
2 participants