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

name,category,catenum,nums
123,C,C1,0
111,C,C2,0
4223,C,C3,0
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()