| from __future__ import annotations |
|
|
| import altair as alt |
| import pandas as pd |
|
|
|
|
| def build_trend_chart(dataframe: pd.DataFrame, show_error_bands: bool = False) -> alt.Chart | None: |
| if dataframe.empty: |
| return None |
|
|
| chart_data = dataframe.copy() |
| chart_data = chart_data.dropna(subset=["timestamp", "value"]) |
| if chart_data.empty: |
| return None |
|
|
| chart_data["repo_class"] = chart_data["repo_id"] + " | " + chart_data["class"] |
|
|
| base = alt.Chart(chart_data).encode( |
| x=alt.X("timestamp:T", title="Time"), |
| y=alt.Y("value:Q", title="Metric value"), |
| color=alt.Color("repo_id:N", title="Repo"), |
| strokeDash=alt.StrokeDash("class:N", title="Class"), |
| tooltip=[ |
| alt.Tooltip("timestamp:T", title="Timestamp"), |
| alt.Tooltip("repo_id:N", title="Repo"), |
| alt.Tooltip("revision:N", title="Revision"), |
| alt.Tooltip("class:N", title="Class"), |
| alt.Tooltip("metric:N", title="Metric"), |
| alt.Tooltip("value:Q", title="Value", format=".4f"), |
| alt.Tooltip("std:Q", title="Std", format=".4f"), |
| ], |
| ) |
|
|
| line = base.mark_line(point=True) |
|
|
| chart: alt.Chart | alt.LayerChart = line |
| band_data = chart_data.dropna(subset=["std"]).copy() |
| if show_error_bands and not band_data.empty: |
| band_data["lower"] = band_data["value"] - band_data["std"] |
| band_data["upper"] = band_data["value"] + band_data["std"] |
|
|
| band = alt.Chart(band_data).mark_area(opacity=0.15).encode( |
| x=alt.X("timestamp:T", title="Time"), |
| y=alt.Y("lower:Q", title="Metric value"), |
| y2="upper:Q", |
| color=alt.Color("repo_id:N", title="Repo"), |
| detail="repo_class:N", |
| ) |
| chart = band + line |
|
|
| metric_count = chart_data["metric"].nunique() |
| if metric_count > 1: |
| return chart.facet(row=alt.Row("metric:N", title=None)).resolve_scale(y="independent") |
|
|
| return chart |
|
|
|
|
| def build_latest_comparison_chart(dataframe: pd.DataFrame, metric: str) -> alt.Chart | None: |
| if dataframe.empty: |
| return None |
|
|
| latest = dataframe[dataframe["is_latest"] & (dataframe["metric"] == metric)].dropna(subset=["value"]) |
| if latest.empty: |
| return None |
|
|
| return ( |
| alt.Chart(latest) |
| .mark_bar() |
| .encode( |
| x=alt.X("repo_id:N", title="Repo", sort="-y"), |
| y=alt.Y("value:Q", title=f"Latest {metric}"), |
| color=alt.Color("class:N", title="Class"), |
| tooltip=[ |
| alt.Tooltip("repo_id:N", title="Repo"), |
| alt.Tooltip("revision:N", title="Revision"), |
| alt.Tooltip("class:N", title="Class"), |
| alt.Tooltip("value:Q", title="Value", format=".4f"), |
| alt.Tooltip("std:Q", title="Std", format=".4f"), |
| ], |
| ) |
| ) |
|
|
|
|
| def build_class_small_multiples(dataframe: pd.DataFrame, metric: str) -> alt.Chart | None: |
| if dataframe.empty: |
| return None |
|
|
| plot_df = dataframe[dataframe["metric"] == metric].dropna(subset=["value"]) |
| if plot_df.empty: |
| return None |
|
|
| chart = ( |
| alt.Chart(plot_df) |
| .mark_line(point=True) |
| .encode( |
| x=alt.X("timestamp:T", title="Time"), |
| y=alt.Y("value:Q", title=metric), |
| color=alt.Color("repo_id:N", title="Repo"), |
| tooltip=[ |
| alt.Tooltip("timestamp:T", title="Timestamp"), |
| alt.Tooltip("repo_id:N", title="Repo"), |
| alt.Tooltip("revision:N", title="Revision"), |
| alt.Tooltip("class:N", title="Class"), |
| alt.Tooltip("value:Q", title="Value", format=".4f"), |
| ], |
| ) |
| ) |
|
|
| return chart.facet(column=alt.Column("class:N", title=None, sort="ascending")) |
|
|