mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-03 01:52:16 +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
|
// TODO Hack because ColorLegend only takes &str
|
||||||
let mut rows = Vec::new();
|
let mut rows = Vec::new();
|
||||||
for (idx, p) in phases.iter().enumerate() {
|
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((
|
rows.push((
|
||||||
format!("{}: {}", label, p.description),
|
p.describe(ui.primary.sim.time()),
|
||||||
rotating_color_map(idx + 1),
|
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);
|
sim.debug_car(id);
|
||||||
if let Some(t) = sim.agent_to_trip(AgentID::Car(id)) {
|
if let Some(t) = sim.agent_to_trip(AgentID::Car(id)) {
|
||||||
println!("Trip log for {}", t);
|
println!("Trip log for {}", t);
|
||||||
for ev in sim.get_analytics().get_trip_log(t) {
|
for p in sim.get_analytics().get_trip_phases(t, map) {
|
||||||
println!("- {}", ev);
|
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);
|
sim.debug_ped(id);
|
||||||
if let Some(t) = sim.agent_to_trip(AgentID::Pedestrian(id)) {
|
if let Some(t) = sim.agent_to_trip(AgentID::Pedestrian(id)) {
|
||||||
println!("Trip log for {}", t);
|
println!("Trip log for {}", t);
|
||||||
for ev in sim.get_analytics().get_trip_log(t) {
|
for p in sim.get_analytics().get_trip_phases(t, map) {
|
||||||
println!("- {}", ev);
|
println!("- {}", p.describe(sim.time()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::common::TripExplorer;
|
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::sandbox::gameplay::{cmp_count_fewer, cmp_count_more, cmp_duration_shorter};
|
||||||
use crate::ui::UI;
|
use crate::ui::UI;
|
||||||
use abstutil::prettyprint_usize;
|
use abstutil::prettyprint_usize;
|
||||||
@ -23,6 +23,7 @@ impl Scoreboard {
|
|||||||
vec![
|
vec![
|
||||||
(hotkey(Key::Escape), "quit"),
|
(hotkey(Key::Escape), "quit"),
|
||||||
(hotkey(Key::B), "browse trips"),
|
(hotkey(Key::B), "browse trips"),
|
||||||
|
(hotkey(Key::P), "examine parking overhead"),
|
||||||
],
|
],
|
||||||
ctx,
|
ctx,
|
||||||
);
|
);
|
||||||
@ -89,7 +90,7 @@ impl Scoreboard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl State for 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);
|
self.menu.event(ctx);
|
||||||
if self.menu.action("quit") {
|
if self.menu.action("quit") {
|
||||||
return Transition::Pop;
|
return Transition::Pop;
|
||||||
@ -97,6 +98,12 @@ impl State for Scoreboard {
|
|||||||
if self.menu.action("browse trips") {
|
if self.menu.action("browse trips") {
|
||||||
return Transition::Push(WizardState::new(Box::new(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
|
Transition::Keep
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,23 +283,6 @@ impl Analytics {
|
|||||||
per_mode
|
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> {
|
pub fn get_trip_phases(&self, trip: TripID, map: &Map) -> Vec<TripPhase> {
|
||||||
let mut phases: Vec<TripPhase> = Vec::new();
|
let mut phases: Vec<TripPhase> = Vec::new();
|
||||||
for (t, id, maybe_req, md) in &self.trip_log {
|
for (t, id, maybe_req, md) in &self.trip_log {
|
||||||
@ -324,6 +307,61 @@ impl Analytics {
|
|||||||
}
|
}
|
||||||
phases
|
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 {
|
pub struct TripPhase {
|
||||||
@ -333,3 +371,24 @@ pub struct TripPhase {
|
|||||||
pub path: Option<(Distance, Path)>,
|
pub path: Option<(Distance, Path)>,
|
||||||
pub description: String,
|
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