在最近一个非常广泛的问题中,人们被问到如何使用matplotlib绘制几个符号,如"圆形,正方形,矩形,星形,温度计和箱形图".从该列表中,除了温度计之外的所有温度计都很明显,如文档中所示或许多现有的stackoverflow答案中所示.由于OP似乎根本不对热量计感兴趣,我宁愿在这里专门询问一个关于温度计的新问题.
如何在matplotlib中绘制温度计?
原则上你可以绘制你喜欢的任何符号,使它成为a marker或a Path.然而,温度计似乎没有任何unicode符号.字体很棒有一个温度计符号,可以在matplotlib中绘制FontAwesome符号.然而,只有5种不同的填充物
此外,这种字体符号的颜色是均匀的,但理想情况下,温度计的内部部分("水银柱")具有不同的颜色(可能由于关联原因可能主要是红色)或者使用不同的颜色来编码温度.颜色也是.
那么,在颜色和填充水平方面,水柱可以编码温度符号(或实际上是任何其他数量)吗?如果是这样,怎么样?
(我在下面给出了答案,欢迎使用该方法的替代方案或改进方法作为进一步的答案.)
Imp*_*est 12
绘制由两部分组成的温度计的选项是创建两个Paths,外壳和内部水银柱.为此,可以从头开始创建路径,并允许内部路径根据(规范化的)输入参数而变化.
然后可以将两条路径绘制为单独的散点图.在下文中,我们创建了一个具有scatter方法的类,该方法与通常类似scatter,除了它还需要额外temp的温度参数和温度tempnorm归一化作为输入.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.path as mpath
class TemperaturePlot():
@staticmethod
def get_hull():
verts1 = np.array([[0,-128],[70,-128],[128,-70],[128,0],
[128,32.5],[115.8,61.5],[96,84.6],[96,288],
[96,341],[53,384],[0,384]])
verts2 = verts1[:-1,:] * np.array([-1,1])
codes1 = [1,4,4,4,4,4,4,2,4,4,4]
verts3 = np.array([[0,-80],[44,-80],[80,-44],[80,0],
[80,34.3],[60.7,52],[48,66.5],[48,288],
[48,314],[26.5,336],[0,336]])
verts4 = verts3[:-1,:] * np.array([-1,1])
verts = np.concatenate((verts1, verts2[::-1], verts4, verts3[::-1]))
codes = codes1 + codes1[::-1][:-1]
return mpath.Path(verts/256., codes+codes)
@staticmethod
def get_mercury(s=1):
a = 0; b = 64; c = 35
d = 320 - b
e = (1-s)*d
verts1 = np.array([[a,-b],[c,-b],[b,-c],[b,a],[b,c],[c,b],[a,b]])
verts2 = verts1[:-1,:] * np.array([-1,1])
verts3 = np.array([[0,0],[32,0],[32,288-e],[32,305-e],
[17.5,320-e],[0,320-e]])
verts4 = verts3[:-1,:] * np.array([-1,1])
codes = [1] + [4]*12 + [1,2,2,4,4,4,4,4,4,2,2]
verts = np.concatenate((verts1, verts2[::-1], verts3, verts4[::-1]))
return mpath.Path(verts/256., codes)
def scatter(self, x,y, temp=1, tempnorm=None, ax=None, **kwargs):
self.ax = ax or plt.gca()
temp = np.atleast_1d(temp)
ec = kwargs.pop("edgecolor", "black")
kwargs.update(linewidth=0)
self.inner = self.ax.scatter(x,y, **kwargs)
kwargs.update(c=None, facecolor=ec, edgecolor=None, color=None)
self.outer = self.ax.scatter(x,y, **kwargs)
self.outer.set_paths([self.get_hull()])
if not tempnorm:
mi, ma = np.nanmin(temp), np.nanmax(temp)
if mi == ma:
mi=0
tempnorm = plt.Normalize(mi,ma)
ipaths = [self.get_mercury(tempnorm(t)) for t in temp]
self.inner.set_paths(ipaths)
Run Code Online (Sandbox Code Playgroud)
这个类的用法可能如下所示,
plt.rcParams["figure.figsize"] = (5.5,3)
plt.rcParams["figure.dpi"] = 72*3
fig, ax = plt.subplots()
p = TemperaturePlot()
p.scatter([.25,.5,.75], [.3,.4,.5], s=[800,1200,1600], temp=[28,39,35], color="C3",
ax=ax, transform=ax.transAxes)
plt.show()
Run Code Online (Sandbox Code Playgroud)
在那里我们绘制了3个温度计,其中不同的温度由"水银"柱的填充表示.由于没有给出标准化,它将[28,39,35]使其最小值和最大值之间的温度标准化.
或者我们可以使用color(c)并 temp显示温度
np.random.seed(42)
fig, ax = plt.subplots()
n = 42
x = np.linspace(0,100,n)
y = np.cumsum(np.random.randn(n))+5
ax.plot(x,y, color="darkgrey", lw=2.5)
p = TemperaturePlot()
p.scatter(x[::4],y[::4]+3, s=300, temp=y[::4], c=y[::4], edgecolor="k", cmap="RdYlBu_r")
ax.set_ylim(-6,18)
plt.show()
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
181 次 |
| 最近记录: |