如何使用多个xaxis数据绘制条形图?

2024-04-19 22:11:04 发布

您现在位置:Python中文网/ 问答频道 /正文

我想用Python绘制一个条形图,类似于Excel。然而,我正努力拥有两个不同的x轴。例如,对于每种大小(如8M),我想绘制所有5种策略的结果。对于每种策略,都有3个指标(适合、启动和扩展)

enter image description here

您可以在此处here下载原始excel文件

这是我目前的代码:

    
df = pd.read_excel("data.xlsx",sheet_name="Sheet1")
r1= df['Fit']
r2= df['Boot']
r3= df['Exp']

x= df['strategy']

n_groups = 5

# create plot
fig, ax = plt.subplots()
index = np.arange(n_groups)
names = ["8M","16M","32M","64M","128M"]

bar_width = 0.1
opacity = 0.8

Fit8= [r1[0],r1[1],r1[2],r1[3],r1[4]]
Boot8= [r2[0],r2[1],r2[2],r2[3],r2[4]]
Exp8= [r3[0],r3[1],r3[2],r3[3],r3[4]]

Fit16= [r1[5],r1[6],r1[7],r1[8],r1[9]]
Boot16= [r2[5],r2[6],r2[7],r2[8],r2[9]]
Exp16= [r3[5],r3[6],r3[7],r3[8],r3[9]]

rects1 = plt.bar(
    index, Fit8, bar_width,
    alpha=opacity,
    color='g',
    label='Fit'
)

rects2 = plt.bar(
    index + 0.1, Boot8, bar_width,
    alpha=opacity,
    color='b',
    label='Boot'
)

rects3 = plt.bar(
    index + 0.2, Exp8, bar_width,
    alpha=opacity,
    color='y',
    label='EXP'
)

rects4 = plt.bar(
    index + 0.5, Fit16, bar_width,
    alpha=opacity,
    color='g'
)

rects5 = plt.bar(
    index + 0.6, Boot16, bar_width,
    alpha=opacity,
    color='b'
)

rects6 = plt.bar(
    index + 0.7, Exp16, bar_width,
    alpha=opacity,
    color='y'
)


plt.xticks(index + 0.2, (names))

plt.legend()
plt.tight_layout()
plt.show()

Tags: alphadfindex绘制barpltwidthexcel
1条回答
网友
1楼 · 发布于 2024-04-19 22:11:04

像这样的

enter image description here

代码如下:

import pandas as pd
import pylab as plt

# read dataframe, take advantage of Multiindex
df = pd.read_excel(
    "data.xlsx",
    sheet_name="Sheet1", engine='openpyxl',
    index_col=[0, 1],
)
# plot the content of the dataframe
ax = df.plot.bar()

# Show minor ticks
ax.minorticks_on()

# Get location of the center of each bar
bar_locations = list(map(lambda x: x.get_x() + x.get_width() / 2., ax.patches))

# Set minor and major tick positions
# Minor are used for S1, ..., S5
# Major for sizes 8M, ..., 128M
# tick locations are sorted according to the 3 metrics, so first all the 25 bars for the fit, then the 25
# for the boot and at the end the 25 for the exp. We set the major tick at the position of the bar at the center
# of the size group, that is the third boot bar of each size.
ax.set_xticks(bar_locations[27:50:5], minor=False)  # use the 7th bar of each size group
ax.set_xticks(bar_locations[len(df):2 * len(df)], minor=True)  # use the bar in the middle of each group of 3 bars

# Labels for groups of 3 bars and for each group of size
ax.set_xticklabels(df.index.get_level_values(0)[::5], minor=False, rotation=0)
ax.set_xticklabels(df.index.get_level_values(1), minor=True, rotation=0)

# Set tick parameters
ax.tick_params(axis='x', which='major', pad=15, bottom='off')
ax.tick_params(axis='x', which='both', top='off')

# You can use a different color for each group
# You can comment out these lines if you don't like it
size_colors = 'rgbym'
# major ticks
for l, c in zip(ax.get_xticklabels(minor=False), size_colors):
    l.set_color(c)
    l.set_fontweight('bold')
