From 800008dc0341c6278428545d5d08d6a62f76fb4c Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Thu, 30 Jan 2020 15:33:27 -0800 Subject: [PATCH] making the histogram more clear about same trips --- data/MANIFEST.txt | 14 +-- ezgui/src/managed.rs | 3 +- ezgui/src/widgets/histogram.rs | 86 +++++++++++++------ game/src/common/overlays.rs | 4 +- .../sandbox/gameplay/fix_traffic_signals.rs | 19 ++-- 5 files changed, 88 insertions(+), 38 deletions(-) diff --git a/data/MANIFEST.txt b/data/MANIFEST.txt index 97e886579a..45cc9be3be 100644 --- a/data/MANIFEST.txt +++ b/data/MANIFEST.txt @@ -6,16 +6,16 @@ a5e849fa8883569519976ebfef3ae269 data/system/night_colors.json a673b8d627cdcb58791d4c1fb9d28574 data/system/maps/caphill.bin d8bbb98f4d4674fbea4d2879829c3756 data/system/maps/montlake.bin a0fb461cefa6ab26082bd0d1a56073be data/system/maps/23rd.bin -c1f770d7a77bd009cec2595137321b85 data/system/synthetic_maps/signal_double.json -bfdbd18dd24a125d6f42f5b812be583f data/system/synthetic_maps/signal_single.json -7707b64b382c09a9635993856be6571c data/system/synthetic_maps/signal_fan_in.json +204aaa2615e42d2a4b173141360f41d4 data/system/synthetic_maps/signal_double.json +363c7fcb79a9b76a721b54c9eaad9bad data/system/synthetic_maps/signal_single.json +c7216021e149874c605d9941bce0d850 data/system/synthetic_maps/signal_fan_in.json 170bc2dd2ff2af864bd593e54963b1dc data/system/scenarios/ballard/weekday.bin bfb6c5abe4b9de1f9b254c0c2a5cdf52 data/system/scenarios/23rd/weekday.bin f9f0a109966db097617a13122ecaa6f3 data/system/scenarios/downtown/weekday.bin dd54763cfda7fce4c401ae122c6daf57 data/system/scenarios/huge_seattle/weekday.bin 47dea892a1c4331da02494d15ce02a02 data/system/scenarios/caphill/weekday.bin 7d6a8e8f5d716ce8674ed63d27f2da51 data/system/scenarios/montlake/weekday.bin -692ce00b68b552eb05921dcf9d978a53 data/system/prebaked_results/23rd/weekday.bin -9b03eee27c1a20f941848360ff4e6425 data/system/prebaked_results/signal_single/tutorial lvl1.bin -fd451f62137814d9c91f38cc2e2bea62 data/system/prebaked_results/signal_single/tutorial lvl2.bin -ffaca90577fa26563bc3dcca09842ed5 data/system/prebaked_results/montlake/weekday.bin +8bf8ddb00479aa0dea08bfa3eeb0978b data/system/prebaked_results/23rd/weekday.bin +1cca5ea035284433ddf0ba357df919ce data/system/prebaked_results/signal_single/tutorial lvl1.bin +bff631e1d02bc82d5e5ab8d58c71f186 data/system/prebaked_results/signal_single/tutorial lvl2.bin +12b02b6543d44a5e5b6f73295034a743 data/system/prebaked_results/montlake/weekday.bin diff --git a/ezgui/src/managed.rs b/ezgui/src/managed.rs index fc009c32a1..9722dc9fa1 100644 --- a/ezgui/src/managed.rs +++ b/ezgui/src/managed.rs @@ -817,7 +817,8 @@ impl Composite { } pub fn align_above(&mut self, ctx: &mut EventCtx, other: &Composite) { - self.vert = VerticalAlignment::TopAt(other.top_level.rect.y1); + // Small padding + self.vert = VerticalAlignment::TopAt(other.top_level.rect.y1 - 5.0); self.recompute_layout(ctx); } } diff --git a/ezgui/src/widgets/histogram.rs b/ezgui/src/widgets/histogram.rs index d90b19d90f..78b33d7c13 100644 --- a/ezgui/src/widgets/histogram.rs +++ b/ezgui/src/widgets/histogram.rs @@ -24,37 +24,16 @@ impl Histogram { let width = 0.25 * ctx.canvas.window_width; let height = 0.3 * ctx.canvas.window_height; - // TODO Generic "bucket into 10 groups, give (min, max, count)" - let min_x = unsorted_dts.iter().min().cloned().unwrap_or(Duration::ZERO); - let max_x = unsorted_dts.iter().max().cloned().unwrap_or(Duration::ZERO); - let num_buckets = 10; - let bucket_size = (max_x - min_x) / (num_buckets as f64); - // lower, upper, count - let mut bars: Vec<(Duration, Duration, usize)> = (0..num_buckets) - .map(|idx| { - let i = idx as f64; - (min_x + bucket_size * i, min_x + bucket_size * (i + 1.0), 0) - }) - .collect(); - for dt in unsorted_dts { - // TODO Could sort them and do this more efficiently. - if dt == max_x { - // Most bars represent [low, high) except the last - bars[num_buckets - 1].2 += 1; - } else { - let bin = ((dt - min_x) / bucket_size).floor() as usize; - bars[bin].2 += 1; - } - } + let (min_x, max_x, bars) = bucketize(unsorted_dts, num_buckets); let min_y = 0; let max_y = bars.iter().map(|(_, _, cnt)| *cnt).max().unwrap(); let mut outlines = Vec::new(); for (idx, (min, max, cnt)) in bars.into_iter().enumerate() { - let color = if max < Duration::ZERO { + let color = if min < Duration::ZERO { Color::RED - } else if min < Duration::ZERO { + } else if min == Duration::ZERO && max == Duration::ZERO { Color::YELLOW } else { Color::GREEN @@ -156,3 +135,62 @@ impl Widget for Histogram { self.top_left = top_left; } } + +// min, max, bars +// TODO This has bugs. Perfect surface area to unit test. +fn bucketize( + unsorted_dts: Vec, + num_buckets: usize, +) -> (Duration, Duration, Vec<(Duration, Duration, usize)>) { + assert!(num_buckets >= 3); + if unsorted_dts.is_empty() { + return ( + Duration::ZERO, + Duration::ZERO, + vec![(Duration::ZERO, Duration::ZERO, 0)], + ); + } + + let min_x = *unsorted_dts.iter().min().unwrap(); + let max_x = *unsorted_dts.iter().max().unwrap(); + + let bucket_size = (max_x - min_x) / ((num_buckets - 3) as f64); + // lower, upper, count + let mut bars: Vec<(Duration, Duration, usize)> = Vec::new(); + let mut min = min_x; + while min < max_x { + let max = min + bucket_size; + if min < Duration::ZERO && max > Duration::ZERO { + bars.push((min, Duration::ZERO, 0)); + bars.push((Duration::ZERO, Duration::ZERO, 0)); + bars.push((Duration::ZERO, max, 0)); + } else { + bars.push((min, max, 0)); + } + + min = max; + } + if bars.is_empty() { + assert_eq!(min, max_x); + bars.push((Duration::ZERO, Duration::ZERO, 0)); + } else { + //assert_eq!(bars.len(), num_buckets); + } + + for dt in unsorted_dts { + // TODO Could sort them and do this more efficiently. + let mut ok = false; + for (min, max, count) in bars.iter_mut() { + if (dt >= *min && dt < *max) || (*min == *max && dt == *min) { + *count += 1; + ok = true; + break; + } + } + // Most bars represent [low, high) except the last and the [0, 0] one + if !ok { + bars.last_mut().unwrap().2 += 1; + } + } + (min_x, max_x, bars) +} diff --git a/game/src/common/overlays.rs b/game/src/common/overlays.rs index a44cc820a6..d05f5ea6fc 100644 --- a/game/src/common/overlays.rs +++ b/game/src/common/overlays.rs @@ -542,8 +542,10 @@ impl Overlays { ManagedWidget::draw_text(ctx, { let mut txt = Text::from(Line("Are finished trips ")); txt.append(Line("faster").fg(Color::GREEN)); - txt.append(Line(" or ")); + txt.append(Line(", ")); txt.append(Line("slower").fg(Color::RED)); + txt.append(Line(", or ")); + txt.append(Line("the same").fg(Color::YELLOW)); txt.append(Line("?")); txt }), diff --git a/game/src/sandbox/gameplay/fix_traffic_signals.rs b/game/src/sandbox/gameplay/fix_traffic_signals.rs index 9c83361fec..665353ad5f 100644 --- a/game/src/sandbox/gameplay/fix_traffic_signals.rs +++ b/game/src/sandbox/gameplay/fix_traffic_signals.rs @@ -74,7 +74,7 @@ fn make_top_center(ctx: &mut EventCtx, ui: &UI, mode: GameplayMode) -> WrappedCo .get_analytics() .all_finished_trips(ui.primary.sim.time()); let (baseline, _, _) = ui.prebaked().all_finished_trips(ui.primary.sim.time()); - txt.add(Line("Average trip time: ")); + txt.add(Line("Average trip time: ").size(20)); if now.count() > 0 && baseline.count() > 0 { txt.append_all(cmp_duration_shorter( now.select(Statistic::Mean), @@ -91,10 +91,19 @@ fn make_top_center(ctx: &mut EventCtx, ui: &UI, mode: GameplayMode) -> WrappedCo vec![ ManagedWidget::row(vec![ ManagedWidget::draw_text(ctx, txt).margin(5), - WrappedComposite::text_button(ctx, "details", None).margin(5), - ]) - .centered(), - ManagedWidget::draw_text(ctx, Text::from(Line(format!("Goal: {} faster", GOAL)))), + WrappedComposite::nice_text_button( + ctx, + Text::from(Line("details").size(20)), + None, + "details", + ) + .align_right(), + ]), + ManagedWidget::draw_text( + ctx, + Text::from(Line(format!("Goal: {} faster", GOAL)).size(20)), + ) + .margin(5), ], ) .cb(