mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-25 11:44:25 +03:00
show blank plots, rather than skipping out when there's no data. handle
the current time and lots of edge cases
This commit is contained in:
parent
21724aa826
commit
af7112592f
@ -12,11 +12,11 @@ pub struct Plot {
|
||||
}
|
||||
|
||||
impl Plot {
|
||||
pub fn new<T: Ord + PartialEq + Copy + Yvalue<T>>(
|
||||
pub fn new<T: Ord + PartialEq + Copy + core::fmt::Debug + Yvalue<T>>(
|
||||
title: &str,
|
||||
series: Vec<Series<T>>,
|
||||
ctx: &EventCtx,
|
||||
) -> Option<Plot> {
|
||||
) -> Plot {
|
||||
let mut batch = GeomBatch::new();
|
||||
let mut labels = MultiText::new();
|
||||
|
||||
@ -36,17 +36,26 @@ impl Plot {
|
||||
// Assume min_x is Duration::ZERO and min_y is 0
|
||||
let max_x = series
|
||||
.iter()
|
||||
.map(|s| s.pts.iter().map(|(t, _)| *t).max().unwrap())
|
||||
.map(|s| {
|
||||
s.pts
|
||||
.iter()
|
||||
.map(|(t, _)| *t)
|
||||
.max()
|
||||
.unwrap_or(Duration::ZERO)
|
||||
})
|
||||
.max()
|
||||
.unwrap();
|
||||
.unwrap_or(Duration::ZERO);
|
||||
let max_y = series
|
||||
.iter()
|
||||
.map(|s| s.pts.iter().map(|(_, cnt)| *cnt).max().unwrap())
|
||||
.map(|s| {
|
||||
s.pts
|
||||
.iter()
|
||||
.map(|(_, value)| *value)
|
||||
.max()
|
||||
.unwrap_or(T::zero())
|
||||
})
|
||||
.max()
|
||||
.unwrap();
|
||||
if max_x == Duration::ZERO {
|
||||
return None;
|
||||
}
|
||||
.unwrap_or(T::zero());
|
||||
|
||||
let num_x_labels = 5;
|
||||
for i in 0..num_x_labels {
|
||||
@ -73,33 +82,34 @@ impl Plot {
|
||||
);
|
||||
|
||||
for s in series {
|
||||
let mut pts = Vec::new();
|
||||
if max_y == T::zero() {
|
||||
pts.push(Pt2D::new(x1, y2));
|
||||
pts.push(Pt2D::new(x2, y2));
|
||||
} else {
|
||||
for (t, y) in s.pts {
|
||||
let percent_x = t / max_x;
|
||||
let percent_y = y.to_percent(max_y);
|
||||
pts.push(Pt2D::new(
|
||||
x1 + (x2 - x1) * percent_x,
|
||||
// Y inversion! :D
|
||||
y2 - (y2 - y1) * percent_y,
|
||||
));
|
||||
}
|
||||
if max_x == Duration::ZERO {
|
||||
continue;
|
||||
}
|
||||
let mut pts = Vec::new();
|
||||
for (t, y) in s.pts {
|
||||
let percent_x = t / max_x;
|
||||
let percent_y = y.to_percent(max_y);
|
||||
pts.push(Pt2D::new(
|
||||
x1 + (x2 - x1) * percent_x,
|
||||
// Y inversion! :D
|
||||
y2 - (y2 - y1) * percent_y,
|
||||
));
|
||||
}
|
||||
pts.dedup();
|
||||
if pts.len() >= 2 {
|
||||
batch.push(
|
||||
s.color,
|
||||
PolyLine::new(pts).make_polygons(Distance::meters(5.0)),
|
||||
);
|
||||
}
|
||||
batch.push(
|
||||
s.color,
|
||||
PolyLine::new(pts).make_polygons(Distance::meters(5.0)),
|
||||
);
|
||||
}
|
||||
|
||||
Some(Plot {
|
||||
Plot {
|
||||
draw: ctx.prerender.upload(batch),
|
||||
labels,
|
||||
legend,
|
||||
rect: ScreenRectangle { x1, y1, x2, y2 },
|
||||
})
|
||||
}
|
||||
}
|
||||
pub fn draw(&self, g: &mut GfxCtx) {
|
||||
self.legend.draw(g);
|
||||
|
@ -276,12 +276,7 @@ impl GameplayState {
|
||||
},
|
||||
*time != ui.primary.sim.time(),
|
||||
) {
|
||||
if let Some(s) = bus_delays(route, ui, ctx) {
|
||||
*overlays = Overlays::BusDelaysOverTime(s);
|
||||
} else {
|
||||
println!("No route delay info yet");
|
||||
*overlays = Overlays::Inactive;
|
||||
}
|
||||
*overlays = Overlays::BusDelaysOverTime(bus_delays(route, ui, ctx));
|
||||
}
|
||||
|
||||
// TODO Expensive
|
||||
@ -425,15 +420,12 @@ fn bus_route_panel(id: BusRouteID, ui: &UI, stat: Statistic, prebaked: &Analytic
|
||||
txt
|
||||
}
|
||||
|
||||
fn bus_delays(route: BusRouteID, ui: &UI, ctx: &mut EventCtx) -> Option<Plot> {
|
||||
fn bus_delays(route: BusRouteID, ui: &UI, ctx: &mut EventCtx) -> Plot {
|
||||
let delays_per_stop = ui
|
||||
.primary
|
||||
.sim
|
||||
.get_analytics()
|
||||
.bus_arrivals_over_time(ui.primary.sim.time(), route);
|
||||
if delays_per_stop.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut series = Vec::new();
|
||||
for (stop, delays) in delays_per_stop {
|
||||
|
@ -121,14 +121,7 @@ impl Overlays {
|
||||
Overlays::IntersectionDelay(time, calculate_intersection_delay(ctx, ui))
|
||||
}
|
||||
"cumulative throughput" => Overlays::Throughput(time, calculate_thruput(ctx, ui)),
|
||||
"finished trips" => {
|
||||
if let Some(s) = trip_stats(ui, ctx) {
|
||||
Overlays::FinishedTrips(time, s)
|
||||
} else {
|
||||
println!("No data on finished trips yet");
|
||||
Overlays::Inactive
|
||||
}
|
||||
}
|
||||
"finished trips" => Overlays::FinishedTrips(time, trip_stats(ui, ctx)),
|
||||
"chokepoints" => Overlays::Chokepoints(time, calculate_chokepoints(ctx, ui)),
|
||||
"bike network" => Overlays::BikeNetwork(calculate_bike_network(ctx, ui)),
|
||||
_ => unreachable!(),
|
||||
@ -343,11 +336,7 @@ fn calculate_bike_network(ctx: &mut EventCtx, ui: &UI) -> RoadColorer {
|
||||
colorer.build(ctx, &ui.primary.map)
|
||||
}
|
||||
|
||||
fn trip_stats(ui: &UI, ctx: &mut EventCtx) -> Option<Plot> {
|
||||
if ui.primary.sim.get_analytics().finished_trips.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
fn trip_stats(ui: &UI, ctx: &mut EventCtx) -> Plot {
|
||||
let lines: Vec<(&str, Color, Option<TripMode>)> = vec![
|
||||
(
|
||||
"walking",
|
||||
@ -389,6 +378,13 @@ fn trip_stats(ui: &UI, ctx: &mut EventCtx) -> Option<Plot> {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Don't forget the last batch
|
||||
for (_, _, mode) in &lines {
|
||||
pts_per_mode
|
||||
.get_mut(mode)
|
||||
.unwrap()
|
||||
.push((ui.primary.sim.time(), counts.get(*mode)));
|
||||
}
|
||||
|
||||
Plot::new(
|
||||
"finished trips",
|
||||
|
Loading…
Reference in New Issue
Block a user