mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-29 17:34:58 +03:00
split the plot into 3 pieces, use layouting for the axes
This commit is contained in:
parent
f1566b48c9
commit
e7d9efc4e4
@ -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))
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
@ -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)),
|
||||
)
|
||||
|
@ -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)),
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user