Skip to content

API

plotfig.bar

plot_one_group_bar_figure

plot_one_group_bar_figure(data, ax=None, labels_name=None, width=0.5, colors=None, dots_size=35, dots_color=None, title_name='', x_label_name='', y_label_name='', statistic=False, test_method='ttest_ind', p_list=None, errorbar_type='se', **kwargs)

绘制单组柱状图,包含散点和误差条。

Parameters:

Name Type Description Default
data list[NumArray]

包含多个数据集的列表,每个数据集是一个数字数组。

required
ax Axes | None

matplotlib 的 Axes 对象,用于绘图。默认为 None,使用当前的 Axes。

None
labels_name list[str] | None

每个数据集的标签名称。默认为 None,使用索引作为标签。

None
width Num

柱子的宽度。默认为 0.5。

0.5
colors list[str] | None

每个柱子的颜色。默认为 None,使用灰色。

None
dots_size Num

散点的大小。默认为 35。

35
dots_color list[list[str]] | None

每个数据集中散点的颜色。默认为 None,使用灰色。

None
title_name str

图表的标题。默认为空字符串。

''
x_label_name str

X 轴的标签。默认为空字符串。

''
y_label_name str

Y 轴的标签。默认为空字符串。

''
statistic bool

是否进行统计检验并标注显著性标记。默认为 False。

False
test_method str

统计检验的方法,支持 "ttest_ind"、"ttest_rel" 和 "mannwhitneyu"。默认为 "ttest_ind"。

'ttest_ind'
p_list list[float] | None

外部提供的 p 值列表,用于统计检验。默认为 None。

None
errorbar_type str

误差条类型,支持 "sd"(标准差)和 "se"(标准误)。默认为 "se"。

'se'
**kwargs Any

其他可选参数,用于进一步定制图表样式。

{}

Returns:

Type Description
None

None

Source code in src/plotfig/bar.py
def plot_one_group_bar_figure(
    data: list[NumArray],
    ax: Axes | None = None,
    labels_name: list[str] | None = None,
    width: Num = 0.5,
    colors: list[str] | None = None,
    dots_size: Num = 35,
    dots_color: list[list[str]] | None = None,
    title_name: str = "",
    x_label_name: str = "",
    y_label_name: str = "",
    statistic: bool = False,
    test_method: str = "ttest_ind",
    p_list: list[float] | None = None,
    errorbar_type: str = "se",
    **kwargs: Any,
) -> None:
    """绘制单组柱状图,包含散点和误差条。

    Args:
        data (list[NumArray]): 包含多个数据集的列表,每个数据集是一个数字数组。
        ax (Axes | None, optional): matplotlib 的 Axes 对象,用于绘图。默认为 None,使用当前的 Axes。
        labels_name (list[str] | None, optional): 每个数据集的标签名称。默认为 None,使用索引作为标签。
        width (Num, optional): 柱子的宽度。默认为 0.5。
        colors (list[str] | None, optional): 每个柱子的颜色。默认为 None,使用灰色。
        dots_size (Num, optional): 散点的大小。默认为 35。
        dots_color (list[list[str]] | None, optional): 每个数据集中散点的颜色。默认为 None,使用灰色。
        title_name (str, optional): 图表的标题。默认为空字符串。
        x_label_name (str, optional): X 轴的标签。默认为空字符串。
        y_label_name (str, optional): Y 轴的标签。默认为空字符串。
        statistic (bool, optional): 是否进行统计检验并标注显著性标记。默认为 False。
        test_method (str, optional): 统计检验的方法,支持 "ttest_ind"、"ttest_rel" 和 "mannwhitneyu"。默认为 "ttest_ind"。
        p_list (list[float] | None, optional): 外部提供的 p 值列表,用于统计检验。默认为 None。
        errorbar_type (str, optional): 误差条类型,支持 "sd"(标准差)和 "se"(标准误)。默认为 "se"。
        **kwargs (Any): 其他可选参数,用于进一步定制图表样式。

    Returns:
        None
    """

    if ax is None:
        ax = plt.gca()
    if labels_name is None:
        labels_name = [str(i) for i in range(len(data))]
    if colors is None:
        colors = ["gray"] * len(data)

    np.random.seed(1998)

    means, sds, ses = [], [], []
    x_positions = np.arange(len(labels_name))
    scatter_positions = []

    for i, d in enumerate(data):
        mean, sd, se = compute_summary(d)
        means.append(mean)
        sds.append(sd)
        ses.append(se)
        scatter_x = np.random.normal(i, 0.1, len(d))
        scatter_positions.append(scatter_x)

    if errorbar_type == "sd":
        error_values = sds
    elif errorbar_type == "se":
        error_values = ses

    # 绘制柱子
    ax.bar(x_positions, means, width=width, color=colors, alpha=1, edgecolor="k")
    ax.errorbar(
        x_positions,
        means,
        error_values,
        fmt="none",
        linewidth=1,
        capsize=3,
        color="black",
    )

    # 绘制散点
    for i, d in enumerate(data):
        if dots_color is None:
            add_scatter(ax, scatter_positions[i], d, ["gray"] * len(d), dots_size)
        else:
            add_scatter(ax, scatter_positions[i], d, dots_color[i], dots_size)

    # 美化
    ax.spines[["top", "right"]].set_visible(False)
    ax.set_title(
        title_name,
        fontsize=kwargs.get("title_fontsize", 10),
        pad=kwargs.get("title_pad", 20),
    )
    ax.set_xlabel(x_label_name, fontsize=kwargs.get("x_label_fontsize", 10))
    ax.set_ylabel(y_label_name, fontsize=kwargs.get("y_label_fontsize", 10))
    ax.set_xticks(x_positions)
    ax.set_xticklabels(
        labels_name,
        ha=kwargs.get("x_label_ha", "center"),
        rotation_mode="anchor",
        fontsize=kwargs.get("x_tick_fontsize", 10),
        rotation=kwargs.get("x_tick_rotation", 0),
    )
    ax.tick_params(
        axis="y",
        labelsize=kwargs.get("y_tick_fontsize", 10),
        rotation=kwargs.get("y_tick_rotation", 0),
    )

    all_values = np.concatenate(data)
    set_yaxis(ax, all_values, kwargs)

    # 添加统计显著性标记
    if statistic:
        comparisons = []
        idx = 0
        for i in range(len(data)):
            for j in range(i + 1, len(data)):
                if test_method == "external":
                    p = p_list[idx]
                    idx += 1
                else:
                    _, p = perform_stat_test(data[i], data[j], test_method)
                if p <= 0.05:
                    comparisons.append((i, j, p))

        y_max = ax.get_ylim()[1]
        interval = (y_max - np.max(all_values)) / (len(comparisons) + 1)
        annotate_significance(
            ax,
            comparisons,
            np.max(all_values),
            interval,
            line_color=kwargs.get("line_color", "0.5"),
            star_offset=interval / 5,
            fontsize=kwargs.get("asterisk_fontsize", 10),
            color=kwargs.get("asterisk_color", "k"),
        )

plot_one_group_violin_figure

plot_one_group_violin_figure(data, ax=None, labels_name=None, width=0.8, colors=None, show_dots=False, dots_size=35, title_name='', x_label_name='', y_label_name='', statistic=False, test_method='ttest_ind', p_list=None, show_means=False, show_extrema=True, **kwargs)

绘制单组小提琴图,包含散点和统计显著性标记。

Parameters:

Name Type Description Default
data list[NumArray]

包含多个数据集的列表,每个数据集是一个数字数组。

required
ax Axes | None

matplotlib 的 Axes 对象,用于绘图。默认为 None,使用当前的 Axes。

None
labels_name list[str] | None

每个数据集的标签名称。默认为 None,使用索引作为标签。

None
width Num

小提琴图的宽度。默认为 0.8。

0.8
colors list[str] | None

每个小提琴图的颜色。默认为 None,使用灰色。

None
show_dots bool

是否显示散点。默认为 False。

False
dots_size Num

散点的大小。默认为 35。

35
title_name str

图表的标题。默认为空字符串。

''
x_label_name str

X 轴的标签。默认为空字符串。

''
y_label_name str

Y 轴的标签。默认为空字符串。

''
statistic bool

是否进行统计检验并标注显著性标记。默认为 False。

False
test_method str

统计检验的方法,支持 "ttest_ind"、"ttest_rel" 和 "mannwhitneyu"。默认为 "ttest_ind"。

'ttest_ind'
p_list list[float] | None

外部提供的 p 值列表,用于统计检验。默认为 None。

None
show_means bool

是否显示均值线。默认为 False。

False
show_extrema bool

是否显示极值线。默认为 True。

True
**kwargs Any

其他可选参数,用于进一步定制图表样式。

{}

Returns:

Type Description
None

None

Source code in src/plotfig/bar.py
def plot_one_group_violin_figure(
    data: list[NumArray],
    ax: Axes | None = None,
    labels_name: list[str] | None = None,
    width: Num = 0.8,
    colors: list[str] | None = None,
    show_dots: bool = False,
    dots_size: Num = 35,
    title_name: str = "",
    x_label_name: str = "",
    y_label_name: str = "",
    statistic: bool = False,
    test_method: str = "ttest_ind",
    p_list: list[float] | None = None,
    show_means: bool = False,
    show_extrema: bool = True,
    **kwargs: Any,
) -> None:
    """绘制单组小提琴图,包含散点和统计显著性标记。

    Args:
        data (list[NumArray]): 包含多个数据集的列表,每个数据集是一个数字数组。
        ax (Axes | None, optional): matplotlib 的 Axes 对象,用于绘图。默认为 None,使用当前的 Axes。
        labels_name (list[str] | None, optional): 每个数据集的标签名称。默认为 None,使用索引作为标签。
        width (Num, optional): 小提琴图的宽度。默认为 0.8。
        colors (list[str] | None, optional): 每个小提琴图的颜色。默认为 None,使用灰色。
        show_dots (bool, optional): 是否显示散点。默认为 False。
        dots_size (Num, optional): 散点的大小。默认为 35。
        title_name (str, optional): 图表的标题。默认为空字符串。
        x_label_name (str, optional): X 轴的标签。默认为空字符串。
        y_label_name (str, optional): Y 轴的标签。默认为空字符串。
        statistic (bool, optional): 是否进行统计检验并标注显著性标记。默认为 False。
        test_method (str, optional): 统计检验的方法,支持 "ttest_ind"、"ttest_rel" 和 "mannwhitneyu"。默认为 "ttest_ind"。
        p_list (list[float] | None, optional): 外部提供的 p 值列表,用于统计检验。默认为 None。
        show_means (bool, optional): 是否显示均值线。默认为 False。
        show_extrema (bool, optional): 是否显示极值线。默认为 True。
        **kwargs (Any): 其他可选参数,用于进一步定制图表样式。

    Returns:
        None
    """

    ax = ax or plt.gca()
    labels_name = labels_name or [str(i) for i in range(len(data))]
    colors = colors or ["gray"] * len(data)

    np.random.seed(1998)  # 固定随机种子保证散点位置可复现

    # 绘制小提琴图
    parts = ax.violinplot(
        dataset=list(data),
        positions=np.arange(len(data)),
        widths=width,
        showmeans=show_means,
        showextrema=show_extrema,
    )

    # 设置小提琴颜色(修改默认样式)
    for pc, color in zip(parts["bodies"], colors):
        pc.set_facecolor(color)
        pc.set_edgecolor("black")
        pc.set_alpha(0.7)

    # 修改内部线条颜色
    if show_extrema:
        parts["cmins"].set_color("black")  # 最小值线
        parts["cmaxes"].set_color("black")  # 最大值线
        parts["cbars"].set_color("black")  # 中线(median)
    if show_means:
        parts["cmeans"].set_color("black")  # 均值线

    # 绘制散点(复用现有函数)
    if show_dots:
        scatter_positions = [
            np.random.normal(i, 0.1, len(d)) for i, d in enumerate(data)
        ]
        for i, d in enumerate(data):
            add_scatter(ax, scatter_positions[i], d, colors[i], dots_size)

    # 美化坐标轴(复用现有函数)
    ax.spines[["top", "right"]].set_visible(False)
    ax.set_title(title_name, fontsize=kwargs.get("title_fontsize", 10), pad=20)
    ax.set_xlabel(x_label_name, fontsize=kwargs.get("x_label_fontsize", 10))
    ax.set_ylabel(y_label_name, fontsize=kwargs.get("y_label_fontsize", 10))
    ax.set_xticks(np.arange(len(data)))
    ax.set_xticklabels(
        labels_name,
        fontsize=kwargs.get("x_tick_fontsize", 10),
        rotation=kwargs.get("x_tick_rotation", 0),
    )

    # 设置Y轴(复用现有函数)
    all_values = np.concatenate(data)
    set_yaxis(ax, all_values, kwargs)

    # 添加统计标记(复用现有函数)
    if statistic:
        comparisons = []
        idx = 0
        for i in range(len(data)):
            for j in range(i + 1, len(data)):
                if test_method == "external":
                    p = p_list[idx] if p_list else 1.0
                    idx += 1
                else:
                    _, p = perform_stat_test(data[i], data[j], test_method)
                if p <= 0.05:
                    comparisons.append((i, j, p))

        if comparisons:
            y_max = ax.get_ylim()[1]
            interval = (y_max - np.max(all_values)) / (len(comparisons) + 1)
            annotate_significance(
                ax,
                comparisons,
                np.max(all_values),
                interval,
                line_color=kwargs.get("line_color", "0.5"),
                star_offset=interval / 5,
                fontsize=kwargs.get("asterisk_fontsize", 10),
                color=kwargs.get("asterisk_color", "k"),
            )

plot_multi_group_bar_figure

plot_multi_group_bar_figure(data, ax=None, bar_width=0.2, bar_gap=0.1, bar_color=None, errorbar_type='se', dots_color='gray', dots_size=35, group_labels=None, bar_labels=None, title_name='', y_label_name='', statistic=False, test_method='external', p_list=None, legend=True, legend_position=(1.2, 1), **kwargs)

绘制多组柱状图,包含散点和误差条。

Parameters:

Name Type Description Default
data list[list[NumArray]]

包含多个组的数据,每组是一个数据集列表,每个数据集是一个数字数组。

required
ax Axes | None

matplotlib 的 Axes 对象,用于绘图。默认为 None,使用当前的 Axes。

None
bar_width Num

每个柱子的宽度。默认为 0.2。

0.2
bar_gap Num

柱子之间的间隙。默认为 0.1。

0.1
bar_color list[str] | None

每个柱子的颜色。默认为 None,使用灰色。

None
errorbar_type str

误差条类型,支持 "sd"(标准差)和 "se"(标准误)。默认为 "se"。

'se'
dots_color str

散点的颜色。默认为 "gray"。

'gray'
dots_size int

散点的大小。默认为 35。

35
group_labels list[str] | None

每组的标签名称。默认为 None,使用 "Group i" 作为标签。

None
bar_labels list[str] | None

每个柱子的标签名称。默认为 None,使用 "Bar i" 作为标签。

None
title_name str

图表的标题。默认为空字符串。

''
y_label_name str

Y 轴的标签。默认为空字符串。

''
statistic bool

是否进行统计检验并标注显著性标记。默认为 False。

False
test_method str

统计检验的方法,支持 "external"(外部提供 p 值)和其他方法。默认为 "external"。

'external'
p_list list[list[Num]] | None

外部提供的 p 值列表,用于统计检验。默认为 None。

None
legend bool

是否显示图例。默认为 True。

True
legend_position tuple[Num, Num]

图例的位置。默认为 (1.2, 1)。

(1.2, 1)
**kwargs Any

其他可选参数,用于进一步定制图表样式。

{}

Returns:

Type Description
None

None

