1

Creation of 100 charts in less then second, but writing them on disk on converting to base64 representation without writing them on disk takes 10 second, so the overhead is in creation of png/jpg representation itself, is there way to speed plt.savefig ?

With bbox_inches="tight" there is futher slowdown, so I guess there could be some way to speed things up.

All jumps in execution time are between steps 2 and 3 (logging with datetime.datetime.now();print is enought is this case I think):

import numpy as np
import datetime
data = np.random.rand(20, 100)

list_base64 = []
path = 'YOUR_PATH'
file = "test.jpg"

for i in range(data.shape[1]):
    ct = datetime.datetime.now();print(f"current time: {i} 1", ct)
    if i==0:
        ct0=ct
    plt.plot(data[:,i])
    ct = datetime.datetime.now();print(f"current time: {i} 2", ct)
    
    plt.savefig(path + file, dpi=10, bbox_inches="tight")
    ct = datetime.datetime.now();print(f"current time: {i} 3", ct)

    plt.close()
    ct = datetime.datetime.now();print(f"current time: {i} 4", ct)
    
    plot_file = open(path + file, 'rb')
    ct = datetime.datetime.now();print(f"current time: {i} 5", ct)

    base64_string = base64.b64encode(plot_file.read()).decode()
    ct = datetime.datetime.now();print(f"current time: {i} 6", ct)

    plot_file.close()
    ct = datetime.datetime.now();print(f"current time: {i} 7", ct)

    base64_string = chart_to_base64(plt)
    ct = datetime.datetime.now();print(f"current time: {i} 8", ct)

    list_base64.append(base64_string) 
    ct = datetime.datetime.now();print(f"current time: {i} 9", ct)
print('loop starts at:', ct0)
Qbik
  • 5,885
  • 14
  • 62
  • 93
  • 3
    Matplotlib isn't aimed at speed, but at good quality figures. Hence don't expect it do write 100 charts/second, that's not its aim. – 9769953 Apr 15 '21 at 11:26
  • 2
    At 100 graphs/sec, you're 4 times over the standard 24 frames/sec for film. How often do you need to run this loop, that it is important that you get it that fast? – 9769953 Apr 15 '21 at 11:29
  • 2
    This job seems to be parallelizable; you could get some speed increase if you run the creation of the figures in separate processes (assuming you have multiple cores on your PC). – Niko Föhr Apr 15 '21 at 11:39
  • 2
    Site note: the `logging` module may take a bit to get started with, but it is cleaner and can include the current timestamp automatically; instead of using `ct = datetime.datetime.now(); print(...)`, you'd use e.g. `logging.debug("%d 8", i)` after setting the logging formatter. – 9769953 Apr 15 '21 at 11:44
  • Use `io.BytesIO` to do the conversion of file to base64 in memory; that is at least somewhat faster. See e.g. https://stackoverflow.com/questions/38061267/matplotlib-graphic-image-to-base64 . – 9769953 Apr 15 '21 at 11:46
  • Those images are supposed to be textures for three.js library where there is going to be 400 cubes with those textures, refreshed every 60 seconds by React front-end, io.BytesIO works with plt.savefig method so running overhead is pretty the same, serving them is also similar as their creation in form of files is cause of overhead, creation of 10px x 10px images is also slow so I fell there is some high constant cost of functions calls – Qbik Apr 15 '21 at 12:43
  • 2
    At 10x10 px images, you are probably better sending the data to your frontend and do the plotting in Three.js itself. At that image size, you don't need the quality that Matplotlib provides: you wouldn't be able to properly see the tick marks and labels, or even the axes: 10x10 pixels is about the size of a single letter. – 9769953 Apr 15 '21 at 13:02
  • @0 0 10x10px was for test surpose only – Qbik Apr 16 '21 at 08:04

0 Answers0