如何用箭头填充pyplot条形图的条形图?

2024-09-26 22:53:37 发布

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

我试图创建一个条形图,其中的条形图通过让条内的箭头指向基点来包含其他信息。在

现在,我只能用彩色条创建一个。因为方向需要8种颜色加上一种不存在的颜色,这并不像我希望的那样好。也有区分颜色的困难。在

import matplotlib.pyplot as plt
import numpy as np

x = range(12)
y_bar = np.random.random(12)

colors = ['green', 'yellow', 'blue', 'pink', 'orange']
bar_cols = [ colors[int(b*100) % len(colors)] for b in y_bar]

plt.bar(x, y_bar, color=bar_cols)
plt.show()

因此,箭头指向一个由单独变量提供的方向,是直观和容易看到的。在

我不知道怎么做。我已经尝试过使用图案填充,但似乎只有有限的一组符号。在

有没有办法在酒吧里放些箭?在

编辑: 这是一个pciture,它看起来像什么,我要的是什么。箭头的形状可以不同。当然,预计还会有更多的支柱。由于任务数据的原因,甚至有一些没有箭头。 barchar with arrows


Tags: import颜色asnpbarpltrandom箭头
2条回答

在条形图中绘制箭头的一个选择就是填充。不过,这有点牵扯。我们需要创建一些自定义图案填充,如下所示:How to fill a polygon with a custom hatch in matplotlib?在这里我们可以使用箭头的路径。在

因此,在下面,我们将matplotlib.hatch.Shapes子类化并创建一个箭头的路径。现在的问题是我们需要一些参数来插入到阴影中,以便能够定义角度。然后我们可以定义一个自定义的图案填充图案,我选择这样

hatch="arr{angle}{size}{density}"

在哪里

  • 角度:0到360之间的整数
  • 大小:2到20之间的整数
  • 密度:一些整数>;=1

这与我之前在this question上的回答类似。 根据路径旋转的角度,大小和密度基本上决定了显示多少个箭头大小。注意,不是所有的参数看起来都很好,有些参数会导致图案填充重叠。在

^{pr2}$

{angle}{9}{3}的输出:

enter image description here

{angle}{11}{2}的输出:

enter image description here


下面是关于填充图案及其管理方式的说明。或者换句话说,ArrowHatch如何知道它应该创建一个图案填充?
将使用matplotlib.hatch._hatch_types内任何图案填充的顶点应用图案填充。这就是为什么我们需要将ArrowHatch类附加到这个列表中。根据这个类的属性num_vertices是否大于零,它将有助于最终的图案填充。这就是为什么我们在init函数中将其设置为self.num_lines = 0。但是,如果提供给_hatch_types列表中每个类的字符串hatch包含我们的匹配模式,那么我们将self.num_rows设置为0以外的值(对于形状,它应该是一个偶数,因为它们是在2个移位的行中生成的),这样它就有助于填充。
这个概念有点异国情调,因为基本上每个类本身都根据hatch字符串自行决定是否参与图案填充。一方面,这是非常方便的,因为它可以很容易地组合不同的图案填充类型,例如"///++oo"。另一方面,它使它很难用于图案填充,它需要一个输入参数,如本例中的角度。而且还需要注意不要在图案填充中使用任何字符,这是其他图案填充所使用的;例如,我最初想使用类似于"arrow45.8,9,2"的东西,因为o.和{}是其他有效的图案填充类型,因此结果会显示到处都是点。

这里有一个解决方案,它使用ax.annotate在每个条内绘制箭头。由于OP不太清楚箭头应该是什么样子,所以我把每个条分成矩形(在代码中我称它们为squares,但如果你确定了绘图的纵横比,它们就只是正方形),并为每个矩形绘制了一个中心箭头,其方向由用户提供的角度给出(这里是一个称为wind_direction)。在

在代码中,我将Axes的纵横比设置为x-和y-极限的纵横比,这使得Axes呈正方形,因此可以轻松绘制长度相同的箭头,而不受其方向的影响。如果不需要,可以注释掉相应的行。如果箭头的长度必须相同而不受限制,则必须计算图形的纵横比,例如请参见here如何进行此操作。在

我还用度数标注了每个条上的风向,以便检查箭头是否与给定的风向一致。在

from matplotlib import pyplot as plt
import numpy as np

fig,ax = plt.subplots()

x = np.arange(12)
wind_strength = np.random.random(12)
wind_direction = np.linspace(0,2*np.pi,12, endpoint = False)

colors = ['green', 'yellow', 'blue', 'pink', 'orange']
bar_cols = [colors[i%len(colors)] for i,s in enumerate(wind_strength)]

bars = ax.bar(x,wind_strength, color=bar_cols)

##computing the aspect ratio of the plot ranges:
xlim = ax.get_xlim()
ylim = ax.get_ylim()
aspect = (xlim[1]-xlim[0])/(ylim[1]-ylim[0])


##comment out this line if you don't care about the arrows being the
##same length
ax.set_aspect(aspect)


##dividing each bar into 'squares' and plotting an arrow into each square
##with orientation given by wind direction
for bar,angle in zip(bars,wind_direction):
    (x1,y1),(x2,y2) = bar.get_bbox().get_points()
    w = x2-x1
    h = w/aspect
    x_mid = (x1+x2)/2

    dx = np.sin(angle)*w
    dy = np.cos(angle)*h

    ##the top and bottom of the current square:
    y_bottom = y1
    y_top = y_bottom+h

    ##draw at least one arrow (for very small bars)
    first = True

    while y_top < y2 or first:
        y_mid = (y_top+y_bottom)/2

        ax.annotate(
            '',xytext=(x_mid-dx/2,y_mid-dy/2),
            xy=(x_mid+dx/2,y_mid+dy/2),
            arrowprops=dict(arrowstyle="->"),
        )

        ##next square
        y_bottom = y_top
        y_top += h

        ##first arrow drawn:
        first = False

    ##annotating the wind direction:
    ax.text(x_mid, y2+0.05, '{}'.format(int(180*angle/np.pi)), ha = 'center')

plt.show()

最终结果如下:

result of the above code

希望这有帮助。在

相关问题 更多 >

    热门问题