Source code in src/plotfig/bar.py
def plot_multi_group_bar_figure(
    data: list[list[NumArray]],
    ax: plt.Axes | None = None,
    bar_width: Num = 0.2,
    bar_gap: Num = 0.1,
    bar_color: list[str] | None = None,
    errorbar_type: str = "se",
    dots_color: str = "gray",
    dots_size: int = 35,
    group_labels: list[str] | None = None,
    bar_labels: list[str] | None = None,
    title_name: str = "",
    y_label_name: str = "",
    statistic: bool = False,
    test_method: str = "external",
    p_list: list[list[Num]] | None = None,
    legend: bool = True,
    legend_position: tuple[Num, Num] = (1.2, 1),
    **kwargs: Any,
) -> None:
    """绘制多组柱状图,包含散点和误差条。

    Args:
        data (list[list[NumArray]]): 包含多个组的数据,每组是一个数据集列表,每个数据集是一个数字数组。
        ax (plt.Axes | None, optional): matplotlib 的 Axes 对象,用于绘图。默认为 None,使用当前的 Axes。
        bar_width (Num, optional): 每个柱子的宽度。默认为 0.2。
        bar_gap (Num, optional): 柱子之间的间隙。默认为 0.1。
        bar_color (list[str] | None, optional): 每个柱子的颜色。默认为 None,使用灰色。
        errorbar_type (str, optional): 误差条类型,支持 "sd"(标准差)和 "se"(标准误)。默认为 "se"。
        dots_color (str, optional): 散点的颜色。默认为 "gray"。
        dots_size (int, optional): 散点的大小。默认为 35。
        group_labels (list[str] | None, optional): 每组的标签名称。默认为 None,使用 "Group i" 作为标签。
        bar_labels (list[str] | None, optional): 每个柱子的标签名称。默认为 None,使用 "Bar i" 作为标签。
        title_name (str, optional): 图表的标题。默认为空字符串。
        y_label_name (str, optional): Y 轴的标签。默认为空字符串。
        statistic (bool, optional): 是否进行统计检验并标注显著性标记。默认为 False。
        test_method (str, optional): 统计检验的方法,支持 "external"(外部提供 p 值)和其他方法。默认为 "external"。
        p_list (list[list[Num]] | None, optional): 外部提供的 p 值列表,用于统计检验。默认为 None。
        legend (bool, optional): 是否显示图例。默认为 True。
        legend_position (tuple[Num, Num], optional): 图例的位置。默认为 (1.2, 1)。
        **kwargs (Any): 其他可选参数,用于进一步定制图表样式。

    Returns:
        None
    """

    # 动态参数
    if ax is None:
        ax = plt.gca()
    n_groups = len(data)
    if group_labels is None:
        group_labels = [f"Group {i + 1}" for i in range(n_groups)]
    # 把所有子列表展开成一个大列表
    all_values = [x for sublist1 in data for sublist2 in sublist1 for x in sublist2]

    x_positions_all = []
    for index_group, group_data in enumerate(data):
        n_bars = len(group_data)
        if bar_labels is None:
            bar_labels = [f"Bar {i + 1}" for i in range(n_bars)]
        if bar_color is None:
            bar_color = ["gray"] * n_bars

        x_positions = (
            np.arange(n_bars) * (bar_width + bar_gap)
            + bar_width / 2
            + index_group
            - (n_bars * bar_width + (n_bars - 1) * bar_gap) / 2
        )
        x_positions_all.append(x_positions)

        # 计算均值、标准差、标准误
        means = [compute_summary(group_data[i])[0] for i in range(n_bars)]
        sds = [compute_summary(group_data[i])[1] for i in range(n_bars)]
        ses = [compute_summary(group_data[i])[2] for i in range(n_bars)]
        if errorbar_type == "sd":
            error_values = sds
        elif errorbar_type == "se":
            error_values = ses
        # 绘制柱子
        bars = ax.bar(
            x_positions, means, width=bar_width, color=bar_color, alpha=1, edgecolor="k"
        )
        ax.errorbar(
            x_positions,
            means,
            error_values,
            fmt="none",
            linewidth=1,
            capsize=3,
            color="black",
        )
        # 绘制散点
        for index_bar, dot in enumerate(group_data):
            dot_x_pos = np.random.normal(
                x_positions[index_bar], scale=bar_width / 7, size=len(dot)
            )
            add_scatter(ax, dot_x_pos, dot, dots_color, dots_size=dots_size)
    if legend:
        ax.legend(bars, bar_labels, bbox_to_anchor=legend_position)
    # x轴
    ax.set_xticks(np.arange(n_groups))
    ax.set_xticklabels(
        group_labels,
        fontsize=kwargs.get("x_tick_fontsize", 10),
        rotation=kwargs.get("x_tick_rotation", 0),
    )
    # 美化
    ax.spines[["top", "right"]].set_visible(False)
    ax.set_title(
        title_name,
        fontsize=kwargs.get("title_fontsize", 15),
        pad=kwargs.get("title_pad", 20),
    )
    ax.set_ylabel(y_label_name, fontsize=kwargs.get("y_label_fontsize", 10))
    set_yaxis(ax, all_values, kwargs)
    # 添加统计显著性标记
    if statistic:
        for index_group, group_data in enumerate(data):
            x_positions = x_positions_all[index_group]
            comparisons = []
            idx = 0
            for i in range(len(group_data)):
                for j in range(i + 1, len(group_data)):
                    if test_method == "external":
                        p = p_list[index_group][idx]
                        idx += 1
                    if p <= 0.05:
                        comparisons.append((x_positions[i], x_positions[j], p))
            y_max = ax.get_ylim()[1]
            interval = (y_max - np.max(all_values)) / (len(comparisons) + 1)
            annotate_significance(
                ax,
                comparisons,
                np.max(all_values),
                interval,
                line_color=kwargs.get("line_color", "0.5"),
                star_offset=interval / 5,
                fontsize=kwargs.get("asterisk_fontsize", 10),
                color=kwargs.get("asterisk_color", "k"),
            )

plotfig.correlation

plot_correlation_figure

plot_correlation_figure(data1, data2, ax=None, stats_method='spearman', ci=False, dots_color='steelblue', dots_size=1, line_color='r', title_name='', title_fontsize=10, title_pad=10, x_label_name='', x_label_fontsize=10, x_tick_fontsize=10, x_tick_rotation=0, x_major_locator=None, x_max_tick_to_value=None, x_format='normal', y_label_name='', y_label_fontsize=10, y_tick_fontsize=10, y_tick_rotation=0, y_major_locator=None, y_max_tick_to_value=None, y_format='normal', asterisk_fontsize=10, show_p_value=False)

绘制两个数据集之间的相关性图,支持线性回归、置信区间和统计方法(Spearman 或 Pearson)。

Parameters:

Name Type Description Default
data1 list[Num] | ndarray

第一个数据集,可以是整数或浮点数列表或数组。

required
data2 list[Num] | ndarray

第二个数据集,可以是整数或浮点数列表或数组。

required
ax Axes | None

matplotlib 的 Axes 对象,用于绘图。默认为 None,使用当前 Axes。

None
stats_method str

相关性统计方法,支持 "spearman" 和 "pearson"。默认为 "spearman"。

'spearman'
ci bool

是否绘制置信区间带。默认为 False。

False
dots_color str

散点的颜色。默认为 "steelblue"。

'steelblue'
dots_size int | float

散点的大小。默认为 1。

1
line_color str

回归线的颜色。默认为 "r"(红色)。

'r'
title_name str

图形标题。默认为空字符串。

''
title_fontsize int

标题字体大小。默认为 10。

10
title_pad int

标题与图形之间的间距。默认为 10。

10
x_label_name str

X 轴标签名称。默认为空字符串。

''
x_label_fontsize int

X 轴标签字体大小。默认为 10。

10
x_tick_fontsize int

X 轴刻度标签字体大小。默认为 10。

10
x_tick_rotation int

X 轴刻度标签旋转角度。默认为 0。

0
x_major_locator float | None

设置 X 轴主刻度间隔。默认为 None。

None
x_max_tick_to_value float | None

设置 X 轴最大显示刻度值。默认为 None。

None
x_format str

X 轴格式化方式,支持 "normal", "sci", "1f", "percent"。默认为 "normal"。

'normal'
y_label_name str

Y 轴标签名称。默认为空字符串。

''
y_label_fontsize int

Y 轴标签字体大小。默认为 10。

10
y_tick_fontsize int

Y 轴刻度标签字体大小。默认为 10。

10
y_tick_rotation int

Y 轴刻度标签旋转角度。默认为 0。

0
y_major_locator float | None

设置 Y 轴主刻度间隔。默认为 None。

None
y_max_tick_to_value float | None

设置 Y 轴最大显示刻度值。默认为 None。

None
y_format str

Y 轴格式化方式,支持 "normal", "sci", "1f", "percent"。默认为 "normal"。

'normal'
asterisk_fontsize int

显著性星号字体大小。默认为 10。

10
show_p_value bool

是否显示 p 值。默认为 True。

False

Returns:

Type Description
None

None

Source code in src/plotfig/correlation.py
def plot_correlation_figure(
    data1: list[Num] | np.ndarray,
    data2: list[Num] | np.ndarray,
    ax: plt.Axes | None = None,
    stats_method: str = "spearman",
    ci: bool = False,
    dots_color: str = "steelblue",
    dots_size: int | float = 1,
    line_color: str = "r",
    title_name: str = "",
    title_fontsize: int = 10,
    title_pad: int = 10,
    x_label_name: str = "",
    x_label_fontsize: int = 10,
    x_tick_fontsize: int = 10,
    x_tick_rotation: int = 0,
    x_major_locator: float | None = None,
    x_max_tick_to_value: float | None = None,
    x_format: str = "normal",  # 支持 "normal", "sci", "1f", "percent"
    y_label_name: str = "",
    y_label_fontsize: int = 10,
    y_tick_fontsize: int = 10,
    y_tick_rotation: int = 0,
    y_major_locator: float | None = None,
    y_max_tick_to_value: float | None = None,
    y_format: str = "normal",  # 支持 "normal", "sci", "1f", "percent"
    asterisk_fontsize: int = 10,
    show_p_value: bool = False,
) -> None:
    """
    绘制两个数据集之间的相关性图,支持线性回归、置信区间和统计方法(Spearman 或 Pearson)。

    Args:
        data1 (list[Num] | np.ndarray): 第一个数据集,可以是整数或浮点数列表或数组。
        data2 (list[Num] | np.ndarray): 第二个数据集,可以是整数或浮点数列表或数组。
        ax (plt.Axes | None, optional): matplotlib 的 Axes 对象,用于绘图。默认为 None,使用当前 Axes。
        stats_method (str, optional): 相关性统计方法,支持 "spearman" 和 "pearson"。默认为 "spearman"。
        ci (bool, optional): 是否绘制置信区间带。默认为 False。
        dots_color (str, optional): 散点的颜色。默认为 "steelblue"。
        dots_size (int | float, optional): 散点的大小。默认为 1。
        line_color (str, optional): 回归线的颜色。默认为 "r"(红色)。
        title_name (str, optional): 图形标题。默认为空字符串。
        title_fontsize (int, optional): 标题字体大小。默认为 10。
        title_pad (int, optional): 标题与图形之间的间距。默认为 10。
        x_label_name (str, optional): X 轴标签名称。默认为空字符串。
        x_label_fontsize (int, optional): X 轴标签字体大小。默认为 10。
        x_tick_fontsize (int, optional): X 轴刻度标签字体大小。默认为 10。
        x_tick_rotation (int, optional): X 轴刻度标签旋转角度。默认为 0。
        x_major_locator (float | None, optional): 设置 X 轴主刻度间隔。默认为 None。
        x_max_tick_to_value (float | None, optional): 设置 X 轴最大显示刻度值。默认为 None。
        x_format (str, optional): X 轴格式化方式,支持 "normal", "sci", "1f", "percent"。默认为 "normal"。
        y_label_name (str, optional): Y 轴标签名称。默认为空字符串。
        y_label_fontsize (int, optional): Y 轴标签字体大小。默认为 10。
        y_tick_fontsize (int, optional): Y 轴刻度标签字体大小。默认为 10。
        y_tick_rotation (int, optional): Y 轴刻度标签旋转角度。默认为 0。
        y_major_locator (float | None, optional): 设置 Y 轴主刻度间隔。默认为 None。
        y_max_tick_to_value (float | None, optional): 设置 Y 轴最大显示刻度值。默认为 None。
        y_format (str, optional): Y 轴格式化方式,支持 "normal", "sci", "1f", "percent"。默认为 "normal"。
        asterisk_fontsize (int, optional): 显著性星号字体大小。默认为 10。
        show_p_value (bool, optional): 是否显示 p 值。默认为 True。

    Returns:
        None
    """
    def set_axis(
        ax, axis, label, labelsize, ticksize, rotation, locator, max_tick_value, fmt
    ):
        if axis == "x":
            set_label = ax.set_xlabel
            get_ticks = ax.get_xticks
            set_ticks = ax.set_xticks
            axis_formatter = ax.xaxis.set_major_formatter
            axis_major_locator = ax.xaxis.set_major_locator
        else:
            set_label = ax.set_ylabel
            get_ticks = ax.get_yticks
            set_ticks = ax.set_yticks
            axis_formatter = ax.yaxis.set_major_formatter
            axis_major_locator = ax.yaxis.set_major_locator

        set_label(label, fontsize=labelsize)
        ax.tick_params(axis=axis, which="major", labelsize=ticksize, rotation=rotation)
        if locator is not None:
            axis_major_locator(MultipleLocator(locator))
        if max_tick_value is not None:
            set_ticks([i for i in get_ticks() if i <= max_tick_value])

        if fmt == "sci":
            formatter = ScalarFormatter(useMathText=True)
            formatter.set_powerlimits((-2, 2))
            axis_formatter(formatter)
        elif fmt == "1f":
            axis_formatter(FormatStrFormatter("%.1f"))
        elif fmt == "percent":
            axis_formatter(FuncFormatter(lambda x, pos: f"{x:.0%}"))

    if ax is None:
        ax = plt.gca()

    A = np.asarray(data1)
    B = np.asarray(data2)

    slope, intercept, r_value, p_value, _ = stats.linregress(A, B)
    x_seq = np.linspace(A.min(), A.max(), 100)
    y_pred = slope * x_seq + intercept

    ax.scatter(A, B, c=dots_color, s=dots_size, alpha=0.8)
    ax.plot(x_seq, y_pred, line_color, lw=2)

    if ci:
        n = len(A)
        dof = n - 2
        t_val = stats.t.ppf(0.975, dof)
        x_mean = A.mean()
        residuals = B - (slope * A + intercept)
        s_err = np.sqrt(np.sum(residuals**2) / dof)
        SSxx = np.sum((A - x_mean) ** 2)
        conf_interval = t_val * s_err * np.sqrt(1 / n + (x_seq - x_mean) ** 2 / SSxx)
        ax.fill_between(
            x_seq,
            y_pred - conf_interval,
            y_pred + conf_interval,
            color="salmon",
            alpha=0.3,
        )

    ax.spines[["top", "right"]].set_visible(False)
    ax.set_title(title_name, fontsize=title_fontsize, pad=title_pad)

    set_axis(
        ax,
        "x",
        x_label_name,
        x_label_fontsize,
        x_tick_fontsize,
        x_tick_rotation,
        x_major_locator,
        x_max_tick_to_value,
        x_format,
    )
    set_axis(
        ax,
        "y",
        y_label_name,
        y_label_fontsize,
        y_tick_fontsize,
        y_tick_rotation,
        y_major_locator,
        y_max_tick_to_value,
        y_format,
    )

    # 标注r值或rho值
    if stats_method == "spearman":
        s, p = stats.spearmanr(A, B)
        label = r"$\rho$"
    elif stats_method == "pearson":
        s, p = stats.pearsonr(A, B)
        label = "r"
    else:
        print(f"没有统计方法 {stats_method},请检查拼写。更换为默认的 spearman 方法。")
        s, p = stats.spearmanr(A, B)
        label = r"$\rho$"

    if show_p_value:
        asterisk = f" p={p:.4f}"
    else:
        asterisk = " ***" if p < 0.001 else " **" if p < 0.01 else " *" if p < 0.05 else ""
    x_start, x_end = ax.get_xlim()
    y_start, y_end = ax.get_ylim()
    ax.text(
        x_start + (x_end - x_start) * 0.1,
        y_start + (y_end - y_start) * 0.9,
        f"{label}={s:.3f}{asterisk}",
        va="center",
        fontsize=asterisk_fontsize,
    )
    return

plotfig.matrix

plot_matrix_figure

plot_matrix_figure(data, ax=None, row_labels_name=None, col_labels_name=None, cmap='bwr', vmin=None, vmax=None, aspect='equal', colorbar=True, colorbar_label_name='', colorbar_pad=0.1, colorbar_label_fontsize=10, colorbar_tick_fontsize=10, colorbar_tick_rotation=0, row_labels_fontsize=10, col_labels_fontsize=10, x_rotation=60, title_name='', title_fontsize=15, title_pad=20, diag_border=False, **imshow_kwargs)

Plot a matrix as a heatmap with optional labels, colorbar, and title.

Parameters:

Name Type Description Default
data ndarray

2D array of shape (N, M) to display as the matrix.

required
ax Axes | None

Matplotlib axes to plot on. If None, uses current axes.

None
row_labels_name Sequence[str] | None

List of labels for the rows.

None
col_labels_name Sequence[str] | None

List of labels for the columns.

None
cmap str

Colormap to use for the matrix.

'bwr'
vmin Num | None

Minimum value for color scaling. Defaults to data.min().

None
vmax Num | None

Maximum value for color scaling. Defaults to data.max().

None
aspect str

Aspect ratio of the plot. Usually "equal" or "auto".

'equal'
colorbar bool

Whether to show a colorbar.

True
colorbar_label_name str

Label for the colorbar.

''
colorbar_pad Num

Padding between the colorbar and the matrix.

0.1
colorbar_label_fontsize Num

Font size of the colorbar label.

10
colorbar_tick_fontsize Num

Font size of the colorbar ticks.

10
colorbar_tick_rotation Num

Rotation angle of the colorbar tick labels.

0
row_labels_fontsize Num

Font size for the row labels.

10
col_labels_fontsize Num

Font size for the column labels.

10
x_rotation Num

Rotation angle for the x-axis (column) labels.

60
title_name Num

Title of the plot.

''
title_fontsize Num

Font size of the title.

15
title_pad Num

Padding above the title.

20
diag_border bool

Whether to draw borders along the diagonal cells.

False
**imshow_kwargs Any

Additional keyword arguments for imshow().

{}

Returns:

Name Type Description
AxesImage AxesImage

The image object created by imshow().

