Designing Operations Research Solutions: A User-friendly Routing Application with Streamlit | by Bruno Scalia C. F. Leite | Sep, 2023

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.

primaryColor = "#5300A5"
backgroundColor = "#403E43"
secondaryBackgroundColor = "#1C1B1E"
textColor = "#F5F3F7"
font = "sans serif"
base = "dark"

Let us start filling the content of 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 List

import 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 = None

if "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
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 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.write("Welcome to the Traveling Salesman Problem solver.")

One of the utility functions I defined reads content from the 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)

And then let us define solver parameters and upload an input file…

Source link

Be the first to comment

Leave a Reply

Your email address will not be published.