且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

在 matplotlib 中同时更改线宽和颜色

更新时间:2023-11-26 23:44:46

作为灵感使用

函数 windline 接受带有 x、y、偏差(如每个 x 值的厚度值)和用于颜色映射的颜色数组的 numpy 数组作为参数.我认为可以通过乱七八糟的其他细节来大大改善它,但原理虽然不完美,但应该是扎实的.

The figure above is a great artwork showing the wind speed, wind direction and temperature simultaneously. detailedly:

  • The X axes represent the date
  • The Y axes shows the wind direction(Southern, western, etc)
  • The variant widths of the line were stand for the wind speed through timeseries
  • The variant colors of the line were stand for the atmospheric temperature

This simple figure visualized 3 different attribute without redundancy.

So, I really want to reproduce similar plot in matplotlib.

My attempt now

## Reference 1 http://***.com/questions/19390895/matplotlib-plot-with-variable-line-width
## Reference 2 http://***.com/questions/17240694/python-how-to-plot-one-line-in-different-colors

def plot_colourline(x,y,c):
    c = plt.cm.jet((c-np.min(c))/(np.max(c)-np.min(c)))
    lwidths=1+x[:-1]
    ax = plt.gca()
    for i in np.arange(len(x)-1):
        ax.plot([x[i],x[i+1]], [y[i],y[i+1]], c=c[i],linewidth = lwidths[i])# = lwidths[i])
    return

x=np.linspace(0,4*math.pi,100)
y=np.cos(x)
lwidths=1+x[:-1]

fig = plt.figure(1, figsize=(5,5))
ax  = fig.add_subplot(111)
plot_colourline(x,y,prop)

ax.set_xlim(0,4*math.pi)
ax.set_ylim(-1.1,1.1)

Does someone has a more interested way to achieve this? Any advice would be appreciate!

Using as inspiration another question.

One option would be to use fill_between. But perhaps not in the way it was intended. Instead of using it to create your line, use it to mask everything that is not the line. Under it you can have a pcolormesh or contourf (for example) to map color any way you want.

Look, for instance, at this example:

import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import interp1d

def windline(x,y,deviation,color):
    y1 = y-deviation/2
    y2 = y+deviation/2
    tol = (y2.max()-y1.min())*0.05
    X, Y = np.meshgrid(np.linspace(x.min(), x.max(), 100), np.linspace(y1.min()-tol, y2.max()+tol, 100))
    Z = X.copy()
    for i in range(Z.shape[0]):
        Z[i,:] = c

    #plt.pcolormesh(X, Y, Z)
    plt.contourf(X, Y, Z, cmap='seismic')

    plt.fill_between(x, y2, y2=np.ones(x.shape)*(y2.max()+tol), color='w')
    plt.fill_between(x, np.ones(x.shape) * (y1.min() - tol), y2=y1, color='w')
    plt.xlim(x.min(), x.max())
    plt.ylim(y1.min()-tol, y2.max()+tol)
    plt.show()

x = np.arange(100)
yo = np.random.randint(20, 60, 21)
y = interp1d(np.arange(0, 101, 5), yo, kind='cubic')(x)
dv = np.random.randint(2, 10, 21)
d = interp1d(np.arange(0, 101, 5), dv, kind='cubic')(x)
co = np.random.randint(20, 60, 21)
c = interp1d(np.arange(0, 101, 5), co, kind='cubic')(x)
windline(x, y, d, c)

, which results in this:

The function windline accepts as arguments numpy arrays with x, y , a deviation (like a thickness value per x value), and color array for color mapping. I think it can be greatly improved by messing around with other details but the principle, although not perfect, should be solid.