Source code in src/plotfig/matrix.py
def plot_matrix_figure(
    data: np.ndarray,
    ax: Axes | None = None,
    row_labels_name: Sequence[str] | None = None,
    col_labels_name: Sequence[str] | None = None,
    cmap: str = "bwr",
    vmin: Num | None = None,
    vmax: Num | None = None,
    aspect: str = "equal",
    colorbar: bool = True,
    colorbar_label_name: str = "",
    colorbar_pad: Num = 0.1,
    colorbar_label_fontsize: Num = 10,
    colorbar_tick_fontsize: Num = 10,
    colorbar_tick_rotation: Num = 0,
    row_labels_fontsize: Num = 10,
    col_labels_fontsize: Num = 10,
    x_rotation: Num = 60,
    title_name: str = "",
    title_fontsize: Num = 15,
    title_pad: Num = 20,
    diag_border: bool = False,
    **imshow_kwargs: Any,
) -> AxesImage:
    """Plot a matrix as a heatmap with optional labels, colorbar, and title.

    Args:
        data (np.ndarray): 2D array of shape (N, M) to display as the matrix.
        ax (Axes | None): Matplotlib axes to plot on. If None, uses current axes.
        row_labels_name (Sequence[str] | None): List of labels for the rows.
        col_labels_name (Sequence[str] | None): List of labels for the columns.
        cmap (str): Colormap to use for the matrix.
        vmin (Num | None): Minimum value for color scaling. Defaults to data.min().
        vmax (Num | None): Maximum value for color scaling. Defaults to data.max().
        aspect (str): Aspect ratio of the plot. Usually "equal" or "auto".
        colorbar (bool): Whether to show a colorbar.
        colorbar_label_name (str): Label for the colorbar.
        colorbar_pad (Num): Padding between the colorbar and the matrix.
        colorbar_label_fontsize (Num): Font size of the colorbar label.
        colorbar_tick_fontsize (Num): Font size of the colorbar ticks.
        colorbar_tick_rotation (Num): Rotation angle of the colorbar tick labels.
        row_labels_fontsize (Num): Font size for the row labels.
        col_labels_fontsize (Num): Font size for the column labels.
        x_rotation (Num): Rotation angle for the x-axis (column) labels.
        title_name (Num): Title of the plot.
        title_fontsize (Num): Font size of the title.
        title_pad (Num): Padding above the title.
        diag_border (bool): Whether to draw borders along the diagonal cells.
        **imshow_kwargs (Any): Additional keyword arguments for `imshow()`.

    Returns:
        AxesImage: The image object created by `imshow()`.
    """
    ax = ax or plt.gca()
    vmin = vmin if vmin is not None else np.min(data)
    vmax = vmax if vmax is not None else np.max(data)

    im = ax.imshow(
        data, cmap=cmap, vmin=vmin, vmax=vmax, aspect=aspect, **imshow_kwargs
    )
    ax.set_title(title_name, fontsize=title_fontsize, pad=title_pad)
    if diag_border:
        for i in range(data.shape[0]):
            ax.add_patch(
                plt.Rectangle(
                    (i - 0.5, i - 0.5), 1, 1, fill=False, edgecolor="black", lw=0.5
                )
            )

    if col_labels_name is not None:
        ax.set_xticks(np.arange(data.shape[1]))
        ax.set_xticklabels(
            col_labels_name,
            fontsize=col_labels_fontsize,
            rotation=x_rotation,
            ha="right",
            rotation_mode="anchor",
        )

    if row_labels_name is not None:
        ax.set_yticks(np.arange(data.shape[0]))
        ax.set_yticklabels(row_labels_name, fontsize=row_labels_fontsize)

    if colorbar:
        divider = make_axes_locatable(ax)
        cax = divider.append_axes("right", size="5%", pad=colorbar_pad)
        cbar = ax.figure.colorbar(im, cax=cax)
        cbar.ax.set_ylabel(
            colorbar_label_name,
            rotation=-90,
            va="bottom",
            fontsize=colorbar_label_fontsize,
        )
        cbar.ax.tick_params(
            labelsize=colorbar_tick_fontsize, rotation=colorbar_tick_rotation
        )
        # Match colorbar height to the main plot
        ax_pos = ax.get_position()
        cax.set_position(
            [cax.get_position().x0, ax_pos.y0, cax.get_position().width, ax_pos.height]
        )

    return im

plotfig.circos

plot_asymmetric_circle_figure

plot_asymmetric_circle_figure(connectome, labels=None, node_colors=None, vmin=None, vmax=None, figsize=(10, 10), labels_fontsize=15, face_color='w', nodeedge_color='w', text_color='k', cmap='bwr', linewidth=1, title_name='', title_fontsize=20, colorbar=False, colorbar_size=0.2, colorbar_fontsize=10, colorbar_pos=(0, 0), manual_colorbar=False, manual_colorbar_pos=(1, 0.4, 0.01, 0.2), manual_cmap='bwr', manual_colorbar_name='', manual_colorbar_label_fontsize=10, manual_colorbar_fontsize=10, manual_colorbar_rotation=-90, manual_colorbar_pad=20, manual_colorbar_draw_border=True, manual_colorbar_tickline=False, manual_colorbar_nticks=False)

绘制类circos连接图

Parameters:

Name Type Description Default
connectome NDArray

连接矩阵.

required
labels list[str] | None

节点名称. Defaults to None.

None
node_colors list[str] | None

节点颜色. Defaults to None.

None
vmin Num | None

最小值. Defaults to None.

None
vmax Num | None

最大值. Defaults to None.

None
figsize Tuple[Num, Num]

图大小. Defaults to (10, 10).

(10, 10)
labels_fontsize Num

节点名字大小. Defaults to 15.

15
face_color str

图背景颜色. Defaults to "w".

'w'
nodeedge_color str

节点轮廓颜色. Defaults to "w".

'w'
text_color str

文本颜色. Defaults to "k".

'k'
cmap str

colorbar颜色. Defaults to "bwr".

'bwr'
linewidth Num

连接线宽度. Defaults to 1.

1
title_name str

图标题名称. Defaults to "".

''
title_fontsize Num

图标题字体大小. Defaults to 20.

20
colorbar bool

是否绘制colorbar. Defaults to False.

False
colorbar_size Num

colorbar大小. Defaults to 0.2.

0.2
colorbar_fontsize Num

colorbar字体大小. Defaults to 10.

10
colorbar_pos Tuple[Num, Num]

colorbar位置. Defaults to (0, 0).

(0, 0)
manual_colorbar bool

高级colorbar. Defaults to False.

False
manual_colorbar_pos Tuple[Num, Num, Num, Num]

高级colorbar位置. Defaults to (1, 0.4, 0.01, 0.2).

(1, 0.4, 0.01, 0.2)
manual_cmap str

高级colorbar cmap. Defaults to "bwr".

'bwr'
manual_colorbar_name str

高级colorbar名字. Defaults to "".

''
manual_colorbar_label_fontsize Num

高级colorbar label字体大小. Defaults to 10.

10
manual_colorbar_fontsize Num

高级colorbar字体大小. Defaults to 10.

10
manual_colorbar_rotation Num

高级colorbar旋转. Defaults to -90.

-90
manual_colorbar_pad Num

高级colorbar标题间隔距离. Defaults to 20.

20
manual_colorbar_draw_border bool

高级colorbar轮廓. Defaults to True.

True
manual_colorbar_tickline bool

高级colorbar tick线. Defaults to False.

False
manual_colorbar_nticks bool

高级colorbar tick数量. Defaults to False.

False

Returns:

Type Description
Figure

plt.Figure: description

Source code in src/plotfig/circos.py
def plot_asymmetric_circle_figure(
    connectome: npt.NDArray,
    labels: list[str] | None = None,
    node_colors: list[str] | None = None,
    vmin: Num | None = None,
    vmax: Num | None = None,
    figsize: Tuple[Num, Num] = (10, 10),
    labels_fontsize: Num = 15,
    face_color: str = "w",
    nodeedge_color: str = "w",
    text_color: str = "k",
    cmap: str = "bwr",
    linewidth: Num = 1,
    title_name: str = "",
    title_fontsize: Num = 20,
    colorbar: bool = False,
    colorbar_size: Num = 0.2,
    colorbar_fontsize: Num = 10,
    colorbar_pos: Tuple[Num, Num] = (0, 0),
    manual_colorbar: bool = False,
    manual_colorbar_pos: Tuple[Num, Num, Num, Num] = (1, 0.4, 0.01, 0.2),
    manual_cmap: str = "bwr",
    manual_colorbar_name: str = "",
    manual_colorbar_label_fontsize: Num = 10,
    manual_colorbar_fontsize: Num = 10,
    manual_colorbar_rotation: Num = -90,
    manual_colorbar_pad: Num = 20,
    manual_colorbar_draw_border: bool = True,
    manual_colorbar_tickline: bool = False,
    manual_colorbar_nticks: bool = False,
) -> plt.Figure:
    """绘制类circos连接图

    Args:
        connectome (npt.NDArray): 连接矩阵.
        labels (list[str] | None, optional): 节点名称. Defaults to None.
        node_colors (list[str] | None, optional): 节点颜色. Defaults to None.
        vmin (Num | None, optional): 最小值. Defaults to None.
        vmax (Num | None, optional): 最大值. Defaults to None.
        figsize (Tuple[Num, Num], optional): 图大小. Defaults to (10, 10).
        labels_fontsize (Num, optional): 节点名字大小. Defaults to 15.
        face_color (str, optional): 图背景颜色. Defaults to "w".
        nodeedge_color (str, optional): 节点轮廓颜色. Defaults to "w".
        text_color (str, optional): 文本颜色. Defaults to "k".
        cmap (str, optional): colorbar颜色. Defaults to "bwr".
        linewidth (Num, optional): 连接线宽度. Defaults to 1.
        title_name (str, optional): 图标题名称. Defaults to "".
        title_fontsize (Num, optional): 图标题字体大小. Defaults to 20.
        colorbar (bool, optional): 是否绘制colorbar. Defaults to False.
        colorbar_size (Num, optional): colorbar大小. Defaults to 0.2.
        colorbar_fontsize (Num, optional): colorbar字体大小. Defaults to 10.
        colorbar_pos (Tuple[Num, Num], optional): colorbar位置. Defaults to (0, 0).
        manual_colorbar (bool, optional): 高级colorbar. Defaults to False.
        manual_colorbar_pos (Tuple[Num, Num, Num, Num], optional): 高级colorbar位置. Defaults to (1, 0.4, 0.01, 0.2).
        manual_cmap (str, optional): 高级colorbar cmap. Defaults to "bwr".
        manual_colorbar_name (str, optional): 高级colorbar名字. Defaults to "".
        manual_colorbar_label_fontsize (Num, optional): 高级colorbar label字体大小. Defaults to 10.
        manual_colorbar_fontsize (Num, optional): 高级colorbar字体大小. Defaults to 10.
        manual_colorbar_rotation (Num, optional): 高级colorbar旋转. Defaults to -90.
        manual_colorbar_pad (Num, optional): 高级colorbar标题间隔距离. Defaults to 20.
        manual_colorbar_draw_border (bool, optional): 高级colorbar轮廓. Defaults to True.
        manual_colorbar_tickline (bool, optional): 高级colorbar tick线. Defaults to False.
        manual_colorbar_nticks (bool, optional): 高级colorbar tick数量. Defaults to False.

    Returns:
        plt.Figure: _description_
    """
    # 设置默认值
    if vmax is None:
        vmax = np.max((np.max(connectome), -np.min(connectome)))
    if vmin is None:
        vmin = np.min((np.min(connectome), -np.max(connectome)))
    count = connectome.shape[0]
    if labels is None:
        labels = [str(i) for i in range(count)]
    if node_colors is None:
        node_colors = ["#ff8f8f"] * count
    node_angles = mne.viz.circular_layout(labels, labels)
    # 画图
    fig, ax = plt.subplots(figsize=figsize, subplot_kw={"polar": True})
    fig.subplots_adjust(left=0.1, right=0.9, top=0.9, bottom=0.1)
    plot_connectivity_circle(
        connectome,
        labels,
        node_angles=node_angles,
        node_colors=node_colors,
        fontsize_names=labels_fontsize,
        facecolor=face_color,
        node_edgecolor=nodeedge_color,
        textcolor=text_color,
        colormap=cmap,
        vmin=vmin,
        vmax=vmax,
        linewidth=linewidth,
        title=title_name,
        fontsize_title=title_fontsize,
        colorbar=colorbar,
        colorbar_size=colorbar_size,
        colorbar_pos=colorbar_pos,
        fontsize_colorbar=colorbar_fontsize,
        fig=fig,
        ax=ax,
        interactive=False,
        show=False,
    )
    # 如有需要,禁用自动colorbar,手动生成colorbar
    if manual_colorbar:
        # 手动创建colorbar,拥有更多的设置
        cax = fig.add_axes(manual_colorbar_pos)
        norm = plt.Normalize(vmin=vmin, vmax=vmax)
        sm = plt.cm.ScalarMappable(cmap=manual_cmap, norm=norm)
        sm.set_array([])
        cbar = fig.colorbar(sm, cax=cax)
        cbar.outline.set_visible(manual_colorbar_draw_border)
        cbar.ax.set_ylabel(
            manual_colorbar_name,
            fontsize=manual_colorbar_label_fontsize,
            rotation=manual_colorbar_rotation,
            labelpad=manual_colorbar_pad,
        )
        if not manual_colorbar_tickline:
            cbar.ax.tick_params(length=0)  # 不显示竖线
        cbar.ax.yaxis.set_ticks_position("left")
        cbar.ax.tick_params(labelsize=manual_colorbar_fontsize)
        if manual_colorbar_nticks:
            ticks = np.linspace(vmin, vmax, manual_colorbar_nticks)
            cbar.set_ticks(ticks)
    return fig

plot_symmetric_circle_figure

plot_symmetric_circle_figure(connectome, labels=None, node_colors=None, vmin=None, vmax=None, figsize=(10, 10), labels_fontsize=15, face_color='w', nodeedge_color='w', text_color='k', cmap='bwr', linewidth=1, title_name='', title_fontsize=20, colorbar=False, colorbar_size=0.2, colorbar_fontsize=10, colorbar_pos=(0, 0), manual_colorbar=False, manual_colorbar_pos=(1, 0.4, 0.01, 0.2), manual_cmap='bwr', manual_colorbar_name='', manual_colorbar_label_fontsize=10, manual_colorbar_fontsize=10, manual_colorbar_rotation=-90, manual_colorbar_pad=20, manual_colorbar_draw_border=True, manual_colorbar_tickline=False, manual_colorbar_nticks=False)

绘制类circos连接图

Parameters:

Name Type Description Default
connectome NDArray

连接矩阵.

required
labels list[str] | None

节点名称. Defaults to None.

None
node_colors list[str] | None

节点颜色. Defaults to None.

None
vmin Num | None

最小值. Defaults to None.

None
vmax Num | None

最大值. Defaults to None.

None
figsize Tuple[Num, Num]

图大小. Defaults to (10, 10).

(10, 10)
labels_fontsize Num

节点名字大小. Defaults to 15.

15
face_color str

图背景颜色. Defaults to "w".

'w'
nodeedge_color str

节点轮廓颜色. Defaults to "w".

'w'
text_color str

文本颜色. Defaults to "k".

'k'
cmap str

colorbar颜色. Defaults to "bwr".

'bwr'
linewidth Num

连接线宽度. Defaults to 1.

1
title_name str

图标题名称. Defaults to "".

''
title_fontsize Num

图标题字体大小. Defaults to 20.

20
colorbar bool

是否绘制colorbar. Defaults to False.

False
colorbar_size Num

colorbar大小. Defaults to 0.2.

0.2
colorbar_fontsize Num

colorbar字体大小. Defaults to 10.

10
colorbar_pos Tuple[Num, Num]

colorbar位置. Defaults to (0, 0).

(0, 0)
manual_colorbar bool

高级colorbar. Defaults to False.

False
manual_colorbar_pos Tuple[Num, Num, Num, Num]

高级colorbar位置. Defaults to (1, 0.4, 0.01, 0.2).

(1, 0.4, 0.01, 0.2)
manual_cmap str

高级colorbar cmap. Defaults to "bwr".

'bwr'
manual_colorbar_name str

高级colorbar名字. Defaults to "".

''
manual_colorbar_label_fontsize Num

高级colorbar label字体大小. Defaults to 10.

10
manual_colorbar_fontsize Num

高级colorbar字体大小. Defaults to 10.

10
manual_colorbar_rotation Num

高级colorbar旋转. Defaults to -90.

-90
manual_colorbar_pad Num

高级colorbar标题间隔距离. Defaults to 20.

20
manual_colorbar_draw_border bool

高级colorbar轮廓. Defaults to True.

True
manual_colorbar_tickline bool

高级colorbar tick线. Defaults to False.

False
manual_colorbar_nticks bool

高级colorbar tick数量. Defaults to False.

False

Returns:

Type Description
Figure

plt.Figure: description

