Skip to content
Snippets Groups Projects
Verified Commit ee3ee660 authored by Marco Aceti's avatar Marco Aceti
Browse files

Add delays chart in trajectories map

parent 11eaa446
No related branches found
No related tags found
No related merge requests found
Pipeline #2834 passed
...@@ -48,9 +48,11 @@ ...@@ -48,9 +48,11 @@
return currentTime; return currentTime;
} }
const data = {{ this.get_data() }}; const train_count_data = {{ this.get_train_count_data() }};
const startTime = moment(data[0]['x']); const delays_data = {{ this.get_delays_data() }};
const endTime = moment(data[data.length - 1]['x']);
const startTime = moment(train_count_data[0]['x']);
const endTime = moment(train_count_data[train_count_data.length - 1]['x']);
const timeHighlighter = { const timeHighlighter = {
id: 'timeHighlighter', id: 'timeHighlighter',
...@@ -73,10 +75,18 @@ ...@@ -73,10 +75,18 @@
let chart = new Chart(ctx, { let chart = new Chart(ctx, {
type: 'line', type: 'line',
data: { data: {
datasets: [{ datasets: [
data: data, {
data: train_count_data,
label: "Circulating train count", label: "Circulating train count",
}], yAxisID: 'y',
},
{
data: delays_data,
label: "Mean delay",
yAxisID: 'y1',
}
],
}, },
options: { options: {
scales: { scales: {
...@@ -90,6 +100,20 @@ ...@@ -90,6 +100,20 @@
isoWeekday: true, isoWeekday: true,
} }
}, },
y: {
display: true,
type: 'linear',
position: 'left',
},
y1: {
display: true,
type: 'linear',
position: 'right',
title: {
display: true,
text: "Minutes"
}
}
}, },
elements: { elements: {
point: { point: {
...@@ -98,12 +122,8 @@ ...@@ -98,12 +122,8 @@
} }
}, },
plugins: { plugins: {
title: {
display: true,
text: "Circulating train count",
},
legend: { legend: {
display: false, display: true,
} }
}, },
}, },
......
...@@ -229,7 +229,7 @@ def train_stop_geojson(st: pd.DataFrame, train: pd.DataFrame) -> list[dict]: ...@@ -229,7 +229,7 @@ def train_stop_geojson(st: pd.DataFrame, train: pd.DataFrame) -> list[dict]:
return ret return ret
class TrainCountChart(MacroElement): class StatsChart(MacroElement):
"""Helper class to compute and embed the train count chart.""" """Helper class to compute and embed the train count chart."""
def __init__(self, df: pd.DataFrame, *args, **kwargs): def __init__(self, df: pd.DataFrame, *args, **kwargs):
...@@ -239,34 +239,48 @@ class TrainCountChart(MacroElement): ...@@ -239,34 +239,48 @@ class TrainCountChart(MacroElement):
df (pd.DataFrame): the train stop data df (pd.DataFrame): the train stop data
""" """
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.df = df
def get_data(self) -> list[dict[str, str | int]]: # Prepare dataset
"""Utility function used by the template to get the computed data, trains = df.groupby("train_hash")
in a JS-likable format. self.data = pd.DataFrame(index=df.train_hash.unique())
""" self.data["departure"] = trains.first()["departure_actual"].fillna(
trains = self.df.groupby("train_hash")
trains_n = pd.DataFrame(index=self.df.train_hash.unique())
trains_n["departure"] = trains.first()["departure_actual"].fillna(
trains.first()["departure_expected"] trains.first()["departure_expected"]
) )
trains_n["arrival"] = trains.last()["arrival_actual"].fillna( self.data["arrival"] = trains.last()["arrival_actual"].fillna(
trains.first()["arrival_expected"] trains.first()["arrival_expected"]
) )
self.data["delay"] = trains.mean(numeric_only=True)["departure_delay"].fillna(
trains.mean(numeric_only=True)["arrival_delay"]
)
js_dataset: list[dict[str, str | int]] = [] def get_train_count_data(self) -> list[dict[str, str | int]]:
for time in fill_time(trains_n.departure.min(), trains_n.arrival.max()): """Return circulating train count in a JS-likable format."""
js_dataset.append( ret: list[dict[str, str | int]] = []
for time in fill_time(self.data.departure.min(), self.data.arrival.max()):
subset: pd.DataFrame = self.data.loc[
(time >= self.data.departure) & (time <= self.data.arrival)
]
ret.append(
{ {
"x": time.isoformat(), "x": time.isoformat(),
"y": len( "y": len(subset),
trains_n.loc[ }
(time >= trains_n.departure) & (time <= trains_n.arrival) )
return ret
def get_delays_data(self) -> list[dict[str, str | float]]:
ret: list[dict[str, str | float]] = []
for time in fill_time(self.data.departure.min(), self.data.arrival.max()):
subset: pd.DataFrame = self.data.loc[
(time >= self.data.departure) & (time <= self.data.arrival)
] ]
), ret.append(
{
"x": time.isoformat(),
"y": subset.delay.mean() if len(subset) > 20 else "NaN",
} }
) )
return js_dataset return ret
class MarkerLegend(MacroElement): class MarkerLegend(MacroElement):
...@@ -325,8 +339,8 @@ def build_map(st: pd.DataFrame, df: pd.DataFrame) -> None: ...@@ -325,8 +339,8 @@ def build_map(st: pd.DataFrame, df: pd.DataFrame) -> None:
m.get_root().add_child(legend) m.get_root().add_child(legend)
# Add train count chart # Add train count chart
macro = TrainCountChart(df) macro = StatsChart(df)
with open(ASSETS_PATH / "templates" / "train_count.html", "r") as f: with open(ASSETS_PATH / "templates" / "stats_chart.html", "r") as f:
macro._template = Template("\n".join(f.readlines())) macro._template = Template("\n".join(f.readlines()))
m.get_root().add_child(macro) m.get_root().add_child(macro)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment