Today we’ll redo some past exercises using pandas and Streamlit. Here are some useful reference pages:
- Streamlit widgets
- pandas User Guide and API reference (note: its name is lowercase.)
We’ll start with a Streamlit warmup.
Temperature Converter ¶
To begin, create a new folder called lab10 and create a new file in that
folder called temp_convert.py, starting from template.py as usual.
Add this code chunk just after the docstring (don’t try to understand how it works). It makes it so you can Run the file within Thonny instead of needing to use a System Shell.
# Shim to make "Run" in Thonny behave like "streamlit run this_file.py" on Terminal
import sys, streamlit.web.cli, streamlit.runtime.runtime
if '__file__' not in globals(): raise Exception("Save the file first!")
if not streamlit.runtime.runtime.Runtime.exists():
sys.argv[:] = ['streamlit', 'run', __file__]; sys.exit(streamlit.web.cli.main())
# End shim.
-
Make a Streamlit app that has a
st.number_input()widget for a temperature in degrees C andst.write()s the corresponding temperature in degrees F.- The label for the number input should describe the purpose (e.g., “Temperature in degrees C”)
- The output should describe what it is, a temperature in degrees F.
- Optional, come back to this: You could try using a
st.metricwidget instead of thest.write. Try ast.columnsalso.
-
Add a
st.radiowidget above the number input to allow the user to choose whether to convert C to F or F to C. Modify the label for thenumber_input, the conversion logic, and the output message accordingly. For the list ofoptions, you can use["F to C", "C to F"].
The formulas are:
- degrees F minus 32 times 5/9 gives degrees C
- degrees C times 9/5 plus 32 gives degrees F.
Test the following:
- 0 degrees C is 32 degrees F
- 212 degrees F is 100 degrees C
- negative 40 is the same in both systems.
Employees ¶
In Lab 8, we read employee data from a file and wrote code to compute the average salary by rank. pandas makes this very easy, as we’ll see.
-
In a file named
employee_summary.py, importpandasandstreamlitusing their canonical names (pd,st). -
Use
pd.read_csvto read theemployees.txtfile from Lab 8.- Since the CSV doesn’t include a header row, you’ll need to pass
names=["given_name", "family_name", "rank", "salary"]as a second argument toread_csvto tell Pandas what the column names are. - Assign the result to a variable called
employees. - Use
st.dataframe(employees)to show the employees data in the Streamlit app; check that you have 100 rows and the correct column names.
- Since the CSV doesn’t include a header row, you’ll need to pass
-
Sort the
employeesdata framebythesalarycolumn:employees.sort_values(by = 'salary', inplace=True). Theinplaceargument tells pandas to mutate the dataframe instead of returning a sorted copy. Do this before thest.dataframeso you can see the result. (What changes if you also passascending = False?) -
Compute the average
salarybyrank, using a single line of code involvinggroupby()and eithermean()oragg(). See the class slides or the Tutorial section on grouping. Usest.dataframe()to report the results. Usesort_values()(no arguments needed this time) to sort by salary. (Can you make it so that the rank with the highest average salary comes first?)
Optional Extensions:
-
Replace the file input with a
st.file_uploaderwidget. When the page first runs, thefile_uploaderwill returnNone, so you’ll need to checkif employee_file is not None:or the like before running the rest of the employee-handling code. (Or:if employee_file is None: st.stop()to stop execution early.) -
Report the highest and lowest paid employees. This can be done simply by passing
employees.iloc[0](or -1) tost.dataframeafter sorting by salary. -
Make the display more user-friendly somehow. For example, you might add headers and subheaders, clean up debugging output, use
st.write()to show the data for the highest and lowest paid, or change the column names on the salary-by-rank table.
Climate Plot ¶
In Lab 9, we plotted some global climate data by reading in the CSV and manually converting the data types. Now let’s do it with pandas.
-
Create a
climate_plot.pyfrom the template, with streamlit and pandas imports as usual. -
Read the
1880-2024.csvfile that you had downloaded for that lab. This time the file does have headers (so we don’t need to passnames=), but it has extra rows that we need to skip. So useread_csv(filename, skiprows=N), using the appropriate filename and the appropriate number forN, the number of extra rows at the top of the file we need to skip. Make sure not to skip the names this time. -
Make a quick and dirty plot using
st.line_chart. See if you can figure out how to tell it what to put on thexandyaxes.
Optional extension: Try using plotly to make a more refined chart. (Here’s the documentation for plotly)
- See the plotly documentation page for line charts for a demo.
- But instead of
fig.show(), usest.plotly_chart(fig, use_container_width=True). - Try to set the
titlefor the full plot and the y axis. Here’s a documentation page that may be helpful. - Add a horizontal line at
y=0by callingfig.add_hline()(docs).
Optional extension: use st.pyplot() to display the same figure that you made for that lab. You’ll need to:
- Use
import matplotlib; matplotlib.use("Agg")at the top of the Python file - Use
fig, ax = plt.subplots()right before making the plot - Use
st.pyplot(fig)instead ofplt.show()to show the figure.
Optional ¶
- Use streamlit to plot the Collatz function from Lab 8.
Streamlit Session State
- Try out using streamlit’s session state to enable richer interactions. For example, study this example of the temperature conversion example above:
temp = st.number_input("Temperature", key="temp")
def on_change_unit():
print("Old unit:", unit, "New unit:", st.session_state.unit)
if st.session_state.unit == "F":
# Changing from C to F
st.session_state.temp = temp * 9/5 + 32
else:
# Changing from F to C
st.session_state.temp = (temp - 32) * 5/9
unit = st.radio("Unit", ["F", "C"], on_change=on_change_unit, key="unit")
Notice that:
- We provide a
keyargument to thest.number_inputandst.radiowidgets, so we can access their current values inst.session_state. - We define a function
on_change_unitthat is called whenever the radio button changes.- This function reads the current value of the temperature and the unit from
st.session_state, and updates the temperature in the opposite unit. - Setting the
st.session_state.tempvalue sets the value of thest.number_inputwidget.
- This function reads the current value of the temperature and the unit from
- We pass the
on_changeargument to thest.radiowidget to specify the function to call when the radio button changes. - When the button changes, streamlit first calls the
on_change_unitfunction, then re-runs the code for the whole page.