blob: 6ee2215a3916668daab3735021b784c34e5924b1 [file]
#!/usr/bin/env python3
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
"""Shared plotting style for language benchmark reports."""
from __future__ import annotations
import os
import shutil
import subprocess
from pathlib import Path
import numpy as np
from matplotlib.ticker import MaxNLocator
PLOT_RC_PARAMS = {
"figure.facecolor": "white",
"axes.facecolor": "white",
"axes.titleweight": "normal",
"axes.labelcolor": "#222222",
"xtick.color": "#222222",
"ytick.color": "#222222",
"font.size": 10,
"axes.titlesize": 11,
"axes.labelsize": 10,
"xtick.labelsize": 9,
"ytick.labelsize": 9,
"legend.fontsize": 8,
}
GRID_COLOR = "#D9DEE7"
SPINE_COLOR = "#8A939E"
BAR_EDGE_COLOR = "white"
GROUP_X = np.array([0.0, 0.66])
GROUP_BAR_WIDTH = 0.16
GROUP_OFFSET_STEP = 0.175
GROUP_X_LIMITS = (-0.35, 1.01)
def apply_benchmark_style(plt) -> None:
plt.rcParams.update(PLOT_RC_PARAMS)
def format_throughput_label(value: float) -> str:
def format_scaled(scaled: float, suffix: str) -> str:
return f"{scaled:.2f}".rstrip("0").rstrip(".") + suffix
if value >= 1e9:
return format_scaled(value / 1e9, "G")
if value >= 1e6:
return format_scaled(value / 1e6, "M")
if value >= 1e3:
return format_scaled(value / 1e3, "K")
return f"{value:.0f}"
def format_throughput_tick(value: float, _position) -> str:
return format_throughput_label(value)
def style_throughput_axis(ax) -> None:
ax.set_axisbelow(True)
ax.grid(True, axis="y", color=GRID_COLOR, linestyle="-", linewidth=0.7)
ax.grid(False, axis="x")
ax.yaxis.set_major_locator(MaxNLocator(nbins=5, min_n_ticks=3))
ax.tick_params(axis="both", width=0.8, length=3)
for spine in ax.spines.values():
spine.set_color(SPINE_COLOR)
spine.set_linewidth(0.8)
def serializer_offset(index: int, count: int) -> float:
return (index - (count - 1) / 2) * GROUP_OFFSET_STEP
def set_grouped_operation_axis(ax, labels=("Serialize", "Deserialize")) -> None:
ax.set_xticks(GROUP_X)
ax.set_xticklabels(list(labels))
ax.set_xlim(*GROUP_X_LIMITS)
def add_compact_legend(ax) -> None:
ax.legend(
loc="upper right",
frameon=True,
framealpha=0.95,
edgecolor="#D6DAE0",
borderpad=0.3,
labelspacing=0.3,
handlelength=1.4,
handletextpad=0.45,
)
def save_benchmark_figure(fig, path: str | Path) -> None:
fig.savefig(path, dpi=170, bbox_inches="tight", pad_inches=0.12)
def format_markdown_with_prettier(*paths: str | Path) -> None:
prettier = shutil.which("prettier")
if prettier is None or not paths:
return
subprocess.run(
[
prettier,
"--write",
"--ignore-path",
os.devnull,
*(str(path) for path in paths),
],
check=True,
)