【问题标题】:Add horizontal line with conditional coloring添加带有条件着色的水平线
【发布时间】:2019-09-23 20:17:45
【问题描述】:

我使用matplotlib.pyplot 制作了contourf 绘图。现在我想要在y = 0 有条件着色的水平线(或类似ax.vspan 的东西也可以)。我会告诉你我有什么和我想得到什么。我想用一个数组来做到这一点,比如说landsurface,它代表陆地、海洋或冰。该数组填充有1(陆地)、2(海洋)或3(冰),并具有len(locs)(即x轴)。

这是剧情代码:

plt.figure()
ax=plt.axes()
clev=np.arange(0.,50.,.5)
plt.contourf(locs,height-surfaceheight,var,clev,extend='max')
plt.xlabel('Location')
plt.ylabel('Height above ground level [m]')
cbar = plt.colorbar()
cbar.ax.set_ylabel('o3 mixing ratio [ppb]')
plt.show()

这是我目前所拥有的:

这就是我想要的:

非常感谢!

【问题讨论】:

标签: python matplotlib


【解决方案1】:

简介

我将使用line collection

因为我没有你的原始数据,所以我使用简单的正弦曲线伪造了一些数据,并在基线上绘制了与曲线的小值、中值和高值对应的颜色代码

代码

普通样板,我们需要显式导入LineCollection

import matplotlib.pyplot as plt                                                  
import numpy as np                                                               
from matplotlib.collections import LineCollection

只是为了绘制一些东西,一条正弦曲线(x r

x = np.linspace(0, 50, 101)                                                      
y = np.sin(0.3*x)

从曲线值(对应于您的表面类型)到LineCollection 颜色的颜色编码,请注意LineCollection 要求将颜色指定为 RGBA 元组,但我已经看过示例使用颜色字符串,呸!

# 1 when near min, 2 when near 0, 3 when near max
z = np.where(y<-0.5, 1, np.where(y<+0.5, 2, 3))                                  

col_d = {1:(0.4, 0.4, 1.0, 1), # blue, near min
         2:(0.4, 1.0, 0.4, 1), # green, near zero
         3:(1.0, 0.4, 0.4, 1)} # red, near max                     
# prepare the list of colors
colors = [col_d[n] for n in z]                                                   

在一个线集合中,我们需要一个段序列,在这里我决定将我的编码线放在y=0,但您可以在s 中添加一个常量来上下移动它。
我承认形成段序列有点棘手......

# build the sequence of segments
s = np.zeros(101)                                                                
segments=np.array(list(zip(zip(x,x[1:]),zip(s,s[1:])))).transpose((0,2,1))       
# and fill the LineCollection
lc = LineCollection(segments, colors=colors, linewidths=5, 
                    antialiaseds=0, # to prevent artifacts between lines 
                    zorder=3        # to force drawing over the curve)                                                                 lc = LineCollection(segments, colors=colors, linewidths=5) # possibly add zorder=...                      

最后,我们把所有东西都放在画布上

# plot the function and the line collection
fig, ax = plt.subplots()                                                         
ax.plot(x,y)                                                                     
ax.add_collection(lc) 

【讨论】:

  • 这就像一个魅力,谢谢。有什么方法可以去除垂直的灰色/白色条,使 LineCollection 看起来是连续的?
  • 重新竖条,试试antialiaseds=1(或者是antialiaseds=0?)——否则你可以尝试在每个的x坐标上添加一个非常小的ε段结束。免责声明,我没有测试过这两个想法。
  • @Bollehenk 我检查过,它是antialiaseds=0...我已经编辑了答案,我还强制使用zorder=3 在前景中绘制颜色编码线。
【解决方案2】:

我建议使用正确的extent 添加imshow(),例如:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colorbar as colorbar
import matplotlib.colors as colors

### generate some data
np.random.seed(19680801)
npts = 50
x = np.random.uniform(0, 1, npts)
y = np.random.uniform(0, 1, npts)
X,Y=np.meshgrid(x,y)
z = x * np.exp(-X**2 - Y**2)*100

### create a colormap of three distinct colors for each landmass
landmass_cmap=colors.ListedColormap(["b","r","g"])
x_land=np.linspace(0,1,len(x)) ## this should be scaled to your "location"

## generate some fake landmass types (either 0, 1, or 2) with probabilites
y_land=np.random.choice(3, len(x), p=[0.1, 0.6, 0.3]) 
print(y_land) 

fig=plt.figure()
ax=plt.axes()
clev=np.arange(0.,50.,.5)

## adjust the "height" of the landmass 
x0,x1=0,1
y0,y1=0,0.05 ## y1 is the "height" of the landmass
## make sure that you're passing sensible zorder here and in your .contourf()
im = ax.imshow(y_land.reshape((-1,len(x))),cmap=landmass_cmap,zorder=2,extent=(x0,x1,y0,y1))
plt.contourf(x,y,z,clev,extend='max',zorder=1)

ax.set_xlim(0,1)
ax.set_ylim(0,1)

ax.plot()
ax.set_xlabel('Location')
ax.set_ylabel('Height above ground level [m]')
cbar = plt.colorbar()
cbar.ax.set_ylabel('o3 mixing ratio [ppb]')

## add a colorbar for your listed colormap
cax = fig.add_axes([0.2, 0.95, 0.5, 0.02]) # x-position, y-position, x-width, y-height
bounds = [0,1,2,3]
norm = colors.BoundaryNorm(bounds, landmass_cmap.N)
cb2 = colorbar.ColorbarBase(cax, cmap=landmass_cmap,
                                norm=norm,
                                boundaries=bounds,
                                ticks=[0.5,1.5,2.5],
                                spacing='proportional',
                                orientation='horizontal')
cb2.ax.set_xticklabels(['sea','land','ice'])

plt.show()

产量:

【讨论】:

    猜你喜欢
    • 2021-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-25
    • 2022-06-14
    • 1970-01-01
    • 1970-01-01
    • 2012-04-05
    相关资源
    最近更新 更多