Filechooser UI should now have smaller buttons; Added enzyme activity zones & legend; added legend for data lines; default view renders a graph; graph now updates properly after clearing data and after selecting a reference profile
This commit is contained in:
parent
c7264ded31
commit
f328a6dae6
4
main.kv
4
main.kv
|
@ -12,6 +12,7 @@
|
||||||
text: 'Continuing will clear the graph and turn off logging to file.'
|
text: 'Continuing will clear the graph and turn off logging to file.'
|
||||||
BoxLayout:
|
BoxLayout:
|
||||||
orientation: 'horizontal'
|
orientation: 'horizontal'
|
||||||
|
size_hint_y: 0.1
|
||||||
Button:
|
Button:
|
||||||
id: cancel_button
|
id: cancel_button
|
||||||
text: 'Cancel'
|
text: 'Cancel'
|
||||||
|
@ -70,11 +71,10 @@
|
||||||
text: 'Select a reference temperature profile (csv)'
|
text: 'Select a reference temperature profile (csv)'
|
||||||
size_hint_y: 0.1
|
size_hint_y: 0.1
|
||||||
FileChooserListView:
|
FileChooserListView:
|
||||||
size_hint_y: 0.8
|
|
||||||
id: filechooser
|
id: filechooser
|
||||||
filters: ['*.csv']
|
filters: ['*.csv']
|
||||||
BoxLayout:
|
BoxLayout:
|
||||||
size_hiny_y: 0.1
|
size_hint_y: 0.1
|
||||||
orientation: 'horizontal'
|
orientation: 'horizontal'
|
||||||
Button:
|
Button:
|
||||||
text: 'Cancel'
|
text: 'Cancel'
|
||||||
|
|
94
main.py
94
main.py
|
@ -8,7 +8,7 @@ from kivy.core.image.img_pygame import ImageLoaderPygame
|
||||||
import kivy.graphics.texture
|
import kivy.graphics.texture
|
||||||
from kivy.graphics.texture import Texture
|
from kivy.graphics.texture import Texture
|
||||||
from kivy.logger import Logger
|
from kivy.logger import Logger
|
||||||
from kivy.properties import DictProperty, ListProperty, NumericProperty, ObjectProperty, StringProperty
|
from kivy.properties import BooleanProperty, DictProperty, ListProperty, NumericProperty, ObjectProperty, StringProperty
|
||||||
from kivy.uix.boxlayout import BoxLayout
|
from kivy.uix.boxlayout import BoxLayout
|
||||||
from kivy.uix.button import Button
|
from kivy.uix.button import Button
|
||||||
from kivy.uix.dropdown import DropDown
|
from kivy.uix.dropdown import DropDown
|
||||||
|
@ -23,6 +23,8 @@ import kivy.lang
|
||||||
import matplotlib
|
import matplotlib
|
||||||
matplotlib.use('Agg')
|
matplotlib.use('Agg')
|
||||||
import matplotlib.image
|
import matplotlib.image
|
||||||
|
import matplotlib.lines
|
||||||
|
import matplotlib.patches
|
||||||
import matplotlib.pyplot
|
import matplotlib.pyplot
|
||||||
import numpy
|
import numpy
|
||||||
import os
|
import os
|
||||||
|
@ -366,6 +368,21 @@ class PlotWidget(Image):
|
||||||
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('')
|
||||||
|
# @TODO Include a way to change these properties.
|
||||||
|
show_betaglucan = BooleanProperty(True)
|
||||||
|
show_protease = BooleanProperty(True)
|
||||||
|
show_betaamylase = BooleanProperty(True)
|
||||||
|
show_alphaamylase = BooleanProperty(True)
|
||||||
|
|
||||||
|
# Common data that we should only instantiate once
|
||||||
|
# Source : http://www.howtobrew.com/section3/chapter14-1.html
|
||||||
|
# accessed on march 21, 2015
|
||||||
|
# x_vertices = ((x, y), width, height, color, legend_string)
|
||||||
|
betaglucan_vertices = ((0, 35), 12000, 10, '#57ff14', 'Betaglucanase')
|
||||||
|
protease_vertices = ((0,45), 12000, 10, '#f3ff14', 'Protease / Peptidase')
|
||||||
|
betaamylase_vertices = ((0,55), 12000, 10.6, '#ffc014', 'Beta Amylase')
|
||||||
|
alphaamylase_vertices = ((0, 67.7), 12000, 4.5, '#ff6614', 'Alpha Amylase')
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super(PlotWidget, self).__init__(**kwargs)
|
super(PlotWidget, self).__init__(**kwargs)
|
||||||
|
@ -381,6 +398,34 @@ class PlotWidget(Image):
|
||||||
self.image_data = None
|
self.image_data = None
|
||||||
self._image_raw_data = None
|
self._image_raw_data = None
|
||||||
self.reference_profile = None
|
self.reference_profile = None
|
||||||
|
self.do_update()
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
#matplotlib.patches.Polygon(vertices, facecolor = color)
|
||||||
|
)
|
||||||
|
legend_handles.append(p)
|
||||||
|
legend_strings.append(name)
|
||||||
|
self.figure.legend(legend_handles, legend_strings, 'upper left',
|
||||||
|
title = 'Enzyme Activity Zones')
|
||||||
|
|
||||||
|
|
||||||
def clear_data(self):
|
def clear_data(self):
|
||||||
|
@ -390,6 +435,7 @@ class PlotWidget(Image):
|
||||||
self.texture = None
|
self.texture = None
|
||||||
self.image_output_file = ''
|
self.image_output_file = ''
|
||||||
self.raw_data_output_file = ''
|
self.raw_data_output_file = ''
|
||||||
|
self.do_update()
|
||||||
|
|
||||||
|
|
||||||
def do_update(self):
|
def do_update(self):
|
||||||
|
@ -417,30 +463,44 @@ class PlotWidget(Image):
|
||||||
|
|
||||||
|
|
||||||
def to_image_data(self):
|
def to_image_data(self):
|
||||||
if not self.data.any():
|
# Add in polygons for hilightning particular temperature ranges of interest.
|
||||||
return
|
plot_args = []
|
||||||
#Logger.debug('self.data: ' + str(self.data))
|
t = None
|
||||||
#Logger.debug('self.data shape: ' + str(self.data.shape))
|
time_max = 60
|
||||||
|
temp_max = 80
|
||||||
|
handles = []
|
||||||
|
if self.data.any():
|
||||||
data = numpy.copy(self.data)
|
data = numpy.copy(self.data)
|
||||||
data = data.transpose()
|
data = data.transpose()
|
||||||
#Logger.debug('transpoed data: ' + str(data))
|
|
||||||
#Logger.debug('transposed data shape: ' + str(data.shape))
|
|
||||||
t, temperature = numpy.split(data, 2, axis = 0)
|
t, temperature = numpy.split(data, 2, axis = 0)
|
||||||
reference_data = None
|
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 self.reference_profile is not None and self.reference_profile.any():
|
if self.reference_profile is not None and self.reference_profile.any():
|
||||||
reference_data = numpy.copy(self.reference_profile)
|
reference_data = numpy.copy(self.reference_profile)
|
||||||
reference_data = reference_data.transpose()
|
reference_data = reference_data.transpose()
|
||||||
t2, reference_temperature = numpy.split(reference_data, 2, axis = 0)
|
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
|
# Add t[0] to all reference points to make it fit on the current graph
|
||||||
|
if t:
|
||||||
t2 = numpy.add(t2, t[0][0])
|
t2 = numpy.add(t2, t[0][0])
|
||||||
#Logger.debug('PlotWidget: reference profile t: ' + str(t2))
|
if t2[0][-1] > time_max:
|
||||||
#Logger.debug('PlotWidget: reference profile temp: ' + str(reference_temperature))
|
time_max = t2[0][-1]
|
||||||
#Logger.debug('PlotWidget: time: ' + str(t[0]))
|
if numpy.nanmax(reference_temperature[0]) > temp_max:
|
||||||
#Logger.debug('PlotWidget: temperature: ' + str(temperature[0]))
|
temp_max = numpy.nanmax(reference_temperature[0])
|
||||||
if reference_data is not None and reference_data.any():
|
plot_args.extend((t2[0], reference_temperature[0], 'r'))
|
||||||
self.plot_axes.plot(t[0], temperature[0], 'b', t2[0], reference_temperature[0], 'r')
|
handles.append('Reference Temperature Profile')
|
||||||
else:
|
lines = self.plot_axes.plot(*plot_args)
|
||||||
self.plot_axes.plot(t[0], temperature[0], 'b')
|
# Patches must be changed after the axes are plotted.
|
||||||
|
self.update_patches(time_max)
|
||||||
|
self.plot_axes.legend(lines, handles, 'upper right', title = 'Temperature Profiles')
|
||||||
|
if not lines:
|
||||||
|
# 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 = StringIO.StringIO()
|
image_data = StringIO.StringIO()
|
||||||
self.figure.savefig(image_data, format = 'png')
|
self.figure.savefig(image_data, format = 'png')
|
||||||
image_data.seek(0)
|
image_data.seek(0)
|
||||||
|
@ -487,6 +547,7 @@ class PlotWidget(Image):
|
||||||
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()
|
||||||
|
self.do_update()
|
||||||
|
|
||||||
|
|
||||||
def load_reference_profile(self):
|
def load_reference_profile(self):
|
||||||
|
@ -496,6 +557,7 @@ class PlotWidget(Image):
|
||||||
delimiter=',')
|
delimiter=',')
|
||||||
Logger.debug('PlotWidget: reference_profile: ' + str(self.reference_profile))
|
Logger.debug('PlotWidget: reference_profile: ' + str(self.reference_profile))
|
||||||
|
|
||||||
|
|
||||||
class YesNoModalView(Popup):
|
class YesNoModalView(Popup):
|
||||||
|
|
||||||
def process(self, result, *args, **kwargs):
|
def process(self, result, *args, **kwargs):
|
||||||
|
|
Loading…
Reference in New Issue