Skip to content

Commit 11da41f

Browse files
committed
Change to a cheap visualisation
1 parent e488ada commit 11da41f

File tree

2 files changed

+74
-25
lines changed

2 files changed

+74
-25
lines changed

anim.py

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
import pandas as pd
1616
import pedpy
1717
import plotly.graph_objects as go
18+
from matplotlib.patches import Circle
19+
from matplotlib.figure import Figure as MatplotlibFigure
1820
from plotly.graph_objs import Figure, Scatter
1921
from plotly.graph_objs.layout import Shape
2022
from shapely import Polygon
@@ -141,8 +143,6 @@ def _get_colormap(
141143
)
142144

143145
return [scatter_trace]
144-
145-
146146
def _get_shapes_for_frame(
147147
frame_data: pd.DataFrame,
148148
min_value: float,
@@ -444,3 +444,54 @@ def animate(
444444
height=height,
445445
title_note=title_note,
446446
)
447+
def plot_frame_fast(
448+
data_df: pd.DataFrame,
449+
area: pedpy.WalkableArea,
450+
frame_num: int,
451+
*,
452+
radius: float = 0.1,
453+
xlim: Tuple[float, float] | None = None,
454+
ylim: Tuple[float, float] | None = None,
455+
) -> MatplotlibFigure:
456+
"""Render a single frame with matplotlib for fast inspection."""
457+
frame_data = data_df[data_df["frame"] == frame_num].copy()
458+
frame_data["radius"] = radius
459+
min_value = float(data_df["motivation"].min())
460+
max_value = float(data_df["motivation"].max())
461+
462+
fig, ax = plt.subplots(figsize=(7, 9), constrained_layout=True)
463+
x, y = area.polygon.exterior.xy
464+
ax.plot(np.array(x), np.array(y), color="black", linewidth=1.0)
465+
for inner in area.polygon.interiors:
466+
xi, yi = zip(*inner.coords[:])
467+
ax.plot(np.array(xi), np.array(yi), color="black", linewidth=1.0)
468+
469+
cmap = plt.cm.jet_r
470+
norm = plt.Normalize(vmin=min_value, vmax=max_value if max_value > min_value else min_value + 1.0)
471+
for row in frame_data.itertuples():
472+
circle = Circle(
473+
(row.x, row.y),
474+
radius=row.radius,
475+
facecolor=cmap(norm(row.motivation)),
476+
edgecolor="none",
477+
)
478+
ax.add_patch(circle)
479+
480+
sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
481+
sm.set_array([])
482+
fig.colorbar(sm, ax=ax, label="Motivation")
483+
minx, miny, maxx, maxy = area.bounds
484+
if xlim is None:
485+
xlim = (minx - 0.5, maxx + 0.5)
486+
if ylim is None:
487+
ylim = (miny - 0.5, maxy + 0.5)
488+
ax.set_xlim(*xlim)
489+
ax.set_ylim(*ylim)
490+
ax.set_aspect("equal")
491+
ax.set_xticks([])
492+
ax.set_yticks([])
493+
for spine in ax.spines.values():
494+
spine.set_visible(False)
495+
ax.set_xlabel("")
496+
ax.set_ylabel("")
497+
return fig

app.py

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import pandas as pd
1212
import pedpy
1313
import streamlit as st
14-
from anim import animate
14+
from anim import plot_frame_fast
1515
from jupedsim.internal.notebook_utils import read_sqlite_file
1616
from src import docs
1717
import glob
@@ -43,13 +43,20 @@
4343
c1, c2, _c3 = st.columns(3)
4444
data = simulation_tab()
4545
config_file, output_file, fps = ui_simulation_controls(data)
46+
if "show_frame_viewer" not in st.session_state:
47+
st.session_state.show_frame_viewer = False
4648

4749
if c1.button("Run Simulation"):
4850
call_simulation(config_file, output_file, data)
4951

5052
if c2.button("Visualization"):
53+
st.session_state.show_frame_viewer = True
54+
55+
if st.session_state.show_frame_viewer:
5156
output_path = Path(output_file)
52-
if output_path.exists():
57+
if not output_path.exists():
58+
st.warning(f"Trajectory file not found: {output_file}")
59+
else:
5360
trajectory_data, walkable_area = read_sqlite_file(output_file)
5461
motivation_path = output_path.with_name(
5562
output_path.stem + "_motivation.csv"
@@ -67,31 +74,22 @@
6774
data_with_motivation["motivation"] = data_with_motivation[
6875
"motivation"
6976
].fillna(1.0)
70-
data_with_motivation["gender"] = 1
71-
data_with_motivation["speed"] = 0.0
72-
width = data["motivation_parameters"]["width"]
73-
vertices = data["motivation_parameters"]["motivation_doors"][
74-
0
75-
]["vertices"]
76-
x0 = 0.5 * (vertices[0][0] + vertices[1][0]) - width
77-
y0 = 0.5 * (vertices[0][1] + vertices[1][1]) - width
78-
x1 = 0.5 * (vertices[0][0] + vertices[1][0]) + width
79-
y1 = 0.5 * (vertices[1][1] + vertices[1][1]) + width
80-
81-
animation = animate(
77+
frames = sorted(data_with_motivation["frame"].unique().tolist())
78+
frame_step = max(1, int(fps))
79+
selected_frame = st.slider(
80+
"Frame",
81+
min_value=int(frames[0]),
82+
max_value=int(frames[-1]),
83+
value=int(frames[0]),
84+
step=frame_step,
85+
)
86+
fig = plot_frame_fast(
8287
data_with_motivation,
8388
walkable_area,
84-
every_nth_frame=int(fps),
85-
color_mode="Motivation",
89+
frame_num=selected_frame,
8690
radius=0.1,
87-
x0=x0,
88-
y0=y0,
89-
x1=x1,
90-
y1=y1,
9191
)
92-
st.plotly_chart(animation)
93-
else:
94-
st.warning(f"Trajectory file not found: {output_file}")
92+
st.pyplot(fig)
9593

9694
params = extract_motivation_parameters(data)
9795
mapping = params.get("mapping_block", {})

0 commit comments

Comments
 (0)