3

Whenever a new txt file is added to a directory, I would like to plot and show the data from the file. If another file appears, I want the plot to update and show the new data. Creating a plot outside the main caused thread errors, so I made a (not very good) fix using global variables.

The problem is that a white figure appears and the plots do not show. After stopping the program, the white figure disappears and the plot appears. The correct image is saved to file, but I would like the image to be shown in real time. If I comment out the plt.show(), no plots appear.

I tried the "Dynamically updating plot in matplotlib" answer (Dynamically updating plot in matplotlib) but found that because it never called show(), no window appeared. If I tried calling show(), it blocked updates.

Inserting plt.pause() did not work (Real time matplotlib plot is not working while still in a loop)

The example code did not work (How to update a plot in matplotlib?)

Here is my code:

import time
from watchdog.observers import Observer
from watchdog.events import PatternMatchingEventHandler
import matplotlib.pyplot as plt
import numpy as np
import config

class MyHandler(PatternMatchingEventHandler):
    patterns=["*.txt", "*.TXT"]

    def on_created(self, event):
        self.process(event)

    def process(self, event):
        filename = event.src_path
        if '_AIt' in filename:
            config.isnew=True
            config.fname=filename


if __name__ == '__main__':
    observer = Observer()
    observer.schedule(MyHandler(), path='.', recursive=True)
    observer.start()

    dat=[0,1]
    fig = plt.figure()
    ax = fig.add_subplot(111)
    Ln, = ax.plot(dat)
    ax.set_xlim([0,10])
    ax.set_ylim([-1,1])
    plt.ion()
    plt.show()    

    try:
        while True:
            time.sleep(1)
            if config.isnew:
                config.isnew=False

                dataarray = np.array(np.transpose(np.loadtxt(config.fname)))
                dat = dataarray[15] #AI0
                Ln.set_ydata(dat)
                Ln.set_xdata(range(len(dat)))
                plt.savefig(config.fname[:-4] + '.png', bbox_inches='tight')
                plt.draw()

    except KeyboardInterrupt:
        observer.stop()
    observer.join()

config.py (creates default values of the configuration setting)

isnew=False
fname=""

I am confused because the following example code works well (from pylab.ion() in python 2, matplotlib 1.1.1 and updating of the plot while the program runs)

import pylab
import time
import matplotlib.pyplot as plt
import numpy as np

dat=[0,1]
fig = plt.figure()
ax = fig.add_subplot(111)
Ln, = ax.plot(dat)
ax.set_xlim([0,20])
ax.set_ylim([0,40])
plt.ion()
plt.show()    

for i in range (18):
    dat=np.array(range(20))+i
    Ln.set_ydata(dat)
    Ln.set_xdata(range(len(dat)))
    plt.pause(1)

print 'done with loop'
Community
  • 1
  • 1
allie
  • 31
  • 1

1 Answers1

1

The following should do what you want:

import time
from watchdog.observers import Observer
from watchdog.events import PatternMatchingEventHandler
import matplotlib.pyplot as plt

plt.ion()  # enter interactive mode
ax = fig.add_subplot(111)
Ln, = ax.plot(dat)
ax.set_xlim([0,10])
ax.set_ylim([-1,1])
plt.draw()  # non-blocking drawing
plt.pause(.001)  # This line is essential, without it the plot won't be shown

try:
    while True:
        time.sleep(1)
        if config.isnew:
            ...
            plt.draw()
            plt.pause(.001)

except KeyboardInterrupt:
    observer.stop()
observer.join()

The essential thin is to call plt.pause after the plt.draw call, else it won't be drawn, as the other python code block matplotlib. The value .001 is simply a try. I don't really know how it works under the hood, but this seems to work.

DerWeh
  • 1,721
  • 1
  • 15
  • 26
  • If anyone else struggles with this: it is essential to move the plotting out of the on_created function and into the While True - loop – 5norre Oct 13 '20 at 09:10