Skip to content

Commit

Permalink
Format units on plots (#156)
Browse files Browse the repository at this point in the history
  • Loading branch information
dianaclarke committed Aug 24, 2021
1 parent bb52381 commit 8320347
Show file tree
Hide file tree
Showing 6 changed files with 526 additions and 84 deletions.
155 changes: 107 additions & 48 deletions conbench/app/_plots.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import dateutil

from ..hacks import sorted_data
from ..units import formatter_for_unit


class TimeSeriesPlotMixin:
Expand All @@ -30,9 +31,9 @@ def get_display_unit(unit):
if unit == "s":
return "seconds"
elif unit == "B/s":
return "bytes/seconds"
return "bytes/second"
elif unit == "i/s":
return "items/seconds"
return "items/second"
else:
return unit

Expand Down Expand Up @@ -62,82 +63,140 @@ def get_date_format():
)


def _simple_source(data, unit):
unit_fmt = formatter_for_unit(unit)
cases, points, means = [], [], []
points_formated, units_formatted = [], set()

for *values, point in data:
cases.append("-".join(values))
points.append(point)
formatted = unit_fmt(float(point), unit)
means.append(formatted)
formated_point, formatted_unit = formatted.split(" ", 1)
points_formated.append(formated_point)
units_formatted.add(formatted_unit)

unit_formatted = units_formatted.pop() if len(units_formatted) == 1 else None
if unit_formatted:
points = points_formated

axis_unit = unit_formatted if unit_formatted is not None else unit
if axis_unit == unit:
axis_unit = get_display_unit(unit)

source_data = dict(x=cases, y=points, means=means)
return bokeh.models.ColumnDataSource(data=source_data), axis_unit


def simple_bar_plot(benchmarks, height=400, width=400):
if len(benchmarks) > 30:
return None
if len(benchmarks) == 1:
return None

name = benchmarks[0]["tags"]["name"]
unit = get_display_unit(benchmarks[0]["stats"]["unit"])

cases, times = [], []
unit = benchmarks[0]["stats"]["unit"]
data = sorted_data(benchmarks)
for *values, timing in data:
cases.append("-".join(values))
times.append(timing)
source, axis_unit = _simple_source(data, unit)

tooltips = [("mean", "@means")]
hover = bokeh.models.HoverTool(tooltips=tooltips)

p = bokeh.plotting.figure(
x_range=cases,
x_range=source.data["x"],
title=get_title(benchmarks, name),
toolbar_location=None,
plot_height=height,
plot_width=width,
tools="",
tools=[hover],
)
p.vbar(
x="x",
top="y",
source=source,
width=0.9,
line_color="white",
color="silver",
)
p.vbar(x=cases, top=times, width=0.9, line_color="white", color="silver")

p.y_range.start = 0
p.x_range.range_padding = 0.1
p.xgrid.grid_line_color = None
p.xaxis.major_label_orientation = 1
p.yaxis.axis_label = unit
p.yaxis.axis_label = axis_unit

return p


def time_series_plot(history, benchmark_id, height=250, width=1000):
unit = get_display_unit(history[0]["unit"])
current = [h for h in history if h["benchmark_id"] == benchmark_id]
with_dist = [h for h in history if h["distribution_mean"]]

times = [h["mean"] for h in history]
commits = [h["message"] for h in history]
dates = [dateutil.parser.isoparse(h["timestamp"]) for h in history]

times_x = [c["mean"] for c in current]
commits_x = [c["message"] for c in current]
dates_x = [dateutil.parser.isoparse(c["timestamp"]) for c in current]

times_mean = [w["distribution_mean"] for w in with_dist]
commits_mean = [w["message"] for w in with_dist]
dates_mean = [dateutil.parser.isoparse(w["timestamp"]) for w in with_dist]

alert_min, alert_max = [], []
for w in with_dist:
alert = 5 * float(w["distribution_stdev"])
alert_min.append(float(w["distribution_mean"]) - alert)
alert_max.append(float(w["distribution_mean"]) + alert)
def _should_format(data, unit):
unit_fmt = formatter_for_unit(unit)

units_formatted = set()
for x in data:
units_formatted.add(unit_fmt(float(x["mean"]), unit).split(" ", 1)[1])

unit_formatted = units_formatted.pop() if len(units_formatted) == 1 else None

should = unit_formatted is not None
axis_unit = unit_formatted if unit_formatted is not None else unit
if axis_unit == unit:
axis_unit = get_display_unit(unit)

return should, axis_unit


def _source(
data,
unit,
formatted=False,
distribution_mean=False,
alert_min=False,
alert_max=False,
):
key = "distribution_mean" if distribution_mean else "mean"
unit_fmt = formatter_for_unit(unit)
commits = [x["message"] for x in data]
dates = [dateutil.parser.isoparse(x["timestamp"]) for x in data]

points, means = [], []
if alert_min:
for x in data:
alert = 5 * float(x["distribution_stdev"])
points.append(float(x["distribution_mean"]) - alert)
means.append(unit_fmt(points[-1], unit))
elif alert_max:
for x in data:
alert = 5 * float(x["distribution_stdev"])
points.append(float(x["distribution_mean"]) + alert)
means.append(unit_fmt(points[-1], unit))
else:
points = [x[key] for x in data]
means = [unit_fmt(float(x[key]), unit) for x in data]

source_data = dict(x=dates, y=times, commit=commits)
source = bokeh.models.ColumnDataSource(data=source_data)
if formatted:
points = [x.split(" ")[0] for x in means]

source_data_x = dict(x=dates_x, y=times_x, commit=commits_x)
source_x = bokeh.models.ColumnDataSource(data=source_data_x)
source_data = dict(x=dates, y=points, commits=commits, means=means)
return bokeh.models.ColumnDataSource(data=source_data)

source_data_mean = dict(x=dates_mean, y=times_mean, commit=commits_mean)
source_mean = bokeh.models.ColumnDataSource(data=source_data_mean)

source_data_alert_min = dict(x=dates_mean, y=alert_min, commit=commits_mean)
source_alert_min = bokeh.models.ColumnDataSource(data=source_data_alert_min)
def time_series_plot(history, benchmark_id, height=250, width=1000):
unit = history[0]["unit"]
current = [h for h in history if h["benchmark_id"] == benchmark_id]
with_dist = [h for h in history if h["distribution_mean"]]
formatted, axis_unit = _should_format(history, unit)

source_data_alert_max = dict(x=dates_mean, y=alert_max, commit=commits_mean)
source_alert_max = bokeh.models.ColumnDataSource(data=source_data_alert_max)
source = _source(history, unit, formatted=formatted)
source_x = _source(current, unit, formatted=formatted)
source_mean = _source(with_dist, unit, formatted=formatted, distribution_mean=True)
source_alert_min = _source(with_dist, unit, formatted=formatted, alert_min=True)
source_alert_max = _source(with_dist, unit, formatted=formatted, alert_max=True)

tooltips = [
("date", "$x{%F}"),
("mean", "$y{0.000}"),
("unit", unit),
("commit", "@commit"),
("mean", "@means"),
("commit", "@commits"),
]
hover = bokeh.models.HoverTool(
tooltips=tooltips,
Expand All @@ -153,7 +212,7 @@ def time_series_plot(history, benchmark_id, height=250, width=1000):

p.xaxis.formatter = get_date_format()
p.xaxis.major_label_orientation = 1
p.yaxis.axis_label = unit
p.yaxis.axis_label = axis_unit

p.line(source=source, legend_label="History")
p.line(source=source_mean, color="#ffa600", legend_label="Mean")
Expand Down

0 comments on commit 8320347

Please sign in to comment.