• [Python画图][科研可视化]小提琴图变形代码实现


    背景

    一组数据需要实现如下形状。经过辨识应该是小提琴图的变形。需要做些调整才能实现。
    在这里插入图片描述

    数据格式

    name,category,catenum,nums
    123,C,C1,0
    111,C,C2,0
    4223,C,C3,0
    
    • 1
    • 2
    • 3
    • 4

    代码

    import random
    
    import matplotlib.pyplot as plt
    import pandas as pd
    import seaborn as sns
    import warnings
    
    warnings.filterwarnings('ignore')
    
    colors = ["#FADDDD", "#C5D9F0"]
    
    df = pd.read_csv("test.csv")
    # Create the violin plot using catplot
    g = sns.catplot(x="name", y="nums", hue="category",
                    data=df, orient="v", height=4, aspect=3, palette=colors,
                    kind="violin", dodge=True, cut=0, bw=0.5, inner="stick")  # Set inner to None
    
    # Set y-axis limits
    g.set(ylim=(0, df["nums"].max()))  # Set the upper limit to the maximum age in the dataset
    plt.xticks(rotation=45,ha='right')
    
    # 获取每个小提琴的横坐标
    violin_positions = {}
    for i, name in enumerate(df["name"].unique()):
        violin_positions[name] = g.ax.get_xticks()[i]
    
    x_ranges = []
    for ax in g.axes.flat:
        x_ranges.append(ax.get_xlim())
    print(x_ranges)
    # 打印各个小提琴图的横坐标范围
    for i, x_range in enumerate(x_ranges):
        print(f"Category {i+1}: {x_range}")
    
    distance = x_ranges[0][1]-x_ranges[0][0]
    every_dis = round(distance/(16*2),2)
    print(every_dis)
    last_ax = []
    group_by_cate = {}
    category_max = {}
    for index, row in df.iterrows():
        x = row["name"]
        y = row["nums"]
        category = row["category"]
        catenum = row["catenum"]
        temp = {"name": x, "nums": y, "catenum": catenum,"category":category}
        last_ax.append(temp)
        cate_name = x+"-"+str(y)+"-"+category
        cate_name_num = group_by_cate.get(cate_name)
        if cate_name_num == None:
            cate_name_num = 0
        group_by_cate.update({cate_name:cate_name_num+1})
        cate_num = x+"-"+category
        max = category_max.get(cate_num)
        if max is None:
            max = 0
        if max < y:
            max = y
        category_max.update({cate_num:max})
    print(group_by_cate)
    print(category_max)
    last_ax_data = pd.DataFrame(last_ax)
    last_ax_data.to_csv("last_ax.csv")
    
    sc_colors = ['red', 'blue']
    has_draw = {}
    for i in last_ax:
        name = i.get("name")
        y = i.get("nums")
        category = i.get("category")
        cate_name = name + "-" + str(y) + "-" + category
        gory_nums = group_by_cate.get(cate_name)
        cate_num = name+"-"+category
        max = category_max.get(cate_num)
        x = violin_positions.get(name)
        new_x = x
        col = 0
        has_draw_nums = has_draw.get(cate_name)
        size = 21
        if has_draw_nums==None:
            has_draw_nums=0
        if category=="C":
            # c分类的横坐标左移
            if gory_nums == 1:
                new_x = x-round((0.41/2),2)
            elif gory_nums==2:
                new_x = x-round((0.41/2),2)-round(random.uniform(-0.05,0.05),2)
                # y = y + round(random.uniform(-0.2,0.2),2)
            elif gory_nums==3:
                new_x = x-round((0.41/2),2)
                if y == max and y>0:
                    y = y + round(random.uniform(-0.1,0),2)
                elif y!=0:
                    y = y + round(random.uniform(-0.2,0.2),2)
            else:
                if y!=0 and has_draw_nums>=4:
                    continue
                new_x = x-round((0.41/2),2)-round(random.uniform(-0.1,0.1),2)
                if y == max and y!=0:
                    y = y + round(random.uniform(-0.1,0),2)
                elif y!=0:
                    y = y + round(random.uniform(-0.2,0.2),2)
                    size = 50
                if max==0:
                    new_x = x-round((0.41/2),2)-round(random.uniform(-0.18,0.18),2)
                    y = y+0.02
        elif category=="P":
            col = 1
            # p分类的横坐标右移
            if gory_nums == 1:
                new_x = x+round((0.41/2),2)
            elif gory_nums==2:
                new_x = x+round((0.41/2),2)+round(random.uniform(-0.05,0.05),2)
                # y = y + round(random.uniform(-0.2,0.2),2)
            elif gory_nums==3:
                new_x = x+round((0.41/2),2)
                if y == max and y>0:
                    y = y + round(random.uniform(-0.1,0),2)
                elif y!=0:
                    y = y + round(random.uniform(-0.2,0.2),2)
            else:
                if y!=0 and has_draw_nums>=4:
                    continue
                new_x = x+round((0.41/2),2)+round(random.uniform(-0.1,0.1),2)
                if y == max and y>0:
                    y = y + round(random.uniform(-0.1,0),2)
                elif y!=0:
                    y = y + round(random.uniform(-0.2,0.2),2)
                    size = 50
                if max==0:
                    new_x = x+round((0.41/2),2)-round(random.uniform(-0.18,0.18),2)
                    y = y+0.02
        has_draw.update({cate_name:has_draw_nums+1})
    
        plt.scatter(new_x, y, color=sc_colors[col], marker='o', edgecolor=sc_colors[col],s=size,facecolor='none', linewidth=1, alpha=0.5)
        # if gory_nums>3:
    print(has_draw)
        # 根据类别筛选对应的小提琴图范围
    
    # plt.scatter(new_x, y, color='purple', marker='o', edgecolor='purple', linewidth=1, alpha=0.5)
    # for ax in g.axes.flat:
    # 获取小提琴图的限制范围
    # limits = ax.get_xlim()
    # print(limits)
    # 绘制散点图
    # for index, row in processed_data.iterrows():
    #     # 获取散点的位置
    #     x = row["name"]
    #     y = row["nums"]
    #     category = row["category"]
    #
    #     # 根据类别筛选对应的小提琴图范围
    #     if category == "C":
    #         new_x = x - 1  # 向左移动3个位置
    #     elif category == "P":
    #         new_x = x + 1  # 向右移动3个位置
    #     else:
    #         new_x = x
    #
    #     # 在小提琴曲线内部绘制散点图
    #     plt.scatter(new_x, y, color='purple', marker='o', edgecolor='purple', linewidth=1, alpha=0.5)
    
    # Adjust legend location and display
    plt.yticks(range(0, int(df["nums"].max()) + 2, 1))
    plt.subplots_adjust(bottom=0.5)
    plt.show()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
  • 相关阅读:
    SparkSql中的窗口函数
    Clickhouse引擎—数据库引擎
    分布式消息队列RocketMQ介绍
    4.6、在线调试工具 ILA 的使用
    使用AOP进行日志记录
    【退役之重学Java】关于Spring Cloud 微服务和分布式
    nrm 镜像源管理工具
    使用$dispatch接连栽两个跟头!!
    2023年中国儿童滑板车优点、市场规模及发展前景分析[图]
    计算机设计大赛 深度学习实现语义分割算法系统 - 机器视觉
  • 原文地址:https://blog.csdn.net/qq_27695659/article/details/133693456