Update leaflet center from callback

Hi,
I have a django-plotlyy-dash app with a leaflet map in it.
The plotly fig updates with a callback function.
On the leaflet map I have markers, they also updat with a callback function.
Now, I would like the map to recenter if the marker changes.
Here’s what is in my views.py:

the dash app:

app.layout = html.Div([

    dcc.DatePickerRange(

    id='my-date-picker-range',

    start_date_placeholder_text="Start Period",

    end_date_placeholder_text="End Period",

    calendar_orientation='vertical',

    end_date = date.today(),

    start_date = date.today() - timedelta( days = 4)

    ),

    #html.Div(id='output-container-date-picker-range'), 

    

    dcc.Graph (id='fig_1',figure= fig),

    dl.Map(

        [

            dl.LayersControl(

                [

                    dl.BaseLayer(

                        dl.TileLayer(),

                        name="OpenStreetMaps",

                        checked=True,

                    ),

                    dl.BaseLayer(

                        dl.TileLayer(

                            url="https://www.ign.es/wmts/mapa-raster?request=getTile&layer=MTN&TileMatrixSet=GoogleMapsCompatible&TileMatrix={z}&TileCol={x}&TileRow={y}&format=image/jpeg",

                            attribution="IGN",

                        ),

                        

                        name="IGN",

                        checked=False,

                    ),

                    dl.MarkerClusterGroup(id="markers", children=[marker])

                ],

            ),

            

        ],

        zoom=20,

        center=(latitude, longitude),

    )],

    style={

        "height": "50vh",

    },

)

@app.callback(

    

    #Output('output-container-date-picker-range', 'children')

    [

    dash.dependencies.Output('fig_1', component_property='figure'),

    dash.dependencies.Output('markers', component_property='marker')

    ],

    [dash.dependencies.Input('my-date-picker-range', 'start_date'),

    dash.dependencies.Input('my-date-picker-range', 'end_date')

    ])

def update_output(start_date, end_date):

    print("start date : "  + start_date )

    print(" end date : "  + end_date )

    string_prefix = 'You have selected: '

    if start_date is not None:

        start_date_object = date.fromisoformat(start_date)

        print( start_date_object )

        start_date_string = start_date_object.strftime('%B %d, %Y')

        string_prefix = string_prefix + 'Start Date: ' + start_date_string + ' | '

    if end_date is not None:

        end_date_object = date.fromisoformat(end_date)

        end_date_string = end_date_object.strftime('%B %d, %Y')

        string_prefix = string_prefix + 'End Date: ' + end_date_string

    if len(string_prefix) == len('You have selected: '):

        return 'Select a date to change the selection'

    else:

        timerange = (end_date_object - start_date_object)

        days = timerange.days

        print (days)

        string = '-' + str(days) + 'd'

        print (string)

        df = utils.getinflux(sensor.serial,string)

        print (df)

        fig_1, marker, latitude, longitude = utils.createfig(df)

        print (latitude)

        print(fig_1)

        return (fig_1, marker)

Any suggestion on how to manipulate the ‘center’ of the map with a callback is very welcome !

1 Like

@Emil can you maybe please take a look at this? I have a similar concern but cant seem to make it work.

Thanks

@GoharS Could you post a MWE, i.e. a piece of code that runs independently and demonstrates the issue? There are a number of bugs in the original post, so it is not clear to me what the issue is.

Hi @Emil ,
Many thanks for getting back to me. I found the answer in this GitHub issue: Possibility to have zoom and center as Inputs in dash callback? · Issue #32 · thedirtyfew/dash-leaflet · GitHub

I think this is also posted by you?

Great that you got it working. Yes, that is also me :slightly_smiling_face:

In my case the old example does not work. There is no firing of callback with the current version. Can you please rerun the example ? However to see a map I had to explivcitly indicate the zoom level

I need to get the current viewport in a callback.

thanks

import dash
import dash_leaflet as dl
from dash_leaflet import Map
import dash_leaflet as dl

import dash_html_components as html
import json

from dash.dependencies import Output, Input, State

    
app = dash.Dash()
app.layout = html.Div([
dl.Map(children=dl.TileLayer(), center=[0,0],zoom=5, style={'width': '1000px', 'height': '500px'}, id="map"),

html.Div(id="output1"), html.Div(id="output2"), html.Div(id="output3")
])

@app.callback(Output("output1", "children"), [Input("map", "zoom")])
def func(viewport):
        print(viewport)
        return json.dumps(viewport)

@app.callback(Output("output2", "children"), [Input("map", "center")])
def func(viewport):
        print(viewport)
        return json.dumps(viewport)

@app.callback(Output("output3", "children"), [Input("map", "viewport")])
def func(viewport):
        print(viewport)
        return json.dumps(viewport)

if __name__ == '__main__':
        app.run_server()

Also having issues getting the example in the documentation to work ( MapContainer (dash-leaflet.com)), I also need to be update to update the map via the viewport

What issues are you having with the example in the docs? What version are you on?

Hi Emil,

I am trying to run the example below as I would like to have a similar callback to update the map zoom and position using the viewport parameter. I’m using dash-leaflet 1.0.4.

I can see this output the terminal output:

127.0.0.1 - - [24/Nov/2023 07:41:02] “POST /_dash-update-component HTTP/1.1” 200 -

so it is attempting to update, but nothing is happening and I don’t know much about javascript.

import dash_leaflet as dl
from dash import Dash, html, Output, Input

import dash_leaflet as dl
from dash import Dash, html, Output, Input

app = Dash()
app.layout = html.Div([
    dl.Map([
        dl.TileLayer()
    ], center=[56, 10], zoom=6, style={'height': '50vh'}, id="map"),
    html.Button("Fly to Paris", id="btn")
])

@app.callback(Output("map", "viewport"), Input("btn", "n_clicks"), prevent_initial_call=True)
def fly_to_paris(_):
    return dict(center=[48.864716, 2.349014], zoom=10, transition="flyTo")

if __name__ == '__main__':
    app.run_server()

Could you try with a later version, e.g. 1.0.11 as the docs suggest?

Thanks Emil, I can confirm it is working with v1.0.11.