Source code in src/plotfig/circos.py
def plot_symmetric_circle_figure(
    connectome: npt.NDArray,
    labels: list[str] | None = None,
    node_colors: list[str] | None = None,
    vmin: Num | None = None,
    vmax: Num | None = None,
    figsize: Tuple[Num, Num] = (10, 10),
    labels_fontsize: Num = 15,
    face_color: str = "w",
    nodeedge_color: str = "w",
    text_color: str = "k",
    cmap: str = "bwr",
    linewidth: Num = 1,
    title_name: str = "",
    title_fontsize: Num = 20,
    colorbar: bool = False,
    colorbar_size: Num = 0.2,
    colorbar_fontsize: Num = 10,
    colorbar_pos: Tuple[Num, Num] = (0, 0),
    manual_colorbar: bool = False,
    manual_colorbar_pos: Tuple[Num, Num, Num, Num] = (1, 0.4, 0.01, 0.2),
    manual_cmap: str = "bwr",
    manual_colorbar_name: str = "",
    manual_colorbar_label_fontsize: Num = 10,
    manual_colorbar_fontsize: Num = 10,
    manual_colorbar_rotation: Num = -90,
    manual_colorbar_pad: Num = 20,
    manual_colorbar_draw_border: bool = True,
    manual_colorbar_tickline: bool = False,
    manual_colorbar_nticks: bool = False,
) -> plt.Figure:
    """绘制类circos连接图

    Args:
        connectome (npt.NDArray): 连接矩阵.
        labels (list[str] | None, optional): 节点名称. Defaults to None.
        node_colors (list[str] | None, optional): 节点颜色. Defaults to None.
        vmin (Num | None, optional): 最小值. Defaults to None.
        vmax (Num | None, optional): 最大值. Defaults to None.
        figsize (Tuple[Num, Num], optional): 图大小. Defaults to (10, 10).
        labels_fontsize (Num, optional): 节点名字大小. Defaults to 15.
        face_color (str, optional): 图背景颜色. Defaults to "w".
        nodeedge_color (str, optional): 节点轮廓颜色. Defaults to "w".
        text_color (str, optional): 文本颜色. Defaults to "k".
        cmap (str, optional): colorbar颜色. Defaults to "bwr".
        linewidth (Num, optional): 连接线宽度. Defaults to 1.
        title_name (str, optional): 图标题名称. Defaults to "".
        title_fontsize (Num, optional): 图标题字体大小. Defaults to 20.
        colorbar (bool, optional): 是否绘制colorbar. Defaults to False.
        colorbar_size (Num, optional): colorbar大小. Defaults to 0.2.
        colorbar_fontsize (Num, optional): colorbar字体大小. Defaults to 10.
        colorbar_pos (Tuple[Num, Num], optional): colorbar位置. Defaults to (0, 0).
        manual_colorbar (bool, optional): 高级colorbar. Defaults to False.
        manual_colorbar_pos (Tuple[Num, Num, Num, Num], optional): 高级colorbar位置. Defaults to (1, 0.4, 0.01, 0.2).
        manual_cmap (str, optional): 高级colorbar cmap. Defaults to "bwr".
        manual_colorbar_name (str, optional): 高级colorbar名字. Defaults to "".
        manual_colorbar_label_fontsize (Num, optional): 高级colorbar label字体大小. Defaults to 10.
        manual_colorbar_fontsize (Num, optional): 高级colorbar字体大小. Defaults to 10.
        manual_colorbar_rotation (Num, optional): 高级colorbar旋转. Defaults to -90.
        manual_colorbar_pad (Num, optional): 高级colorbar标题间隔距离. Defaults to 20.
        manual_colorbar_draw_border (bool, optional): 高级colorbar轮廓. Defaults to True.
        manual_colorbar_tickline (bool, optional): 高级colorbar tick线. Defaults to False.
        manual_colorbar_nticks (bool, optional): 高级colorbar tick数量. Defaults to False.

    Returns:
        plt.Figure: _description_
    """
    # 设置默认值
    if vmax is None:
        vmax = np.max((np.max(connectome), -np.min(connectome)))
    if vmin is None:
        vmin = np.min((np.min(connectome), -np.max(connectome)))
    count = connectome.shape[0]
    count_half = int(count / 2)
    if labels is None:
        labels = [str(i) for i in range(count_half)]
    if node_colors is None:
        node_colors = ["#ff8f8f"] * count_half
    labels = labels + [i + " " for i in labels[::-1]]
    node_colors = node_colors + list(node_colors[::-1])
    node_angles = mne.viz.circular_layout(
        labels, labels, group_boundaries=[0, len(labels) / 2]
    )
    # 常规矩阵需要做对称转换
    data_upper_left = connectome[0:count_half, 0:count_half]
    data_down_right = connectome[count_half:count, count_half:count]
    data_down_left = connectome[count_half:count, 0:count_half]
    data_upper_right = connectome[0:count_half, count_half:count]
    data_down_right = data_down_right[::-1][:, ::-1]
    data_down_left = data_down_left[::-1]
    data_upper_right = data_upper_right[:, ::-1]
    connectome_upper = np.concatenate((data_upper_left, data_upper_right), axis=1)
    connectome_lower = np.concatenate((data_down_left, data_down_right), axis=1)
    connectome = np.concatenate((connectome_upper, connectome_lower), axis=0)
    # 画图
    fig, ax = plt.subplots(figsize=figsize, subplot_kw={"polar": True})
    fig.subplots_adjust(left=0.1, right=0.9, top=0.9, bottom=0.1)
    plot_connectivity_circle(
        connectome,
        labels,
        node_angles=node_angles,
        node_colors=node_colors,
        fontsize_names=labels_fontsize,
        facecolor=face_color,
        node_edgecolor=nodeedge_color,
        textcolor=text_color,
        colormap=cmap,
        vmin=vmin,
        vmax=vmax,
        linewidth=linewidth,
        title=title_name,
        fontsize_title=title_fontsize,
        colorbar=colorbar,
        colorbar_size=colorbar_size,
        colorbar_pos=colorbar_pos,
        fontsize_colorbar=colorbar_fontsize,
        fig=fig,
        ax=ax,
        interactive=False,
        show=False,
    )
    # 如有需要,禁用自动colorbar,手动生成colorbar
    if manual_colorbar:
        # 手动创建colorbar,拥有更多的设置
        cax = fig.add_axes(manual_colorbar_pos)
        norm = plt.Normalize(vmin=vmin, vmax=vmax)
        sm = plt.cm.ScalarMappable(cmap=manual_cmap, norm=norm)
        sm.set_array([])
        cbar = fig.colorbar(sm, cax=cax)
        cbar.outline.set_visible(manual_colorbar_draw_border)
        cbar.ax.set_ylabel(
            manual_colorbar_name,
            fontsize=manual_colorbar_label_fontsize,
            rotation=manual_colorbar_rotation,
            labelpad=manual_colorbar_pad,
        )
        if not manual_colorbar_tickline:
            cbar.ax.tick_params(length=0)  # 不显示竖线
        cbar.ax.yaxis.set_ticks_position("left")
        cbar.ax.tick_params(labelsize=manual_colorbar_fontsize)
        if manual_colorbar_nticks:
            ticks = np.linspace(vmin, vmax, manual_colorbar_nticks)
            cbar.set_ticks(ticks)
    return fig

plotfig.brain_surface

plot_chimpanzee_brain_figure

plot_chimpanzee_brain_figure(data, surf='veryinflated', atlas='bna', vmin=None, vmax=None, plot=True, cmap='Reds', colorbar=True, colorbar_location='right', colorbar_label_name='', colorbar_label_rotation=0, colorbar_decimals=1, colorbar_fontsize=8, colorbar_nticks=2, colorbar_shrink=0.15, colorbar_aspect=8, colorbar_draw_border=False, title_name='', title_fontsize=15, title_y=0.9, rjx_colorbar=False, rjx_colorbar_direction='vertical', horizontal_center=True, rjx_colorbar_outline=False, rjx_colorbar_label_name='', rjx_colorbar_tick_fontsize=10, rjx_colorbar_label_fontsize=10, rjx_colorbar_tick_rotation=0, rjx_colorbar_tick_length=0, rjx_colorbar_nticks=2)

绘制黑猩猩大脑表面图,支持 BNA 图谱。

Parameters:

Name Type Description Default
data dict[str, float]

包含 ROI 名称及其对应值的字典。

required
surf str

大脑表面类型(如 "veryinflated", "midthickness")。默认为 "veryinflated"。

'veryinflated'
atlas str

使用的图谱名称,目前仅支持 "bna"。默认为 "bna"。

'bna'
vmin Num

颜色映射的最小值。可以是整数或浮点数。默认为 None。

None
vmax Num

颜色映射的最大值。可以是整数或浮点数。默认为 None。

None
plot bool

是否直接绘制图形。默认为 True。

True
cmap str

颜色映射方案。默认为 "Reds"。

'Reds'
colorbar bool

是否显示颜色条。默认为 True。

True
colorbar_location str

颜色条的位置。默认为 "right"。

'right'
colorbar_label_name str

颜色条的标签名称。默认为空字符串。

''
colorbar_label_rotation int

颜色条标签的旋转角度。默认为 0。

0
colorbar_decimals int

颜色条刻度的小数位数。默认为 1。

1
colorbar_fontsize int

颜色条标签的字体大小。默认为 8。

8
colorbar_nticks int

颜色条上的刻度数量。默认为 2。

2
colorbar_shrink float

颜色条的缩放比例。默认为 0.15。

0.15
colorbar_aspect int

颜色条的宽高比。默认为 8。

8
colorbar_draw_border bool

是否绘制颜色条边框。默认为 False。

False
title_name str

图形标题。默认为空字符串。

''
title_fontsize int

标题字体大小。默认为 15。

15
title_y float

标题在 y 轴上的位置(范围通常为 0~1)。默认为 0.9。

0.9
rjx_colorbar bool

是否使用自定义颜色条。默认为 False。

False
rjx_colorbar_direction str

自定义颜色条方向,支持 "vertical" 或 "horizontal"。默认为 "vertical"。

'vertical'
horizontal_center bool

水平颜色条是否居中。默认为 True。

True
rjx_colorbar_outline bool

自定义颜色条是否显示边框。默认为 False。

False
rjx_colorbar_label_name str

自定义颜色条标签名称。默认为空字符串。

''
rjx_colorbar_tick_fontsize int

自定义颜色条刻度字体大小。默认为 10。

10
rjx_colorbar_label_fontsize int

自定义颜色条标签字体大小。默认为 10。

10
rjx_colorbar_tick_rotation int

自定义颜色条刻度标签旋转角度。默认为 0。

0
rjx_colorbar_tick_length int

自定义颜色条刻度长度。默认为 0。

0
rjx_colorbar_nticks int

自定义颜色条上的刻度数量。默认为 2。

2

Returns:

Type Description
Figure | tuple[ndarray, ndarray]

Union[plt.Figure, tuple[np.ndarray, np.ndarray]]: 如果 plot=True,返回 matplotlib 的 Figure 对象;

Figure | tuple[ndarray, ndarray]

否则返回左右脑数据数组的元组 (lh_parc, rh_parc)

Source code in src/plotfig/brain_surface.py
def plot_chimpanzee_brain_figure(
    data: dict[str, float],
    surf: str = "veryinflated",
    atlas: str = "bna",
    vmin: Num | None = None,
    vmax: Num | None = None,
    plot: bool = True,
    cmap: str = "Reds",
    colorbar: bool = True,
    colorbar_location: str = "right",
    colorbar_label_name: str = "",
    colorbar_label_rotation: int = 0,
    colorbar_decimals: int = 1,
    colorbar_fontsize: int = 8,
    colorbar_nticks: int = 2,
    colorbar_shrink: float = 0.15,
    colorbar_aspect: int = 8,
    colorbar_draw_border: bool = False,
    title_name: str = "",
    title_fontsize: int = 15,
    title_y: float = 0.9,
    rjx_colorbar: bool = False,
    rjx_colorbar_direction: str = "vertical",
    horizontal_center: bool = True,
    rjx_colorbar_outline: bool = False,
    rjx_colorbar_label_name: str = "",
    rjx_colorbar_tick_fontsize: int = 10,
    rjx_colorbar_label_fontsize: int = 10,
    rjx_colorbar_tick_rotation: int = 0,
    rjx_colorbar_tick_length: int = 0,
    rjx_colorbar_nticks: int = 2,
) -> plt.Figure | tuple[np.ndarray, np.ndarray]:
    """
    绘制黑猩猩大脑表面图,支持 BNA 图谱。

    Args:
        data (dict[str, float]): 包含 ROI 名称及其对应值的字典。
        surf (str, optional): 大脑表面类型(如 "veryinflated", "midthickness")。默认为 "veryinflated"。
        atlas (str, optional): 使用的图谱名称,目前仅支持 "bna"。默认为 "bna"。
        vmin (Num, optional): 颜色映射的最小值。可以是整数或浮点数。默认为 None。
        vmax (Num, optional): 颜色映射的最大值。可以是整数或浮点数。默认为 None。
        plot (bool, optional): 是否直接绘制图形。默认为 True。
        cmap (str, optional): 颜色映射方案。默认为 "Reds"。
        colorbar (bool, optional): 是否显示颜色条。默认为 True。
        colorbar_location (str, optional): 颜色条的位置。默认为 "right"。
        colorbar_label_name (str, optional): 颜色条的标签名称。默认为空字符串。
        colorbar_label_rotation (int, optional): 颜色条标签的旋转角度。默认为 0。
        colorbar_decimals (int, optional): 颜色条刻度的小数位数。默认为 1。
        colorbar_fontsize (int, optional): 颜色条标签的字体大小。默认为 8。
        colorbar_nticks (int, optional): 颜色条上的刻度数量。默认为 2。
        colorbar_shrink (float, optional): 颜色条的缩放比例。默认为 0.15。
        colorbar_aspect (int, optional): 颜色条的宽高比。默认为 8。
        colorbar_draw_border (bool, optional): 是否绘制颜色条边框。默认为 False。
        title_name (str, optional): 图形标题。默认为空字符串。
        title_fontsize (int, optional): 标题字体大小。默认为 15。
        title_y (float, optional): 标题在 y 轴上的位置(范围通常为 0~1)。默认为 0.9。
        rjx_colorbar (bool, optional): 是否使用自定义颜色条。默认为 False。
        rjx_colorbar_direction (str, optional): 自定义颜色条方向,支持 "vertical" 或 "horizontal"。默认为 "vertical"。
        horizontal_center (bool, optional): 水平颜色条是否居中。默认为 True。
        rjx_colorbar_outline (bool, optional): 自定义颜色条是否显示边框。默认为 False。
        rjx_colorbar_label_name (str, optional): 自定义颜色条标签名称。默认为空字符串。
        rjx_colorbar_tick_fontsize (int, optional): 自定义颜色条刻度字体大小。默认为 10。
        rjx_colorbar_label_fontsize (int, optional): 自定义颜色条标签字体大小。默认为 10。
        rjx_colorbar_tick_rotation (int, optional): 自定义颜色条刻度标签旋转角度。默认为 0。
        rjx_colorbar_tick_length (int, optional): 自定义颜色条刻度长度。默认为 0。
        rjx_colorbar_nticks (int, optional): 自定义颜色条上的刻度数量。默认为 2。

    Returns:
        Union[plt.Figure, tuple[np.ndarray, np.ndarray]]: 如果 `plot=True`,返回 matplotlib 的 Figure 对象;
        否则返回左右脑数据数组的元组 `(lh_parc, rh_parc)`。
    """

    # 设置必要文件路径
    current_dir = op.dirname(__file__)
    neuromaps_data_dir = op.join(current_dir, "data/neurodata")
    if atlas == "bna":
        lh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/chimpanzee_BNA/ChimpBNA.L.32k_fs_LR.label.gii",
        )
        rh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/chimpanzee_BNA/ChimpBNA.R.32k_fs_LR.label.gii",
        )
        df = pd.read_csv(
            op.join(current_dir, "data/atlas_tables", "chimpanzee_bna.csv")
        )
    # 获取文件Underlay
    lh = op.join(
        neuromaps_data_dir,
        f"surfaces/chimpanzee_BNA/ChimpYerkes29_v1.2.L.{surf}.32k_fs_LR.surf.gii",
    )
    rh = op.join(
        neuromaps_data_dir,
        f"surfaces/chimpanzee_BNA/ChimpYerkes29_v1.2.R.{surf}.32k_fs_LR.surf.gii",
    )
    p = Plot(lh, rh)
    # 将原始数据拆分成左右脑数据
    lh_data, rh_data = {}, {}
    for roi in data:
        if "lh_" in roi:
            lh_data[roi] = data[roi]
        elif "rh_" in roi:
            rh_data[roi] = data[roi]
    # 加载图集分区数据
    lh_roi_list, rh_roi_list = (
        list(df["ROIs_name"])[0 : int(len(df["ROIs_name"]) / 2)],
        list(df["ROIs_name"])[int(len(df["ROIs_name"]) / 2) : len(df["ROIs_name"])],
    )
    # 处理左脑数据
    lh_parc = nib.load(lh_atlas_dir).darrays[0].data
    roi_vertics = {roi: [] for roi in lh_roi_list}
    for vertex_index, label in enumerate(lh_parc):
        if label - 1 >= 0:
            roi_vertics[lh_roi_list[label - 1]].append(vertex_index)
    lh_parc = np.full(lh_parc.shape, np.nan)
    for roi in lh_data:
        lh_parc[roi_vertics[roi]] = lh_data[roi]
    # 处理右脑数据
    rh_parc = nib.load(rh_atlas_dir).darrays[0].data
    roi_vertics = {roi: [] for roi in rh_roi_list}
    for vertex_index, label in enumerate(rh_parc):
        if label - 1 - len(lh_roi_list) >= 0:
            roi_vertics[rh_roi_list[label - 1 - len(lh_roi_list)]].append(vertex_index)
    rh_parc = np.full(rh_parc.shape, np.nan)
    for roi in rh_data:
        rh_parc[roi_vertics[roi]] = rh_data[roi]
    # 画图
    if plot:
        # 画图元素参数设置
        if vmin is None:
            vmin = min(data.values())
        if vmax is None:
            vmax = max(data.values())
        if vmin > vmax:
            print("vmin必须小于等于vmax")
            return
        if vmin == vmax:
            vmin = min(0, vmin)
            vmax = max(0, vmax)
        # colorbar参数设置
        colorbar_kws = {
            "location": colorbar_location,
            "label_direction": colorbar_label_rotation,
            "decimals": colorbar_decimals,
            "fontsize": colorbar_fontsize,
            "n_ticks": colorbar_nticks,
            "shrink": colorbar_shrink,
            "aspect": colorbar_aspect,
            "draw_border": colorbar_draw_border,
        }
        p.add_layer(
            {"left": lh_parc, "right": rh_parc},
            cbar=colorbar,
            cmap=cmap,
            color_range=(vmin, vmax),
            cbar_label=colorbar_label_name,
            zero_transparent=False,
        )
        fig = p.build(cbar_kws=colorbar_kws)
        fig.suptitle(title_name, fontsize=title_fontsize, y=title_y)
        ############################################### rjx_colorbar ###############################################
        sm = ScalarMappable(cmap=cmap)
        sm.set_array((vmin, vmax))  # 设置值范围
        if rjx_colorbar:
            formatter = ScalarFormatter(useMathText=True)  # 科学计数法相关
            formatter.set_powerlimits(
                (-3, 3)
            )  # <=-1也就是小于等于0.1,>=2,也就是大于等于100,会写成科学计数法
            if rjx_colorbar_direction == "vertical":
                cax = fig.add_axes(
                    [1, 0.425, 0.01, 0.15]
                )  # [left, bottom, width, height]
                cbar = fig.colorbar(
                    sm, cax=cax, orientation="vertical", cmap=cmap
                )  # "vertical", "horizontal"
                cbar.outline.set_visible(rjx_colorbar_outline)
                cbar.ax.set_ylabel(
                    rjx_colorbar_label_name, fontsize=rjx_colorbar_label_fontsize
                )
                cbar.ax.yaxis.set_label_position(
                    "left"
                )  # 原本设置y轴label默认在右边,现在换到左边
                cbar.ax.tick_params(
                    axis="y",
                    which="major",
                    labelsize=rjx_colorbar_tick_fontsize,
                    rotation=rjx_colorbar_tick_rotation,
                    length=rjx_colorbar_tick_length,
                )
                cbar.set_ticks(np.linspace(vmin, vmax, rjx_colorbar_nticks))
                if vmax < 0.001 or vmax > 1000:  # y轴设置科学计数法
                    cbar.ax.yaxis.set_major_formatter(formatter)
                    cbar.ax.yaxis.get_offset_text().set_visible(
                        False
                    )  # 隐藏默认的偏移文本
                    exponent = math.floor(math.log10(vmax))
                    # 手动添加文本
                    cbar.ax.text(
                        1.05,
                        1.15,
                        rf"$\times 10^{{{exponent}}}$",
                        transform=cbar.ax.transAxes,
                        fontsize=rjx_colorbar_tick_fontsize,
                        verticalalignment="bottom",
                        horizontalalignment="left",
                    )
            elif rjx_colorbar_direction == "horizontal":
                if horizontal_center:
                    cax = fig.add_axes([0.44, 0.5, 0.15, 0.01])
                else:
                    cax = fig.add_axes([0.44, 0.05, 0.15, 0.01])
                cbar = fig.colorbar(sm, cax=cax, orientation="horizontal", cmap=cmap)
                cbar.outline.set_visible(rjx_colorbar_outline)
                cbar.ax.set_title(
                    rjx_colorbar_label_name, fontsize=rjx_colorbar_label_fontsize
                )
                cbar.ax.tick_params(
                    axis="x",
                    which="major",
                    labelsize=rjx_colorbar_tick_fontsize,
                    rotation=rjx_colorbar_tick_rotation,
                    length=rjx_colorbar_tick_length,
                )
                if vmax < 0.001 or vmax > 1000:  # y轴设置科学计数法
                    cbar.ax.xaxis.set_major_formatter(formatter)
            cbar.set_ticks([vmin, vmax])
            ########################################### rjx_colorbar ###############################################
        return fig
    return lh_parc, rh_parc

