boviz.histogram 源代码

import os
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter, FixedLocator, NullLocator, NullFormatter

from boviz.config import GLOBAL_COLORS, set_default_dpi_figsize_savedir
from boviz.style import (
    set_default_style,
    set_sans_style,
    set_cm_style,
    set_ax_style,
    apply_axis_scientific_format,
    apply_axis_limits_and_ticks,
    save_or_display_legend,
)
from boviz.utils import generate_plot_filename, save_figure

[文档] def plot_histogram( label: str, x: list[float], y: list[float], xy_label: tuple[str, str], information: str = None, factor: list[(float, float)] = None, title: str = "Histogram", ylog: bool = False, sci: tuple[float, float] = [None, None], save: bool = False, show: bool = False, font_style: str = None, font_weight: str = "bold", categorical_x: bool = True, show_values: bool = True, ) -> str: """ 绘制柱状图(直方图) Args: x (list[int]): 核数列表 y (list[float]): 对应的运行时间列表 label (str, optional): 图例标签. Defaults to "Runtime". xy_label (tuple[str, str], optional): x轴和y轴标签. Defaults to ("Number of Cores", "Runtime (s)"). title (str, optional): 图表标题. Defaults to "Multi-core Performance". legend_location (str, optional): 图例位置. Defaults to "best". ylog (bool, optional): 是否使用对数y轴. Defaults to False. sci (tuple[float, float], optional): x轴和y轴的科学计数法阈值. Defaults to [None, None]. save (bool, optional): 是否保存图表. Defaults to True. show (bool, optional): 是否显示图表. Defaults to True. font_style (str, optional): 字体风格,"sans"表示无衬线字体,None表示默认字体. Defaults to None. font_weight (str, optional): 字体粗细,"bold"表示粗体,"normal"表示正常字体. Defaults to "bold". categorical_x (bool, optional): 是否将x轴作为类别处理(等间距). Defaults to True. Returns: str: 保存的图表路径 """ if not font_style: if font_weight == 'bold': set_cm_style(bold=True) elif font_weight == 'normal': set_cm_style(bold=False) else: raise ValueError("Invalid font_weight. Choose 'bold' or 'normal'.") elif font_style == 'sans': if font_weight == 'bold': set_sans_style(bold=True) elif font_weight == 'normal': set_sans_style(bold=False) else: raise ValueError("Invalid font_weight. Choose 'bold' or 'normal'.") elif font_style == 'times': if font_weight == 'bold': set_default_style(bold=True) elif font_weight == 'normal': set_default_style(bold=False) else: raise ValueError("Invalid font_weight. Choose 'bold' or 'normal'.") else: raise ValueError("Invalid font_style. Choose 'sans', 'times' or None.") dpi, figuresize, savedir = set_default_dpi_figsize_savedir() fig, ax = plt.subplots(figsize=figuresize, dpi=dpi) save_dir = os.path.join(savedir, "Histograms") set_ax_style(ax) ax.tick_params(axis="both", length=2.5, direction="in", width=0.75, which="both", pad=4) if factor: y = np.asarray(y, dtype=float) y = y * factor[0] + factor[1] # 绘制柱状图 colors = plt.cm.Dark2.colors if categorical_x: width = 0.28 x_pos = np.arange(len(x)) bars = ax.bar(x_pos, y, color=colors, edgecolor="black", linewidth=0.5, width=width, label=label) ax.set_xticks(x_pos) ax.set_xticklabels([str(v) for v in x], fontweight=font_weight) # ✅ 两端空白 = 条间距的一半 gap = 0.75 ax.set_xlim(-gap, len(x) - 1 + gap) else: # 数值轴:按数值比例排布(你原来的画法) bars = ax.bar(x, y, color=colors, edgecolor="black", linewidth=0.5, width=0.6, label=label) ax.set_xlim(min(x) - 0.6, max(x) + 0.6) if show_values: ymin, ymax = ax.get_ylim() ax.set_ylim(ymin, ymax * 1.1) # 上限增加 5% for bar, val in zip(bars, y): ax.text( bar.get_x() + bar.get_width() / 2, bar.get_height(), f"{val:.2f}", # 保留两位小数 ha="center", va="bottom", fontweight=font_weight, fontsize=6 ) ax.set_title(title, pad=7.5, fontweight=font_weight) ax.set_xlabel(xy_label[0], fontweight=font_weight, labelpad=2) ax.set_ylabel(xy_label[1], fontweight=font_weight, labelpad=3) label_suffix = f"({information})" if information else None if sci[0]: apply_axis_scientific_format(ax, 'x', sci[0]) if sci[1]: apply_axis_scientific_format(ax, 'y', sci[1]) if ylog: ax.set_yscale('log') ax.set_ylim(0.0, 0.6) ax.yaxis.set_major_locator(FixedLocator([0.002, 0.01, 0.1, 0.6])) ax.yaxis.set_major_formatter(FuncFormatter(lambda y, _: f'{y:g}')) ax.yaxis.set_minor_locator(NullLocator()) ax.yaxis.set_minor_formatter(NullFormatter()) plt.tight_layout(pad=0.1) filename = generate_plot_filename(title=title, suffix=label_suffix) save_path = os.path.join(save_dir, filename) if save: save_figure(save_path, dpi=dpi) if show: plt.show() plt.close() return save_path