【问题标题】:Pandas and Matplotlib - Need vaccination percentage by country and bar plot for Preferred vaccine in specific country using dropdownPandas 和 Matplotlib - 需要按国家/地区的疫苗接种百分比和使用下拉菜单在特定国家/地区首选疫苗的条形图
【发布时间】:2021-09-25 16:52:06
【问题描述】:

这是数据集。

    location    date    vaccine total_vaccinations
0   Austria 2021-01-08  Johnson&Johnson 0
1   Austria 2021-01-08  Moderna 0
2   Austria 2021-01-08  Oxford/AstraZeneca  0
3   Austria 2021-01-08  Pfizer/BioNTech 30938
4   Austria 2021-01-15  Johnson&Johnson 0
... ... ... ... ...
8633    Uruguay 2021-07-05  Pfizer/BioNTech 1024793
8634    Uruguay 2021-07-05  Sinovac 3045997
8635    Uruguay 2021-07-06  Oxford/AstraZeneca  43245
8636    Uruguay 2021-07-06  Pfizer/BioNTech 1038942
8637    Uruguay 2021-07-06  Sinovac 3079853
8638 rows × 4 columns

我正在使用 Jupyter 笔记本。

  1. 按国家/地区划分的疫苗接种需求百分比
  2. 使用下拉菜单在特定国家/地区使用首选疫苗绘制条形图(交互式绘图小部件)

