How to Style Streamlit Metrics in Custom CSS
Barri
Posted on March 18, 2023
Steamlit has established itself as an interactive, open-source framework for visualising and displaying charts, graphs, plots and ML models in a web app. Like its predecessor and rival, Dash, it plays a big role in analytics, AI, and ML visualization — areas where traditional BI dashboards cannot reach.
There are many advantages to using streamlit for data science, machine learning and visualisation. I find streamlit very intuitive and I like its simplicity and ease of use. The learning curve is short, it provides valuable components called widgets for easy arrangement and ordering of data, but my personal favourite is that everything is done in pure Python and deployed as a webapp. Streamlit framework supports all major libraries associated with data science and data visualization. This has made it a personal favourite of many and has pushed its fast rise in a short time.
Unlike Dash, Streamlit is limited in how it can be styled within the framework of the app. This can be frustrating for users who want to work with colors, and different styles to grab the attention of the audience. Using the markdown functionality of streamlit, I’ll be walking us through how we can include an external CSS file to style a metric widget.
What you’ll need
- A working streamlit application
- Knowledge of basic CSS
The Metric Widget
The metric widget is an API reference that displays KPIs and quantitative figures, like numbers in a card-like format. It takes five parameters — label, value, delta, delta_color and help.
The label is the title for the metric. The value is the value of the metric. This is the text/number that will be displayed boldly. The delta is the indicator of how the metric has changed and is displayed with an arrow below the value. The delta_color is the colour of the delta and help is an optional tooltip displayed next to the label.
Streamlit's official API documentation for the metric widget has this code as their use case.
col1, col2, col3 = st.columns(3)
col1.metric(“Temperature”, “70 °F”, “1.2 °F”) """Temperature is the label, 70 °F is the value and 1.2 °F is the delta."""
col2.metric(“Wind”, “9 mph”, “-8%”)
col3.metric(“Humidity”, “86%”, “4%”)
"""A neat combination of st.columns with metrics."""
The output is the image above. It places the three metrics side by side, but there is no telling where each metric card starts or ends. All figures and their delta are on a bland white background.
Analyzing the data
To create our metric, I’ll be using the Avocado Prices (2020) dataset from Kaggle. We will analyze it to determine what our metric values will be. In this case, I want the total sales of each year (2015–2020) and the percentage increase in sales between 2015–2020 to be displayed as a metric.
To get each year, I subsetted the year column and filtered it by the different years. Each year has its own variable — the value of which is rounded to one decimal place. This variable will be the value of our metric.
import pandas as pd
import streamlit as st
import plotly.express as px
st.header(“Avocado Interactive Sales Visualization with Streamlit”)
df = pd.read_csv(“avocado-updated-2020.csv”)
"""PANDAS ANALYSIS"""
df.drop_duplicates(inplace = True) """drop duplicates"""
st.write(“””Total Bags of Avocados Sold Through 2015–2020“””)
""" to calculate the total number of bags sold each year"""
"""2015"""
yr_15 = round(df[df[‘year’] == 2015][‘total_bags’].sum())
"""2016"""
yr_16 = round(df[df[‘year’] == 2016][‘total_bags’].sum())
"""2017"""
yr_17 = round(df[df[‘year’] == 2017][‘total_bags’].sum())
"""2018"""
yr_18 = round(df[df[‘year’] == 2018][‘total_bags’].sum())
"""2019"""
yr_19 = round(df[df[‘year’] == 2019][‘total_bags’].sum())
"""2020"""
yr_20 = round(df[df[‘year’] == 2020][‘total_bags’].sum())
"""calculate percentage increase between 2015 and 2020"""
per_increase = round((int(yr_20 — yr_15)/ yr_15) * 100, 1)
percent_increase = f”{per_increase}%”
St.Markdown and Unsafe HTML
- Create a new file and name it using the .css extension. For this project, our CSS sheet is called ‘style.css’.
Within our python file, we need to create a path that links to the external CSS file. We will use st.markdown to link to the file and override Streamlit’s default position not to allow HTML code in their application.
Streamlit is concerned about developers deploying unsafe apps if HTML is allowed in the code. The idea is that users should always be able to trust Streamlit applications, and with HTML in the code, applications become vulnerable and susceptible to hacks. To turn it on, we will switch the unsafe_allow_html to become True.
The Markdown code plays an important role here. It houses the HTML code that reads the CSS styling and also turns on the HTML.
"""LINK TO THE CSS FILE"""
with open(‘style.css’)as f:
st.markdown(f”<style>{f.read()}</style>”, unsafe_allow_html = True)
Creating the metrics
I created two different sets of columns. The first set takes four metrics and the second takes three.
The delta in this analysis is the percentage difference between the previous year and the current year.
"""WE CREATE FOUR COLUMNS HERE TO HOLD THE METRIC"""
col1, col2, col3, col4 = st.columns(4)
col1.metric(label = “2015 Sales”,
value = (yr_15),
)
col2.metric(label = “2016 Sales”,
value = (yr_16),
delta = round(float((yr_16 — yr_15)/yr_15) *100, 1)
)
col3.metric(label = “2017 Sales”,
value = (yr_17),
delta = round(float((yr_17 — yr_16)/yr_16) *100)
)
col4.metric(label = “2018 Sales”,
value = (yr_18),
delta = round(float((yr_18 — yr_17)/yr_17) *100,1)
)
st.markdown(“<hr/>”, unsafe_allow_html = True)
col5, col6, col7 = st.columns(3)
col5.metric(label = “2019 Sales”,
value = (yr_19),
delta = round(float((yr_19 — yr_18)/yr_18) *100, 1)
)
col6.metric(label = “2020 Sales”,
value = (yr_20),
delta = round(float((yr_20 — yr_19)/yr_19) *100)
)
col7.metric(label = “% increase between 2015–2020”,
value = (percent_increase)
This is what the dashboard looks like.
Styling the CSS
- Inspect the web app page where your streamlit application is running and extract the id of the metric columns. They usually don’t change so you can use the one in the CSS code of this tutorial.
NB: The id for three columns is different from that of the four columns. If your page has multiple columns of the same number, one id affects them all.
For example, if you have a set of three columns to hold three metrics and another three columns to hold different plots; when you inspect it, you’ll find they both have the same CSS id. Any CSS styling done to the column with metrics will affect the column with plots.
/* use this code inside your css file */
div.css-12w0qpk.e1tzin5v2{
background-color: #f5f5f5;
border: 2px solid;
padding: 20px 20px 20px 20px;
border-radius: 10px;
color: #ffc300;
box-shadow: 10px;
}
div.css-1r6slb0.e1tzin5v2{
background-color: #f5f5f5;
border: 2px solid; /* #900c3f */
border-radius: 10px;
padding: 20px 20px 20px 70px;
color: green;
}
div.css-50ug3q.e16fv1kl3{
font-weight: 900;
}
Our CSS code changes the background color, highlights the borders around each metric value, and changes the font color, font size of the text and paddings in each border. In the end, we have a dashboard that looks like this:
The app is deployed here on Streamlit Cloud.
Conclusion
There are many ways you can style metrics on your dashboards. One fun way would be to make them circular. This would look good on short figures or text. You should also check out Streamlit's full documentation here on how to use metrics and markdowns.
Posted on March 18, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.