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'
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With