0

How can I make this code with drop down menu to chose between "New Cases" and 2 other columns that I have in my csv file

# load in new csv to merge with geodata
import pandas as pd
df = pd.read_csv("ALLCOUNTRIES-PREDICTED.csv", header=0, encoding="utf-8")
import plotly.express as px

fig = px.choropleth(df,                                   
                 locations="iso_alpha_3",
                 color="New Cases",                     # identify representing column
                 hover_name="Country",                # identify country code column                                  
                 animation_frame="Date",              # identify date column
                 projection="equirectangular",          # select projection
                 color_continuous_scale = 'Reds',    # select prefer color scale
                 range_color=[0,10000]                  # select range of dataset

                 ) 
fig.show()  
fig.write_html("example_map1.html")    
dhuhahuss
  • 3
  • 3
  • Your question isn't reproducible without your data so I would recommend you upload a sample of your `df` as properly formatted text. however, for now I can point you in the direction of this answer: https://stackoverflow.com/questions/59406167/plotly-how-to-filter-a-pandas-dataframe-using-a-dropdown-menu – Derek O Nov 06 '21 at 23:03
  • have deleted answer as updatemenus is not way to go... need to use something that allows use of **dash** but comment didn't indicate this acceptable – Rob Raymond Nov 08 '21 at 10:16

1 Answers1

2
  • source OWID COVID data. Renamed columns to be consistent with column names in question
  • core concept. Build a figure for each column. Each figure contains traces (data), frames and layout. Key is that each frame name is unique, hence addition of a suffix (a, b or c)
  • integrate three figures
    • traces is simple, just traces from first figure
    • frames is relatively simple, all frames from all figures
    • layout take layout from first figure without play/pause buttons
  • updatemenus is drop down of required columns. args are sliders and coloraxis from appropriate figure
  • have used different color scales for each column. have used a different max for range_color for each column, calculated from underlying data
  • play / pause have been removed - they can be made to partially work using this concept https://plotly.com/python/animations/#defining-button-arguments However this means you then need to updatemenus from updatemenus which really does not work in a completely static structure that updatemenus is
import pandas as pd
import io, requests
import plotly.express as px
import plotly.graph_objects as go

# get OWID COVID data
dfall = pd.read_csv(
    io.StringIO(
        requests.get(
            "https://raw.githubusercontent.com/owid/covid-19-data/master/public/data/owid-covid-data.csv"
        ).text
    )
)

# filter make data frame have same columns as question and filter to a few days..
dfall["date"] = pd.to_datetime(dfall["date"])
df = dfall.rename(
    columns={
        "iso_code": "iso_alpha_3",
        "new_cases": "New Cases",
        "location": "Country",
        "date": "Date",
    }
).loc[lambda d: d["Date"].ge("1-nov-2021")]
df["Date"] = df["Date"].dt.strftime("%Y-%b-%d")

# three columns we're going to build choropleths from
cols = ["New Cases", "new_deaths", "new_vaccinations"]

# build figures for each of the required columns
# key technique is append a suffix to animation frame so each frame has it's
# own name...
figs = [
    px.choropleth(
        df.assign(Date=lambda d: d["Date"] + f"~{suffix}"),
        locations="iso_alpha_3",
        color=c,  # identify representing column
        hover_name="Country",  # identify country code column
        animation_frame="Date",  # identify date column
        projection="equirectangular",  # select projection
        color_continuous_scale=color,  # select prefer color scale
        range_color=[
            0,
            df.groupby("Date")[c].quantile(0.75).mean(),
        ],  # select range of dataset
    )
    for c, color, suffix in zip(cols, ["Blues", "Reds", "Greens"], list("abc"))
]

# play / pause don't work as don't stop between columns..
layout = {
    k: v
    for k, v in figs[0].to_dict()["layout"].items()
    if k not in ["template", "updatemenus"]
}


# build figure from all frames, with layout excluding play/pause buttons
fig = go.Figure(
    data=figs[0].data, frames=[fr for f in figs for fr in f.frames], layout=layout
)

# finally build drop down menu...
fig = fig.update_layout(
    updatemenus=[
        {
            "buttons": [
                {
                    "label": c,
                    "method": "relayout",
                    "args": [
                        {
                            "coloraxis": col_fig.layout.coloraxis,
                            "sliders": col_fig.layout.sliders,
                        }
                    ],
                }
                for c, col_fig in zip(cols, figs)
            ]
        }
    ]
)

fig

enter image description here

dash / plotly solution

  • using dash it becomes very simple, just build as many figures as columns
  • dropdown with call back just picks appropriate figure
