split the plot into 3 pieces, use layouting for the axes

This commit is contained in:
Dustin Carlino 2019-12-21 10:43:26 -08:00
parent f1566b48c9
commit e7d9efc4e4
5 changed files with 83 additions and 64 deletions

View File

@ -155,11 +155,11 @@ impl ManagedWidget {
ManagedWidget::new(WidgetType::Slider(label.to_string()))
}
pub fn duration_plot(plot: Plot<Duration>) -> ManagedWidget {
pub(crate) fn duration_plot(plot: Plot<Duration>) -> ManagedWidget {
ManagedWidget::new(WidgetType::DurationPlot(plot))
}
pub fn usize_plot(plot: Plot<usize>) -> ManagedWidget {
pub(crate) fn usize_plot(plot: Plot<usize>) -> ManagedWidget {
ManagedWidget::new(WidgetType::UsizePlot(plot))
}

View File

@ -1,6 +1,7 @@
use crate::layout::Widget;
use crate::{
Color, DrawBoth, EventCtx, GeomBatch, GfxCtx, Line, ScreenDims, ScreenPt, ScreenRectangle, Text,
Color, DrawBoth, EventCtx, GeomBatch, GfxCtx, Line, ManagedWidget, ScreenDims, ScreenPt,
ScreenRectangle, Text,
};
use abstutil::prettyprint_usize;
use geom::{Bounds, Circle, Distance, Duration, FindClosest, PolyLine, Pt2D, Time};
@ -20,9 +21,13 @@ pub struct Plot<T> {
impl<T: 'static + Ord + PartialEq + Copy + core::fmt::Debug + Yvalue<T>> Plot<T> {
// TODO I want to store y_zero in the trait, but then we can't Box max_y.
pub fn new(series: Vec<Series<T>>, y_zero: T, ctx: &EventCtx) -> Plot<T> {
// Returns (plot, X axis labels, Y axis labels)
fn new(
series: Vec<Series<T>>,
y_zero: T,
ctx: &EventCtx,
) -> (Plot<T>, ManagedWidget, ManagedWidget) {
let mut batch = GeomBatch::new();
let mut labels: Vec<(Text, ScreenPt)> = Vec::new();
let width = 0.5 * ctx.canvas.window_width;
let height = 0.4 * ctx.canvas.window_height;
@ -51,25 +56,6 @@ impl<T: 'static + Ord + PartialEq + Copy + core::fmt::Debug + Yvalue<T>> Plot<T>
.max()
.unwrap_or(y_zero);
let num_x_labels = 5;
for i in 0..num_x_labels {
let percent_x = (i as f64) / ((num_x_labels - 1) as f64);
let t = max_x.percent_of(percent_x);
labels.push((
Text::from(Line(t.to_string())),
ScreenPt::new(percent_x * width, height),
));
}
let num_y_labels = 5;
for i in 0..num_y_labels {
let percent_y = (i as f64) / ((num_y_labels - 1) as f64);
labels.push((
Text::from(Line(max_y.from_percent(percent_y).prettyprint())).with_bg(),
ScreenPt::new(0.0, (1.0 - percent_y) * height),
));
}
let mut closest = FindClosest::new(&Bounds::from(&vec![
Pt2D::new(0.0, 0.0),
Pt2D::new(width, height),
@ -98,15 +84,41 @@ impl<T: 'static + Ord + PartialEq + Copy + core::fmt::Debug + Yvalue<T>> Plot<T>
}
}
Plot {
draw: DrawBoth::new(ctx, batch, labels),
let plot = Plot {
draw: DrawBoth::new(ctx, batch, Vec::new()),
closest,
max_x,
max_y: Box::new(max_y),
top_left: ScreenPt::new(0.0, 0.0),
dims: ScreenDims::new(width, height + ctx.default_line_height()),
};
let num_x_labels = 4;
let mut row = Vec::new();
for i in 0..num_x_labels {
let percent_x = (i as f64) / ((num_x_labels - 1) as f64);
let t = max_x.percent_of(percent_x);
row.push(ManagedWidget::draw_text(
ctx,
Text::from(Line(t.to_string())),
));
}
let x_axis = ManagedWidget::row(row);
let num_y_labels = 4;
let mut col = Vec::new();
for i in 0..num_y_labels {
let percent_y = (i as f64) / ((num_y_labels - 1) as f64);
col.push(ManagedWidget::draw_text(
ctx,
Text::from(Line(max_y.from_percent(percent_y).prettyprint())),
));
}
col.reverse();
let y_axis = ManagedWidget::col(col);
(plot, x_axis, y_axis)
}
pub fn draw(&self, g: &mut GfxCtx) {
@ -141,6 +153,32 @@ impl<T: 'static + Ord + PartialEq + Copy + core::fmt::Debug + Yvalue<T>> Plot<T>
}
}
impl Plot<usize> {
pub fn new_usize(series: Vec<Series<usize>>, ctx: &EventCtx) -> ManagedWidget {
let (plot, x_axis, y_axis) = Plot::new(series, 0, ctx);
ManagedWidget::col(vec![
ManagedWidget::row(vec![
y_axis.evenly_spaced(),
ManagedWidget::usize_plot(plot),
]),
x_axis.evenly_spaced(),
])
}
}
impl Plot<Duration> {
pub fn new_duration(series: Vec<Series<Duration>>, ctx: &EventCtx) -> ManagedWidget {
let (plot, x_axis, y_axis) = Plot::new(series, Duration::ZERO, ctx);
ManagedWidget::col(vec![
ManagedWidget::row(vec![
y_axis.evenly_spaced(),
ManagedWidget::duration_plot(plot),
]),
x_axis.evenly_spaced(),
])
}
}
impl<T> Widget for Plot<T> {
fn get_dims(&self) -> ScreenDims {
self.dims

View File

@ -37,14 +37,9 @@ impl InfoPanel {
.bg(Color::grey(0.5)),
);
col.push(
ManagedWidget::duration_plot(intersection_delay(
i,
Duration::hours(1),
ctx,
ui,
))
.bg(Color::grey(0.5))
.margin(10),
intersection_delay(i, Duration::hours(1), ctx, ui)
.bg(Color::grey(0.5))
.margin(10),
);
}
col.push(
@ -52,14 +47,9 @@ impl InfoPanel {
.bg(Color::grey(0.5)),
);
col.push(
ManagedWidget::usize_plot(intersection_throughput(
i,
Duration::hours(1),
ctx,
ui,
))
.bg(Color::grey(0.5))
.margin(10),
intersection_throughput(i, Duration::hours(1), ctx, ui)
.bg(Color::grey(0.5))
.margin(10),
);
}
ID::Lane(l) => {
@ -71,14 +61,9 @@ impl InfoPanel {
.bg(Color::grey(0.5)),
);
col.push(
ManagedWidget::usize_plot(road_throughput(
ui.primary.map.get_l(l).parent,
Duration::hours(1),
ctx,
ui,
))
.bg(Color::grey(0.5))
.margin(10),
road_throughput(ui.primary.map.get_l(l).parent, Duration::hours(1), ctx, ui)
.bg(Color::grey(0.5))
.margin(10),
);
}
_ => {}
@ -324,8 +309,8 @@ fn intersection_throughput(
bucket: Duration,
ctx: &EventCtx,
ui: &UI,
) -> Plot<usize> {
Plot::new(
) -> ManagedWidget {
Plot::new_usize(
ui.primary
.sim
.get_analytics()
@ -337,13 +322,12 @@ fn intersection_throughput(
pts,
})
.collect(),
0,
ctx,
)
}
fn road_throughput(r: RoadID, bucket: Duration, ctx: &EventCtx, ui: &UI) -> Plot<usize> {
Plot::new(
fn road_throughput(r: RoadID, bucket: Duration, ctx: &EventCtx, ui: &UI) -> ManagedWidget {
Plot::new_usize(
ui.primary
.sim
.get_analytics()
@ -355,7 +339,6 @@ fn road_throughput(r: RoadID, bucket: Duration, ctx: &EventCtx, ui: &UI) -> Plot
pts,
})
.collect(),
0,
ctx,
)
}
@ -365,7 +348,7 @@ fn intersection_delay(
bucket: Duration,
ctx: &EventCtx,
ui: &UI,
) -> Plot<Duration> {
) -> ManagedWidget {
let mut series: Vec<(Statistic, Vec<(Time, Duration)>)> = Statistic::all()
.into_iter()
.map(|stat| (stat, Vec::new()))
@ -385,7 +368,7 @@ fn intersection_delay(
}
}
Plot::new(
Plot::new_duration(
series
.into_iter()
.enumerate()
@ -395,7 +378,6 @@ fn intersection_delay(
pts,
})
.collect(),
Duration::ZERO,
ctx,
)
}

View File

@ -11,7 +11,7 @@ use ezgui::{
hotkey, Choice, Color, Composite, EventCtx, HorizontalAlignment, Key, Line, ManagedWidget,
ModalMenu, Plot, Series, Text, VerticalAlignment,
};
use geom::{Duration, Statistic, Time};
use geom::{Statistic, Time};
use map_model::BusRouteID;
use sim::Analytics;
@ -201,7 +201,7 @@ fn bus_delays(id: BusRouteID, ui: &UI, ctx: &mut EventCtx) -> Composite {
(HorizontalAlignment::Center, VerticalAlignment::Center),
ManagedWidget::col(vec![
ManagedWidget::draw_text(ctx, Text::from(Line(format!("delays for {}", route.name)))),
ManagedWidget::duration_plot(Plot::new(series, Duration::ZERO, ctx)).margin(10),
Plot::new_duration(series, ctx).margin(10),
])
.bg(Color::grey(0.3)),
)

View File

@ -388,7 +388,7 @@ impl Overlays {
.push((ui.primary.sim.time(), counts.get(*mode)));
}
let plot = Plot::new(
let plot = Plot::new_usize(
lines
.into_iter()
.map(|(label, color, m)| Series {
@ -397,7 +397,6 @@ impl Overlays {
pts: pts_per_mode.remove(&m).unwrap(),
})
.collect(),
0,
ctx,
);
let composite = Composite::aligned(
@ -405,7 +404,7 @@ impl Overlays {
(HorizontalAlignment::Center, VerticalAlignment::Center),
ManagedWidget::col(vec![
ManagedWidget::draw_text(ctx, Text::from(Line("finished trips"))),
ManagedWidget::usize_plot(plot).margin(10),
plot.margin(10),
])
.bg(Color::grey(0.3)),
);