Search code examples
pythonplotlymaps

How to plot a map with time-slider and zoom on a city with plotly in python


I want to create an interactive map that shows the evolution of a variable (number of bikes) on different points of a city.

Why not by using plotly.

I would like to do something like this : https://amaral.northwestern.edu/blog/step-step-how-plot-map-slider-represent-time-evolu with a slider.

However, I don't achieve to reproduce it with focusing on a city, I can't choose a scope more precise than "europe".

Do you know how to do it with a zoom ?


Solution

    • you have not provided any code or sample data. Hence have used this http://api.citybik.es/v2/ https://github.com/eskerda/pybikes project to source some bike data
    • data is just latest, so build up data in a pickle file for evolution
    • simple case of using Plotly Express and animation_frame argument

    data sources

    import requests
    import pandas as pd
    from pathlib import Path
    import plotly.express as px
    
    # avalaible data sources...
    pd.json_normalize(
        requests.get("http://api.citybik.es/v2/networks").json()["networks"]
    ).loc[lambda d: d["location.city"].eq("London")]
    

    bike stand sourcing and plotting

    df = pd.json_normalize(
        requests.get("http://api.citybik.es/v2/networks/santander-cycles").json()[
            "network"
        ]["stations"]
    )
    
    # build up some data over time
    df["timestamp"] = pd.to_datetime(df["timestamp"]).round("15min")
    f = Path.cwd().joinpath("bikes.pickle")
    if not f.exists():
        df.to_pickle(f)
    else:
        df = pd.concat([pd.read_pickle(f), df])
        df = df.groupby(["timestamp","id"], as_index=False).first()
        df.to_pickle(f)
    
    # now just plot it on a map with evolution by time
    df["ts_str"] = df["timestamp"].dt.strftime("%d-%b %H:%M")
    px.scatter_mapbox(
        df,
        lat="latitude",
        lon="longitude",
        size="free_bikes",
        hover_data=["name"],
        animation_frame="ts_str",
    ).update_layout(
        mapbox={"style": "carto-positron", "zoom":11}, margin={"l": 0, "r": 0, "t": 0, "b": 0}
    )
    

    enter image description here