Skip to content

Commit

Permalink
some formating and add missing dependency for gps
Browse files Browse the repository at this point in the history
  • Loading branch information
chraibi committed Mar 2, 2024
1 parent f6bc0f5 commit adca748
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 56 deletions.
4 changes: 2 additions & 2 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
import streamlit as st

import analysis_tab
import contacts_tab
import datafactory
import docs
import map_tab
import traj_tab
import ui
import contacts_tab

# Basic configuration for logging
logging.basicConfig(
Expand Down Expand Up @@ -40,6 +40,6 @@

if selected == "Analysis":
analysis_tab.run_tab3()

if selected == "Contacts":
contacts_tab.call_main()
118 changes: 70 additions & 48 deletions contacts_tab.py
Original file line number Diff line number Diff line change
@@ -1,101 +1,114 @@
""" Map of the gps trajectories coupled with the contacts locations. """

from typing import Tuple

import folium
import matplotlib.colors as mcolors
import numpy as np
import pandas as pd
import streamlit as st
import plotly.express as px
import plotly.graph_objects as go
import matplotlib.colors as mcolors

from typing import Tuple
import streamlit as st
from matplotlib import colormaps
from streamlit_folium import st_folium
from plotly.graph_objects import Figure
from streamlit_folium import st_folium

def load_data(gps_path: str, contacts_path: str) -> tuple:

def load_data(
gps_path: str, contacts_path: str
) -> Tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame]:
"""
Load GPS tracks and contact data from pickled files.
Args:
gps_path (str): The path to the GPS data directory.
contacts_path (str): The path to the contacts data directory.
Returns:
tuple: A tuple containing all GPS tracks and contact GPS merged data.
"""
all_gps_tracks = pd.read_pickle(gps_path + 'all_gps_tracks.pickle')
contact_gps_merged = pd.read_pickle(contacts_path + 'contacts_gps_merged.pickle')
contacts_data = pd.read_pickle(contacts_path + 'contacts_data.pickle')
all_gps_tracks = pd.read_pickle(gps_path + "all_gps_tracks.pickle")
contact_gps_merged = pd.read_pickle(contacts_path + "contacts_gps_merged.pickle")
contacts_data = pd.read_pickle(contacts_path + "contacts_data.pickle")
return all_gps_tracks, contact_gps_merged, contacts_data


def initialize_map(all_gps_tracks: pd.DataFrame) -> folium.Map:
"""
Initialize the map centered on the middle point of Ludovic-Gardre1's first track.
Args:
all_gps_tracks (pd.DataFrame): DataFrame containing all GPS tracks.
Returns:
folium.Map: A folium map object.
"""
first_track_df = all_gps_tracks[all_gps_tracks['name_subj'] == 'Ludovic-Gardre1']
map_center = first_track_df.iloc[len(first_track_df) // 2][['latitude', 'longitude']].tolist()
first_track_df = all_gps_tracks[all_gps_tracks["name_subj"] == "Ludovic-Gardre1"]
map_center = first_track_df.iloc[len(first_track_df) // 2][
["latitude", "longitude"]
].tolist()
return folium.Map(location=map_center, zoom_start=17.5)


def add_tile_layer(map_object: folium.Map) -> None:
"""
Add a Google Satellite tile layer to enhance the map visualization.
Args:
map_object (folium.Map): The folium map object to which the tile layer will be added.
"""
google_satellite = folium.TileLayer(
tiles='http://www.google.cn/maps/vt?lyrs=s@189&gl=cn&x={x}&y={y}&z={z}',
attr='Google',
name='Google Satellite',
tiles="http://www.google.cn/maps/vt?lyrs=s@189&gl=cn&x={x}&y={y}&z={z}",
attr="Google",
name="Google Satellite",
overlay=True,
control=True,
opacity=1.
opacity=1.0,
)
google_satellite.add_to(map_object)


def plot_gps_tracks(map_object: folium.Map, all_gps_tracks: pd.DataFrame) -> None:
"""
Plot each GPS track on the map with a unique color.
Args:
map_object (folium.Map): The folium map object where tracks will be plotted.
all_gps_tracks (pd.DataFrame): DataFrame containing all GPS tracks.
"""
unique_tracks = all_gps_tracks['name_subj'].unique()
viridis = colormaps.get_cmap('viridis')
unique_tracks = all_gps_tracks["name_subj"].unique()
viridis = colormaps.get_cmap("viridis")
for track_index, name_subj in enumerate(unique_tracks):
track_df = all_gps_tracks[all_gps_tracks['name_subj'] == name_subj]
track_points = track_df[['latitude', 'longitude']].values.tolist()
track_df = all_gps_tracks[all_gps_tracks["name_subj"] == name_subj]
track_points = track_df[["latitude", "longitude"]].values.tolist()
rgba_color = viridis(track_index / len(unique_tracks))
hex_color = mcolors.to_hex(rgba_color)
folium.PolyLine(track_points, color=hex_color, weight=2.5, opacity=1, popup=name_subj).add_to(map_object)
folium.PolyLine(
track_points, color=hex_color, weight=2.5, opacity=1, popup=name_subj
).add_to(map_object)


def add_contact_markers(map_object: folium.Map, contact_gps_merged: pd.DataFrame, path_icon: str) -> None:
def add_contact_markers(
map_object: folium.Map, contact_gps_merged: pd.DataFrame, path_icon: str
) -> None:
"""
Add markers for each contact point on the map.
Args:
map_object (folium.Map): The folium map object where markers will be added.
contact_gps_merged (pd.DataFrame): DataFrame containing contact GPS merged data.
"""
for index, row in contact_gps_merged.iterrows():
icon_person = folium.features.CustomIcon(
icon_image=path_icon + '/contact_icon.png',
icon_size=(30, 30)
icon_image=path_icon + "/contact_icon.png", icon_size=(30, 30)
)
folium.Marker(
location=[row['latitude'], row['longitude']],
location=[row["latitude"], row["longitude"]],
icon=icon_person,
popup=row['name_subj'],
popup=row["name_subj"],
).add_to(map_object)


def plot_histogram(df: pd.DataFrame) -> Figure:
"""
Creates an interactive bar chart using Plotly to visualize the total number of collisions.
Expand All @@ -107,40 +120,49 @@ def plot_histogram(df: pd.DataFrame) -> Figure:
Figure: The Plotly figure object for the histogram.
"""
# Slider for selecting the number of bins
bins = st.slider('Select number of bins:', min_value=5, max_value=11, value=10, step=3)
fig = px.histogram(df['Total-number-of-collisions'], x='Total-number-of-collisions', nbins=bins)
print(df['Total-number-of-collisions'])
bins = st.slider(
"Select number of bins:", min_value=5, max_value=11, value=10, step=3
)
fig = px.histogram(
df["Total-number-of-collisions"], x="Total-number-of-collisions", nbins=bins
)
print(df["Total-number-of-collisions"])
fig.update_layout(
xaxis_title='Number of contacts along the path',
yaxis_title='Number of people') # Set the range for the log scale
xaxis_title="Number of contacts along the path", yaxis_title="Number of people"
) # Set the range for the log scale

