1

I have been trying to put together a Plotly Dash app that will pull up our clients current hours and historical hours with the current hours being represented as a gauge of how many have been used versus how many are allowed, which varies from client to client so there is no set value I can input as an overall value. So, value = hours spent and range is [0, hours allowed]

I have tried using .iloc, and .values but neither have worked to single out the integer as an independent variable to be used. However, I also have a feeling that I am screwing something up in general with the dash, so if anyone can help me unscrew this so I can get it presented by Friday would be lovely.

Edit

@mozway, sorry about that (also, apparently enter sends). The csv looks like this:

    Client | Hours Spent | Hours Allowed | Last Updated
     XXXX  |     30.81   |          60   |  2021-09-07

And so on. As for pinpoint, it gives me a error at the Indicator figure


    elif client != "All":
    dff = dfhours.query('Client == "{}"'.format(client))
    ha = dff.values[0][5]
        
    fig = go.Figure(go.Indicator(
        domain = {'x': [0, 1], 'y': [0, 1]},
        value = dff['Hours Spent'],
        mode = "gauge+number",
        gauge = {'axis': {'range':[None, ha]}}))
    
    ValueError: 
        Invalid value of type 'pandas.core.series.Series' received
    for the 'value' property of indicator
    Received value: 0    30.81
    Name: Hours Spent, dtype: float64
    
    The 'value' property is a number and may be specified as:
      - An int or float

It is supposed to use the values from Hours Spent as the Value for the gauge, and the Hours Allowed as the end of the gauge.