plot_chimpanzee_hemi_brain_figure

plot_chimpanzee_hemi_brain_figure(data, hemi='lh', surf='veryinflated', atlas='bna', vmin=None, vmax=None, cmap='Reds', colorbar=True, colorbar_location='right', colorbar_label_name='', colorbar_label_rotation=0, colorbar_decimals=1, colorbar_fontsize=8, colorbar_nticks=2, colorbar_shrink=0.15, colorbar_aspect=8, colorbar_draw_border=False, title_name='', title_fontsize=15, title_y=0.9)

绘制黑猩猩大脑单侧(左脑或右脑)表面图,支持 BNA 图谱。

Parameters:

Name Type Description Default
data dict[str, float]

包含 ROI 名称及其对应值的字典。

required
hemi str

脑半球选择,支持 "lh"(左脑)或 "rh"(右脑)。默认为 "lh"。

'lh'
surf str

大脑表面类型(如 "veryinflated", "midthickness")。默认为 "veryinflated"。

'veryinflated'
atlas str

使用的图谱名称,目前仅支持 "bna"。默认为 "bna"。

'bna'
vmin Num

颜色映射的最小值。可以是整数或浮点数。默认为 None。

None
vmax Num

颜色映射的最大值。可以是整数或浮点数。默认为 None。

None
cmap str

颜色映射方案。默认为 "Reds"。

'Reds'
colorbar bool

是否显示颜色条。默认为 True。

True
colorbar_location str

颜色条的位置。默认为 "right"。

'right'
colorbar_label_name str

颜色条的标签名称。默认为空字符串。

''
colorbar_label_rotation int

颜色条标签的旋转角度。默认为 0。

0
colorbar_decimals int

颜色条刻度的小数位数。默认为 1。

1
colorbar_fontsize int

颜色条标签的字体大小。默认为 8。

8
colorbar_nticks int

颜色条上的刻度数量。默认为 2。

2
colorbar_shrink float

颜色条的缩放比例。默认为 0.15。

0.15
colorbar_aspect int

颜色条的宽高比。默认为 8。

8
colorbar_draw_border bool

是否绘制颜色条边框。默认为 False。

False
title_name str

图形标题。默认为空字符串。

''
title_fontsize int

标题字体大小。默认为 15。

15
title_y float

标题在 y 轴上的位置(范围通常为 0~1)。默认为 0.9。

0.9

Returns:

Type Description
Figure

plt.Figure: 返回一个 matplotlib 的 Figure 对象,表示生成的大脑表面图。

Source code in src/plotfig/brain_surface.py
def plot_chimpanzee_hemi_brain_figure(
    data: dict[str, float],
    hemi: str = "lh",
    surf: str = "veryinflated",
    atlas: str = "bna",
    vmin: Num | None = None,
    vmax: Num | None = None,
    cmap: str = "Reds",
    colorbar: bool = True,
    colorbar_location: str = "right",
    colorbar_label_name: str = "",
    colorbar_label_rotation: int = 0,
    colorbar_decimals: int = 1,
    colorbar_fontsize: int = 8,
    colorbar_nticks: int = 2,
    colorbar_shrink: float = 0.15,
    colorbar_aspect: int = 8,
    colorbar_draw_border: bool = False,
    title_name: str = "",
    title_fontsize: int = 15,
    title_y: float = 0.9,
) -> plt.Figure:
    """
    绘制黑猩猩大脑单侧(左脑或右脑)表面图,支持 BNA 图谱。

    Args:
        data (dict[str, float]): 包含 ROI 名称及其对应值的字典。
        hemi (str, optional): 脑半球选择,支持 "lh"(左脑)或 "rh"(右脑)。默认为 "lh"。
        surf (str, optional): 大脑表面类型(如 "veryinflated", "midthickness")。默认为 "veryinflated"。
        atlas (str, optional): 使用的图谱名称,目前仅支持 "bna"。默认为 "bna"。
        vmin (Num, optional): 颜色映射的最小值。可以是整数或浮点数。默认为 None。
        vmax (Num, optional): 颜色映射的最大值。可以是整数或浮点数。默认为 None。
        cmap (str, optional): 颜色映射方案。默认为 "Reds"。
        colorbar (bool, optional): 是否显示颜色条。默认为 True。
        colorbar_location (str, optional): 颜色条的位置。默认为 "right"。
        colorbar_label_name (str, optional): 颜色条的标签名称。默认为空字符串。
        colorbar_label_rotation (int, optional): 颜色条标签的旋转角度。默认为 0。
        colorbar_decimals (int, optional): 颜色条刻度的小数位数。默认为 1。
        colorbar_fontsize (int, optional): 颜色条标签的字体大小。默认为 8。
        colorbar_nticks (int, optional): 颜色条上的刻度数量。默认为 2。
        colorbar_shrink (float, optional): 颜色条的缩放比例。默认为 0.15。
        colorbar_aspect (int, optional): 颜色条的宽高比。默认为 8。
        colorbar_draw_border (bool, optional): 是否绘制颜色条边框。默认为 False。
        title_name (str, optional): 图形标题。默认为空字符串。
        title_fontsize (int, optional): 标题字体大小。默认为 15。
        title_y (float, optional): 标题在 y 轴上的位置(范围通常为 0~1)。默认为 0.9。

    Returns:
        plt.Figure: 返回一个 matplotlib 的 Figure 对象,表示生成的大脑表面图。
    """
    # 设置必要文件路径
    current_dir = op.dirname(__file__)
    neuromaps_data_dir = op.join(current_dir, "data/neurodata")
    if atlas == "bna":
        lh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/chimpanzee_BNA/ChimpBNA.L.32k_fs_LR.label.gii",
        )
        rh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/chimpanzee_BNA/ChimpBNA.R.32k_fs_LR.label.gii",
        )
        df = pd.read_csv(
            op.join(current_dir, "data/atlas_tables", "chimpanzee_bna.csv")
        )
    # 获取文件Underlay
    lh = op.join(
        neuromaps_data_dir,
        f"surfaces/chimpanzee_BNA/ChimpYerkes29_v1.2.L.{surf}.32k_fs_LR.surf.gii",
    )
    rh = op.join(
        neuromaps_data_dir,
        f"surfaces/chimpanzee_BNA/ChimpYerkes29_v1.2.R.{surf}.32k_fs_LR.surf.gii",
    )
    if hemi == "lh":
        p = Plot(lh, size=(800, 400), zoom=1.2)
    elif hemi == "rh":
        p = Plot(rh, size=(800, 400), zoom=1.2)
    # 将原始数据拆分成左右脑数据
    lh_data, rh_data = {}, {}
    for roi in data:
        if "lh_" in roi:
            lh_data[roi] = data[roi]
        elif "rh_" in roi:
            rh_data[roi] = data[roi]
    # 加载分区数据
    lh_roi_list, rh_roi_list = (
        list(df["ROIs_name"])[0 : int(len(df["ROIs_name"]) / 2)],
        list(df["ROIs_name"])[int(len(df["ROIs_name"]) / 2) : len(df["ROIs_name"])],
    )
    # 处理左脑数据
    lh_parc = nib.load(lh_atlas_dir).darrays[0].data
    roi_vertics = {roi: [] for roi in lh_roi_list}
    for vertex_index, label in enumerate(lh_parc):
        if label - 1 >= 0:
            roi_vertics[lh_roi_list[label - 1]].append(vertex_index)
    lh_parc = np.full(lh_parc.shape, np.nan)
    for roi in lh_data:
        lh_parc[roi_vertics[roi]] = lh_data[roi]
    # 处理右脑数据
    rh_parc = nib.load(rh_atlas_dir).darrays[0].data
    roi_vertics = {roi: [] for roi in rh_roi_list}
    for vertex_index, label in enumerate(rh_parc):
        if label - len(lh_roi_list) - 1 >= 0:
            roi_vertics[rh_roi_list[label - len(lh_roi_list) - 1]].append(vertex_index)
    rh_parc = np.full(rh_parc.shape, np.nan)
    for roi in rh_data:
        rh_parc[roi_vertics[roi]] = rh_data[roi]
    # 画图元素参数设置
    if vmin is None:
        vmin = min(data.values())
    if vmax is None:
        vmax = max(data.values())
    if vmin > vmax:
        print("vmin必须小于等于vmax")
        return
    if vmin == vmax:
        vmin = min(0, vmin)
        vmax = max(0, vmax)
    # colorbar参数设置
    colorbar_kws = {
        "location": colorbar_location,
        "label_direction": colorbar_label_rotation,
        "decimals": colorbar_decimals,
        "fontsize": colorbar_fontsize,
        "n_ticks": colorbar_nticks,
        "shrink": colorbar_shrink,
        "aspect": colorbar_aspect,
        "draw_border": colorbar_draw_border,
    }
    if hemi == "lh":
        p.add_layer(
            {"left": lh_parc},
            cbar=colorbar,
            cmap=cmap,
            color_range=(vmin, vmax),
            cbar_label=colorbar_label_name,
            zero_transparent=False,
        )
    else:
        p.add_layer(
            {"left": rh_parc},
            cbar=colorbar,
            cmap=cmap,
            color_range=(vmin, vmax),
            cbar_label=colorbar_label_name,
            zero_transparent=False,
        )  # 很怪,但是这里就是写“{'left': rh_parc}”
    fig = p.build(cbar_kws=colorbar_kws)
    fig.suptitle(title_name, fontsize=title_fontsize, y=title_y)
    return fig

plot_human_brain_figure

plot_human_brain_figure(data, surf='veryinflated', atlas='glasser', vmin=None, vmax=None, plot=True, cmap='Reds', as_outline=False, colorbar=True, colorbar_location='right', colorbar_label_name='', colorbar_label_rotation=0, colorbar_decimals=1, colorbar_fontsize=8, colorbar_nticks=2, colorbar_shrink=0.15, colorbar_aspect=8, colorbar_draw_border=False, title_name='', title_fontsize=15, title_y=0.9, rjx_colorbar=False, rjx_colorbar_direction='vertical', horizontal_center=True, rjx_colorbar_outline=False, rjx_colorbar_label_name='', rjx_colorbar_tick_fontsize=10, rjx_colorbar_label_fontsize=10, rjx_colorbar_tick_rotation=0, rjx_colorbar_tick_length=0, rjx_colorbar_nticks=2)

绘制人类大脑表面图,支持 Glasser 和 BNA 图谱。

Parameters:

Name Type Description Default
data dict[str, float]

包含 ROI 名称及其对应值的字典。

required
surf str

大脑表面类型(如 "veryinflated", "inflated")。默认为 "veryinflated"。

'veryinflated'
atlas str

使用的图谱名称,支持 "glasser" 或 "bna"。默认为 "glasser"。

'glasser'
vmin Num

颜色映射的最小值。可以是整数或浮点数。默认为 None。

None
vmax Num

颜色映射的最大值。可以是整数或浮点数。默认为 None。

None
plot bool

是否直接绘制图形。默认为 True。

True
cmap str

颜色映射方案。默认为 "Reds"。

'Reds'
as_outline bool

是否以轮廓形式显示颜色层。默认为 False。

False
colorbar bool

是否显示颜色条。默认为 True。

True
colorbar_location str

颜色条的位置。默认为 "right"。

'right'
colorbar_label_name str

颜色条的标签名称。默认为空字符串。

''
colorbar_label_rotation int

颜色条标签的旋转角度。默认为 0。

0
colorbar_decimals int

颜色条刻度的小数位数。默认为 1。

1
colorbar_fontsize int

颜色条标签的字体大小。默认为 8。

8
colorbar_nticks int

颜色条上的刻度数量。默认为 2。

2
colorbar_shrink float

颜色条的缩放比例。默认为 0.15。

0.15
colorbar_aspect int

颜色条的宽高比。默认为 8。

8
colorbar_draw_border bool

是否绘制颜色条边框。默认为 False。

False
title_name str

图形标题。默认为空字符串。

''
title_fontsize int

标题字体大小。默认为 15。

15
title_y float

标题在 y 轴上的位置(范围通常为 0~1)。默认为 0.9。

0.9
rjx_colorbar bool

是否使用自定义颜色条。默认为 False。

False
rjx_colorbar_direction str

自定义颜色条方向,支持 "vertical" 或 "horizontal"。默认为 "vertical"。

'vertical'
horizontal_center bool

水平颜色条是否居中。默认为 True。

True
rjx_colorbar_outline bool

自定义颜色条是否显示边框。默认为 False。

False
rjx_colorbar_label_name str

自定义颜色条标签名称。默认为空字符串。

''
rjx_colorbar_tick_fontsize int

自定义颜色条刻度字体大小。默认为 10。

10
rjx_colorbar_label_fontsize int

自定义颜色条标签字体大小。默认为 10。

10
rjx_colorbar_tick_rotation int

自定义颜色条刻度标签旋转角度。默认为 0。

0
rjx_colorbar_tick_length int

自定义颜色条刻度长度。默认为 0。

0
rjx_colorbar_nticks int

自定义颜色条上的刻度数量。默认为 2。

2

Returns:

Type Description
Figure | tuple[ndarray, ndarray]

Union[plt.Figure, tuple[np.ndarray, np.ndarray]]: 如果 plot=True,返回 matplotlib 的 Figure 对象;

Figure | tuple[ndarray, ndarray]

否则返回左右脑数据数组的元组 (lh_parc, rh_parc)

