我正在尝试创建一个条形图,其中条形图包含附加信息,方法是让条形图中的箭头指向基点。
现在我只设法用彩色条创建一个。由于需要8种方向的颜色加上一种不存在的颜色,它不如我希望的那么好。区分颜色也很困难。
Microsoft.Data.OData (>= 5.6.2)
因此,箭头指向由单独变量提供的方向,直观且易于查看。
我不知道该怎么做。我已经尝试过使用阴影线,但似乎只有一组有限的符号。
有没有办法在酒吧里拿到一些箭头?
编辑: 这是一个pciture,它看起来如何,我追求的是什么。箭头的形状可以不同。当然,预计会有更多的支柱。由于任务数据,甚至可能有一些没有任何箭头。 https://github.com/artoolkitx/jsartoolkit5
答案 0 :(得分:3)
这是一个使用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()
最终结果如下:
希望这有帮助。
答案 1 :(得分:2)
在栏内绘制箭头的一个选项确实是阴影线。然而,这有点牵扯。需要创建一些自定义填充,如下面的答案所示:How to fill a polygon with a custom hatch in matplotlib?这里我们可以使用箭头的路径。
在下文中,我们将子类matplotlib.hatch.Shapes
子类化并创建一些箭头路径。现在的问题是我们需要一些参数来插入阴影线,以便能够定义角度。然后我们可以定义一个自定义的阴影图案,我选择看起来像这样
hatch="arr{angle}{size}{density}"
其中
这与我之前关于this question的回答类似。 取决于角度,路径旋转,尺寸和密度基本上确定了显示多大尺寸的箭头。请注意,并非所有参数都看起来很好,有些参数会导致重叠。
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.offsetbox
import matplotlib.hatch
from matplotlib.patches import Polygon
class ArrowHatch(matplotlib.hatch.Shapes):
"""
Arrow hatch. Use with hatch="arr{angle}{size}{density}"
angle: integer number between 0 and 360
size: some integer between 2 and 20
density: some integer >= 1
"""
filled = True
size = 1
def __init__(self, hatch, density):
v1 = [[.355,0], [.098, .1], [.151,.018], [-.355,.018]]
v2 = np.copy(v1)[::-1]
v2[:,1] *= -1
v = np.concatenate((v1,v2))
self.path = Polygon(v, closed=True, fill=False).get_path()
self.num_lines = 0
if len(hatch) >= 5:
if hatch[:3] == "arr":
h = hatch[3:].strip("{}").split("}{")
angle = np.deg2rad(float(h[0]))
self.size = float(h[1])/10.
d = int(h[2])
self.num_rows = 2*(int(density)//6*d)
self.num_vertices = (self.num_lines + 1) * 2
R = np.array([[np.cos(angle), -np.sin(angle)],
[np.sin(angle), np.cos(angle)]])
self.shape_vertices = np.dot(R,self.path.vertices.T).T
self.shape_codes = self.path.codes
matplotlib.hatch.Shapes.__init__(self, hatch, density)
matplotlib.hatch._hatch_types.append(ArrowHatch)
n = 7
a = 1017
x = np.arange(n)
y = np.linspace(0.2*a,a,len(x))
fig, ax = plt.subplots()
bar = ax.bar(x,y, ec="k", color="lightblue")
angles = [0,45,360-45,90,225,360-90,160]
for b, a in zip(bar, angles):
f = 'arr{{{}}}{{9}}'.format(a)
b.set_hatch(f)
plt.show()
使用{angle}{9}{3}
输出:
使用{angle}{11}{2}
输出:
{{3}}
<小时/> 关于孵化模式及其管理方式的说明如下。或者换句话说,
ArrowHatch
如何知道它应该创建一个舱口?
将使用matplotlib.hatch._hatch_types
内任何剖面线的顶点应用阴影线。这就是我们需要将ArrowHatch
类附加到此列表的原因。根据此类是否具有大于零的属性num_vertices
,它将有助于最终的阴影线。这就是我们在init函数中将其设置为self.num_lines = 0
的原因。但是,如果hatch
(提供给_hatch_types
列表中每个类的字符串包含我们的匹配模式,则我们将self.num_rows
设置为0以外的值(它应该是偶数形状,因为它们以2个移位的行产生),这样它可以有助于孵化
这个概念有点奇特,因为基本上每个类本身都决定是否参与孵化,具体取决于hatch
字符串。一方面,这非常方便,因为它允许容易地组合不同的舱口类型,例如, "///++oo"
。另一方面,它使得难以用于需要输入参数的舱口,在这种情况下作为角度。还需要注意不要在孵化中使用任何角色,其他舱口使用;例如,我最初想要使用类似"arrow45.8,9,2"
的内容,因为o
,.
和,
是其他有效的填充类型,因此效果不佳遍布整个地方的点。