
As previously described, we can define general Streamlit settings in the config.toml
file inside the .streamlit
folder. In the TSP example, I used it to define colors and font. This is kind of a light purple layout, but you can try different colors. Just make sure to define them in Hex color codes.
[theme]
primaryColor = "#5300A5"
backgroundColor = "#403E43"
secondaryBackgroundColor = "#1C1B1E"
textColor = "#F5F3F7"
font = "sans serif"
base = "dark"
Let us start filling the content of app.py
with the Python imports. The package os will be used to manage file paths in our operating system; BytesIO will be used to emulate an output downloadable file kept in memory instead of disk; json will be used to serialize our output solution; List is just a typehint.
To work with dataframes, pandas will be used; the solver Highs is imported from pyomo to solve our problem (in case of a MIP); streamlit is the base of the interface; and streamlit_folium will be used to insert a folium Map into the app. Additional custom functions defined in the internal package are also imported.
import os
from io import BytesIO
import json
from typing import Listimport pandas as pd
from pyomo.contrib.appsi.solvers.highs import Highs
import streamlit as st
from streamlit_folium import st_folium
from optimize.tsp import get_distance_xy, build_mip, solve_mip, TSP, plot_tour, request_matrix,\
plot_map, get_coord_path
The session_state
attributes will store the tour of a current solution, the pandas dataframe of a given input file, the value of that solution, and the route coordinate path (obtained from OpenStreetMap).
# Create current solution as session_state
if "tour" not in st.session_state:
st.session_state.tour = Noneif "dataframe" not in st.session_state:
st.session_state.dataframe = None
if "sol" not in st.session_state:
st.session_state.sol = None
if "route_path" not in st.session_state:
st.session_state.route_path = None
Some of the utility functions used are:
- driving_distances: To obtain the distance matrix from OpenStreetMap provided a dataframe (important to cache results here).
- upload_callback: Resets
session_state
attributes when a new input file is loaded. - update_path: Given a tour, obtain map coordinates of the correspoinding driving path to plot results.
# Finds distance matrix
@st.cache
def driving_distances(dataframe: pd.DataFrame):
return request_matrix(dataframe)["distances"] / 1000# Callback uploading a new file
def upload_callback():
st.session_state.tour = None
st.session_state.sol = None
st.session_state.route_path = None
# Update route path after solution
def update_path(tour: List[int], dataframe: pd.DataFrame):
coord_rt = dataframe.loc[tour, :]
path = get_coord_path(coord_rt)
st.session_state.route_path = path
And then let us configure the page layout. In the following script, we include an icon and a title for the web page; then we include the same icon on the sidebar and write an introduction in markdown style. I suggest you run streamlit run app.py
and check the results so far.
# Path to icon
icon_path = os.path.join("assets", "icon_tsp.png")# Set the page config to wide mode
st.set_page_config(
page_title="TSP",
page_icon=icon_path,
layout="wide",
)
st.sidebar.image(icon_path)
st.title("TSP")
st.write("Welcome to the Traveling Salesman Problem solver.")
One of the utility functions I defined reads content from the README.md
file and display this content if the user selects this option. As I want to keep the conditional to display the content independent of a possible re-run, I used a selectbox instead of a button to do so.
display_tutorial = st.checkbox("Display tutorial")
if display_tutorial:
section = st.selectbox("Choose a section", ["Execution", "Solutions", "Contact"], index=1)
tutorial = read_section(section)
st.markdown(tutorial)
And then let us define solver parameters and upload an input file…
Be the first to comment