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. misc<span style='color:red;'>40</span>

    misc40

    2024-07-14 08:54:02      40 阅读
  2. leetcode40

    2024-07-14 08:54:02       34 阅读
  3. 40. 组合总和 II

    2024-07-14 08:54:02       55 阅读
  4. leetcode(402,44 53)

    2024-07-14 08:54:02       57 阅读
  5. day40_mysql

    2024-07-14 08:54:02       35 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-14 08:54:02       66 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-14 08:54:02       70 阅读
  3. 在Django里面运行非项目文件

    2024-07-14 08:54:02       57 阅读
  4. Python语言-面向对象

    2024-07-14 08:54:02       68 阅读

热门阅读

  1. RabbitMQ的工作模式

    2024-07-14 08:54:02       17 阅读
  2. 跨域问题出现的原因,怎么解决?

    2024-07-14 08:54:02       21 阅读
  3. Isaac sim中使用不同的backone

    2024-07-14 08:54:02       17 阅读
  4. Python中的pytest的使用

    2024-07-14 08:54:02       26 阅读
  5. Power BI 工具介绍

    2024-07-14 08:54:02       24 阅读
  6. 【C语言】多线程服务器

    2024-07-14 08:54:02       22 阅读
  7. 数学建模如何创新

    2024-07-14 08:54:02       27 阅读
  8. 【Qt】使用临时对象的坑

    2024-07-14 08:54:02       21 阅读
  9. C++智能指针的用法

    2024-07-14 08:54:02       23 阅读
  10. vue怎样自定义指令?

    2024-07-14 08:54:02       21 阅读