gpt4 book ai didi

python - Matplotlib - 基于数据的动态(条形)图表高度?

转载 作者:行者123 更新时间:2023-12-03 23:19:08 27 4
gpt4 key购买 nike

在使用 matplotlib 挣扎了比我想承认的时间更长的时间之后,我试图在我使用过的几乎任何其他绘图库中做一些轻而易举的事情,我决定向 Stackiverse 寻求一些见解。简而言之,我需要的是创建多个水平条形图,所有条形图都共享 x 轴,y 轴上具有不同数量的值,并且所有条形都具有相同的高度,而图表本身会根据条目。我需要绘制的简化数据结构类似于:

[
{"name": "Category 1", "entries": [
{"name": "Entry 1", "value": 5},
{"name": "Entry 2", "value": 2},
]},
{"name": "Category 2", "entries": [
{"name": "Entry 1", "value": 1},
]},
{"name": "Category 3", "entries": [
{"name": "Entry 1", "value": 1},
{"name": "Entry 2", "value": 10},
{"name": "Entry 3", "value": 4},
]},
]

最接近我想要的结果是使用:

import matplotlib.pyplot as plt

def plot_data(data):
total_categories = len(data) # holds how many charts to create
max_values = 1 # holds the maximum number of bars to create
for category in data:
max_values = max(max_values, len(category["entries"]))
fig = plt.figure(1)
ax = None
for index, category in enumerate(data):
entries = []
values = []
for entry in category["entries"]:
entries.append(entry["name"])
values.append(entry["value"])
if not entries:
continue # do not create empty charts
y_ticks = range(1, len(entries) + 1)
ax = fig.add_subplot(total_categories, 1, index + 1, sharex=ax)
ax.barh(y_ticks, values)
ax.set_ylim(0, max_values + 1) # limit the y axis for fixed height
ax.set_yticks(y_ticks)
ax.set_yticklabels(entries)
ax.invert_yaxis()
ax.set_title(category["name"], loc="left")
fig.tight_layout()

由于 y 限制 (set_ylim()) 设置为数据中的最大条形数,这将保持条形高度相同(至少在整个图中),无论有多少条目具有某个类别。但是,它也会在条目数少于最大数量的类别中留下令人讨厌的差距。或者把一切都放在一个视觉角度,我试图从 得到它。实际 预期 :

IMG LINK

我尝试根据条目数量通过 gridspec 和不同的比例来消除差距,但这最终看起来更加“倾斜”和不一致。我尝试生成多个图表并操纵图形大小,然后在后期处理中将它们拼接在一起,但我找不到一种方法来可靠地使条形高度保持不变,无论数据如何。我确信有一种方法可以从 matplotlib 中的某个晦涩对象中提取精确缩放所需的指标,但在这一点上,如果我尝试跟踪整个绘图过程,恐怕我会继续进行另一次野鹅追逐。

此外,如果可以在数据周围折叠单个子图,我如何根据数据使图形增长?例如,如果我要向上述数据添加第四个类别,而不是让图形“增长”另一个图表的高度,它实际上会缩小所有图表以适应默认图形大小的所有内容。现在,我想我理解了带有轴单位和所有这些的 matplotlib 背后的逻辑,我知道我可以设置图形大小来增加整体高度,但我不知道如何在图表中保持一致,即如何有无论数据如何,条形高度都完全相同?

我真的需要手动绘制所有内容以获得我想要的吗?如果是这样,我可能只是转储整个 matplotlib 包并从头开始创建我自己的 SVG。事后看来,考虑到我在这件事上花费的时间,一开始我可能应该这样做,但现在我太固执了,无法放弃(或者我是可怕的沉没成本谬论的受害者)。

有任何想法吗?

谢谢

最佳答案

我认为同时具有相等的条宽(垂直方向的宽度)和不同的子图大小的唯一方法实际上是手动定位图中的轴。

为此,您可以指定条应该有多大(以英寸为单位)以及要以该条宽度为单位的子图之间的间距。根据这些数字以及要绘制的数据量,您可以计算出以英寸为单位的总图形高度。
然后根据数据量和先前子图中的间距定位每个子图(通过 fig.add_axes )。从而你很好地填满了情节。
添加一组新数据将使图形变大。

data = [
{"name": "Category 1", "entries": [
{"name": "Entry 1", "value": 5},
{"name": "Entry 2", "value": 2},
]},
{"name": "Category 2", "entries": [
{"name": "Entry 1", "value": 1},
]},
{"name": "Category 3", "entries": [
{"name": "Entry 1", "value": 1},
{"name": "Entry 2", "value": 10},
{"name": "Entry 3", "value": 4},
]},
{"name": "Category 4", "entries": [
{"name": "Entry 1", "value": 6},
]},
]

import matplotlib.pyplot as plt
import numpy as np

def plot_data(data,
barwidth = 0.2, # inch per bar
spacing = 3, # spacing between subplots in units of barwidth
figx = 5, # figure width in inch
left = 4, # left margin in units of bar width
right=2): # right margin in units of bar width

tc = len(data) # "total_categories", holds how many charts to create
max_values = [] # holds the maximum number of bars to create
for category in data:
max_values.append( len(category["entries"]))
max_values = np.array(max_values)

# total figure height:
figy = ((np.sum(max_values)+tc) + (tc+1)*spacing)*barwidth #inch

fig = plt.figure(figsize=(figx,figy))
ax = None
for index, category in enumerate(data):
entries = []
values = []
for entry in category["entries"]:
entries.append(entry["name"])
values.append(entry["value"])
if not entries:
continue # do not create empty charts
y_ticks = range(1, len(entries) + 1)
# coordinates of new axes [left, bottom, width, height]
coord = [left*barwidth/figx,
1-barwidth*((index+1)*spacing+np.sum(max_values[:index+1])+index+1)/figy,
1-(left+right)*barwidth/figx,
(max_values[index]+1)*barwidth/figy ]

ax = fig.add_axes(coord, sharex=ax)
ax.barh(y_ticks, values)
ax.set_ylim(0, max_values[index] + 1) # limit the y axis for fixed height
ax.set_yticks(y_ticks)
ax.set_yticklabels(entries)
ax.invert_yaxis()
ax.set_title(category["name"], loc="left")


plot_data(data)
plt.savefig(__file__+".png")
plt.show()

enter image description here

关于python - Matplotlib - 基于数据的动态(条形)图表高度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42191668/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com