Search code examples
pythonperformanceplotfigure

Efficient way of plotting multiple figures in Python


I was wondering of there is more efficient method of plotting multiples figures in Python. For example:

x = np.linspace(0, 2*np.pi, 100)
y = np.sin(x)
y_shifted = np.sin(x+np.pi)
plt.plot(x, y)
plt.plot(x, y_shifted)

here we plot two figures on top of each other. But wouldn't it be more efficient to save the values of the functions first(e.g. to another array), and then plot them over the arguments? If yes, how could we do this?

Thanks!


Solution

  • I tried furas suggestion:

    After 100 figures with 1k lines each, these are my results:

    Plot one at a time:
    Time to plot: Min: 0.504s, Max: 6.728s, Avg: 0.929s
    Time to show: Min: 0.727s, Max: 11.425s, Avg: 1.250s
    
    Plot all at once
    Time to plot: Min: 0.341s, Max: 7.839s, Avg: 0.776s
    Time to show: Min: 0.724s, Max: 8.165s, Avg: 1.294s
    

    Soo... about the same? Maybe a bit quicker? The difference between approaches is small compared to the differences between runs, so IMO not worth to worry about. If your application feels slow, this is not going to save the day.

    Code to generate:

    import numpy as np
    from matplotlib import pyplot as plt
    from random import uniform
    import time
    
    def plot_one_at_a_time():
        start = time.time()
        x = np.linspace(0, 2*np.pi, 100)
        for i in range(1000):
            shift = uniform(0, 100)
            y_shifted = np.sin(x+shift)
            plt.plot(x, y_shifted)
        plotdonetime = time.time()
        plt.show()
        showdonetime = time.time()
        
        plot_times_one.append(plotdonetime-start)
        show_times_one.append(showdonetime-plotdonetime)
    
    def plot_at_once():
        start = time.time()
        x = np.linspace(0, 2*np.pi, 100)
        data = []
        for i in range(1000):
            shift = uniform(0, 100)
            y_shifted = np.sin(x+shift)
            data.append(x)
            data.append(y_shifted)
        plt.plot(*data)  
        plotdonetime = time.time()
        plt.show()
        showdonetime = time.time()
    
        plot_times_all.append(plotdonetime-start)
        show_times_all.append(showdonetime-plotdonetime)
    
    
    plot_times_one = []
    show_times_one = []
    plot_times_all = []
    show_times_all = []
    
    for i in range(100):
        plot_one_at_a_time()
        plot_at_once()
    
    print("Plot one at a time:")
    print("Time to plot: Min: {:.3f}s, Max: {:.3f}s, Avg: {:.3f}s".format(np.min(plot_times_one), np.amax(plot_times_one), np.mean(plot_times_one)))
    print("Time to show: Min: {:.3f}s, Max: {:.3f}s, Avg: {:.3f}s".format(np.min(show_times_one), np.amax(show_times_one), np.mean(show_times_one)))
    print()
    print("Plot all at once")
    print("Time to plot: Min: {:.3f}s, Max: {:.3f}s, Avg: {:.3f}s".format(np.min(plot_times_all), np.amax(plot_times_all), np.mean(plot_times_all)))
    print("Time to show: Min: {:.3f}s, Max: {:.3f}s, Avg: {:.3f}s".format(np.min(show_times_all), np.amax(show_times_all), np.mean(show_times_all)))