# minor ticks
for i, l in enumerate(ax.get_xticklabels(minor=True)):
    l.set_color(size_colors[i // len(size_colors)])

# remove x axis label
ax.set_xlabel('')

plt.tight_layout()
plt.show()

这里的主要思想是使用PandasMultiindex,并进行一些小的调整

编辑 如果需要组之间的空格,可以在数据框中添加虚拟类别(也称为策略)以创建人工空格,获得:

enter image description here

代码如下:

import numpy as np
import pandas as pd
import pylab as plt

# read dataframe, take advantage of Multiindex
df = pd.read_excel(
    "data.xlsx",
    sheet_name="Sheet1", engine='openpyxl',
    index_col=[0, 1],
)
# plot the content of the dataframe
sizes = list(df.index.get_level_values(0).drop_duplicates())
strategies = list(df.index.get_level_values(1).drop_duplicates())
n_sizes = len(sizes)
n_strategies = len(strategies)
n_metrics = len(df.columns)

empty_rows = pd.DataFrame(
    data=[[np.nan] * n_metrics] * n_sizes, index=pd.MultiIndex.from_tuples([(s, 'SN') for s in sizes], names=df.index.names),
    columns=df.columns,
)

old_columns = list(df.columns)
df = df.merge(empty_rows, how='outer', left_index=True, right_index=True, sort=False).drop(
    columns=[f'{c}_y' for c in df.columns]
).sort_index(
    ascending=True, level=0, key=lambda x: sorted(x, key=lambda y: int(y[:-1]))
)
df.columns = old_columns

# Update number of strategies
n_strategies += 1

# Plot with Pandas
ax = df.plot.bar()

# Show minor ticks
ax.minorticks_on()

# Get location of the center of each bar
bar_locations = list(map(lambda x: x.get_x() + x.get_width() / 2., ax.patches))

# Set minor and major tick positions
# Major for sizes 8M, ..., 128M
# Minor are used for S1, ..., S5, SN
# Tick locations are sorted according to the 3 metrics, so first 30 (5 sizes * 6 strategies) bars for the fit,
# then 30 (5 sizes * 6 strategies) for the boot and at the end 30 (5 sizes * 6 strategies) for the exp.
# We set the major tick at the position of the bar at the center of the size group (+7),
# that is the third boot bar of each size.
n_bars_per_metric = n_sizes * n_strategies
strategy_ticks = bar_locations[len(df):2 * len(df)]
strategy_ticks = np.concatenate([strategy_ticks[b * n_strategies:b * n_strategies + n_strategies - 1] for b in range(n_sizes)])  # get only positions of the first 5 bars
size_ticks = strategy_ticks[2::n_sizes] + 0.01

ax.set_xticks(size_ticks, minor=False)  # use the 7th bar of each size group
ax.set_xticks(strategy_ticks, minor=True)  # use the bar in the middle of each group of 3 bars

# Labels for groups of 3 bars and for each group of size
ax.set_xticklabels(sizes, minor=False, rotation=0)
ax.set_xticklabels(strategies * n_sizes, minor=True, rotation=0)

# Set tick parameters
ax.tick_params(axis='x', which='major', pad=15, bottom=False)
ax.tick_params(axis='x', which='both', top=False)

# You can use a different color for each group
# You can comment out these lines if you don't like it
size_colors = 'rgbym'
# major ticks
for l, c in zip(ax.get_xticklabels(minor=False), size_colors):
    l.set_color(c)
    l.set_fontweight('bold')
# minor ticks
for i, l in enumerate(ax.get_xticklabels(minor=True)):
    l.set_color(size_colors[i // len(size_colors)])

# remove x axis label
ax.set_xlabel('')

plt.tight_layout()
plt.show()

如您所见,您必须使用数据帧,添加一些额外的代码。也许有一个更简单的解决方案,但这是我能想到的第一个

相关问题 更多 >