Source code in src/plotfig/brain_surface.py
def plot_human_brain_figure(
    data: dict[str, float],
    surf: str = "veryinflated",
    atlas: str = "glasser",
    vmin: Num | None = None,
    vmax: Num | None = None,
    plot: bool = True,
    cmap: str = "Reds",
    as_outline: bool = False,
    colorbar: bool = True,
    colorbar_location: str = "right",
    colorbar_label_name: str = "",
    colorbar_label_rotation: int = 0,
    colorbar_decimals: int = 1,
    colorbar_fontsize: int = 8,
    colorbar_nticks: int = 2,
    colorbar_shrink: float = 0.15,
    colorbar_aspect: int = 8,
    colorbar_draw_border: bool = False,
    title_name: str = "",
    title_fontsize: int = 15,
    title_y: float = 0.9,
    rjx_colorbar: bool = False,
    rjx_colorbar_direction: str = "vertical",
    horizontal_center: bool = True,
    rjx_colorbar_outline: bool = False,
    rjx_colorbar_label_name: str = "",
    rjx_colorbar_tick_fontsize: int = 10,
    rjx_colorbar_label_fontsize: int = 10,
    rjx_colorbar_tick_rotation: int = 0,
    rjx_colorbar_tick_length: int = 0,
    rjx_colorbar_nticks: int = 2,
) -> plt.Figure | tuple[np.ndarray, np.ndarray]:
    """
    绘制人类大脑表面图,支持 Glasser 和 BNA 图谱。

    Args:
        data (dict[str, float]): 包含 ROI 名称及其对应值的字典。
        surf (str, optional): 大脑表面类型(如 "veryinflated", "inflated")。默认为 "veryinflated"。
        atlas (str, optional): 使用的图谱名称,支持 "glasser" 或 "bna"。默认为 "glasser"。
        vmin (Num, optional): 颜色映射的最小值。可以是整数或浮点数。默认为 None。
        vmax (Num, optional): 颜色映射的最大值。可以是整数或浮点数。默认为 None。
        plot (bool, optional): 是否直接绘制图形。默认为 True。
        cmap (str, optional): 颜色映射方案。默认为 "Reds"。
        as_outline (bool, optional): 是否以轮廓形式显示颜色层。默认为 False。
        colorbar (bool, optional): 是否显示颜色条。默认为 True。
        colorbar_location (str, optional): 颜色条的位置。默认为 "right"。
        colorbar_label_name (str, optional): 颜色条的标签名称。默认为空字符串。
        colorbar_label_rotation (int, optional): 颜色条标签的旋转角度。默认为 0。
        colorbar_decimals (int, optional): 颜色条刻度的小数位数。默认为 1。
        colorbar_fontsize (int, optional): 颜色条标签的字体大小。默认为 8。
        colorbar_nticks (int, optional): 颜色条上的刻度数量。默认为 2。
        colorbar_shrink (float, optional): 颜色条的缩放比例。默认为 0.15。
        colorbar_aspect (int, optional): 颜色条的宽高比。默认为 8。
        colorbar_draw_border (bool, optional): 是否绘制颜色条边框。默认为 False。
        title_name (str, optional): 图形标题。默认为空字符串。
        title_fontsize (int, optional): 标题字体大小。默认为 15。
        title_y (float, optional): 标题在 y 轴上的位置(范围通常为 0~1)。默认为 0.9。
        rjx_colorbar (bool, optional): 是否使用自定义颜色条。默认为 False。
        rjx_colorbar_direction (str, optional): 自定义颜色条方向,支持 "vertical" 或 "horizontal"。默认为 "vertical"。
        horizontal_center (bool, optional): 水平颜色条是否居中。默认为 True。
        rjx_colorbar_outline (bool, optional): 自定义颜色条是否显示边框。默认为 False。
        rjx_colorbar_label_name (str, optional): 自定义颜色条标签名称。默认为空字符串。
        rjx_colorbar_tick_fontsize (int, optional): 自定义颜色条刻度字体大小。默认为 10。
        rjx_colorbar_label_fontsize (int, optional): 自定义颜色条标签字体大小。默认为 10。
        rjx_colorbar_tick_rotation (int, optional): 自定义颜色条刻度标签旋转角度。默认为 0。
        rjx_colorbar_tick_length (int, optional): 自定义颜色条刻度长度。默认为 0。
        rjx_colorbar_nticks (int, optional): 自定义颜色条上的刻度数量。默认为 2。

    Returns:
        Union[plt.Figure, tuple[np.ndarray, np.ndarray]]: 如果 `plot=True`,返回 matplotlib 的 Figure 对象;
        否则返回左右脑数据数组的元组 `(lh_parc, rh_parc)`。
    """

    # 设置必要文件路径
    current_dir = op.dirname(__file__)
    neuromaps_data_dir = op.join(current_dir, "data/neurodata")
    if atlas == "glasser":
        lh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/human_Glasser/fsaverage.L.Glasser.32k_fs_LR.label.gii",
        )
        rh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/human_Glasser/fsaverage.R.Glasser.32k_fs_LR.label.gii",
        )
        df = pd.read_csv(op.join(current_dir, "data/atlas_tables/human_glasser.csv"))
    elif atlas == "bna":
        lh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/human_BNA/fsaverage.L.BNA.32k_fs_LR.label.gii",
        )
        rh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/human_BNA/fsaverage.R.BNA.32k_fs_LR.label.gii",
        )
        df = pd.read_csv(op.join(current_dir, "data/atlas_tables", "human_bna.csv"))
    # 获取文件Underlay
    lh = op.join(
        neuromaps_data_dir,
        f"surfaces/human_fsLR/tpl-fsLR_den-32k_hemi-L_{surf}.surf.gii",
    )
    rh = op.join(
        neuromaps_data_dir,
        f"surfaces/human_fsLR/tpl-fsLR_den-32k_hemi-R_{surf}.surf.gii",
    )
    p = Plot(lh, rh)
    # 将原始数据拆分成左右脑数据
    lh_data, rh_data = {}, {}
    for roi in data:
        if "lh_" in roi:
            lh_data[roi] = data[roi]
        elif "rh_" in roi:
            rh_data[roi] = data[roi]
    # 加载图集分区数据
    lh_roi_list, rh_roi_list = (
        list(df["ROIs_name"])[0 : int(len(df["ROIs_name"]) / 2)],
        list(df["ROIs_name"])[int(len(df["ROIs_name"]) / 2) : len(df["ROIs_name"])],
    )
    # 处理左脑数据
    lh_parc = nib.load(lh_atlas_dir).darrays[0].data
    roi_vertics = {roi: [] for roi in lh_roi_list}
    for vertex_index, label in enumerate(lh_parc):
        if label - 1 >= 0:
            roi_vertics[lh_roi_list[label - 1]].append(vertex_index)
    lh_parc = np.full(lh_parc.shape, np.nan)
    for roi in lh_data:
        lh_parc[roi_vertics[roi]] = lh_data[roi]
    # 处理右脑数据
    rh_parc = nib.load(rh_atlas_dir).darrays[0].data
    roi_vertics = {roi: [] for roi in rh_roi_list}
    for vertex_index, label in enumerate(rh_parc):
        if label - 1 - len(lh_roi_list) >= 0:
            roi_vertics[rh_roi_list[label - 1 - len(lh_roi_list)]].append(vertex_index)
    rh_parc = np.full(rh_parc.shape, np.nan)
    for roi in rh_data:
        rh_parc[roi_vertics[roi]] = rh_data[roi]
    # 画图
    if plot:
        # 画图元素参数设置
        if vmin is None:
            vmin = min(data.values())
        if vmax is None:
            vmax = max(data.values())
        if vmin > vmax:
            print("vmin必须小于等于vmax")
            return
        if vmin == vmax:
            vmin = min(0, vmin)
            vmax = max(0, vmax)
        # colorbar参数设置
        colorbar_kws = {
            "location": colorbar_location,
            "label_direction": colorbar_label_rotation,
            "decimals": colorbar_decimals,
            "fontsize": colorbar_fontsize,
            "n_ticks": colorbar_nticks,
            "shrink": colorbar_shrink,
            "aspect": colorbar_aspect,
            "draw_border": colorbar_draw_border,
        }
        p.add_layer(
            {"left": lh_parc, "right": rh_parc},
            cbar=colorbar,
            cmap=cmap,
            color_range=(vmin, vmax),
            cbar_label=colorbar_label_name,
            zero_transparent=False,
            as_outline=as_outline,
        )
        fig = p.build(cbar_kws=colorbar_kws)
        fig.suptitle(title_name, fontsize=title_fontsize, y=title_y)
        ############################################### rjx_colorbar ###############################################
        sm = ScalarMappable(cmap=cmap)
        sm.set_array((vmin, vmax))  # 设置值范围
        if rjx_colorbar:
            if rjx_colorbar_direction == "vertical":
                formatter = ScalarFormatter(useMathText=True)  # 科学计数法相关
                formatter.set_powerlimits(
                    (-3, 3)
                )  # <=-1也就是小于等于0.1,>=2,也就是大于等于100,会写成科学计数法
                cax = fig.add_axes(
                    [1, 0.425, 0.01, 0.15]
                )  # [left, bottom, width, height]
                cbar = fig.colorbar(
                    sm, cax=cax, orientation="vertical", cmap=cmap
                )  # "vertical", "horizontal"
                cbar.outline.set_visible(rjx_colorbar_outline)
                cbar.ax.set_ylabel(
                    rjx_colorbar_label_name, fontsize=rjx_colorbar_label_fontsize
                )
                cbar.ax.yaxis.set_label_position(
                    "left"
                )  # 原本设置y轴label默认在右边,现在换到左边
                cbar.ax.tick_params(
                    axis="y",
                    which="major",
                    labelsize=rjx_colorbar_tick_fontsize,
                    rotation=rjx_colorbar_tick_rotation,
                    length=rjx_colorbar_tick_length,
                )
                cbar.set_ticks(np.linspace(vmin, vmax, rjx_colorbar_nticks))
                if vmax < 0.001 or vmax > 1000:  # y轴设置科学计数法
                    cbar.ax.yaxis.set_major_formatter(formatter)
                    cbar.ax.yaxis.get_offset_text().set_visible(
                        False
                    )  # 隐藏默认的偏移文本
                    exponent = math.floor(math.log10(vmax))
                    # 手动添加文本
                    cbar.ax.text(
                        1.05,
                        1.15,
                        rf"$\times 10^{{{exponent}}}$",
                        transform=cbar.ax.transAxes,
                        fontsize=rjx_colorbar_tick_fontsize,
                        verticalalignment="bottom",
                        horizontalalignment="left",
                    )
            elif rjx_colorbar_direction == "horizontal":
                if horizontal_center:
                    cax = fig.add_axes([0.44, 0.5, 0.15, 0.01])
                else:
                    cax = fig.add_axes([0.44, 0.05, 0.15, 0.01])
                cbar = fig.colorbar(sm, cax=cax, orientation="horizontal", cmap=cmap)
                cbar.outline.set_visible(rjx_colorbar_outline)
                cbar.ax.set_title(
                    rjx_colorbar_label_name, fontsize=rjx_colorbar_label_fontsize
                )
                cbar.ax.tick_params(
                    axis="x",
                    which="major",
                    labelsize=rjx_colorbar_tick_fontsize,
                    rotation=rjx_colorbar_tick_rotation,
                    length=rjx_colorbar_tick_length,
                )
                if vmax < 0.001 or vmax > 1000:  # y轴设置科学计数法
                    cbar.ax.xaxis.set_major_formatter(formatter)
                cbar.set_ticks(np.linspace(vmin, vmax, rjx_colorbar_nticks))
            ########################################### rjx_colorbar ###############################################
        return fig
    return lh_parc, rh_parc

plot_human_hemi_brain_figure

plot_human_hemi_brain_figure(data, hemi='lh', surf='veryinflated', atlas='glasser', vmin=None, vmax=None, cmap='Reds', colorbar=True, colorbar_location='right', colorbar_label_name='', colorbar_label_rotation=0, colorbar_decimals=1, colorbar_fontsize=8, colorbar_nticks=2, colorbar_shrink=0.15, colorbar_aspect=8, colorbar_draw_border=False, title_name='', title_fontsize=15, title_y=0.9)

绘制人类大脑单侧(左脑或右脑)表面图,支持 Glasser 和 BNA 图谱。

Parameters:

Name Type Description Default
data dict[str, float]

包含 ROI 名称及其对应值的字典。

required
hemi str

脑半球选择,支持 "lh"(左脑)或 "rh"(右脑)。默认为 "lh"。

'lh'
surf str

大脑表面类型(如 "veryinflated", "inflated")。默认为 "veryinflated"。

'veryinflated'
atlas str

使用的图谱名称,支持 "glasser" 或 "bna"。默认为 "glasser"。

'glasser'
vmin Num

颜色映射的最小值。可以是整数或浮点数。默认为 None。

None
vmax Num

颜色映射的最大值。可以是整数或浮点数。默认为 None。

None
cmap str

颜色映射方案。默认为 "Reds"。

'Reds'
colorbar bool

是否显示颜色条。默认为 True。

True
colorbar_location str

颜色条的位置。默认为 "right"。

'right'
colorbar_label_name str

颜色条的标签名称。默认为空字符串。

''
colorbar_label_rotation int

颜色条标签的旋转角度。默认为 0。

0
colorbar_decimals int

颜色条刻度的小数位数。默认为 1。

1
colorbar_fontsize int

颜色条标签的字体大小。默认为 8。

8
colorbar_nticks int

颜色条上的刻度数量。默认为 2。

2
colorbar_shrink float

颜色条的缩放比例。默认为 0.15。

0.15
colorbar_aspect int

颜色条的宽高比。默认为 8。

8
colorbar_draw_border bool

是否绘制颜色条边框。默认为 False。

False
title_name str

图形标题。默认为空字符串。

''
title_fontsize int

标题字体大小。默认为 15。

15
title_y float

标题在 y 轴上的位置(范围通常为 0~1)。默认为 0.9。

0.9

Returns:

Type Description
Figure | None

plt.Figure: 返回一个 matplotlib 的 Figure 对象,表示生成的大脑表面图。

Source code in src/plotfig/brain_surface.py
def plot_human_hemi_brain_figure(
    data: dict[str, float],
    hemi: str = "lh",
    surf: str = "veryinflated",
    atlas: str = "glasser",
    vmin: Num | None = None,
    vmax: Num | None = None,
    cmap: str = "Reds",
    colorbar: bool = True,
    colorbar_location: str = "right",
    colorbar_label_name: str = "",
    colorbar_label_rotation: int = 0,
    colorbar_decimals: int = 1,
    colorbar_fontsize: int = 8,
    colorbar_nticks: int = 2,
    colorbar_shrink: float = 0.15,
    colorbar_aspect: int = 8,
    colorbar_draw_border: bool = False,
    title_name: str = "",
    title_fontsize: int = 15,
    title_y: float = 0.9,
) -> plt.Figure | None:
    """
    绘制人类大脑单侧(左脑或右脑)表面图,支持 Glasser 和 BNA 图谱。

    Args:
        data (dict[str, float]): 包含 ROI 名称及其对应值的字典。
        hemi (str, optional): 脑半球选择,支持 "lh"(左脑)或 "rh"(右脑)。默认为 "lh"。
        surf (str, optional): 大脑表面类型(如 "veryinflated", "inflated")。默认为 "veryinflated"。
        atlas (str, optional): 使用的图谱名称,支持 "glasser" 或 "bna"。默认为 "glasser"。
        vmin (Num, optional): 颜色映射的最小值。可以是整数或浮点数。默认为 None。
        vmax (Num, optional): 颜色映射的最大值。可以是整数或浮点数。默认为 None。
        cmap (str, optional): 颜色映射方案。默认为 "Reds"。
        colorbar (bool, optional): 是否显示颜色条。默认为 True。
        colorbar_location (str, optional): 颜色条的位置。默认为 "right"。
        colorbar_label_name (str, optional): 颜色条的标签名称。默认为空字符串。
        colorbar_label_rotation (int, optional): 颜色条标签的旋转角度。默认为 0。
        colorbar_decimals (int, optional): 颜色条刻度的小数位数。默认为 1。
        colorbar_fontsize (int, optional): 颜色条标签的字体大小。默认为 8。
        colorbar_nticks (int, optional): 颜色条上的刻度数量。默认为 2。
        colorbar_shrink (float, optional): 颜色条的缩放比例。默认为 0.15。
        colorbar_aspect (int, optional): 颜色条的宽高比。默认为 8。
        colorbar_draw_border (bool, optional): 是否绘制颜色条边框。默认为 False。
        title_name (str, optional): 图形标题。默认为空字符串。
        title_fontsize (int, optional): 标题字体大小。默认为 15。
        title_y (float, optional): 标题在 y 轴上的位置(范围通常为 0~1)。默认为 0.9。

    Returns:
        plt.Figure: 返回一个 matplotlib 的 Figure 对象,表示生成的大脑表面图。
    """

    # 设置必要文件路径
    current_dir = op.dirname(__file__)
    neuromaps_data_dir = op.join(current_dir, "data/neurodata")
    if atlas == "glasser":
        lh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/human_Glasser/fsaverage.L.Glasser.32k_fs_LR.label.gii",
        )
        rh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/human_Glasser/fsaverage.R.Glasser.32k_fs_LR.label.gii",
        )
        df = pd.read_csv(op.join(current_dir, "data/atlas_tables", "human_glasser.csv"))
    elif atlas == "bna":
        lh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/human_BNA/fsaverage.L.BNA.32k_fs_LR.label.gii",
        )
        rh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/human_BNA/fsaverage.R.BNA.32k_fs_LR.label.gii",
        )
        df = pd.read_csv(op.join(current_dir, "data/atlas_tables", "human_bna.csv"))
    # 获取文件Underlay

    lh = op.join(
        neuromaps_data_dir,
        f"surfaces/human_fsLR/tpl-fsLR_den-32k_hemi-L_{surf}.surf.gii",
    )
    rh = op.join(
        neuromaps_data_dir,
        f"surfaces/human_fsLR/tpl-fsLR_den-32k_hemi-R_{surf}.surf.gii",
    )
    if hemi == "lh":
        p = Plot(lh, size=(800, 400), zoom=1.2)
    elif hemi == "rh":
        p = Plot(rh, size=(800, 400), zoom=1.2)
    # 将原始数据拆分成左右脑数据
    lh_data, rh_data = {}, {}
    for roi in data:
        if "lh_" in roi:
            lh_data[roi] = data[roi]
        elif "rh_" in roi:
            rh_data[roi] = data[roi]
    # 加载图集分区数据
    lh_roi_list, rh_roi_list = (
        list(df["ROIs_name"])[0 : int(len(df["ROIs_name"]) / 2)],
        list(df["ROIs_name"])[int(len(df["ROIs_name"]) / 2) : len(df["ROIs_name"])],
    )
    # 处理左脑数据
    lh_parc = nib.load(lh_atlas_dir).darrays[0].data
    roi_vertics = {roi: [] for roi in lh_roi_list}
    for vertex_index, label in enumerate(lh_parc):
        if label - 1 >= 0:
            roi_vertics[lh_roi_list[label - 1]].append(vertex_index)
    lh_parc = np.full(lh_parc.shape, np.nan)
    for roi in lh_data:
        lh_parc[roi_vertics[roi]] = lh_data[roi]
    # 处理右脑数据
    rh_parc = nib.load(rh_atlas_dir).darrays[0].data
    roi_vertics = {roi: [] for roi in rh_roi_list}
    for vertex_index, label in enumerate(rh_parc):
        if label - 1 - len(lh_roi_list) >= 0:
            roi_vertics[rh_roi_list[label - 1 - len(lh_roi_list)]].append(vertex_index)
    rh_parc = np.full(rh_parc.shape, np.nan)
    for roi in rh_data:
        rh_parc[roi_vertics[roi]] = rh_data[roi]
    # 画图元素参数设置
    if vmin is None:
        vmin = min(data.values())
    if vmax is None:
        vmax = max(data.values())
    if vmin > vmax:
        print("vmin必须小于等于vmax")
        return
    if vmin == vmax:
        vmin = min(0, vmin)
        vmax = max(0, vmax)
    # colorbar参数设置
    colorbar_kws = {
        "location": colorbar_location,
        "label_direction": colorbar_label_rotation,
        "decimals": colorbar_decimals,
        "fontsize": colorbar_fontsize,
        "n_ticks": colorbar_nticks,
        "shrink": colorbar_shrink,
        "aspect": colorbar_aspect,
        "draw_border": colorbar_draw_border,
    }
    if hemi == "lh":
        p.add_layer(
            {"left": lh_parc},
            cbar=colorbar,
            cmap=cmap,
            color_range=(vmin, vmax),
            cbar_label=colorbar_label_name,
            zero_transparent=False,
        )
    elif hemi == "rh":
        p.add_layer(
            {"left": rh_parc},
            cbar=colorbar,
            cmap=cmap,
            color_range=(vmin, vmax),
            cbar_label=colorbar_label_name,
            zero_transparent=False,
        )  # 很怪,但是这里就是写“{'left': rh_parc}”
    fig = p.build(cbar_kws=colorbar_kws)
    fig.suptitle(title_name, fontsize=title_fontsize, y=title_y)
    return fig

plot_macaque_brain_figure

