Reputation: 2649
I wish to produce a single line plot in Matplotlib that has variable transparency, i.e. it starts from solid color to full transparent color.
I tried this but it didn't work.
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2 * np.pi, 500)
y = np.sin(x)
alphas = np.linspace(1, 0, 500)
fig, ax = plt.subplots(1, 1)
ax.plot(x, y, alpha=alphas)
Upvotes: 2
Views: 2513
Reputation: 953
Matplotlib's "LineCollection" allows you to split the line to be plotted into individual line segments and you can assign a color to each segment. The code example below shows how each horizontal "x" value can be assigned an alpha (transparency) value that indexes into a sequential colormap that runs from transparent to a given color. A suitable colormap "myred" was created using Matplotlib's "colors" module.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
import matplotlib.colors as colors
redfade = colors.to_rgb("red") + (0.0,)
myred = colors.LinearSegmentedColormap.from_list('my',[redfade, "red"])
x = np.linspace(0,1, 1000)
y = np.sin(x * 4 * np.pi)
alphas = x * 4 % 1
points = np.vstack((x, y)).T.reshape(-1, 1, 2)
segments = np.hstack((points[:-1], points[1:]))
fig, ax = plt.subplots()
lc = LineCollection(segments, array=alphas, cmap=myred, lw=3)
line = ax.add_collection(lc)
ax.autoscale()
plt.show()
If you are using the standard white background then you can save a few lines by using one of Matplotlib's builtin sequential colormaps that runs from white to a given color. If you remove the lines that created the colormap above and just put the agument cmap="Reds"
in the LineCollection function, it creates a visually similar result.
Upvotes: 4
Reputation: 8269
I don't know how to do this in matplotlib, but it's possible in Altair:
import numpy as np
import pandas as pd
import altair as alt
x = np.linspace(0, 2 * np.pi, 500)
y = np.sin(x)
alt.Chart(
pd.DataFrame({"x": x, "y": y, "o": np.linspace(0, 1, len(x))}),
).mark_point(
).encode(
alt.X("x"),
alt.Y("y"),
alt.Opacity(field="x", type="quantitative", scale=alt.Scale(range=[1, 0]), legend=None),
)
Upvotes: 1
Reputation: 2649
The only solution I found was to plot each segment independently with varying transparency
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2 * np.pi, 500)
y = np.sin(x)
alphas = np.linspace(1, 0, 499)
fig, ax = plt.subplots(1, 1)
for i in range(499):
ax.plot(x[i:i+2], y[i:i+2], 'k', alpha=alphas[i])
But I don't like it... Maybe this is enough for someone
Upvotes: 1