当前位置: 首页 > 面试题库 >

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

江仲渊
2023-03-14
问题内容

在尝试与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链接

我尝试根据条目数的不同通过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()

在此处输入图片说明



 类似资料:
  • 问题内容: 我正在使用json数据创建列类型图。这是我调用的JS函数,用于使用ajax调用获取数据并绘制图表。 如果计数大于特定值(例如10),我希望能够在一天中修改条形的颜色。 这就是json输入到函数的方式。 任何建议我该怎么做? 问题答案: 您可以使用颜色区域(API)根据列的值来具有不同的颜色。 值低于/高于10的示例具有不同的颜色(JSFiddle):

  • 我想要一张堆叠的条形图,那里有一条阈值线。阈值线以上的条色应为红色,阈值线以下的条色应为绿色。问题是,阈值不是恒定的,对于每个x值,它可能有不同的值。我想随时更新这个阈值,以获得某个x值。如何做到这一点?很明显,柱状图的y参数应该是动态的,也许我应该为它们传递一个函数?请帮我做这个。我也认为阈值应该是一个函数,因为我会更新它

  • 场景- > TableView高度是使用纵横比相对于superview的高度动态设置的。 TableViewCell的高度是根据表格视图的高度计算的: 问题 - 最初在委托方法中没有正确计算表格视图高度。但在滚动单元格后正确计算。 尝试的解决方案: 在视图中重新加载。 调用 在单元格中进行. 有什么方法可以正确计算出这个表格的高度吗?

  • 我有一个数据框架,df,就像: 我想绘制两个垂直条形图,每个大陆一个,并排,共享相同的y轴。我已经完成了90%的工作,除了将条的高度添加到子图中。到目前为止,我的代码: 我在这里和那里看到过带有标签的示例,但这些往往只适用于一个条形图,而不是几个子图。

  • 本文向大家介绍利用matplotlib实现根据实时数据动态更新图形,包括了利用matplotlib实现根据实时数据动态更新图形的使用技巧和注意事项,需要的朋友参考一下 我就废话不多说了,直接上代码吧! 二 运行结果 以上这篇利用matplotlib实现根据实时数据动态更新图形就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持呐喊教程。

  • 我正在尝试使用matplotlib创建条形图。 x轴数据是带有年份的列表:[19501960、19701、980、19901、995-2015] y轴数据是一个数量与年数相等的列表。 这是我的代码: 结果是:条与条之间有太多的空间 正如你所看到的,1950-1960年之间的差距是巨大的。我怎么能做到这一点,这样1950-1995年酒吧之间就没有间隙。我知道它的间隔为10年,但看起来并不好。 任何帮