plot_macaque_brain_figure(data, surf='veryinflated', atlas='charm5', vmin=None, vmax=None, plot=True, cmap='Reds', colorbar=True, colorbar_location='right', colorbar_label_name='', colorbar_label_rotation=0, colorbar_decimals=1, colorbar_fontsize=8, colorbar_nticks=2, colorbar_shrink=0.15, colorbar_aspect=8, colorbar_draw_border=False, title_name='', title_fontsize=15, title_y=0.9, rjx_colorbar=False, rjx_colorbar_direction='vertical', horizontal_center=True, rjx_colorbar_outline=False, rjx_colorbar_label_name='', rjx_colorbar_tick_fontsize=10, rjx_colorbar_label_fontsize=10, rjx_colorbar_tick_rotation=0, rjx_colorbar_tick_length=0, rjx_colorbar_nticks=2)

绘制猕猴大脑表面图,支持多种图谱(CHARM5、CHARM6、BNA、D99)。

Parameters:

Name Type Description Default
data dict[str, float]

包含 ROI 名称及其对应值的字典。

required
surf str

大脑表面类型(如 "veryinflated", "inflated")。默认为 "veryinflated"。

'veryinflated'
atlas str

使用的图谱名称,支持 "charm5", "charm6", "bna", "d99"。默认为 "charm5"。

'charm5'
vmin Num

颜色映射的最小值。可以是整数或浮点数。默认为 None。

None
vmax Num

颜色映射的最大值。可以是整数或浮点数。默认为 None。

None
plot bool

是否直接绘制图形。默认为 True。

True
cmap str

颜色映射方案。默认为 "Reds"。

'Reds'
colorbar bool

是否显示颜色条。默认为 True。

True
colorbar_location str

颜色条的位置。默认为 "right"。

'right'
colorbar_label_name str

颜色条的标签名称。默认为空字符串。

''
colorbar_label_rotation int

颜色条标签的旋转角度。默认为 0。

0
colorbar_decimals int

颜色条刻度的小数位数。默认为 1。

1
colorbar_fontsize int

颜色条标签的字体大小。默认为 8。

8
colorbar_nticks int

颜色条上的刻度数量。默认为 2。

2
colorbar_shrink float

颜色条的缩放比例。默认为 0.15。

0.15
colorbar_aspect int

颜色条的宽高比。默认为 8。

8
colorbar_draw_border bool

是否绘制颜色条边框。默认为 False。

False
title_name str

图形标题。默认为空字符串。

''
title_fontsize int

标题字体大小。默认为 15。

15
title_y float

标题在 y 轴上的位置(范围通常为 0~1)。默认为 0.9。

0.9
rjx_colorbar bool

是否使用自定义颜色条。默认为 False。

False
rjx_colorbar_direction str

自定义颜色条方向,支持 "vertical" 或 "horizontal"。默认为 "vertical"。

'vertical'
horizontal_center bool

水平颜色条是否居中。默认为 True。

True
rjx_colorbar_outline bool

自定义颜色条是否显示边框。默认为 False。

False
rjx_colorbar_label_name str

自定义颜色条标签名称。默认为空字符串。

''
rjx_colorbar_tick_fontsize int

自定义颜色条刻度字体大小。默认为 10。

10
rjx_colorbar_label_fontsize int

自定义颜色条标签字体大小。默认为 10。

10
rjx_colorbar_tick_rotation int

自定义颜色条刻度标签旋转角度。默认为 0。

0
rjx_colorbar_tick_length int

自定义颜色条刻度长度。默认为 0。

0
rjx_colorbar_nticks int

自定义颜色条上的刻度数量。默认为 2。

2

Returns:

Type Description
Figure | tuple[ndarray, ndarray]

Union[plt.Figure, tuple[np.ndarray, np.ndarray]]: 如果 plot=True,返回 matplotlib 的 Figure 对象;

Figure | tuple[ndarray, ndarray]

否则返回左右脑数据数组的元组 (lh_parc, rh_parc)

Source code in src/plotfig/brain_surface.py
def plot_macaque_brain_figure(
    data: dict[str, float],
    surf: str = "veryinflated",
    atlas: str = "charm5",
    vmin: Num | None = None,
    vmax: Num | None = None,
    plot: bool = True,
    cmap: str = "Reds",
    colorbar: bool = True,
    colorbar_location: str = "right",
    colorbar_label_name: str = "",
    colorbar_label_rotation: int = 0,
    colorbar_decimals: int = 1,
    colorbar_fontsize: int = 8,
    colorbar_nticks: int = 2,
    colorbar_shrink: float = 0.15,
    colorbar_aspect: int = 8,
    colorbar_draw_border: bool = False,
    title_name: str = "",
    title_fontsize: int = 15,
    title_y: float = 0.9,
    rjx_colorbar: bool = False,
    rjx_colorbar_direction: str = "vertical",
    horizontal_center: bool = True,
    rjx_colorbar_outline: bool = False,
    rjx_colorbar_label_name: str = "",
    rjx_colorbar_tick_fontsize: int = 10,
    rjx_colorbar_label_fontsize: int = 10,
    rjx_colorbar_tick_rotation: int = 0,
    rjx_colorbar_tick_length: int = 0,
    rjx_colorbar_nticks: int = 2,
) -> plt.Figure | tuple[np.ndarray, np.ndarray]:
    """
    绘制猕猴大脑表面图,支持多种图谱(CHARM5、CHARM6、BNA、D99)。

    Args:
        data (dict[str, float]): 包含 ROI 名称及其对应值的字典。
        surf (str, optional): 大脑表面类型(如 "veryinflated", "inflated")。默认为 "veryinflated"。
        atlas (str, optional): 使用的图谱名称,支持 "charm5", "charm6", "bna", "d99"。默认为 "charm5"。
        vmin (Num, optional): 颜色映射的最小值。可以是整数或浮点数。默认为 None。
        vmax (Num, optional): 颜色映射的最大值。可以是整数或浮点数。默认为 None。
        plot (bool, optional): 是否直接绘制图形。默认为 True。
        cmap (str, optional): 颜色映射方案。默认为 "Reds"。
        colorbar (bool, optional): 是否显示颜色条。默认为 True。
        colorbar_location (str, optional): 颜色条的位置。默认为 "right"。
        colorbar_label_name (str, optional): 颜色条的标签名称。默认为空字符串。
        colorbar_label_rotation (int, optional): 颜色条标签的旋转角度。默认为 0。
        colorbar_decimals (int, optional): 颜色条刻度的小数位数。默认为 1。
        colorbar_fontsize (int, optional): 颜色条标签的字体大小。默认为 8。
        colorbar_nticks (int, optional): 颜色条上的刻度数量。默认为 2。
        colorbar_shrink (float, optional): 颜色条的缩放比例。默认为 0.15。
        colorbar_aspect (int, optional): 颜色条的宽高比。默认为 8。
        colorbar_draw_border (bool, optional): 是否绘制颜色条边框。默认为 False。
        title_name (str, optional): 图形标题。默认为空字符串。
        title_fontsize (int, optional): 标题字体大小。默认为 15。
        title_y (float, optional): 标题在 y 轴上的位置(范围通常为 0~1)。默认为 0.9。
        rjx_colorbar (bool, optional): 是否使用自定义颜色条。默认为 False。
        rjx_colorbar_direction (str, optional): 自定义颜色条方向,支持 "vertical" 或 "horizontal"。默认为 "vertical"。
        horizontal_center (bool, optional): 水平颜色条是否居中。默认为 True。
        rjx_colorbar_outline (bool, optional): 自定义颜色条是否显示边框。默认为 False。
        rjx_colorbar_label_name (str, optional): 自定义颜色条标签名称。默认为空字符串。
        rjx_colorbar_tick_fontsize (int, optional): 自定义颜色条刻度字体大小。默认为 10。
        rjx_colorbar_label_fontsize (int, optional): 自定义颜色条标签字体大小。默认为 10。
        rjx_colorbar_tick_rotation (int, optional): 自定义颜色条刻度标签旋转角度。默认为 0。
        rjx_colorbar_tick_length (int, optional): 自定义颜色条刻度长度。默认为 0。
        rjx_colorbar_nticks (int, optional): 自定义颜色条上的刻度数量。默认为 2。

    Returns:
        Union[plt.Figure, tuple[np.ndarray, np.ndarray]]: 如果 `plot=True`,返回 matplotlib 的 Figure 对象;
        否则返回左右脑数据数组的元组 `(lh_parc, rh_parc)`。
    """
    # 设置必要文件路径
    current_dir = op.dirname(__file__)
    neuromaps_data_dir = op.join(current_dir, "data/neurodata")
    if atlas == "charm5":
        lh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/macaque_CHARM5/L.charm5.label.gii",
        )
        rh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/macaque_CHARM5/R.charm5.label.gii",
        )
        df = pd.read_csv(
            op.join(current_dir, "data/atlas_tables", "macaque_charm5.csv")
        )
    elif atlas == "charm6":
        lh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/macaque_CHARM6/L.charm6.label.gii",
        )
        rh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/macaque_CHARM6/R.charm6.label.gii",
        )
        df = pd.read_csv(
            op.join(current_dir, "data/atlas_tables", "macaque_charm6.csv")
        )
    elif atlas == "bna":
        lh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/macaque_BNA/L.charm5.label.gii",
        )
        rh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/macaque_BNA/R.charm5.label.gii",
        )
        df = pd.read_csv(op.join(current_dir, "data/atlas_tables", "macaque_bna.csv"))
    elif atlas == "d99":
        lh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/macaque_D99/L.d99.label.gii",
        )
        rh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/macaque_D99/R.d99.label.gii",
        )
        df = pd.read_csv(op.join(current_dir, "data/atlas_tables", "macaque_d99.csv"))
    # 获取文件Underlay
    lh = op.join(
        neuromaps_data_dir, f"surfaces/macaque_BNA/civm.L.{surf}.32k_fs_LR.surf.gii"
    )
    rh = op.join(
        neuromaps_data_dir, f"surfaces/macaque_BNA/civm.R.{surf}.32k_fs_LR.surf.gii"
    )
    p = Plot(lh, rh)
    # 将原始数据拆分成左右脑数据
    lh_data, rh_data = {}, {}
    for roi in data:
        if "lh_" in roi:
            lh_data[roi] = data[roi]
        elif "rh_" in roi:
            rh_data[roi] = data[roi]
    # 加载图集分区数据
    lh_roi_list, rh_roi_list = (
        list(df["ROIs_name"])[0 : int(len(df["ROIs_name"]) / 2)],
        list(df["ROIs_name"])[int(len(df["ROIs_name"]) / 2) : len(df["ROIs_name"])],
    )
    # 处理左脑数据
    lh_parc = nib.load(lh_atlas_dir).darrays[0].data
    roi_vertics = {roi: [] for roi in lh_roi_list}
    for vertex_index, label in enumerate(lh_parc):
        if label - 1 >= 0:
            roi_vertics[lh_roi_list[label - 1]].append(vertex_index)
    lh_parc = np.full(lh_parc.shape, np.nan)
    for roi in lh_data:
        lh_parc[roi_vertics[roi]] = lh_data[roi]
    # 处理右脑数据
    rh_parc = nib.load(rh_atlas_dir).darrays[0].data
    roi_vertics = {roi: [] for roi in rh_roi_list}
    for vertex_index, label in enumerate(rh_parc):
        if label - 1 - len(lh_roi_list) >= 0:
            roi_vertics[rh_roi_list[label - 1 - len(lh_roi_list)]].append(vertex_index)
    rh_parc = np.full(rh_parc.shape, np.nan)
    for roi in rh_data:
        rh_parc[roi_vertics[roi]] = rh_data[roi]
    # 画图
    if plot:
        # 画图元素参数设置
        if vmin is None:
            vmin = min(data.values())
        if vmax is None:
            vmax = max(data.values())
        if vmin > vmax:
            print("vmin必须小于等于vmax")
            return
        if vmin == vmax:
            vmin = min(0, vmin)
            vmax = max(0, vmax)
        # colorbar参数设置
        colorbar_kws = {
            "location": colorbar_location,
            "label_direction": colorbar_label_rotation,
            "decimals": colorbar_decimals,
            "fontsize": colorbar_fontsize,
            "n_ticks": colorbar_nticks,
            "shrink": colorbar_shrink,
            "aspect": colorbar_aspect,
            "draw_border": colorbar_draw_border,
        }
        p.add_layer(
            {"left": lh_parc, "right": rh_parc},
            cbar=colorbar,
            cmap=cmap,
            color_range=(vmin, vmax),
            cbar_label=colorbar_label_name,
            zero_transparent=False,
        )
        fig = p.build(cbar_kws=colorbar_kws)
        fig.suptitle(title_name, fontsize=title_fontsize, y=title_y)
        ############################################### rjx_colorbar ###############################################
        sm = ScalarMappable(cmap=cmap)
        sm.set_array((vmin, vmax))  # 设置值范围
        if rjx_colorbar:
            formatter = ScalarFormatter(useMathText=True)  # 科学计数法相关
            formatter.set_powerlimits(
                (-3, 3)
            )  # <=-1也就是小于等于0.1,>=2,也就是大于等于100,会写成科学计数法
            if rjx_colorbar_direction == "vertical":
                cax = fig.add_axes(
                    [1, 0.425, 0.01, 0.15]
                )  # [left, bottom, width, height]
                cbar = fig.colorbar(
                    sm, cax=cax, orientation="vertical", cmap=cmap
                )  # "vertical", "horizontal"
                cbar.outline.set_visible(rjx_colorbar_outline)
                cbar.ax.set_ylabel(
                    rjx_colorbar_label_name, fontsize=rjx_colorbar_label_fontsize
                )
                cbar.ax.yaxis.set_label_position(
                    "left"
                )  # 原本设置y轴label默认在右边,现在换到左边
                cbar.ax.tick_params(
                    axis="y",
                    which="major",
                    labelsize=rjx_colorbar_tick_fontsize,
                    rotation=rjx_colorbar_tick_rotation,
                    length=rjx_colorbar_tick_length,
                )
                cbar.set_ticks(np.linspace(vmin, vmax, rjx_colorbar_nticks))
                if vmax < 0.001 or vmax > 1000:  # y轴设置科学计数法
                    cbar.ax.yaxis.set_major_formatter(formatter)
                    cbar.ax.yaxis.get_offset_text().set_visible(
                        False
                    )  # 隐藏默认的偏移文本
                    exponent = math.floor(math.log10(vmax))
                    # 手动添加文本
                    cbar.ax.text(
                        1.05,
                        1.15,
                        rf"$\times 10^{{{exponent}}}$",
                        transform=cbar.ax.transAxes,
                        fontsize=rjx_colorbar_tick_fontsize,
                        verticalalignment="bottom",
                        horizontalalignment="left",
                    )
            elif rjx_colorbar_direction == "horizontal":
                if horizontal_center:
                    cax = fig.add_axes([0.44, 0.5, 0.15, 0.01])
                else:
                    cax = fig.add_axes([0.44, 0.05, 0.15, 0.01])
                cbar = fig.colorbar(sm, cax=cax, orientation="horizontal", cmap=cmap)
                cbar.outline.set_visible(rjx_colorbar_outline)
                cbar.ax.set_title(
                    rjx_colorbar_label_name, fontsize=rjx_colorbar_label_fontsize
                )
                cbar.ax.tick_params(
                    axis="x",
                    which="major",
                    labelsize=rjx_colorbar_tick_fontsize,
                    rotation=rjx_colorbar_tick_rotation,
                    length=rjx_colorbar_tick_length,
                )
                if vmax < 0.001 or vmax > 1000:  # y轴设置科学计数法
                    cbar.ax.xaxis.set_major_formatter(formatter)
            cbar.set_ticks([vmin, vmax])
            ########################################### rjx_colorbar ###############################################
        return fig
    return lh_parc, rh_parc

plot_macaque_hemi_brain_figure

plot_macaque_hemi_brain_figure(data, hemi='lh', surf='veryinflated', atlas='charm5', vmin=None, vmax=None, cmap='Reds', colorbar=True, colorbar_location='right', colorbar_label_name='', colorbar_label_rotation=0, colorbar_decimals=1, colorbar_fontsize=8, colorbar_nticks=2, colorbar_shrink=0.15, colorbar_aspect=8, colorbar_draw_border=False, title_name='', title_fontsize=15, title_y=0.9)

绘制猕猴大脑单侧(左脑或右脑)表面图,支持多种图谱(CHARM5、CHARM6、BNA、D99)。

Parameters:

Name Type Description Default
data dict[str, float]

包含 ROI 名称及其对应值的字典。

required
hemi str

脑半球选择,支持 "lh"(左脑)或 "rh"(右脑)。默认为 "lh"。

'lh'
surf str

大脑表面类型(如 "veryinflated", "inflated")。默认为 "veryinflated"。

'veryinflated'
atlas str

使用的图谱名称,支持 "charm5", "charm6", "bna", "d99"。默认为 "charm5"。

'charm5'
vmin Num

颜色映射的最小值。可以是整数或浮点数。默认为 None。

None
vmax Num

颜色映射的最大值。可以是整数或浮点数。默认为 None。

None
cmap str

颜色映射方案。默认为 "Reds"。

'Reds'
colorbar bool

是否显示颜色条。默认为 True。

True
colorbar_location str

颜色条的位置。默认为 "right"。

'right'
colorbar_label_name str

颜色条的标签名称。默认为空字符串。

''
colorbar_label_rotation int

颜色条标签的旋转角度。默认为 0。

0
colorbar_decimals int

颜色条刻度的小数位数。默认为 1。

1
colorbar_fontsize int

颜色条标签的字体大小。默认为 8。

8
colorbar_nticks int

颜色条上的刻度数量。默认为 2。

2
colorbar_shrink float

颜色条的缩放比例。默认为 0.15。

0.15
colorbar_aspect int

颜色条的宽高比。默认为 8。

8
colorbar_draw_border bool

是否绘制颜色条边框。默认为 False。

False
title_name str

图形标题。默认为空字符串。

''
title_fontsize int

标题字体大小。默认为 15。

15
title_y float

