Dash Leaflet CircleMarker change color on fly

Hi there,
I’ve a map and I would like to display several points (CircleMarker). Regarding the value of the point, the feature delay, the point should change of color.

Example : delay = 0 → color = green, delay = 100 → color = red.

The delay value of each point will change every second so the color of the point could also change each second.

In a first step, I only tried to display the map and with a button change the color of the point but it doesn’t work. I could change, per example, the position, but not the color.
Here the code :


app.layout = html.Div(
    children=[
        dl.Map(
            [
                dl.TileLayer(
                    url="https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png",
                    attribution="CartoDB",
                ),
                dl.LayerGroup(id="circle_group",
                    [
                        dl.CircleMarker(
                            id="circle",
                            center=[45.8182, 8.1275],
                            radius=5,
                            color="#ff0000",
                            fill=True,
                            fillColor="#ff0000",
                            fillOpacity=1,
                        )
                    ]
                ),
            ],
            center=[45.8182, 8.1275],
            zoom=8,
            style={"height": "50vh"},
        ),
        html.Button("Change color", id="color-button"),
    ]
)

@app.callback(Output("circle", "color"), Input("color-button", "n_clicks"))
def update_circle_color(n_clicks):
      if n_clicks is None:
          return "#ff0000" 
      new_color = "#{:06x}".format(random.randint(0, 0xFFFFFF))
      return new_color

I also tried to pass to “dl.LayerGroup” a children to create new point.

app.layout = html.Div(
    children=[
        dl.Map(
            [
                dl.TileLayer(
                    url="https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png",
                    attribution="CartoDB",
                ),
                dl.LayerGroup(id="circle_group"),
    ]
)

@callback(
    Output("circle_group", "children"),
    Input("button_settings", "n_clicks"),
    State("button_settings", "color"),
)
def update_output(n_clicks: int, color: str):
        if n_clicks is None:
              new_color = "#ff0000" 
        esle:
               new_color = "#{:06x}".format(random.randint(0, 0xFFFFFF))
        circle = dl.CircleMarker(
                            id="circle",
                            center=[45.8182, 8.1275],
                            radius=5,
                            color=new_color,
                            fill=True,
                            fillColor=new_color,
                            fillOpacity=1,
                        )
        return circle

Does someone have an idea ?

Did you try without id - or with a random id?

@Emil Thanks for your reply. I did without id but not with a random id.
And indeed with a random id it works.

The id must therefore change. If there are a lot of points and a lot of color modifications to avoid having a large quantity of random IDs, a solution is therefore:

app.layout = html.Div(
    children=[
        dl.Map(
            [
                dl.TileLayer(
                    url="https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png",
                    attribution="CartoDB",
                ),
                dl.LayerGroup(id="circle_group"),
    ]
)

@callback(
    Output("circle_group", "children"),
    Input("button_settings", "n_clicks"),
    State("button_settings", "color"),
)
def update_output(n_clicks: int, color: str):
        if n_clicks is None:
              new_color = "#ff0000" 
        esle:
               new_color = "#{:06x}".format(random.randint(0, 0xFFFFFF))
        circle = [dl.CircleMarker(
                            id=f"circle_{i }_{n_clicks%2}",
                            center=[45.81+i, 8.1275],
                            radius=5,
                            color=new_color,
                            fill=True,
                            fillColor=new_color,
                            fillOpacity=1,
                        ) for i in range(10)
        return circle

Thanks for your help !

1 Like

Hi @Emil ,
Do you know if there is another mean to do this color change ?
The color of the points change. But, as I change the ID (to update the color) each second, when I click on a circle, the popup stay open only 1 second.

If I don’t change the ID of the circle the popup stay open but I don’t have the color that I want and if I change the ID I’ve the right color but I can’t use the popup option.

Any idea ?
Thanks