Python,Matplotlib水平条形图

dced5bon  于 2023-04-21  发布在  Python
关注(0)|答案(1)|浏览(153)

如何在x轴上的不同位置开始水平条?只要在条的开始处留出x天的空白就可以了。我可能需要使用ax.broken_barh来修改它,但这似乎是大量的工作,而且仅仅是让项目在不同的日子开始就需要两倍的数据。我可以在开始处设置一个指定宽度的白色部分吗?

import numpy as np
import matplotlib.pyplot as plt

#Types of work:
category_names = ['Excavation & Foundation', 'Exterior Framing',
                  'Roofing', 'Interior Framing', 'Drywall, Finish & Painting']

#crew days needed on project:
days = {
    '':[0,0,0,0,0],    #this works for creating space at top
    'Proj 1 budget': [10, 15, 7, 32, 26],
    'Proj 1  actual': [10, 14, 7, 30, 28], 
                                           
    'Proj 2 budget': [15, 20, 8, 30, 20],
    'Proj 2  actual': [15, 19, 8, 28, 20], 
                         
    'Proj 3 budget': [7, 15, 5, 20, 20],
    'Proj 3  actual': [7, 14, 5, 19, 20],
    
}

def crew(days, category_names):
   
    labels = list(days.keys())
    data = np.array(list(days.values()))
    data_cum = data.cumsum(axis=1)
    category_colors = plt.colormaps['RdYlGn'](
        np.linspace(0.15, 0.95, data.shape[1]))

    fig, ax = plt.subplots(figsize=(10.4, 4.5))  #set graph lenght & widwth 
    ax.invert_yaxis()
    ax.xaxis.set_visible(True)
    title = ax.set_title('Tasks and Crew-Days')
    title.set_position([0.5, 1.0])               #set title at center
    ax.set_xlim(0, np.sum(data, axis=1).max())
    plt.xlabel('Total Days')
    

    for i, (colname, color) in enumerate(zip(category_names, category_colors)):
        widths = data[:, i]
        starts = data_cum[:, i] - widths
        rects = ax.barh(labels, widths, left=starts, height=0.75,  #bar heigth
                        label=colname, color=color)
        r, g, b, _ = color
        text_color = 'white' if r * g * b < 0.1 else 'black' #use one or the other
        #text_color = 'black'                                  #of these lines
        ax.bar_label(rects, label_type='center', color=text_color) 
        ax.legend(ncols=len(category_names), bbox_to_anchor=(1.0, 1.00),
            loc='upper right', fontsize='small')
  
    return fig, ax

crew(days, category_names)
plt
plt.show()

b1payxdu

b1payxdu1#

我放弃了,用broken_barh重新写了一遍:

import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.patches import Patch

# Define the data as a dictionary
data = {
    'x_values': [[(10, 20), (30, 10), (40, 10), (50, 10), (60, 10)],
                 [(10, 18), (28, 17), (45, 5), (50, 20), (70, 15)],
                 [(15, 15), (30, 10), (40, 15), (55, 25), (80, 10)],
                 [(15, 15), (30, 12), (42, 10), (52, 20), (72, 13)],
                 [(20, 12), (32, 10), (42, 15), (57, 18), (75, 20)],
                 [(20, 14), (34, 10), (44, 16), (60, 20), (80, 15)]],
    'y_values': [(6.0, 2), (8.5, 2), (12.5, 2), (15.0, 2), (19.0, 2), (21.5, 2)]
}

# Define a list of colors and categories for the bars
colors = ('tab:red', 'tab:orange', 'tab:purple', 'tab:blue', 'tab:green')
categories = ('Category 1', 'Category 2', 'Category 3', 'Category 4', 'Category 5')

# Add the colors and categories to each row of the DataFrame
for i in range(len(data['x_values'])):
    data['facecolors'] = [colors] * len(data['x_values'])
    data['categories'] = [categories] * len(data['x_values'])

# Create a pandas DataFrame from the data
df = pd.DataFrame(data)

# Create a new figure and axis
fig, ax = plt.subplots(figsize=(10,6))

# Loop through each row of the DataFrame and plot the broken bar chart
for i, row in df.iterrows():
    ax.broken_barh(row['x_values'], row['y_values'], facecolors=row['facecolors'])

# Create legend entries with color rectangles and category labels
legend_entries = [Patch(facecolor=color, edgecolor='black', label=category) for color, category in zip(colors, categories)]

# Add the legend to the plot
ax.legend(handles=legend_entries, loc='upper right', ncol=5, bbox_to_anchor=(1.0, 1.00))

# Customize the axis labels and limits
ax.set_xlabel('Days')
ax.set_ylabel('Jobs')
ax.set_yticks([7, 9.5, 13.5, 16, 20, 22.5], labels=['#3-actual', '#3-budget',
                                                    '#2-actual', '#2-budget',
                                                    '#1-actual', '#1-budget'])
title = ax.set_title('Tasks and Crew-Days')
title.set_position([0.5, 1.0])               #set title at center
ax.set_ylim(5, 26)
ax.grid(True)

# Display the plot
plt.show()

相关问题