Data is now pulled from sensor queue in batches, no limit to size. Temperature queue check frequency reduced. Image plotting now happens in a background thread.
This commit is contained in:
parent
babac7ae2e
commit
c6e7aefb96
4
main.kv
4
main.kv
|
@ -89,9 +89,8 @@
|
||||||
serial_chooser_button: serial_chooser_button
|
serial_chooser_button: serial_chooser_button
|
||||||
on_dataSources: serial_chooser_button.values = self.dataSources
|
on_dataSources: serial_chooser_button.values = self.dataSources
|
||||||
on_lastTemperature: current_temperature.on_temperature_change(self.lastTemperature)
|
on_lastTemperature: current_temperature.on_temperature_change(self.lastTemperature)
|
||||||
on_lastTemperature: mainplot.on_lastTemperature(self.lastTemperature)
|
|
||||||
on_lastTime: mainplot.on_lastTime(self.lastTime)
|
|
||||||
on_lastStatus: status_bar.update_status(self.lastStatus)
|
on_lastStatus: status_bar.update_status(self.lastStatus)
|
||||||
|
on_lastData: mainplot.update_data(self.lastData)
|
||||||
raw_data_output_file: ''
|
raw_data_output_file: ''
|
||||||
image_output_file: ''
|
image_output_file: ''
|
||||||
on_raw_data_output_file: mainplot.raw_data_output_file = self.raw_data_output_file
|
on_raw_data_output_file: mainplot.raw_data_output_file = self.raw_data_output_file
|
||||||
|
@ -173,4 +172,5 @@
|
||||||
StatusBar:
|
StatusBar:
|
||||||
size_hint_y: 0.1
|
size_hint_y: 0.1
|
||||||
id: status_bar
|
id: status_bar
|
||||||
|
|
||||||
MainWindow:
|
MainWindow:
|
336
main.py
336
main.py
|
@ -1,7 +1,10 @@
|
||||||
|
import io
|
||||||
import kivy
|
import kivy
|
||||||
from kivy.app import App
|
from kivy.app import App
|
||||||
from kivy.clock import Clock
|
from kivy.clock import Clock
|
||||||
import kivy.core.image
|
import kivy.core.image
|
||||||
|
import kivy.config
|
||||||
|
import kivy.core.image
|
||||||
from kivy.core.image import ImageData
|
from kivy.core.image import ImageData
|
||||||
from kivy.core.image.img_pil import ImageLoaderPIL
|
from kivy.core.image.img_pil import ImageLoaderPIL
|
||||||
from kivy.core.image.img_pygame import ImageLoaderPygame
|
from kivy.core.image.img_pygame import ImageLoaderPygame
|
||||||
|
@ -22,6 +25,7 @@ from kivy.uix.spinner import Spinner
|
||||||
import kivy.lang
|
import kivy.lang
|
||||||
import matplotlib
|
import matplotlib
|
||||||
matplotlib.use('Agg')
|
matplotlib.use('Agg')
|
||||||
|
import matplotlib.backends.backend_agg
|
||||||
import matplotlib.image
|
import matplotlib.image
|
||||||
import matplotlib.lines
|
import matplotlib.lines
|
||||||
import matplotlib.patches
|
import matplotlib.patches
|
||||||
|
@ -41,11 +45,13 @@ dataThreadDataQueue = Queue.Queue()
|
||||||
dataThreadCommandQueue = Queue.Queue()
|
dataThreadCommandQueue = Queue.Queue()
|
||||||
defaultSerialPort = '/dev/ttyACM0'
|
defaultSerialPort = '/dev/ttyACM0'
|
||||||
|
|
||||||
|
kivy.config.Config.set('modules', 'monitor', '')
|
||||||
|
|
||||||
class MainApp(App):
|
class MainApp(App):
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
mainWindow = MainWindow()
|
mainWindow = MainWindow()
|
||||||
Clock.schedule_interval(mainWindow.update, 0.25)
|
Clock.schedule_interval(mainWindow.update, 0.5)
|
||||||
return mainWindow
|
return mainWindow
|
||||||
|
|
||||||
|
|
||||||
|
@ -71,6 +77,8 @@ class MainWindow(FloatLayout):
|
||||||
image_output_file = StringProperty('')
|
image_output_file = StringProperty('')
|
||||||
raw_data_output_file = StringProperty('')
|
raw_data_output_file = StringProperty('')
|
||||||
reference_profile_file = StringProperty('')
|
reference_profile_file = StringProperty('')
|
||||||
|
lastData = ListProperty([])
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super(MainWindow, self).__init__(**kwargs)
|
super(MainWindow, self).__init__(**kwargs)
|
||||||
|
@ -83,38 +91,39 @@ class MainWindow(FloatLayout):
|
||||||
def update_last_temperature(self):
|
def update_last_temperature(self):
|
||||||
global dataThreadDataQueue
|
global dataThreadDataQueue
|
||||||
# This breaks if there are more updates in the queue than the frequency of update_last_temperature - it pulls old data out of the queue, and not the most recent.
|
# This breaks if there are more updates in the queue than the frequency of update_last_temperature - it pulls old data out of the queue, and not the most recent.
|
||||||
try:
|
done = False
|
||||||
data = dataThreadDataQueue.get_nowait()
|
data = []
|
||||||
if data is not None:
|
while not done:
|
||||||
Logger.debug('Data: ' + str(data))
|
try:
|
||||||
if self.state != 'paused':
|
data.append(dataThreadDataQueue.get_nowait())
|
||||||
if 'data' in data and 'temperature' in data['data']:
|
except Queue.Empty:
|
||||||
self.lastStatus = {'status' : 'ok', 'message' : ''}
|
done = True
|
||||||
self.lastTemperature = float(data['data']['temperature'])
|
if data:
|
||||||
if 'time' in data:
|
if len(data) > 1:
|
||||||
self.lastTime = float(data['time'])
|
Logger.debug('update_last_temperature: ' + str(len(data)) + ' items retrieved from queue')
|
||||||
if 'exception' in data:
|
last_point = data[-1]
|
||||||
self.lastStatus = {'status' : 'error', 'message' : data['exception']}
|
if self.state == 'paused':
|
||||||
else:
|
# Try to update the last temperature, but not to the plotwidget,
|
||||||
self.lastStatus = {'status' : 'paused', 'message' : 'Data reception halted by user'}
|
# when the data reception is halted.
|
||||||
Logger.debug('MainWindow: state set to ' + str(self.state) + ' : ignoring data')
|
self.lastStatus = {'status' : 'paused', 'message' : 'Data receiption halted by user'}
|
||||||
if dataThreadDataQueue.qsize():
|
if 'data' in last_point and 'temperature' in last_point['data']:
|
||||||
Logger.debug('Queue Size: ' + str(dataThreadDataQueue.qsize()))
|
self.lastTemperature = float(last_point['data']['temperature'])
|
||||||
except Queue.Empty:
|
return
|
||||||
pass
|
if 'data' in last_point and 'temperature' in last_point['data']:
|
||||||
|
self.lastStatus = {'status' : 'ok', 'message' : ''}
|
||||||
|
self.lastTemperature = float(last_point['data']['temperature'])
|
||||||
def on_lastTemperature(self, instance, value):
|
if 'time' in last_point:
|
||||||
Logger.debug('lastTemperature has changed to: ' + str(value))
|
self.lastTime = float(last_point['time'])
|
||||||
|
if 'exception' in last_point:
|
||||||
|
self.lastStatus = {'status' : 'error', 'message' : data['exception']}
|
||||||
def on_lastTime(self, instance, value):
|
self.lastData = data
|
||||||
Logger.debug('lastTime has changed to: ' + str(value))
|
if dataThreadDataQueue.qsize():
|
||||||
|
Logger.debug('update_last_temperature: ' + str(dataThreadDataQueue.qsize()) + ' items left in queue after ' + str(len(data)) + ' items were taken out')
|
||||||
|
|
||||||
def update(self, dt):
|
def update(self, dt):
|
||||||
self.update_data_sources()
|
self.update_data_sources()
|
||||||
self.update_last_temperature()
|
self.update_last_temperature()
|
||||||
|
Logger.debug('MainWindow: FPS ' + str(kivy.clock.Clock.get_fps()))
|
||||||
#Logger.debug('MainWindow: dataThread ' + str(dataThread.name) + ' status: ' + str(dataThread.is_alive()))
|
#Logger.debug('MainWindow: dataThread ' + str(dataThread.name) + ' status: ' + str(dataThread.is_alive()))
|
||||||
|
|
||||||
|
|
||||||
|
@ -378,7 +387,8 @@ class PlotWidget(Image):
|
||||||
show_alphaamylase = BooleanProperty(True)
|
show_alphaamylase = BooleanProperty(True)
|
||||||
file_write_interval = NumericProperty(15)
|
file_write_interval = NumericProperty(15)
|
||||||
image_update_interval = NumericProperty(5)
|
image_update_interval = NumericProperty(5)
|
||||||
|
buildingImage = BooleanProperty(False)
|
||||||
|
imageDataQueue = ObjectProperty(None, allownone = True)
|
||||||
|
|
||||||
# Common data that we should only instantiate once
|
# Common data that we should only instantiate once
|
||||||
# Source : http://www.howtobrew.com/section3/chapter14-1.html
|
# Source : http://www.howtobrew.com/section3/chapter14-1.html
|
||||||
|
@ -392,6 +402,7 @@ class PlotWidget(Image):
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super(PlotWidget, self).__init__(**kwargs)
|
super(PlotWidget, self).__init__(**kwargs)
|
||||||
|
self.imageThread = None
|
||||||
self.data = numpy.array([], dtype=float);
|
self.data = numpy.array([], dtype=float);
|
||||||
self.lastTime = 0
|
self.lastTime = 0
|
||||||
self.lastTemperature = 0
|
self.lastTemperature = 0
|
||||||
|
@ -406,7 +417,7 @@ class PlotWidget(Image):
|
||||||
self._image_raw_data = None
|
self._image_raw_data = None
|
||||||
self.reference_profile = None
|
self.reference_profile = None
|
||||||
Clock.schedule_interval(self.do_update, self.image_update_interval)
|
Clock.schedule_interval(self.do_update, self.image_update_interval)
|
||||||
self.do_update()
|
Clock.schedule_once(self.do_update)
|
||||||
|
|
||||||
|
|
||||||
def on_image_update_interval(self, *args):
|
def on_image_update_interval(self, *args):
|
||||||
|
@ -415,34 +426,6 @@ class PlotWidget(Image):
|
||||||
Clock.schedule_interval(self.do_update, self.image_update_interval)
|
Clock.schedule_interval(self.do_update, self.image_update_interval)
|
||||||
|
|
||||||
|
|
||||||
def update_patches(self, tmax = None):
|
|
||||||
items = [
|
|
||||||
(self.show_betaglucan, self.betaglucan_vertices),
|
|
||||||
(self.show_protease, self.protease_vertices),
|
|
||||||
(self.show_betaamylase, self.betaamylase_vertices),
|
|
||||||
(self.show_alphaamylase, self.alphaamylase_vertices)
|
|
||||||
]
|
|
||||||
legend_handles = []
|
|
||||||
legend_strings = []
|
|
||||||
for show, config in items:
|
|
||||||
color = '0.5' # default color.
|
|
||||||
if show:
|
|
||||||
origin, width, height, color, name = config
|
|
||||||
if tmax is not None:
|
|
||||||
width = tmax
|
|
||||||
p = self.plot_axes.add_patch(
|
|
||||||
matplotlib.patches.Rectangle(origin, width, height,
|
|
||||||
fc = color, visible = True,
|
|
||||||
fill = True)
|
|
||||||
)
|
|
||||||
legend_handles.append(p)
|
|
||||||
legend_strings.append(name)
|
|
||||||
# Disabled for the moment
|
|
||||||
self.figure.legend(legend_handles, legend_strings, 'lower right',
|
|
||||||
title = 'Enzyme Activity Zones')
|
|
||||||
return legend_handles
|
|
||||||
|
|
||||||
|
|
||||||
def clear_data(self):
|
def clear_data(self):
|
||||||
self.update_output_files(True)
|
self.update_output_files(True)
|
||||||
self.data = numpy.array([], dtype=float);
|
self.data = numpy.array([], dtype=float);
|
||||||
|
@ -455,79 +438,49 @@ class PlotWidget(Image):
|
||||||
|
|
||||||
|
|
||||||
def do_update(self, *args):
|
def do_update(self, *args):
|
||||||
image_data = self.to_image_data()
|
if self.buildingImage:
|
||||||
# We can't use ImageLoaders since they assume it's a file on disk.
|
# Check end condition, retrieve data, clean-up
|
||||||
# This replicates code from ImageLoaderPygame.load() and ImageLoaderBase.populate()
|
if self.imageThread.isAlive():
|
||||||
try:
|
return
|
||||||
im = pygame.image.load(image_data)
|
self.imageThread.join(0.01)
|
||||||
except:
|
image_data = None
|
||||||
Logger.warning('Image: Unable to load image from data')
|
try:
|
||||||
raise
|
image_data = self.imageDataQueue.get_nowait()
|
||||||
fmt = ''
|
except Queue.Empty:
|
||||||
if im.get_bytesize() == 3:
|
pass
|
||||||
fmt = 'rgb'
|
if image_data:
|
||||||
elif im.get_bytesize() == 4:
|
image = image_data['kivy_image']
|
||||||
fmt = 'rgba'
|
self.texture = image.texture
|
||||||
data = pygame.image.tostring(im, fmt.upper())
|
self._image_raw_data = image_data['raw_image_data']
|
||||||
self.image_data = ImageData(im.get_width(), im.get_height(), fmt, data)
|
self.imageThread = None
|
||||||
self.texture = Texture.create_from_data(self.image_data)
|
self.imageDataQueue = None
|
||||||
self.texture.flip_vertical()
|
# @TODO self.update_output_files() should may be a scheduled task
|
||||||
# Update output files, if any
|
self.update_output_files()
|
||||||
# @TODO Add in an update interval so the disk isn't hammered on every single update
|
self.buildingImage = False
|
||||||
self.update_output_files()
|
return
|
||||||
|
self.buildingImage = True
|
||||||
|
self.imageDataQueue = Queue.Queue()
|
||||||
def to_image_data(self):
|
settings = {
|
||||||
# Add in polygons for hilightning particular temperature ranges of interest.
|
'patches' : {
|
||||||
plot_args = []
|
'betaglucan' : { 'show' : self.show_betaglucan,
|
||||||
t = None
|
'vertices' : self.betaglucan_vertices},
|
||||||
time_max = 60
|
'protease' : { 'show' : self.show_protease,
|
||||||
temp_max = 80
|
'vertices' : self.protease_vertices},
|
||||||
handles = []
|
'betaamylase' : { 'show' : self.show_betaamylase,
|
||||||
if self.data.any():
|
'vertices' : self.betaamylase_vertices},
|
||||||
#data = numpy.copy(self.data)
|
'alphaamylase' : { 'show' : self.show_alphaamylase,
|
||||||
data = self.data.transpose()
|
'vertices' : self.alphaamylase_vertices},
|
||||||
t, temperature = numpy.split(data, 2, axis = 0)
|
}
|
||||||
if t[0][-1] > time_max:
|
}
|
||||||
time_max = t[0][-1]
|
self.imageThread = threading.Thread(None, threaded_image_builder, None,
|
||||||
#if numpy.nanmax(temperature[0]) > temp_max:
|
[self.data, self.reference_profile,
|
||||||
# temp_max = numpy.nanmax(temperature[0])
|
self.imageDataQueue, settings])
|
||||||
plot_args.extend((t[0], temperature[0], 'b'))
|
self.imageThread.start()
|
||||||
handles.append('Recorded Temperature Profile')
|
|
||||||
if self.reference_profile is not None and self.reference_profile.any():
|
|
||||||
#reference_data = numpy.copy(self.reference_profile)
|
|
||||||
reference_data = self.reference_profile.transpose()
|
|
||||||
t2, reference_temperature = numpy.split(reference_data, 2, axis = 0)
|
|
||||||
# Add t[0] to all reference points to make it fit on the current graph
|
|
||||||
t2 = numpy.add(t2, t[0][0])
|
|
||||||
if t2[0][-1] > time_max:
|
|
||||||
time_max = t2[0][-1]
|
|
||||||
#if numpy.nanmax(reference_temperature[0]) > temp_max:
|
|
||||||
# temp_max = numpy.nanmax(reference_temperature[0])
|
|
||||||
plot_args.extend((t2[0], reference_temperature[0], 'r'))
|
|
||||||
handles.append('Reference Temperature Profile')
|
|
||||||
lines = self.plot_axes.plot(*plot_args)
|
|
||||||
# Patches must be changed after the axes are plotted.
|
|
||||||
self.update_patches()
|
|
||||||
# Disabled the legend for the moment.
|
|
||||||
# @TODO Make a small subplot next to the main plot into which legends may be placed.
|
|
||||||
#self.plot_axes.legend(lines, handles, 'lower right', title = 'Temperature Profiles')
|
|
||||||
# Set a default in case no data is plotted. This may allow patches to show,
|
|
||||||
# and it will look a little nicer before recording starts.
|
|
||||||
#self.plot_axes.set_xlim(0, time_max)
|
|
||||||
self.plot_axes.set_ylim(0, temp_max)
|
|
||||||
image_data = cStringIO.StringIO()
|
|
||||||
self.figure.savefig(image_data, format = 'png')
|
|
||||||
image_data.seek(0)
|
|
||||||
self._image_raw_data = image_data.getvalue()
|
|
||||||
return image_data
|
|
||||||
|
|
||||||
|
|
||||||
def update_output_files(self, force = False):
|
def update_output_files(self, force = False):
|
||||||
# Do this only once every 15 seconds to avoid hitting the disk frequently
|
# Do this only once every 15 seconds to avoid hitting the disk frequently
|
||||||
Logger.debug('update_output_files called')
|
|
||||||
if force or time.time() - self.lastSave > self.file_write_interval:
|
if force or time.time() - self.lastSave > self.file_write_interval:
|
||||||
Logger.debug('update_output_files going ahead')
|
|
||||||
self.update_raw_data_output_file()
|
self.update_raw_data_output_file()
|
||||||
self.update_image_output_file()
|
self.update_image_output_file()
|
||||||
self.lastSave = time.time()
|
self.lastSave = time.time()
|
||||||
|
@ -551,31 +504,24 @@ class PlotWidget(Image):
|
||||||
Logger.debug('update_image_output_file: Unable to open file ' + self.image_output_file)
|
Logger.debug('update_image_output_file: Unable to open file ' + self.image_output_file)
|
||||||
|
|
||||||
|
|
||||||
def on_lastTemperature(self, value):
|
def update_data(self, data = list(), *args):
|
||||||
self.lastTemperature = value
|
points = []
|
||||||
|
for point in data:
|
||||||
|
if 'data' in point and 'time' in point and 'temperature' in point['data']:
|
||||||
def on_lastTime(self, value):
|
points.append(numpy.array([(point['time'], point['data']['temperature'])],
|
||||||
self.lastTime = value
|
dtype=float, ndmin =2))
|
||||||
self.update_data()
|
extra_data = numpy.vstack(tuple(points))
|
||||||
|
|
||||||
|
|
||||||
def update_data(self):
|
|
||||||
if self.lastTime == 0 or self.lastTemperature == 0:
|
|
||||||
return
|
|
||||||
newpoint = numpy.array([(self.lastTime, self.lastTemperature)], dtype=float, ndmin = 2)
|
|
||||||
if not self.data.any():
|
if not self.data.any():
|
||||||
self.data = newpoint
|
self.data = extra_data
|
||||||
return
|
return
|
||||||
#Logger.debug('self.data: ' + str(self.data))
|
#Logger.debug('self.data: ' + str(self.data))
|
||||||
#Logger.debug('newpoint: ' + str(newpoint))
|
#Logger.debug('newpoint: ' + str(newpoint))
|
||||||
self.data = numpy.vstack((self.data, newpoint))
|
self.data = numpy.vstack((self.data, extra_data))
|
||||||
|
|
||||||
|
|
||||||
def on_reference_profile_file(self, *args, **kwargs):
|
def on_reference_profile_file(self, *args, **kwargs):
|
||||||
Logger.debug('PlotWidget: on_reference_profile_file ' + str(self.reference_profile_file))
|
Logger.debug('PlotWidget: on_reference_profile_file ' + str(self.reference_profile_file))
|
||||||
self.load_reference_profile()
|
self.load_reference_profile()
|
||||||
Clock.schedule_once(self.do_update)
|
|
||||||
|
|
||||||
|
|
||||||
def load_reference_profile(self):
|
def load_reference_profile(self):
|
||||||
|
@ -621,6 +567,110 @@ class StatusBar(BoxLayout):
|
||||||
self.ids.status_image.source = './images/warning.png'
|
self.ids.status_image.source = './images/warning.png'
|
||||||
|
|
||||||
|
|
||||||
|
def threaded_image_builder(data, reference_profile, dataQueue, settings = dict()):
|
||||||
|
figure, plot_axes = init_plot(settings)
|
||||||
|
start = time.time()
|
||||||
|
image_data = create_graph(figure, plot_axes, data, reference_profile, settings)
|
||||||
|
Logger.debug('threaded_image_builder: Took ' + str(time.time() - start) + ' seconds to build image data')
|
||||||
|
return_data = dict()
|
||||||
|
start = time.time()
|
||||||
|
image_data_raw = image_data.getvalue()
|
||||||
|
image_bytes = io.BytesIO(image_data_raw)
|
||||||
|
return_data['raw_image_data'] = image_data_raw
|
||||||
|
return_data['kivy_image'] = kivy.core.image.Image(image_bytes, ext = 'png')
|
||||||
|
Logger.debug('threaded_image_builder: Took ' + str(time.time() - start) + ' seconds to manipulate image data')
|
||||||
|
dataQueue.put_nowait(return_data)
|
||||||
|
|
||||||
|
|
||||||
|
def init_plot(settings = dict()):
|
||||||
|
figure = matplotlib.pyplot.figure()
|
||||||
|
plot_axes = figure.add_subplot(1, 1, 1)
|
||||||
|
plot_axes.hold(False)
|
||||||
|
plot_axes.set_ylabel('Temperature (deg C)')
|
||||||
|
plot_axes.set_xlabel('Time')
|
||||||
|
plot_axes.set_title('Recorded Temperature')
|
||||||
|
return figure, plot_axes
|
||||||
|
|
||||||
|
|
||||||
|
def create_graph(figure, plot_axes, data, reference_profile, settings = dict()):
|
||||||
|
# Add in polygons for hilightning particular temperature ranges of interest.
|
||||||
|
plot_args = []
|
||||||
|
t = None
|
||||||
|
time_max = 60
|
||||||
|
temp_max = 80
|
||||||
|
handles = []
|
||||||
|
if data.any():
|
||||||
|
#data = numpy.copy(self.data)
|
||||||
|
data = data.transpose()
|
||||||
|
t, temperature = numpy.split(data, 2, axis = 0)
|
||||||
|
if t[0][-1] > time_max:
|
||||||
|
time_max = t[0][-1]
|
||||||
|
#if numpy.nanmax(temperature[0]) > temp_max:
|
||||||
|
# temp_max = numpy.nanmax(temperature[0])
|
||||||
|
plot_args.extend((t[0], temperature[0], 'b'))
|
||||||
|
handles.append('Recorded Temperature Profile')
|
||||||
|
if reference_profile is not None and reference_profile.any():
|
||||||
|
#reference_data = numpy.copy(self.reference_profile)
|
||||||
|
reference_data = reference_profile.transpose()
|
||||||
|
t2, reference_temperature = numpy.split(reference_data, 2, axis = 0)
|
||||||
|
# Add t[0] to all reference points to make it fit on the current graph
|
||||||
|
t2 = numpy.add(t2, t[0][0])
|
||||||
|
if t2[0][-1] > time_max:
|
||||||
|
time_max = t2[0][-1]
|
||||||
|
#if numpy.nanmax(reference_temperature[0]) > temp_max:
|
||||||
|
# temp_max = numpy.nanmax(reference_temperature[0])
|
||||||
|
plot_args.extend((t2[0], reference_temperature[0], 'r'))
|
||||||
|
handles.append('Reference Temperature Profile')
|
||||||
|
lines = plot_axes.plot(*plot_args)
|
||||||
|
# Patches must be changed after the axes are plotted.
|
||||||
|
graph_update_patches(figure, plot_axes, time_max, settings)
|
||||||
|
# Disabled the legend for the moment.
|
||||||
|
# @TODO Make a small subplot next to the main plot into which legends may be placed.
|
||||||
|
#self.plot_axes.legend(lines, handles, 'lower right', title = 'Temperature Profiles')
|
||||||
|
# Set a default in case no data is plotted. This may allow patches to show,
|
||||||
|
# and it will look a little nicer before recording starts.
|
||||||
|
#self.plot_axes.set_xlim(0, time_max)
|
||||||
|
plot_axes.set_ylim(0, temp_max)
|
||||||
|
image_data = cStringIO.StringIO()
|
||||||
|
# Save a 640x480 image, see http://stackoverflow.com/questions/13714454/specifying-and-saving-a-figure-with-exact-size-in-pixels
|
||||||
|
#canvas = matplotlib.backends.backend_agg.FigureCanvasAgg(figure)
|
||||||
|
#canvas.draw()
|
||||||
|
#renderer = canvas.get_renderer()
|
||||||
|
#raw_data = renderer.tostring_argb()
|
||||||
|
#size = canvas.get_width_height()
|
||||||
|
figure.savefig(image_data, format = 'png', dpi = 96, figsize = (640/96, 480/96))
|
||||||
|
#image_data.seek(0)
|
||||||
|
return image_data
|
||||||
|
#return raw_data, size
|
||||||
|
|
||||||
|
|
||||||
|
def graph_update_patches(figure, plot_axes, time_max, settings):
|
||||||
|
if 'patches' in settings:
|
||||||
|
settings = settings['patches']
|
||||||
|
items = list()
|
||||||
|
for patch_id, patch_settings in settings.iteritems():
|
||||||
|
items.append((patch_settings['show'], patch_settings['vertices']))
|
||||||
|
legend_handles = []
|
||||||
|
legend_strings = []
|
||||||
|
for show, config in items:
|
||||||
|
color = '0.5' # default color.
|
||||||
|
if show:
|
||||||
|
origin, width, height, color, name = config
|
||||||
|
if time_max is not None:
|
||||||
|
width = time_max
|
||||||
|
p = plot_axes.add_patch(
|
||||||
|
matplotlib.patches.Rectangle(origin, width, height,
|
||||||
|
fc = color, visible = True,
|
||||||
|
fill = True)
|
||||||
|
)
|
||||||
|
legend_handles.append(p)
|
||||||
|
legend_strings.append(name)
|
||||||
|
# Disabled for the moment
|
||||||
|
figure.legend(legend_handles, legend_strings, 'lower right',
|
||||||
|
title = 'Enzyme Activity Zones')
|
||||||
|
return legend_handles
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
dataThread = threading.Thread(None, temp_log.threaded_reader, None, ['/dev/ttyACM0', dataThreadDataQueue, dataThreadCommandQueue])
|
dataThread = threading.Thread(None, temp_log.threaded_reader, None, ['/dev/ttyACM0', dataThreadDataQueue, dataThreadCommandQueue])
|
||||||
MainApp().run()
|
MainApp().run()
|
||||||
|
|
Loading…
Reference in New Issue