标题在 y 轴上的位置(范围通常为 0~1)。默认为 0.9。

0.9

Returns:

Type Description
Figure

plt.Figure: 返回一个 matplotlib 的 Figure 对象,表示生成的大脑表面图。

Source code in src/plotfig/brain_surface.py
def plot_macaque_hemi_brain_figure(
    data: dict[str, float],
    hemi: str = "lh",
    surf: str = "veryinflated",
    atlas: str = "charm5",
    vmin: Num | None = None,
    vmax: Num | None = None,
    cmap: str = "Reds",
    colorbar: bool = True,
    colorbar_location: str = "right",
    colorbar_label_name: str = "",
    colorbar_label_rotation: int = 0,
    colorbar_decimals: int = 1,
    colorbar_fontsize: int = 8,
    colorbar_nticks: int = 2,
    colorbar_shrink: float = 0.15,
    colorbar_aspect: int = 8,
    colorbar_draw_border: bool = False,
    title_name: str = "",
    title_fontsize: int = 15,
    title_y: float = 0.9,
) -> plt.Figure:
    """
    绘制猕猴大脑单侧(左脑或右脑)表面图,支持多种图谱(CHARM5、CHARM6、BNA、D99)。

    Args:
        data (dict[str, float]): 包含 ROI 名称及其对应值的字典。
        hemi (str, optional): 脑半球选择,支持 "lh"(左脑)或 "rh"(右脑)。默认为 "lh"。
        surf (str, optional): 大脑表面类型(如 "veryinflated", "inflated")。默认为 "veryinflated"。
        atlas (str, optional): 使用的图谱名称,支持 "charm5", "charm6", "bna", "d99"。默认为 "charm5"。
        vmin (Num, optional): 颜色映射的最小值。可以是整数或浮点数。默认为 None。
        vmax (Num, optional): 颜色映射的最大值。可以是整数或浮点数。默认为 None。
        cmap (str, optional): 颜色映射方案。默认为 "Reds"。
        colorbar (bool, optional): 是否显示颜色条。默认为 True。
        colorbar_location (str, optional): 颜色条的位置。默认为 "right"。
        colorbar_label_name (str, optional): 颜色条的标签名称。默认为空字符串。
        colorbar_label_rotation (int, optional): 颜色条标签的旋转角度。默认为 0。
        colorbar_decimals (int, optional): 颜色条刻度的小数位数。默认为 1。
        colorbar_fontsize (int, optional): 颜色条标签的字体大小。默认为 8。
        colorbar_nticks (int, optional): 颜色条上的刻度数量。默认为 2。
        colorbar_shrink (float, optional): 颜色条的缩放比例。默认为 0.15。
        colorbar_aspect (int, optional): 颜色条的宽高比。默认为 8。
        colorbar_draw_border (bool, optional): 是否绘制颜色条边框。默认为 False。
        title_name (str, optional): 图形标题。默认为空字符串。
        title_fontsize (int, optional): 标题字体大小。默认为 15。
        title_y (float, optional): 标题在 y 轴上的位置(范围通常为 0~1)。默认为 0.9。

    Returns:
        plt.Figure: 返回一个 matplotlib 的 Figure 对象,表示生成的大脑表面图。
    """

    # 设置必要文件路径
    current_dir = op.dirname(__file__)
    neuromaps_data_dir = op.join(current_dir, "data/neurodata")
    if atlas == "charm5":
        lh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/macaque_CHARM5/L.charm5.label.gii",
        )
        rh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/macaque_CHARM5/R.charm5.label.gii",
        )
        df = pd.read_csv(
            op.join(current_dir, "data/atlas_tables", "macaque_charm5.csv")
        )
    elif atlas == "charm6":
        lh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/macaque_CHARM6/L.charm6.label.gii",
        )
        rh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/macaque_CHARM6/R.charm6.label.gii",
        )
        df = pd.read_csv(
            op.join(current_dir, "data/atlas_tables", "macaque_charm6.csv")
        )
    elif atlas == "bna":
        lh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/macaque_BNA/L.charm5.label.gii",
        )
        rh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/macaque_BNA/R.charm5.label.gii",
        )
        df = pd.read_csv(op.join(current_dir, "data/atlas_tables", "macaque_bna.csv"))
    elif atlas == "d99":
        lh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/macaque_D99/L.d99.label.gii",
        )
        rh_atlas_dir = op.join(
            neuromaps_data_dir,
            "atlases/macaque_D99/R.d99.label.gii",
        )
        df = pd.read_csv(op.join(current_dir, "data/atlas_tables", "macaque_d99.csv"))
    # 获取文件Underlay
    lh = op.join(
        neuromaps_data_dir, f"surfaces/macaque_BNA/civm.L.{surf}.32k_fs_LR.surf.gii"
    )
    rh = op.join(
        neuromaps_data_dir, f"surfaces/macaque_BNA/civm.R.{surf}.32k_fs_LR.surf.gii"
    )
    if hemi == "lh":
        p = Plot(lh, size=(800, 400), zoom=1.2)
    elif hemi == "rh":
        p = Plot(rh, size=(800, 400), zoom=1.2)
    # 将原始数据拆分成左右脑数据
    lh_data, rh_data = {}, {}
    for roi in data:
        if "lh_" in roi:
            lh_data[roi] = data[roi]
        elif "rh_" in roi:
            rh_data[roi] = data[roi]
    # 加载分区数据
    lh_roi_list, rh_roi_list = (
        list(df["ROIs_name"])[0 : int(len(df["ROIs_name"]) / 2)],
        list(df["ROIs_name"])[int(len(df["ROIs_name"]) / 2) : len(df["ROIs_name"])],
    )
    # 处理左脑数据
    lh_parc = nib.load(lh_atlas_dir).darrays[0].data
    roi_vertics = {roi: [] for roi in lh_roi_list}
    for vertex_index, label in enumerate(lh_parc):
        if label - 1 >= 0:
            roi_vertics[lh_roi_list[label - 1]].append(vertex_index)
    lh_parc = np.full(lh_parc.shape, np.nan)
    for roi in lh_data:
        lh_parc[roi_vertics[roi]] = lh_data[roi]
    # 处理右脑数据
    rh_parc = nib.load(rh_atlas_dir).darrays[0].data
    roi_vertics = {roi: [] for roi in rh_roi_list}
    for vertex_index, label in enumerate(rh_parc):
        if label - len(lh_roi_list) - 1 >= 0:
            roi_vertics[rh_roi_list[label - len(lh_roi_list) - 1]].append(vertex_index)
    rh_parc = np.full(rh_parc.shape, np.nan)
    for roi in rh_data:
        rh_parc[roi_vertics[roi]] = rh_data[roi]
    # 画图元素参数设置
    if vmin is None:
        vmin = min(data.values())
    if vmax is None:
        vmax = max(data.values())
    if vmin > vmax:
        print("vmin必须小于等于vmax")
        return
    if vmin == vmax:
        vmin = min(0, vmin)
        vmax = max(0, vmax)
    # colorbar参数设置
    colorbar_kws = {
        "location": colorbar_location,
        "label_direction": colorbar_label_rotation,
        "decimals": colorbar_decimals,
        "fontsize": colorbar_fontsize,
        "n_ticks": colorbar_nticks,
        "shrink": colorbar_shrink,
        "aspect": colorbar_aspect,
        "draw_border": colorbar_draw_border,
    }
    if hemi == "lh":
        p.add_layer(
            {"left": lh_parc},
            cbar=colorbar,
            cmap=cmap,
            color_range=(vmin, vmax),
            cbar_label=colorbar_label_name,
            zero_transparent=False,
        )
    else:
        p.add_layer(
            {"left": rh_parc},
            cbar=colorbar,
            cmap=cmap,
            color_range=(vmin, vmax),
            cbar_label=colorbar_label_name,
            zero_transparent=False,
        )  # 很怪,但是这里就是写“{'left': rh_parc}”
    fig = p.build(cbar_kws=colorbar_kws)
    fig.suptitle(title_name, fontsize=title_fontsize, y=title_y)
    return fig

plotfig.brain_connection

plot_brain_connection_figure

plot_brain_connection_figure(connectome, lh_surfgii_file=None, rh_surfgii_file=None, niigz_file=None, nodes_name=None, nodes_size=5, nodes_color=None, output_file=None, scale_method='', line_width=10)

绘制大脑连接图,保存在指定的html文件中

Parameters:

Name Type Description Default
connectome NDArray

连接矩阵

required
lh_surfgii_file str | Path | None

左脑surf.gii文件. Defaults to None.

None
rh_surfgii_file str | Path | None

右脑surf.gii文件. Defaults to None.

None
niigz_file str | Path | None

图集nii文件. Defaults to None.

None
nodes_name List[str] | None

节点名称. Defaults to None.

None
nodes_size Num

节点大小. Defaults to 5.

5
nodes_color List[str] | None

节点颜色. Defaults to None.

None
output_file str | Path | None

保存的完整路径及文件名. Defaults to None.

None
scale_method str

连接scale的形式. Defaults to "".

''
line_width Num

连接粗细. Defaults to 10.

10

Raises:

Type Description
ValueError

参数参数取值不合法时抛出.

Source code in src/plotfig/brain_connection.py
def plot_brain_connection_figure(
    connectome: npt.NDArray,
    lh_surfgii_file: str | Path | None = None,
    rh_surfgii_file: str | Path | None = None,
    niigz_file: str | Path | None = None,
    nodes_name: list[str] | None = None,
    nodes_size: Num = 5,
    nodes_color: list[str] | None = None,
    output_file: str | Path | None = None,
    scale_method: str = "",
    line_width: Num = 10,
) -> None:
    """绘制大脑连接图,保存在指定的html文件中

    Args:
        connectome (npt.NDArray): 连接矩阵
        lh_surfgii_file (str | Path | None, optional): 左脑surf.gii文件. Defaults to None.
        rh_surfgii_file (str | Path | None, optional): 右脑surf.gii文件. Defaults to None.
        niigz_file (str | Path | None, optional): 图集nii文件. Defaults to None.
        nodes_name (List[str] | None, optional): 节点名称. Defaults to None.
        nodes_size (Num, optional): 节点大小. Defaults to 5.
        nodes_color (List[str] | None, optional): 节点颜色. Defaults to None.
        output_file (str | Path | None, optional): 保存的完整路径及文件名. Defaults to None.
        scale_method (str, optional): 连接scale的形式. Defaults to "".
        line_width (Num, optional): 连接粗细. Defaults to 10.

    Raises:
        ValueError: 参数参数取值不合法时抛出.
    """

    nodes_num = connectome.shape[0]
    # 默认参数
    current_dir = op.dirname(__file__)
    neuromaps_data_dir = op.join(current_dir, "data/neurodata")

    if lh_surfgii_file is None:
        lh_surfgii_file = op.join(
            neuromaps_data_dir, "surfaces/macaque_NMT2/L.mid_surface.surf.gii"
        )
    if rh_surfgii_file is None:
        rh_surfgii_file = op.join(
            neuromaps_data_dir, "surfaces/macaque_NMT2/R.mid_surface.surf.gii"
        )
    if niigz_file is None:
        niigz_file = op.join(
            neuromaps_data_dir,
            "volumes/macaque_NMT2/CHARM5_add_13_sgms_asym.nii.gz",
        )
        df = pd.read_csv(
            op.join(current_dir, "data/atlas_tables/macaque_charm5_add_13_sgms.csv")
        )
        nodes_name = df["ROIs_name"].values
    else:
        if nodes_name is None:
            nodes_name = [f"ROI-{i}" for i in range(nodes_num)]
    if nodes_color is None:
        nodes_color = ["white"] * len(nodes_name)
    if output_file is None:
        timestamp = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
        output_file = op.join(f"./{timestamp}.html")
        print(f"由于没有指定保存路径,将默认保存为当前目录下 {timestamp}.html 文件中")

    # 加载suface文件
    vertices_L = nib.load(lh_surfgii_file).darrays[0].data
    faces_L = nib.load(lh_surfgii_file).darrays[1].data
    vertices_R = nib.load(rh_surfgii_file).darrays[0].data
    faces_R = nib.load(rh_surfgii_file).darrays[1].data
    # 左半球
    mesh_L = go.Mesh3d(
        x=vertices_L[:, 0],
        y=vertices_L[:, 1],
        z=vertices_L[:, 2],
        i=faces_L[:, 0],
        j=faces_L[:, 1],
        k=faces_L[:, 2],
        color="white",
        opacity=0.1,
        flatshading=True,
        lighting={"ambient": 0.7, "diffuse": 0.3},
        name="Left Hemisphere",
    )
    # 右半球
    mesh_R = go.Mesh3d(
        x=vertices_R[:, 0],
        y=vertices_R[:, 1],
        z=vertices_R[:, 2],
        i=faces_R[:, 0],
        j=faces_R[:, 1],
        k=faces_R[:, 2],
        color="white",
        opacity=0.1,
        flatshading=True,
        lighting={"ambient": 0.7, "diffuse": 0.3},
        name="Right Hemisphere",
    )
    fig = go.Figure(data=[mesh_L, mesh_R])  # 同时添加两个Mesh

    # 读取图集文件并提取ROI质心
    atlas_data = nib.load(niigz_file).get_fdata()
    affine = nib.load(niigz_file).affine
    # 获取所有ROI标签(排除背景0)
    roi_labels = np.unique(atlas_data)
    roi_labels = roi_labels[roi_labels != 0]
    # 计算每个ROI的质心(体素坐标系)
    centroids_voxel = []
    for label in roi_labels:
        mask = (atlas_data == label).astype(int)
        com = center_of_mass(mask)  # 这是一个xyz坐标
        centroids_voxel.append(com)
    # 将质心从体素坐标转换为真实空间坐标
    centroids_real = []
    for coord in centroids_voxel:
        # 转换为齐次坐标并应用仿射变换
        voxel_homogeneous = np.array([coord[0], coord[1], coord[2], 1])
        real_coord = np.dot(affine, voxel_homogeneous)[:3]
        centroids_real.append(real_coord)
    centroids_real = np.array(centroids_real)

    # 绘制节点
    fig.add_trace(
        go.Scatter3d(
            x=centroids_real[:, 0],
            y=centroids_real[:, 1],
            z=centroids_real[:, 2],
            mode="markers+text",
            marker={
                "size": nodes_size,  # 球体大小
                "color": nodes_color,  # 根据ROI标签分配颜色
                "colorscale": "Rainbow",  # 颜色映射方案
                "opacity": 0.8,
                "line": {"width": 2, "color": "black"},  # 球体边框
            },
            text=[f"{name}" for name in nodes_name],  # 悬停显示标签
            hoverinfo="text+x+y+z",
            showlegend=False,  # 显示在图例中
        )
    )

    # 计算最大连接强度
    if np.all(connectome == 0):
        pass
    else:
        connectome_without_0 = connectome.ravel()[(connectome.ravel() != 0)]
        max_strength = np.abs(connectome_without_0).max()
        # min_strength = np.abs(connectome_without_0).min()

        for i in range(nodes_num):
            for j in range(i + 1, nodes_num):
                value = connectome[i, j]
                if value == 0:
                    continue

                match scale_method:
                    case "width":
                        if value > 0:
                            each_line_color = "#ff0000"
                            each_line_width = (value / max_strength) * line_width
                        elif value < 0:
                            each_line_color = "#0000ff"
                            each_line_width = (-value / max_strength) * line_width
                    case "color":
                        value = value / max_strength  # 缩放到[-1, 1]
                        each_line_width = line_width
                        each_line_color = mcolors.to_hex(
                            cm.bwr(mcolors.Normalize(vmin=-1, vmax=1)(value))
                        )
                        # each_line_color = eval(f"mcolors.to_hex(cm.{cmap}(mcolors.Normalize(vmin=-1, vmax=1)(value)))")
                    case "width_color" | "color_width":
                        value = value / max_strength  # 缩放到[-1, 1]
                        if value > 0:
                            each_line_width = value * line_width
                        elif value < 0:
                            each_line_width = -value * line_width
                        each_line_color = mcolors.to_hex(
                            cm.bwr(mcolors.Normalize(vmin=-1, vmax=1)(value))
                        )
                        # each_line_color = eval(f"mcolors.to_hex(cm.{cmap}(mcolors.Normalize(vmin=-1, vmax=1)(value)))")
                    case "":
                        each_line_width = line_width
                        if value > 0:
                            each_line_color = "#ff0000"
                        elif value < 0:
                            each_line_color = "#0000ff"
                    case _:
                        raise ValueError(
                            "参数 scale_method 必须是 '', 'width', 'color', 'width_color' 或 'color_width'"
                        )

                # 创建单个线段的坐标数据(包含None分隔符)
                connection_line = np.array(
                    [
                        centroids_real[i],
                        centroids_real[j],
                        [None] * 3,  # 添加分隔符确保线段独立
                    ]
                )
                # 添加单独trace
                fig.add_trace(
                    go.Scatter3d(
                        x=connection_line[:, 0],
                        y=connection_line[:, 1],
                        z=connection_line[:, 2],
                        mode="lines",
                        line={
                            "color": each_line_color,
                            "width": each_line_width,  # 动态设置线宽
                        },
                        hoverinfo="none",
                        name=f"{nodes_name[i]}-{nodes_name[j]}",
                    )
                )

    # 原质心球体代码保持不变(建议调整颜色增强对比度)
    fig.update_traces(
        selector={"mode": "markers"},  # 仅更新质心球体
        marker={
            "size": 10,  # 增大球体尺寸
            "colorscale": "Viridis",  # 改用高对比度色阶
            "line": {"width": 3, "color": "black"},
        },
    )
    # 设置布局
    fig.update_layout(
        title="Connection",
        scene={
            "xaxis": {"showbackground": False, "visible": False},
            "yaxis": {"showbackground": False, "visible": False},
            "zaxis": {"showbackground": False, "visible": False},
            "aspectmode": "data",  # 保持坐标轴比例一致
        },
        margin={"l": 0, "r": 0, "b": 0, "t": 30},
    )
    # 显示或保存为HTML
    fig.write_html(output_file)  # 导出为交互式网页

    return