Search code examples
pythonmatplotlibplotdata-visualizationdensity-plot

Color overlapped lines with plt.plot (Matplotlib)


How can I configure plt.plot such that overlapped lines will have darker colors?
For example, I would like to use plt.plot to display the samples in such a way that the density that can be seen in the upper plot will be clear in the lower plot.
From the lower plot it's hard to understand where most of the samples are located

plot example

Here is the code I used in order to generate the example:

import numpy as np
import matplotlib.pyplot as plt

time = 100
n_samples = 7000
x = np.linspace(0, time, n_samples)
r1 = np.random.normal(0, 1, x.size)
r2 = np.random.uniform(-6, 6, x.size)
data = np.dstack((r1, r2)).flatten()

fig, axs = plt.subplots(2, 1, figsize=(9, 6))
axs[0].scatter(np.arange(len(data)), data, alpha=0.1)
axs[1].plot(np.arange(len(data)), data, alpha=0.2)
plt.show()

Solution

  • Update: segmentation and plotting into separated function

    Instead of drawing one large curve, you could create each line segment separately and then draw these. That way, the overlapping segments will be blended via the transparency.

    import matplotlib.pyplot as plt
    from matplotlib.collections import LineCollection
    import numpy as np
    
    def plot_line_as_segments(xs, ys=None, ax=None, **kwargs):
        ax = ax or plt.gca()
        if ys is None:
            ys = xs
            xs = np.arange(len(ys))
        segments = np.c_[xs[:-1], ys[:-1], xs[1:], ys[1:]].reshape(-1, 2, 2)
        added_collection = ax.add_collection(LineCollection(segments, **kwargs))
        ax.autoscale()
        return added_collection
    
    time = 100
    n_samples = 7000
    x = np.linspace(0, time, n_samples)
    r1 = np.random.normal(0, 1, x.size)
    r2 = np.random.uniform(-6, 6, x.size)
    data = np.dstack((r1, r2)).flatten()
    
    fig, axs = plt.subplots(2, 1, figsize=(9, 6))
    axs[0].scatter(np.arange(len(data)), data, alpha=0.1)
    axs[0].margins(x=0)
    
    plot_line_as_segments(data, ax=axs[1], alpha=0.05)
    axs[1].margins(x=0)
    plt.show()
    

    drawing individual segments