Est-il possible de tracer une ligne avec une largeur de ligne variable dans matplotlib? Par exemple:
from pylab import *
x = [1, 2, 3, 4, 5]
y = [1, 2, 2, 0, 0]
width = [.5, 1, 1.5, .75, .75]
plot(x, y, linewidth=width)
Cela ne fonctionne pas car linewidth attend un scalaire.
Remarque: Je connais * fill_between () * et * fill_betweenx () *. Comme ils ne remplissent que les directions x ou y, ils ne rendent pas justice aux cas où vous avez une ligne oblique. Il est souhaitable que le remplissage soit toujours normal à la ligne. C'est pourquoi une ligne de largeur variable est recherchée.
Utilisez LineCollections. Une manière de le faire dans le sens de this exemple de Matplotlib est
import numpy as np
from matplotlib.collections import LineCollection
import matplotlib.pyplot as plt
x = np.linspace(0,4*np.pi,10000)
y = np.cos(x)
lwidths=1+x[:-1]
points = np.array([x, y]).T.reshape(-1, 1, 2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)
lc = LineCollection(segments, linewidths=lwidths,color='blue')
fig,a = plt.subplots()
a.add_collection(lc)
a.set_xlim(0,4*np.pi)
a.set_ylim(-1.1,1.1)
fig.show()
Une alternative à la réponse de Giulio Ghirardo qui divise les lignes en segments, vous pouvez utiliser la fonction de dispersion intégrée de matplotlib qui construit la ligne en utilisant des cercles:
from matplotlib import pyplot as plt
import numpy as np
x = np.linspace(0,10,10000)
y = 2 - 0.5*np.abs(x-4)
lwidths = (1+x)**2 # scatter 'o' marker size is specified by area not radius
plt.scatter(x,y, s=lwidths, color='blue')
plt.xlim(0,9)
plt.ylim(0,2.1)
plt.show()
D'après mon expérience, j'ai rencontré deux problèmes pour diviser la ligne en segments:
Pour une raison quelconque, les segments sont toujours divisés par des lignes blanches très fines. Les couleurs de ces lignes sont mélangées avec les couleurs des segments lorsque vous utilisez une très grande quantité de segments. De ce fait, la couleur de la ligne n’est pas la même que celle souhaitée.
Il ne gère pas très bien les discontinuités très nettes.
Vous pouvez tracer chaque segment de la ligne séparément, avec sa largeur de ligne distincte, quelque chose comme:
from pylab import *
x = [1, 2, 3, 4, 5]
y = [1, 2, 2, 0, 0]
width = [.5, 1, 1.5, .75, .75]
for i in range(len(x)-1):
plot(x[i:i+2], y[i:i+2], linewidth=width[i])
show()
la réponse de gg349 fonctionne bien mais coupe la ligne en plusieurs morceaux, ce qui peut souvent créer un mauvais rendu.
Voici un exemple alternatif qui génère des lignes continues lorsque la largeur est homogène:
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1)
xs = np.cos(np.linspace(0, 8 * np.pi, 200)) * np.linspace(0, 1, 200)
ys = np.sin(np.linspace(0, 8 * np.pi, 200)) * np.linspace(0, 1, 200)
widths = np.round(np.linspace(1, 5, len(xs)))
def plot_widths(xs, ys, widths, ax=None, color='b', xlim=None, ylim=None,
**kwargs):
if not (len(xs) == len(ys) == len(widths)):
raise ValueError('xs, ys, and widths must have identical lengths')
fig = None
if ax is None:
fig, ax = plt.subplots(1)
segmentx, segmenty = [xs[0]], [ys[0]]
current_width = widths[0]
for ii, (x, y, width) in enumerate(Zip(xs, ys, widths)):
segmentx.append(x)
segmenty.append(y)
if (width != current_width) or (ii == (len(xs) - 1)):
ax.plot(segmentx, segmenty, linewidth=current_width, color=color,
**kwargs)
segmentx, segmenty = [x], [y]
current_width = width
if xlim is None:
xlim = [min(xs), max(xs)]
if ylim is None:
ylim = [min(ys), max(ys)]
ax.set_xlim(xlim)
ax.set_ylim(ylim)
return ax if fig is None else fig
plot_widths(xs, ys, widths)
plt.show()