return fig


def plot_cumulative_contacts(df):
""" To plot cumulative contacts as a function of time using Plotly """
def plot_cumulative_contacts(df: pd.DataFrame) -> Figure:
"""To plot cumulative contacts as a function of time using Plotly"""
# Initialize an empty figure
fig = go.Figure()

# Loop through the DataFrame and plot each person's contact times
for index, row in df.iterrows():
times = row.dropna().values # Get the 'Détail' times for the person
if len(times) > 0:
values = np.cumsum(np.concatenate(([0], np.ones(len(times), dtype='int'))))
edges = np.concatenate((times, [df['Duration'].iloc[index].total_seconds()]))
values = np.cumsum(np.concatenate(([0], np.ones(len(times), dtype="int")))) # type: ignore
edges = np.concatenate(
(times, [df["Duration"].iloc[index].total_seconds()])
)
# Add a trace for each person
fig.add_trace(go.Scatter(x=edges, y=values, mode='lines+markers', name=row['Name']))

fig.add_trace(
go.Scatter(x=edges, y=values, mode="lines+markers", name=row["Name"])
)

# Update layout of the figure
fig.update_layout(
title="Cumulative Contacts as a Function of Time",
xaxis_title="Time [microseconds]",
yaxis_title="Cumulative Number of Contacts",
drawstyle='steps-pre'
drawstyle="steps-pre",
)

return fig


def main() -> None:
"""
Main function to orchestrate the map creation process and integrate with Streamlit.
Expand Down Expand Up @@ -169,4 +191,4 @@ def main() -> None:


def call_main() -> None:
main()
main()
4 changes: 3 additions & 1 deletion datafactory.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from typing import List, Union

import pedpy
import requests # type:ignore
import requests # type: ignore
import streamlit as st


Expand All @@ -24,6 +24,8 @@ class DirectionInfo:

@dataclass
class Direction:
"""Data for measurement line."""

info: DirectionInfo
line: pedpy.MeasurementLine

Expand Down
11 changes: 7 additions & 4 deletions map_tab.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@

import folium
import streamlit as st
from streamlit_folium import st_folium
from folium.features import CustomIcon
from streamlit_folium import st_folium


@dataclass
class Camera:
Expand Down Expand Up @@ -63,7 +64,9 @@ def load_cameras_from_json(file_path: str) -> Dict[str, Camera]:
name = info["name"]
field = info["field"]
logo = info["logo"]
cameras[key] = Camera(location=location, url=url, name=name, field=field, logo=logo)
cameras[key] = Camera(
location=location, url=url, name=name, field=field, logo=logo
)

except KeyError as e:
# Handle missing keys in the data
Expand Down Expand Up @@ -153,10 +156,10 @@ def create_map(
polygon.add_to(layer)

for (key, camera), layer in zip(cameras.items(), camera_layers):
icon = CustomIcon(camera.logo, icon_size=(110, 110) )
icon = CustomIcon(camera.logo, icon_size=(110, 110))
coords = camera.location
tooltip = f"{key}: {camera.name}"
folium.Marker(location=coords, tooltip=tooltip,icon=icon).add_to(layer)
folium.Marker(location=coords, tooltip=tooltip, icon=icon).add_to(layer)
vision_fields[key].add_to(layer)

# folium.FitOverlays().add_to(m)
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ kaleido
matplotlib
streamlit_drawable_canvas==0.8.0
streamlit-option-menu
gpxpy
8 changes: 7 additions & 1 deletion ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,13 @@ def init_sidebar() -> Any:
return option_menu(
"Multi-agent modelling of dense crowd dynamics: Predict & Understand",
["About", "Map", "Trajectories", "Analysis", "Contacts"],
icons=["info-square", "pin-map", "people", "bar-chart-line", "exclamation-triangle"],
icons=[
"info-square",
"pin-map",
"people",
"bar-chart-line",
"exclamation-triangle",
],
menu_icon="cast",
default_index=0,
orientation="horizontal",
Expand Down

0 comments on commit adca748

Please sign in to comment.