9  Metrics and Dials

If using Streamlit to create a dashboard, there will often be a requirement to create various elements displaying key performance indicators and performance trends prominently.

9.1 Metrics

import streamlit as st

1st.metric(
2  label="Number of Patients Seen this Week",
3  value=52
  )

st.metric(
  label="Number of Patients Seen this Week - South",
  value=30,
4  delta=7
  )

st.metric(
  label="Number of Patients Seen this Week - North",
  value=12,
5  delta=-4
  )

st.metric(
  label="Waiting List Length",
  value=147,
  delta=-15,
6  delta_color="inverse"
  )

7st.subheader("A metric without its own header")

st.metric(
8  label="This Won't Be Displayed",
  value=5,
  delta=3,
9  label_visibility="collapsed"
  )
1
We are going to be using the st.metric() function.
2
We pass in a string to be used as the metric card’s label.
3
Then we pass in a value to display on the card.
4
We can also provide an optional delta parameter, which is designed to show the difference between the current metric value and a comparison figure, such as the figure in the previous time period.
5
This delta value can also be negative, and this will display in a different colour.
6
If an increase is actually a bad thing and a decrease is a good thing, passing the ‘inverse’ parameter will invert the colours used.
7
If we wanted to make a title that stood out more, we could instead use a subheader.
8
Note that we are going to specify a parameter that means any label passed in here won’t actually get displayed - but you should still specify one.
9
Finally, we use the label_visibility parameter with the argument collapsed to hide the provided label.

9.1.1 Layout

By combining metrics with st.columns, we can make better use of the screen to start building up more of a dashboard layout. The column layout is covered in more detail in the linked chapter.

Warning

To ensure Streamlit apps display well on all screen sizes, on narrower screens you may find that your defined columns are ignored and instead the metrics return to displaying as a single column. If you increase the width of the window, it should automatially update the layout and, if the screen is wide enough, it will respect the column assignments you have provided.

import streamlit as st
import plotly.express as px
import pandas as pd

1st.set_page_config(layout="wide")

st.title("Activity Dashboard")

2col1, col2, col3 = st.columns(3)

3col1.metric(label="Total Number of Patients Seen this Week", value=52)

col2.metric(label="Number of Patients Seen this Week - South", value=30, delta=-5)

col2.metric(label="Number of Patients Seen this Week - North", value=12, delta=-7)

col3.metric(label="Number of Patients Seen this Year", value=1302)

4patients_seen_df = pd.DataFrame(
  {
    'Week': ['2021-01-01', '2021-01-08', '2021-01-15', '2021-01-22', '2021-01-29', '2021-02-05'],
    'Patients Seen': [24, 12, 43, 23, 32, 25]
  }
)

5st.plotly_chart(
  px.line(patients_seen_df, x='Week', y='Patients Seen', title="Total Patients Seen per Week")
  )
1
Here, we’ve started out by setting the page config to ‘wide’. This just means that the page will use the whole width of the viewer’s screen, rather than limiting itself to the middle third.
2
We set up 3 columns using the st.columns feature, unpacking them on the left-hand side of our assign (the equals sign) into three separate variables called col1, col2, col3 for easy reference (though we could call them anything!). col1 will be the leftmost column and as we haven’t specified otherwise, they will be of equal width.
3
We then create our metrics, but instead of using st.metric, we use col1.metric (and so on). This is an easy shorthand to assign the resulting metric to each of the columns we’ve just created.
4
Now we’re just going to quickly make a dummy dataframe so that we can see the impact of putting something underneath the column layout. We wouldn’t usually build the dataframe up like this - we’d load it in from a database or csv.
5
Now we’re just creating a plotly chart container and putting a plotly express line chart in it. Note how rather than being inside one of the columns, it takes up the full width of the screen. This is because we’ve gone back to using st.plotly_chart instead of col1.plotly_chart or similar.

9.1.2 Styling Metric Cards

The Streamlit Extras package provides us with options to apply a style to our metric cards.

You will need to pip install streamlit-extras if it’s not already installed in your environment.

import streamlit as st
import plotly.express as px
import pandas as pd
1from streamlit_extras.metric_cards import style_metric_cards

st.set_page_config(layout="wide")

st.title("Activity Dashboard")

col1, col2, col3 = st.columns(3)

col1.metric(label="Total Number of Patients\nSeen this Week", value=52)

col2.metric(label="Number of Patients\nSeen this Week - South", value=30, delta=-5)

col2.metric(label="Number of Patients\nSeen this Week - North", value=12, delta=-7)

col3.metric(label="Number of Patients Seen this Year", value=1302)

2style_metric_cards(background_color="#6434eb", border_color= "#eb9234", border_size_px=3)

patients_seen_df = pd.DataFrame(
  {
    'Week': ['2021-01-01', '2021-01-08', '2021-01-15', '2021-01-22', '2021-01-29', '2021-02-05'],
    'Patients Seen': [24, 12, 43, 23, 32, 25]
  }
)

st.plotly_chart(
  px.line(patients_seen_df, x='Week', y='Patients Seen', title="Total Patients Seen per Week")
  )
1
We import the function style_metric_cards from streamlit_extras.metric_cards
2
We then use this function after we’ve created our metric cards, passing in the relevant arguments to change the background colour, border colour, border size and more.

Full details of all the available parameters can be found in the streamlit extras documentation

Tip

The six-character alphanumeric codes we passed into the ‘background_color’ and ‘border_color’ arguments are called hex colours and are a common way of specifying colours on computers - particularly in web development.

There are lots of sites to help you look up hex colours to find the perfect one for you.

This page from w3 schools is a starting point.

You can also just go to google and seach ‘hex colour picker’ to bring up an interactive picker straight away!

9.2 Indicators

To get other sorts of displays that we might be familiar with in other dashboarding software, we may need to instead move to plotly or another graphing library rather than using things built in to Streamlit.

import streamlit as st
1import plotly.graph_objects as go

2def indicator(value, title, lower_limit=0, upper_limit=1):
    return go.Figure(
      go.Indicator(
        mode = "gauge+number",
        value = value,
        title = {'text': title},
        domain = {'x': [0, 1], 'y': [0, 1]},
        gauge = {
        'axis': {'range': [lower_limit, upper_limit]}
      }
    )
  )

st.plotly_chart(
3  indicator(
4    value=80,
    title="Percentage of Tasks Completed",
    upper_limit=100
    )
  )

st.plotly_chart(
  indicator(
    value=3,
    title="Number of Patients Seen Today",
    upper_limit=10
    )
  )
1
Instead of importing the plotly.express module, this time we import the graph_objects module as go. This gives us finer control over plotly objects.
2
We define our own custom ‘indicator’ function to make it easier. Don’t worry too much about the code in this function; you could copy it into your own Streamlit dashboards as-is.
3
We can then pass the output of this ‘indicator’ function to st.plotly_chart like usual. We could save this to a fig first if we wished, before passing the fig into st.plotly_chart.
4
We pass in the actual value of the metric, the title to display above the gauge and optionally the relative upper and lower limits that this value could take or should be measured relative to.

Take a look at this documentation from plotly to see how to enhance these charts further, such as

  • adding a target
  • adding segments/reference points to the arc
  • changing the colour of the bar

This page contains additional things you can do with the indicator graph object in Plotly, such as overlaying a metric card on a plotly chart.