Scattermapbox not refreshing when slicing pandas dataframe from callback

Hello there!!!

The problem is, that even when I slice and redo de plot, all the markers are shown in the Scattermap. The callbacks works as far as the hover information goes, enabeling/disabeling the hover based on the slice.

So, this is where I got so far with my code… but I would like to

  1. firt, only show the markes for the data on the callbacks
  2. if possible, adjust zoom and center to fit the new coordinates extension.

I’m sending the data sample as well:

bioma_munic

iN_2

Thanks anyone for the help!

## =====================================================================
# Libraries and Dependencies
import dash
from dash import dcc, html
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc

import plotly.express as px
import plotly.graph_objects as go

import pandas as pd
import numpy as np

def custom_sort(s):
    return s.str.normalize('NFKD').str.encode('ascii', errors='ignore').str.decode('utf-8').str.lower()

def time_grupper(period,df,dtc_column_name):
    
    col = dtc_column_name
    gc = df.copy(deep=True)
    list_sum_Columns = ['requer_area_tot_supres_ha','conced_area_tot_supres_ha']

    if period == 'Diário':
        group = gc.groupby([gc[col].dt.year, gc[col].dt.month, gc[col].dt.day])[list_sum_Columns].sum()
        group.index = pd.to_datetime(group.index.map(lambda x: f'{x[0]}-{x[1]}-{x[2]}'), format='%Y-%m-%d')
        dummy_range = pd.date_range(start=group.index.min(), end=group.index.max(), freq='D')
        group = group.reindex(dummy_range).fillna(0)
    elif period == 'Mensal':
        group = gc.groupby([gc[col].dt.year, gc[col].dt.month])[list_sum_Columns].sum()
        group.index = pd.to_datetime(group.index.map(lambda x: f'{x[0]}-{x[1]}'), format='%Y-%m')
        dummy_range = pd.date_range(start=group.index.min(), end=group.index.max(), freq='M').to_period('M').asfreq('D', how='start').to_timestamp()
        group = group.reindex(dummy_range).fillna(0)
    elif period == 'Anual':
        group = gc.groupby(gc[col].dt.year)[list_sum_Columns].sum()
    elif period == 'Trimestral':
        group = gc.groupby(gc[col].dt.to_period('Q'))[list_sum_Columns].sum()
        group.index = group.index.to_timestamp()
    
    return group

def plot_scatter(geo_data):
    fig = px.scatter_mapbox(geo_data, 
                    lat="latitude", 
                    lon="longitude", 
                    hover_name="num_portaria", 
                    hover_data=["nom_municipio", "area_concedida_por_imovel","num_processo"],
                    size="area_concedida_por_imovel",
                    zoom=5.4,
                    color_discrete_sequence=["green"],  # Set default marker color to green
                    center=dict(lat=-13.09787543902437, lon=-41.16281891614226),
    )

    fig.update_layout(mapbox_style="carto-positron")
    fig.update_layout(margin={"r": 0, "t": 0, "l": 0, "b": 0})
    
    return(fig)

## =====================================================================
# Loading DATA

iN_2 = pd.read_csv('../ASV_Dados/20231027_ASVs_geometrias.csv')
iN_2.dropna(subset=['latitude', 'longitude'], inplace=True)
geom = iN_2.loc[iN_2['estado_uf'] == 'BA']

bioma_munic = pd.read_csv('../ASV_Dados/local e biomas/tabela_biomas.csv',sep=';').sort_values(by=['Município'], key=lambda x: custom_sort(x))

## =====================================================================
# General App Config 
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.LITERA],
                meta_tags=[{
                        "name": "viewport",
                        "content": "width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no",
                    }]
                )

app.title = "Painel ASV"

app.config["suppress_callback_exceptions"] = True

## =====================================================================
# Layout

