matplotlib使用案例3:通过自定义图例类实现图例的任意方向(行 or 列)的排列

这个方法的核心依然是基于matplotlib.legend._get_legend_handles_labels函数。然后将得到的handlers, labels进行重排,使得即使再调用Legend类的绘制方法对图例进行列排列,最终的效果也是图例的行显示,如[1、2、3、4、5、6],当指定ncols=2Legend类的绘制方法得到的图例如下:

1	4
2	5
3	6

如果要实现J借助Legend类的绘制方法得到如下图例:

1	2
3	4
5	6

可以可以发现,将[1、2、3、4、5、6]重排为[1,3,5,4,5,6]即可。这里算法就是先按照行切分的方式将原始的handlers变为(-1,ncols)的2d列表(简单的表示矩阵),然后进行列扫描就行。但是这样要先遍历获取得2d列表的子列表的index=0的元素,然后是index=1,2,…, ncols-1处的元素。由于,这样不利于编程,所以就将2D进行转置,然后进行行扫描,即(列扫描)

# -*- coding: utf-8 -*-
'''
@Time    : 2024/1/5 20:25  \n
@Author  : 月司   \n
@Email   : 815603884@qq.com \n
@File    : legend的横向显示.py   \n
@version : 1.0  \n
@Software: PyCharm  \n
@Desc    : 
'''
from typing import List, Any

import matplotlib.pyplot as plt
# 创建一个新的图例对象
from matplotlib.legend import Legend
import matplotlib.axes as axes

#这个函数可以获得axis对象的已经绘制的artist中的所有的hander和labels,这个可以只给它一个axis参数。注意这个参数需要是列表类的。
from matplotlib.legend import _get_legend_handles_labels as get_legend_handles_labels

# 自定义图例对象
class CustomLegend(Legend):
    def __init__(self, ax:axes.Axes,
                 handlers: List[Any]=None,
                 labels: List[str]=None,
                 horizontal:bool=False,
                 loc:str=None, ncols:int=1, **kwargs):
        if (handlers is None) != (labels is None):  # Check if only one of handlers or labels is provided
            raise ValueError("Both 'handlers' and 'labels' must be specified if one is provided.")

        if (handlers is None) and (labels is None):  # get default handlers and labels from ax
            # 获取当前轴的句柄和标签
            handlers, labels = get_legend_handles_labels(axs=[ax])  # note:  the param axs is list object
        if horizontal:
            handles, labels = map(lambda lst: self.transform_list_to_2d(lst, ncols), [handlers, labels])

        super().__init__(parent=ax, handles=handlers, labels=labels, loc=loc, ncols=ncols, **kwargs)

    def transform_list_to_2d(self,lst, ncol):
        """
        Transform a list into a 2D list and merge elements by indices.

        :param lst: The original list.
        :param ncol: Number of columns,i.e., number of elements per sublist in the 2D list.
        :return: origin_2D new list containing merged elements from the 2D list.
        """
        # 将原始列表转换为二维列表,安按照想要的横向序列切分handlers
        origin_2D = [lst[i:i + ncol] for i in range(0, len(lst), ncol)]
        nrow = len(origin_2D)
        # 简单的先给子列表填充None,这样就是一个矩阵了
        for sub_list in origin_2D:
            # 其实一般都是最后一行空缺
            append_nums = ncol - len(sub_list)
            for i in range(append_nums):
                sub_list.append(None)
        reset_list = []
        # 这里就是完成了形式上转置,实际上没有转置后的列表(矩阵),然后根据转置前后的列和行互换,直接找到对应的转置前的元素
        reset_ncol = nrow
        rest_nrow = ncol
        for row in range(rest_nrow):
            for col in range(reset_ncol):
                # 对于原始的数据就是列扫描
                _item = origin_2D[col][row]
                if _item:
                    reset_list.append(_item)
        return reset_list

if __name__ == '__main__':
    # 示例使用这个函数
    fig, ax = plt.subplots()
    handlers = [ax.scatter(range(10), [i * x for x in range(10)], label=f'Line {i}') for i in range(6)]
    labels=[f'label {i}' for i in range(7)]
    # 创建一个自定义图例
    #leg=CustomLegend(ax, loc='upper left', ncols=2,horizontal=True)
    leg=ax.legend(ncols=2)
    ax.add_artist(leg)

    # 显示图表
    plt.show()

实际上这个直接进行列扫描也是可以的。

得到的效果如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
从上面可以看到横向的图例的布局和竖向图例的布局是一模一样的,但是图例的排序数据变了。另外就是ncols始终控制着图例的列数。这个跟方法1不一样之处,是方法1始终是最后一行或者一列有空缺,而这里明显布局更佳均衡。但是方法1可以更加灵活,比如添加title。

方法1:motplotlib图例案例1:通过多个legend完全控制图例显示顺序(指定按行排序 or 按列排序)

ncols=2的例子:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

月司

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值