Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I change the alpha value dynamically in matplotlib python

I'm seeking how to change an alpha value dynamically which are already plotted.

This is a kind of sample code I want to implement, but I know it is a wrong writing.

import matplotlib.pyplot as plt

fig = plt.subplot(1, 1)

for rate in [0.1 * x for x in range(10, -1, -1)]:
    plt.plot(range(0, 5), range(0, 5), color="r", alpha=rate)
    plt.pause(0.1)

plt.show()

The purpose of this sample code is that I want to decrease the alpha as the processing go on and make the line vanish.

Does somebody know a way to accomplish like this problem? Thank you.

like image 926
ken333 Avatar asked Apr 24 '17 13:04

ken333


People also ask

How do I change the transparency in MatPlotLib?

Matplotlib allows you to regulate the transparency of a graph plot using the alpha attribute. By default, alpha=1. If you would like to form the graph plot more transparent, then you'll make alpha but 1, such as 0.5 or 0.25.

Which parameter should you use to change a plots transparency?

In order to change the transparency of a graph plot in matplotlib we will use the matplotlib. pyplot. plot() function. The plot() function in pyplot module of matplotlib library is used to make 2D illustrations.


2 Answers

I thought, that you wanted to control the alpha value for each point individually, so I set out to do this (based on this):

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.collections import LineCollection

class Vanishing_Line(object):
    def __init__(self, n_points, tail_length, rgb_color):
        self.n_points = int(n_points)
        self.tail_length = int(tail_length)
        self.rgb_color = rgb_color

    def set_data(self, x=None, y=None):
        if x is None or y is None:
            self.lc = LineCollection([])
        else:
            # ensure we don't start with more points than we want
            x = x[-self.n_points:]
            y = y[-self.n_points:]
            # create a list of points with shape (len(x), 1, 2)
            # array([[[  x0  ,  y0  ]],
            #        [[  x1  ,  y1  ]],
            #        ...,
            #        [[  xn  ,  yn  ]]])
            self.points = np.array([x, y]).T.reshape(-1, 1, 2)
            # group each point with the one following it (shape (len(x)-1, 2, 2)):
            # array([[[  x0  ,   y0  ],
            #         [  x1  ,   y1  ]],
            #        [[  x1  ,   y1  ],
            #         [  x2  ,   y2  ]],
            #         ...
            self.segments = np.concatenate([self.points[:-1], self.points[1:]],
                                           axis=1)
            if hasattr(self, 'alphas'):
                del self.alphas
            if hasattr(self, 'rgba_colors'):
                del self.rgba_colors
            #self.lc = LineCollection(self.segments, colors=self.get_colors())
            self.lc.set_segments(self.segments)
            self.lc.set_color(self.get_colors())

    def get_LineCollection(self):
        if not hasattr(self, 'lc'):
            self.set_data()
        return self.lc


    def add_point(self, x, y):
        if not hasattr(self, 'points'):
            self.set_data([x],[y])
        else:
            # TODO: could use a circular buffer to reduce memory operations...
            self.segments = np.concatenate((self.segments,[[self.points[-1][0],[x,y]]]))
            self.points = np.concatenate((self.points, [[[x,y]]]))
            # remove points if necessary:
            while len(self.points) > self.n_points:
                self.segments = self.segments[1:]
                self.points = self.points[1:]
            self.lc.set_segments(self.segments)
            self.lc.set_color(self.get_colors())

    def get_alphas(self):
        n = len(self.points)
        if n < self.n_points:
            rest_length = self.n_points - self.tail_length
            if n <= rest_length:
                return np.ones(n)
            else:
                tail_length = n - rest_length
                tail = np.linspace(1./tail_length, 1., tail_length)
                rest = np.ones(rest_length)
                return np.concatenate((tail, rest))
        else: # n == self.n_points
            if not hasattr(self, 'alphas'):
                tail = np.linspace(1./self.tail_length, 1., self.tail_length)
                rest = np.ones(self.n_points - self.tail_length)
                self.alphas = np.concatenate((tail, rest))
            return self.alphas

    def get_colors(self):
        n = len(self.points)
        if  n < 2:
            return [self.rgb_color+[1.] for i in xrange(n)]
        if n < self.n_points:
            alphas = self.get_alphas()
            rgba_colors = np.zeros((n, 4))
            # first place the rgb color in the first three columns
            rgba_colors[:,0:3] = self.rgb_color
            # and the fourth column needs to be your alphas
            rgba_colors[:, 3] = alphas
            return rgba_colors
        else:
            if hasattr(self, 'rgba_colors'):
                pass
            else:
                alphas = self.get_alphas()
                rgba_colors = np.zeros((n, 4))
                # first place the rgb color in the first three columns
                rgba_colors[:,0:3] = self.rgb_color
                # and the fourth column needs to be your alphas
                rgba_colors[:, 3] = alphas
                self.rgba_colors = rgba_colors
            return self.rgba_colors

def data_gen(t=0):
    "works like an iterable object!"
    cnt = 0
    while cnt < 1000:
        cnt += 1
        t += 0.1
        yield t, np.sin(2*np.pi*t) * np.exp(-t/100.)

def update(data):
    "Update the data, receives whatever is returned from `data_gen`"
    x, y = data
    line.add_point(x, y)
    # rescale the graph by large steps to avoid having to do it every time:
    xmin, xmax = ax.get_xlim()
    if x >= xmax:
        ax.set_xlim(xmin, 2*xmax)
        ax.figure.canvas.draw()
    return line,

if __name__ == '__main__':
    n_points = 100
    tail_length = (3/4.)*n_points
    rgb_color = [0., 0.5, 1.0]
    time_pause = 0 # miliseconds

    x=np.linspace(0, 4*np.pi, 2*n_points)
    y=np.cos(x)

    line = Vanishing_Line(n_points, tail_length, rgb_color)
    fig, ax = plt.subplots()
    ax.add_collection(line.get_LineCollection())
    ax.set_xlim(0, 4*np.pi)
    ax.set_ylim(-1.1,1.1)

    ani = animation.FuncAnimation(fig, update, data_gen, blit=False,
                                  interval=time_pause, repeat=False)

    fig.show()

    mywriter = animation.FFMpegWriter(fps=30)
    ani.save('ani.mp4', writer=mywriter, dpi=600)

It should plot a graphic with a vanishing line (saved with tips from here, and converted from mp4 to gif online):

enter image description here

There appears to be a bug at the start of the animation shown in real time by python when saving the graph, as there appears a line from [10,0] to the first point.

That line does not appear on the saved animation and if you comment the two lines to save to graph that disappears.

I believe the animation saving is running before the animation display, and thus the last point from the saving run is shown on the start of the display run.

like image 152
berna1111 Avatar answered Sep 27 '22 19:09

berna1111


You can update the alpha value of an existing Line2D, using the set_alpha method. The idea would be to plot the line once and then update the alpha in the loop.

import matplotlib.pyplot as plt

fig = plt.subplot(111)
plt.ion()
line, = plt.plot(range(0, 5), range(0, 5), color="r", alpha=1)
for rate in [0.1 * x for x in range(10, -1, -1)]:
    line.set_alpha(rate)
    plt.draw()
    plt.pause(0.1)

plt.ioff()
plt.show()
like image 24
ImportanceOfBeingErnest Avatar answered Sep 27 '22 19:09

ImportanceOfBeingErnest