Circular Barplot for 40 Cases by Group

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# Define the number of cases and data points per case
num_cases = 40
data_points_per_case = 10

# Initialize an empty DataFrame to store the data
data = pd.DataFrame()

# Generate data for each specified case
np.random.seed(42)  # For reproducibility

for i in range(1, num_cases + 1):
    if i % 10 in [1, 2, 3, 7, 8]:  # Cases in [0, 6)
        case_data = np.random.uniform(0, 6, data_points_per_case)
    elif i % 10 in [4, 5, 6, 9, 0]:  # Cases in (-6, 0]
        case_data = np.random.uniform(-6, 0, data_points_per_case)

    data[f'S{i:02}'] = case_data

# Color settings
purple_color = '#5654a2'
red_color = 'red'
light_purple_color = '#827dce'

# Define case classes and groups
case_classes = {
    'A': ['S01', 'S02', 'S03', 'S04', 'S05'],
    'B': ['S06', 'S07'],
    'C': ['S08', 'S09', 'S10'],
    'D': ['S11', 'S12', 'S13', 'S14'],
    'E': ['S15', 'S16', 'S17', 'S18', 'S19', 'S20'],
    'F': ['S21', 'S22', 'S23', 'S24', 'S25'],
    'G': ['S26', 'S27'],
    'H': ['S28', 'S29', 'S30'],
    'I': ['S31', 'S32', 'S33', 'S34'],
    'J': ['S35', 'S36', 'S37', 'S38', 'S39', 'S40']
}

group_classes = {
    'G1': ['A', 'B'],
    'G2': ['C', 'D'],
    'G3': ['E'],
    'G4': ['F', 'G'],
    'G5': ['H', 'I'],
    'G6': ['J']
}

# Map case classes to groups
case_to_group = {case: group for group, classes in group_classes.items() for cls in classes for case in case_classes[cls]}
case_to_class = {case: cls for cls, cases in case_classes.items() for case in cases}

# Define group colors for xticks
group_colors = {
    'G1': 'blue',
    'G2': 'green',
    'G3': 'orange',
    'G4': 'purple',
    'G5': 'brown',
    'G6': 'pink'
}

# Prepare data for circular barplot
values = data.mean()  # Using mean values of the cases
categories = data.columns

# Number of variables we're plotting
num_vars = len(categories)

# Compute angle for each category with a 30° gap between S01 and S40
gap_deg = 30
gap_angle = np.deg2rad(gap_deg + 10)
total_angle = 2 * np.pi - gap_angle

angles = np.linspace(total_angle + gap_angle / 2, gap_angle / 2, num_vars, endpoint=False).tolist()

# Plotting
fig, ax = plt.subplots(figsize=(10, 10), subplot_kw=dict(polar=True))

# Add background colors for classes
class_colors = {
    'A': 'lightgray',
    'B': 'white',
    'C': 'lightgray',
    'D': 'white',
    'E': 'lightgray',
    'F': 'white',
    'G': 'lightgray',
    'H': 'white',
    'I': 'lightgray',
    'J': 'white'
}

for i, (angle, case) in enumerate(zip(angles, categories)):
    cls = case_to_class[case]
    color = class_colors[cls]
    ax.bar(angle, 12, width=total_angle / num_vars, color=color, edgecolor='none', alpha=0.5, bottom=-6, zorder=0)

# Make the plot
for i, (angle, value, case) in enumerate(zip(angles, values, categories)):
    if int(case[1:]) % 10 in [1, 2, 3, 7, 8]:  # Cases in [0, 6)
        color = light_purple_color
        edgecolor = purple_color
    else:  # Cases in (-6, 0]
        color = 'lightcoral'
        edgecolor = red_color

    ax.bar(angle, value, width=total_angle / num_vars, color=color, edgecolor=edgecolor, alpha=0.7, zorder=1)

# Add labels
y_ticks = [ -6, -4, -2, 0, 2, 4, 6]
ax.set_yticks(y_ticks)
ax.set_yticklabels([f'{tick}' for tick in y_ticks], fontsize=10)

ax.set_xticks(angles)
ax.set_xticklabels(categories, fontsize=10)

# Customize labels color based on group
for label, angle in zip(ax.get_xticklabels(), angles):
    case = label.get_text()
    group = case_to_group[case]  # Get the group from the case
    label.set_color(group_colors[group])

# Add class and group labels
displayed_classes = set()
displayed_groups = set()

for angle, case in zip(angles, categories):
    case_class = case_to_class[case]
    group = case_to_group[case]
    if case_class not in displayed_classes:
        ax.text(angle, max(y_ticks) + 1.5, case_class, horizontalalignment='center', size=10, color=group_colors[group], weight='semibold')
        displayed_classes.add(case_class)

    if group not in displayed_groups:
        ax.text(angle, max(y_ticks) + 3, group, horizontalalignment='center', size=12, color=group_colors[group], weight='semibold')
        displayed_groups.add(group)

# Set the start angle to make S01 at 0.5 * np.pi and leave 30° gap
ax.set_theta_offset(0.5 * np.pi + gap_angle / 2)
ax.set_thetamin(gap_deg * 2 / 5)  # Start angle in degrees
ax.set_thetamax(360 - gap_deg * 2 / 5)  # End angle in degrees

# Set a minimum radius to create an empty inner ring
ax.set_ylim(-10, 6)

# plt.title('Circular Barplot for 40 Cases by Group')
plt.show()

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值