app.layout = dbc.Container(
    children=[
        ## =====================================================================
        # Cabeçalho
        dbc.Row([
            dbc.Col([
                html.Div([
                    html.Img(id='logo-seia', src=app.get_asset_url("logo_seia.png"), height=30), 
                    html.H1(children='Painel de Monitoramento - ASV', style={'text-align':'center','color':'darkgreen','padding':'12px'})
                ],style={'display': 'flex', 'align-items': 'center', 'flex-direction': 'row'})
            ], width={"size":8,"offset":2}, className='d-flex justify-content-center'),
        ]),

        ## =====================================================================
        # Corpo do Painel
        dbc.Row([
            dbc.Col([
                dcc.Dropdown(id='biomas-dpdn', multi=True, 
                            value=['Caatinga', 'Cerrado', 'Mata Atlântica'],
                            options=[{'label': bioma, 'value': bioma} for bioma in sorted(bioma_munic['Bioma'].unique())],
                            clearable=False,
                            style={'text-align':'center','align-items':'center','padding':'0px 0px 3px 3px'},
                ),
                dbc.Form(
                    html.Div([
                        # dbc.Label("Seleções Adicionais por Município",style={'display':'flex'}),
                        dbc.Input(id='filter_city',placeholder='Buscar Município...', type='text', className='my-2'),
                        dbc.Checklist(
                                id='switches-in', 
                                options=[{'label': city, 'value': city} for city in bioma_munic['Município']],
                                labelStyle={"display": "flex", "align-items": "center"},
                                style={'height': '75vh', 'overflowY': 'auto'},
                                switch=True,
                                className='bg-light'
                            )
                    ])
                )
            ], width={"size":4}),
            dbc.Col([
                dcc.Loading(
                    id="loading-1",
                        type="default",
                        children=[
                            html.Div([
                                dbc.Card([
                                    dbc.CardHeader('ASVs Concedidas'),
                                    dbc.CardBody(
                                        html.H6(id="num-asv-text", className='card-title')
                                        )], className='bg-success text-white w-50 my-2'
                                ),
                                dbc.Card([
                                    dbc.CardHeader('Hectares liberados'),
                                    dbc.CardBody(
                                        html.H6(id="supres-total-text", className='card-title')
                                        )], className='bg-success text-white w-50 m-2'
                                ),
                        ],className='d-flex justify-content-center'),
                            dcc.Graph(id="map_asv_geom", style={'height': '75vh', 'margin-right': '10px'})
                        ]),
            ],width={"size":8}),
        ]),
        ## =====================================================================
        # Footer
        dbc.Row([
            dbc.Col([
                # html.p("esse é o final")
            ])
        ]),
        ## =====================================================================
        # END
    ], fluid=True
)

## =====================================================================
# APP 
@app.callback(
        Output('switches-in','options'),
        Input('biomas-dpdn','value')
)
def update_bioma_restriction(bioma_slctd):
    if bioma_slctd is None:
        raise dash.exceptions.PreventUpdate
    else:
        list_munic_bioma=bioma_munic[bioma_munic['Bioma'].isin(bioma_slctd)]
        munic_relist = [{'label':city, 'value':city} for city in list_munic_bioma['Município']]
    
    return(munic_relist)

@app.callback(
    [
        Output('map_asv_geom','figure'),
        Output('num-asv-text','children'),
        Output('supres-total-text','children'),
    ],
    [
        Input('switches-in','value'),
        Input('switches-in','options')
    ]
)
def upd_geom(value,options):
    if value: 
        geom_filt = iN_2[iN_2['nom_municipio'].isin(value)]
    else:
        geom_filt = iN_2[iN_2['nom_municipio'].isin([entry['value'] for entry in options])]

    num_asv = len(geom_filt['num_portaria'].unique())
    supress_total = geom_filt['area_concedida_por_imovel'].sum()
    supress_total = '{:,.2f} ha'.format(supress_total).replace(',', 'temp').replace('.', ',').replace('temp', '.')

    fig = plot_scatter(geom_filt)

    return (fig, num_asv, supress_total)
    
if __name__ == "__main__":
    app.run_server(debug=True)```