import pandas as pd
import io, requests
import plotly.express as px
import plotly.graph_objects as go
import dash
from dash.dependencies import Input, Output, State
from jupyter_dash import JupyterDash

# get OWID COVID data
dfall = pd.read_csv(
    io.StringIO(
        requests.get(
            "https://raw.githubusercontent.com/owid/covid-19-data/master/public/data/owid-covid-data.csv"
        ).text
    )
)

# filter make data frame have same columns as question and filter to a few days..
dfall["date"] = pd.to_datetime(dfall["date"])
df = dfall.rename(
    columns={
        "iso_code": "iso_alpha_3",
        "new_cases": "New Cases",
        "location": "Country",
        "date": "Date",
    }
).loc[lambda d: d["Date"].ge("1-nov-2021")]
df["Date"] = df["Date"].dt.strftime("%Y-%b-%d")

# three columns we're going to build choropleths from
cols = ["New Cases", "new_deaths", "new_vaccinations"]

# build figures for each of the required columns
figs = [
    px.choropleth(
        df,
        locations="iso_alpha_3",
        color=c,  # identify representing column
        hover_name="Country",  # identify country code column
        animation_frame="Date",  # identify date column
        projection="equirectangular",  # select projection
        color_continuous_scale=color,  # select prefer color scale
        range_color=[
            0,
            df.groupby("Date")[c].quantile(0.75).mean(),
        ],  # select range of dataset
    )
    for c, color in zip(cols, ["Blues", "Reds", "Greens"])
]

# Build App
app = JupyterDash(__name__)

app.layout = dash.html.Div(
    [
        dash.dcc.Dropdown(
            id="choropleth",
            options=[{"label": c, "value": i} for i, c in enumerate(cols)],
            value=0,
        ),
        dash.dcc.Graph(
            id="map",
        ),
    ]
)

@app.callback(Output("map", "figure"), Input("choropleth", "value"))
def updateGraph(id):
    if not id: return figs[0]
    return figs[int(id)]

# Run app and display result inline in the notebook
app.run_server(mode="inline")
Rob Raymond
  • 29,118
  • 3
  • 14
  • 30
  • thank a lot,, but why (# play / pause don't work as don't stop between columns..) is there any way to make it work?? – dhuhahuss Nov 07 '21 at 09:32
  • actually I think there is a way https://plotly.com/python/animations/#defining-button-arguments I'll dig a bit more into it – Rob Raymond Nov 07 '21 at 11:21
  • can't get it to work - have further explained in answer. I really can't get it to work in a purely **plotly** solution. would be simple with combination of **dash** and **plotly** but you question indicates a 100% **plotly** solution is required – Rob Raymond Nov 08 '21 at 10:20
  • I really appreciate your efforts to help , thanks a lot ,,,its ok with dash and plotly , I just need it to be flexible with play/pause and drop down list – dhuhahuss Nov 08 '21 at 17:20
  • updated with dash / plotly solution – Rob Raymond Nov 08 '21 at 17:50
  • when I running the code I got this error (IncorrectTypeException: The input argument `` is not a list of `dash.dependencies.Input`s.) – dhuhahuss Nov 08 '21 at 19:23
  • what version of dash do you have installed? I'm using 2.0.0 – Rob Raymond Nov 08 '21 at 19:25
  • I have installed 2.0.0 – dhuhahuss Nov 08 '21 at 20:01
  • I am using this line of code to read csv file which is stored in my computer ( dfall = pd.read_csv("predictedcountries-norm.csv", header=0, encoding="utf-8")) – dhuhahuss Nov 08 '21 at 20:22
  • you noted 3 columns but didn't state what they were so I used `cols = ["New Cases", "new_deaths", "new_vaccinations"]` change to be the columns you want – Rob Raymond Nov 08 '21 at 20:30
  • I changed them ,running the code ends with this error (ConnectionError: HTTPConnectionPool(host='127.0.0.1', port=8050): Max retries exceeded with url: /_alive_0a0f5be4-cca2-4a73-981c-ea3971d3548b (Caused by NewConnectionError(': Failed to establish a new connection: [WinError 10061] No connection could be made because the target machine actively refused it')) – dhuhahuss Nov 08 '21 at 20:37
  • never seen that... https://github.com/plotly/jupyter-dash/issues/16 try `app.run_server(mode="inline", debug=False)` as final line. I'm assuming you are running in a jupyter env... – Rob Raymond Nov 08 '21 at 21:14
  • I am running in jupyter notebook ,,I tried your solution but I got the same error – dhuhahuss Nov 08 '21 at 22:31
  • its working now, I add this line (app.run_server(mode="inline", host="localhost",port=8051)) thanks for your help :) – dhuhahuss Nov 09 '21 at 12:28