End Edit


    

    app = dash.Dash(__name__)
    
        dfhours = pd.read_csv("hothours9-7.csv")
        dfhours['Last Updated'] = pd.to_datetime(dfhours['Last Updated'])
    dfclients = pd.read_csv("hotclients9-7.csv")
    clients = clientlist['Client'].unique()
    
    app.layout = html.Div(children=[
        html.H1(
            children='Hello!',
            style={
                'textAlign': 'center'
            }
        ),
        
        html.Br(),
        
        html.Div([
            html.Label('Clients'),
            dcc.Dropdown(
                id='clients-list',
                options=[{'label': i, 'value': i} for i in clients],
                value='All',
                style = {'width': "80%"}
            ),
            dcc.Dropdown(
                id='info-drop',
                options = [{'label': i, 'value': i} for i in ['Historical Hours', 'Current Hours']],
                value = 'Current Hours',
            )
        ]),
        html.Br(),
        
       dcc.Graph(id='info-graph')         
    ])
    
    
    #-------------------------------------------
    
    @app.callback( 
                Output('info-graph','figure'),
                [Input('clients-list','value'),
                 Input('info-drop','value')])
    def update_graph(client,info):    
        if info == "Current Hours":
            if client == "All":
                fig = px.bar(dfhours, x="Client", y="Hours Spent")
            
            elif client != "All":
                dff = dfhours.query('Client == "{}"'.format(client))
                ha = dff.values[0][5]
            
                fig = go.Figure(go.Indicator(
                    domain = {'x': [0, 1], 'y': [0, 1]},
                    value = dff['Hours Spent'],
                    mode = "gauge+number",
                    gauge = {'axis': {'range':[None, ha]}}))
        elif info == 'Historical Hours':
            if client == "All":
                dcc.Checklist(
                    options = [{"label": x, "value": x} for x in dfclients['Client']]),
                fig = px.line(dfclients,x="Last Updated",y="Hours Spent",color="Client")
            
            elif client != "All":
                dff = dfclients.query('Client == "{}"'.format(client)),
                
                fig = px.line(dff, x="Last Updated",y="Hours Spent")
        return fig
    
    
    
    if __name__=='__main__':
        app.run_server(debug=False)

  • 2
    You question is currently not reproducible (we do not know your csv file) and not minimal (can you pinpoint the minimal code needed to show your problem?), also it would be great to provide the expected output. [how to ask good pandas questions](https://stackoverflow.com/questions/20109391/how-to-make-good-reproducible-pandas-examples) – mozway Sep 15 '21 at 06:49
  • 1
    @JosephPadgett You can easily share a sample of your dataframe using `df.to_dict()` as explained [here](https://stackoverflow.com/questions/63163251/pandas-how-to-easily-share-a-sample-dataframe-using-df-to-dict/63163254#63163254) – vestland Sep 15 '21 at 07:42
  • @mozway does that edit help clarify? I am terrible at explaining things haha. – Joseph Padgett Sep 15 '21 at 17:51
  • @Joseph looks like you already have a nice answer, have you tested it? Give the author feedback if this doesn't work as you want – mozway Sep 15 '21 at 18:21

1 Answers1

1
  • have simulated your data...
  • simple case of reset_index() after filtering dataframe then allows you to always access row as index 0 (assumes one row per client)
  • have used dash 1.0.0 hence html and dcc packages are not imported but referenced
  • you construct checklist in callback that is not used anywhere...
from jupyter_dash import JupyterDash
import dash
from dash.dependencies import Input, Output, State
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go

# app = dash.Dash(__name__)
app = JupyterDash(__name__)

# dfhours = pd.read_csv("hothours9-7.csv")
# dfhours['Last Updated'] = pd.to_datetime(dfhours['Last Updated'])
# dfclients = pd.read_csv("hotclients9-7.csv")
# simulate data...
h = np.random.uniform(10, 40, 4)
dfhours = pd.DataFrame(
    {
        "Client": list("ABCD"),
        "Hours Spent": h,
        "Hours Allowed": h * np.random.uniform(1.5, 2, 4),
    }
)
clientlist = pd.DataFrame({"Client": list("ABCD")})
clients = clientlist["Client"].unique()
dfclients = pd.DataFrame(
    {
        "Last Updated": pd.date_range("1-May-2021", periods=60),
        "Client": np.random.choice(list("ABCD"), 60),
        "Hours Spent": np.random.uniform(10, 40, 60),
    }
)

app.layout = dash.html.Div(
    children=[
        dash.html.H1(children="Hello!", style={"textAlign": "center"}),
        dash.html.Br(),
        dash.html.Div(
            [
                dash.html.Label("Clients"),
                dash.dcc.Dropdown(
                    id="clients-list",
                    options=[{"label": i, "value": i} for i in clients],
                    value="All",
                    style={"width": "80%"},
                ),
                dash.dcc.Dropdown(
                    id="info-drop",
                    options=[
                        {"label": i, "value": i}
                        for i in ["Historical Hours", "Current Hours"]
                    ],
                    value="Current Hours",
                ),
            ]
        ),
        dash.html.Br(),
        dash.dcc.Graph(id="info-graph"),
    ]
)


# -------------------------------------------


@app.callback(
    Output("info-graph", "figure"),
    [Input("clients-list", "value"), Input("info-drop", "value")],
)
def update_graph(client, info):
    if info == "Current Hours":
        if client == "All":
            fig = px.bar(dfhours, x="Client", y="Hours Spent")

        elif client != "All":
            dff = dfhours.loc[dfhours["Client"].eq(client)].reset_index(drop=True)

            fig = go.Figure(
                go.Indicator(
                    domain={"x": [0, 1], "y": [0, 1]},
                    value=dff.loc[0, "Hours Spent"],
                    mode="gauge+number",
                    gauge={"axis": {"range": [0, dff.loc[0, "Hours Allowed"]]}},
                )
            )
    elif info == "Historical Hours":
        if client == "All":
            # this is spurious !!!
            dash.dcc.Checklist(
                options=[{"label": x, "value": x} for x in dfclients["Client"]]
            ),
            fig = px.line(dfclients, x="Last Updated", y="Hours Spent", color="Client")

        elif client != "All":
            dff = dfclients.query('Client == "{}"'.format(client))
            fig = px.line(dff, x="Last Updated", y="Hours Spent")
    return fig


if __name__ == "__main__":
    #     app.run_server(debug=False)
    app.run_server(mode="inline")
Rob Raymond
  • 29,118
  • 3
  • 14
  • 30
  • I am about to check this, but I wanted to ask about the checklist. I understand it is kinda dumb, since I think you should be able to filter via the graph anyway, just with several clients it gets kind of cluttered. That's why I wanted the checklist just for that one graph, since the others don't need it. Should I just not worry about that and stick with filtering you can already do natively in the line graph? – Joseph Padgett Sep 15 '21 at 19:42
  • Thanks! That seems to have done the trick. I knew it was something silly like that. – Joseph Padgett Sep 15 '21 at 20:40
  • I get your point wrt to UI for the checklist, but it will never be part of the UI as you construct it and never put in in a html element within the dashboard. effectively it's a zombie. If this worked, consider accepting the answer – Rob Raymond Sep 16 '21 at 08:47