【问题讨论】:

    标签: python pandas dataframe matplotlib bar-chart


    【解决方案1】:
    • 您可以从OWID 获取包括人口数据在内的 COVID 数据
    • 看来这是您从制造商那里获取数据的地方
    • 我可以将数据与整体 COVID 数据合并,以便您记录的所有属性都可用
    • 已使用 plotly,因此它是交互式隐藏/显示痕迹
    • 注意,没有多少国家/地区按制造商发布数据
    import requests, io
    import pandas as pd
    
    # get data by manufactuerer
    dfm = pd.read_csv(io.StringIO(
        requests.get("https://raw.githubusercontent.com/owid/covid-19-data/master/public/data/vaccinations/vaccinations-by-manufacturer.csv").text))
    
    # get all 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))
    
    # join two datasets together and make manufactuerer data columns. NB not all countries publish this data...
    dfv = (
        dfall.set_index(["location", "date"])
        .join(
            dfm.set_index(["location", "date", "vaccine"])
            .unstack("vaccine")
            .droplevel(0, 1),
            how="inner",
        )
        .reset_index()
    )
    
    # filter to latest data only
    dfplot = (
        dfv.sort_values(["iso_code", "date"])
        .groupby("iso_code", as_index=False)
        .last()
        .sort_values("people_fully_vaccinated_per_hundred", ascending=False)
    )
    
    import plotly.express as px
    import plotly.graph_objects as go
    
    # use plotly so it's interactive.  rebase vaccines given by population
    fig = px.bar(
        dfplot.assign(
            **{c: dfplot[c] / dfplot["population"] for c in dfm["vaccine"].unique()}
        ),
        x="location",
        y=dfm["vaccine"].unique(),
    )
    # add a line of people fully vaccinated
    fig.add_trace(
        go.Scatter(
            x=dfplot["location"],
            y=dfplot["people_fully_vaccinated_per_hundred"] / 100,
            name="Fully vaccinated",
            mode="lines",
            line={"color": "purple", "width": 4},
        )
    )
    

    更新

    • 原始要求规定接种疫苗的人数百分比是必需的。这已根据 cmets 删除
    • 需求确实被重述为交互式仪表板,因此使用了 dash
    from jupyter_dash import JupyterDash
    import dash_core_components as dcc
    import dash_html_components as html
    import dash_table
    import dash_bootstrap_components as dbc
    from dash.dependencies import Input, Output, State
    import requests, io
    import pandas as pd
    import plotly.express as px
    
    # get data by manufactuerer
    dfm = pd.read_csv(io.StringIO(
        requests.get("https://raw.githubusercontent.com/owid/covid-19-data/master/public/data/vaccinations/vaccinations-by-manufacturer.csv").text))
    
    
    def buildTab(col="location"):
        dfc = pd.DataFrame({col: dfm[col].unique()})
        return dash_table.DataTable(
            id=col,
            columns=[{"name": c, "id": c} for c in dfc.columns],
            data=dfc.to_dict("records"),
            row_selectable="multi",
            style_header={"fontWeight": "bold"},
            style_as_list_view=True,
            css=[{"selector": ".dash-spreadsheet tr", "rule": "height: 5px;"}],
        )
    
    # Build App
    app = JupyterDash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
    app.layout = html.Div(
        [
            dbc.Row(
                [
                    dbc.Col(
                        buildTab(col="location"),
                        width=3,
                        style={"height": "20vh", "overflow-y": "auto"},
                    ),
                    dbc.Col(
                        buildTab(col="vaccine"),
                        width=3,
                        style={"height": "20vh", "overflow-y": "auto"},
                    ),
                ],
            ),
            html.Div(id="graphs"),
        ],
        style={
            "font-family": "Arial",
            "font-size": "0.9em",
        },
    )
    
    @app.callback(
        Output(component_id="graphs", component_property="children"),
        Input("location", "selected_rows"),
        Input("vaccine", "selected_rows"),
        State("location", "data"),
        State("vaccine", "data"),
    )
    def updateGraphs(selected_location, selected_vaccine, location, vaccine):
        global dfm
        if selected_location and selected_vaccine:
            d = dfm.merge(
                pd.DataFrame(location).iloc[selected_location], on="location", how="inner"
            ).merge(pd.DataFrame(vaccine).iloc[selected_vaccine], on="vaccine", how="inner")
            return dcc.Graph(
                figure=px.bar(
                    d.sort_values(["location", "vaccine", "date"])
                    .groupby(["location", "vaccine"], as_index=False)
                    .last(),
                    x="location",
                    y="total_vaccinations",
                    color="vaccine",
                )
            )
        else:
            return None
    
    # Run app and display result inline in the notebook
    app.run_server(mode="inline")
    

    【讨论】:

    • 您能否仅使用问题中提供的数据框而不是合并进行指导。我怎样才能得到相同的图表,我还需要使用下拉选项
    • 已更新 - 已删除所有可让您在图表上获得百分比的项目,人口和国家疫苗接种率信息不再合并到可用于构建图的数据框中
    【解决方案2】:

    我可以提供按国家/地区划分的百分比,但不能提供条形图部分。您可以使用 groupby、merge 和 math 来获得所需的数字:

    df = pd.DataFrame({'location': ['Austria', 'Austria', 'Austria', 'Austria'],
                       'vaccine': ['Moderna', 'Johnson&Johnson', 'Moderna', 'Johnson&Johnson'],
                       'total_vaccinations': [1, 2, 3, 4]})
    
    # df_tcv = df_total_by_country_by_vaccine
    df_tcv = df.groupby(['location', 'vaccine'], as_index=False)['total_vaccinations'].sum()
    
    df_total_by_country = df_tcv.groupby('location', as_index=False)['total_vaccinations'].sum()
    df_total_by_country = df_total_by_country.rename(columns={'total_vaccinations': 'location_total'})
    
    df_tcv = df_tcv.merge(df_total_by_country, on='location', how='left')
    
    df_tcv['pct_vac_by_c'] = df_tcv['total_vaccinations'] / df_tcv['location_total']
    

    获取 df_tcv:

      location          vaccine  total_vaccinations  location_total  pct_vac_by_c
    0  Austria  Johnson&Johnson                   6              10           0.6
    1  Austria          Moderna                   4              10           0.4
    

    【讨论】:

    • 你能告诉我我提供的数据框吗?在上面的示例中,您已硬编码位置和总疫苗接种次数,并将其放入数据框中。但是我提供的数据框有很多记录,所以我需要使用 for 循环。如果是的话会怎么样?
    猜你喜欢
    • 2011-10-13
    • 1970-01-01
    • 2018-03-23
    • 1970-01-01
    • 1970-01-01
    • 2020-04-04
    • 1970-01-01
    • 1970-01-01
    • 2011-12-20
    相关资源
    最近更新 更多