solub
solub

Reputation: 1363

Matplotlib: How to change the color of a LineCollection according to its coordinates?

Consider the folowing plot:

enter image description here

fig, ax = plt.subplots(figsize = (14, 6))
ax.set_facecolor('k')
ax.set_xlim(0, 100)
ax.set_ylim(0, 100)

xs = np.arange(60, 70)          # xs = np.linspace(60, 70, 100)
ys = np.arange(0, 100, .5)      # ys = np.linspace(0, 100, 100)

v = [[[x, y] for x in xs] for y in ys]

lines = LineCollection(v, linewidth = 1, cmap = plt.cm.Greys_r)
lines.set_array(xs)
ax.add_collection(lines)

How can I change the color of the lines according to their x coordinates (horizontally) so as to create a "shading" effect like this:

enter image description here

Here, the greater x is, the "whiter" the LineCollection is.

Following this reasoning, I thought that specifying lines.set_array(xs) would do the trick but as you can see in my plot the color gradation is still following the y axis. Strangely the pattern is repeating itself, from black to white (every 5) over and over (up to 100).

I think (not sure at all) the problem lies in the v variable that contains the coordinates. The concatenation of x and y might be improper.

Upvotes: 2

Views: 2921

Answers (1)

ImportanceOfBeingErnest
ImportanceOfBeingErnest

Reputation: 339795

The shape of the list v you supply to the LineCollection is indeed not suitable to create a gradient of the desired direction. This is because each line in a LineCollection can only have single color. Here the lines range from x=60 to x=70 and each of those lines has one color.

What you need to do instead is to create a line collection where each line is devided into several segments, each of which can then have its own color.

To this end an array of dimensions (n, m, l), where n is the number of segments, m is the number of points per segment, and l is the dimension (2D, hence l=2) needs to be used.

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.collections import LineCollection
fig, ax = plt.subplots(figsize = (14, 6))
ax.set_facecolor('k')
ax.set_xlim(0, 100)
ax.set_ylim(0, 100)

xs = np.linspace(60, 70, 100)
ys = np.linspace(0, 100, 100)


X,Y = np.meshgrid(xs,ys)
s = X.shape
segs = np.empty(((s[0])*(s[1]-1),2,2))
segs[:,0,0] = X[:,:-1].flatten()
segs[:,1,0] = X[:,1:].flatten()
segs[:,0,1] = Y[:,:-1].flatten()
segs[:,1,1] = Y[:,1:].flatten()

lines = LineCollection(segs, linewidth = 1, cmap = plt.cm.Greys_r)
lines.set_array(X[:,:-1].flatten())
ax.add_collection(lines)

plt.show()

enter image description here

Upvotes: 3

Related Questions