mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-01 02:33:54 +03:00
some analytics on how long people spend parking. need a histogram still
This commit is contained in:
parent
8722620fb0
commit
f483d7ea85
@ -24,17 +24,8 @@ impl TripExplorer {
|
||||
// TODO Hack because ColorLegend only takes &str
|
||||
let mut rows = Vec::new();
|
||||
for (idx, p) in phases.iter().enumerate() {
|
||||
let label = if let Some(t2) = p.end_time {
|
||||
format!("{} .. {} ({})", p.start_time, t2, t2 - p.start_time)
|
||||
} else {
|
||||
format!(
|
||||
"{} .. ongoing ({} so far)",
|
||||
p.start_time,
|
||||
ui.primary.sim.time() - p.start_time
|
||||
)
|
||||
};
|
||||
rows.push((
|
||||
format!("{}: {}", label, p.description),
|
||||
p.describe(ui.primary.sim.time()),
|
||||
rotating_color_map(idx + 1),
|
||||
));
|
||||
}
|
||||
|
@ -93,8 +93,8 @@ fn dump_debug(id: ID, map: &Map, sim: &Sim, draw_map: &DrawMap) {
|
||||
sim.debug_car(id);
|
||||
if let Some(t) = sim.agent_to_trip(AgentID::Car(id)) {
|
||||
println!("Trip log for {}", t);
|
||||
for ev in sim.get_analytics().get_trip_log(t) {
|
||||
println!("- {}", ev);
|
||||
for p in sim.get_analytics().get_trip_phases(t, map) {
|
||||
println!("- {}", p.describe(sim.time()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -102,8 +102,8 @@ fn dump_debug(id: ID, map: &Map, sim: &Sim, draw_map: &DrawMap) {
|
||||
sim.debug_ped(id);
|
||||
if let Some(t) = sim.agent_to_trip(AgentID::Pedestrian(id)) {
|
||||
println!("Trip log for {}", t);
|
||||
for ev in sim.get_analytics().get_trip_log(t) {
|
||||
println!("- {}", ev);
|
||||
for p in sim.get_analytics().get_trip_phases(t, map) {
|
||||
println!("- {}", p.describe(sim.time()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::common::TripExplorer;
|
||||
use crate::game::{State, Transition, WizardState};
|
||||
use crate::game::{msg, State, Transition, WizardState};
|
||||
use crate::sandbox::gameplay::{cmp_count_fewer, cmp_count_more, cmp_duration_shorter};
|
||||
use crate::ui::UI;
|
||||
use abstutil::prettyprint_usize;
|
||||
@ -23,6 +23,7 @@ impl Scoreboard {
|
||||
vec![
|
||||
(hotkey(Key::Escape), "quit"),
|
||||
(hotkey(Key::B), "browse trips"),
|
||||
(hotkey(Key::P), "examine parking overhead"),
|
||||
],
|
||||
ctx,
|
||||
);
|
||||
@ -89,7 +90,7 @@ impl Scoreboard {
|
||||
}
|
||||
|
||||
impl State for Scoreboard {
|
||||
fn event(&mut self, ctx: &mut EventCtx, _: &mut UI) -> Transition {
|
||||
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
|
||||
self.menu.event(ctx);
|
||||
if self.menu.action("quit") {
|
||||
return Transition::Pop;
|
||||
@ -97,6 +98,12 @@ impl State for Scoreboard {
|
||||
if self.menu.action("browse trips") {
|
||||
return Transition::Push(WizardState::new(Box::new(browse_trips)));
|
||||
}
|
||||
if self.menu.action("examine parking overhead") {
|
||||
return Transition::Push(msg(
|
||||
"Parking overhead",
|
||||
ui.primary.sim.get_analytics().analyze_parking_phases(),
|
||||
));
|
||||
}
|
||||
Transition::Keep
|
||||
}
|
||||
|
||||
|
@ -283,23 +283,6 @@ impl Analytics {
|
||||
per_mode
|
||||
}
|
||||
|
||||
pub fn get_trip_log(&self, trip: TripID) -> Vec<String> {
|
||||
self.trip_log
|
||||
.iter()
|
||||
.filter_map(|(t, id, maybe_req, md)| {
|
||||
if *id == trip {
|
||||
if let Some(req) = maybe_req {
|
||||
Some(format!("At {}: {} via {}", t, md, req))
|
||||
} else {
|
||||
Some(format!("At {}: {}", t, md))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn get_trip_phases(&self, trip: TripID, map: &Map) -> Vec<TripPhase> {
|
||||
let mut phases: Vec<TripPhase> = Vec::new();
|
||||
for (t, id, maybe_req, md) in &self.trip_log {
|
||||
@ -324,6 +307,61 @@ impl Analytics {
|
||||
}
|
||||
phases
|
||||
}
|
||||
|
||||
fn get_all_trip_phases(&self) -> BTreeMap<TripID, Vec<TripPhase>> {
|
||||
let mut trips = BTreeMap::new();
|
||||
for (t, id, _, md) in &self.trip_log {
|
||||
let phases: &mut Vec<TripPhase> = trips.entry(*id).or_insert_with(Vec::new);
|
||||
if let Some(ref mut last) = phases.last_mut() {
|
||||
last.end_time = Some(*t);
|
||||
}
|
||||
if md == "trip finished" || md == "trip aborted for some reason" {
|
||||
// TODO Remove aborted trips?
|
||||
continue;
|
||||
}
|
||||
phases.push(TripPhase {
|
||||
start_time: *t,
|
||||
end_time: None,
|
||||
// Don't compute any paths
|
||||
path: None,
|
||||
description: md.clone(),
|
||||
})
|
||||
}
|
||||
trips
|
||||
}
|
||||
|
||||
pub fn analyze_parking_phases(&self) -> Vec<String> {
|
||||
// Of all completed trips involving parking, what percentage of total time was spent as
|
||||
// "overhead" -- not the main driving part of the trip?
|
||||
// TODO This is misleading for border trips -- the driving lasts longer.
|
||||
for (_, phases) in self.get_all_trip_phases() {
|
||||
if phases.last().as_ref().unwrap().end_time.is_none() {
|
||||
continue;
|
||||
}
|
||||
let mut driving_time = Duration::ZERO;
|
||||
let mut overhead = Duration::ZERO;
|
||||
for p in phases {
|
||||
let dt = p.end_time.unwrap() - p.start_time;
|
||||
// TODO New enum instead of strings, if there'll be more analyses like this
|
||||
if p.description.starts_with("CarID(") {
|
||||
driving_time += dt;
|
||||
} else if p.description == "parking somewhere else"
|
||||
|| p.description == "parking on the current lane"
|
||||
{
|
||||
overhead += dt;
|
||||
} else if p.description.starts_with("PedestrianID(") {
|
||||
overhead += dt;
|
||||
} else {
|
||||
// Waiting for a bus. Irrelevant.
|
||||
}
|
||||
}
|
||||
// Only interested in trips with both
|
||||
if driving_time == Duration::ZERO || overhead == Duration::ZERO {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
vec![format!("TODO: need a generic histogram")]
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TripPhase {
|
||||
@ -333,3 +371,24 @@ pub struct TripPhase {
|
||||
pub path: Option<(Distance, Path)>,
|
||||
pub description: String,
|
||||
}
|
||||
|
||||
impl TripPhase {
|
||||
pub fn describe(&self, now: Time) -> String {
|
||||
if let Some(t2) = self.end_time {
|
||||
format!(
|
||||
"{} .. {} ({}): {}",
|
||||
self.start_time,
|
||||
t2,
|
||||
t2 - self.start_time,
|
||||
self.description
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"{} .. ongoing ({} so far): {}",
|
||||
self.start_time,
|
||||
now - self.start_time,
|
||||
self.description
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user