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.' | ||||
|         BoxLayout: | ||||
|             orientation: 'horizontal' | ||||
|             size_hint_y: 0.1 | ||||
|             Button: | ||||
|                 id: cancel_button | ||||
|                 text: 'Cancel' | ||||
|  | @ -70,11 +71,10 @@ | |||
|             text: 'Select a reference temperature profile (csv)' | ||||
|             size_hint_y: 0.1 | ||||
|         FileChooserListView: | ||||
|             size_hint_y: 0.8 | ||||
|             id: filechooser | ||||
|             filters: ['*.csv'] | ||||
|         BoxLayout: | ||||
|             size_hiny_y: 0.1 | ||||
|             size_hint_y: 0.1 | ||||
|             orientation: 'horizontal' | ||||
|             Button: | ||||
|                 text: 'Cancel' | ||||
|  |  | |||
							
								
								
									
										94
									
								
								main.py
								
								
								
								
							
							
						
						
									
										94
									
								
								main.py
								
								
								
								
							|  | @ -8,7 +8,7 @@ from kivy.core.image.img_pygame import ImageLoaderPygame | |||
| import kivy.graphics.texture | ||||
| from kivy.graphics.texture import Texture | ||||
| 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.button import Button | ||||
| from kivy.uix.dropdown import DropDown | ||||
|  | @ -23,6 +23,8 @@ import kivy.lang | |||
| import matplotlib | ||||
| matplotlib.use('Agg') | ||||
| import matplotlib.image | ||||
| import matplotlib.lines | ||||
| import matplotlib.patches | ||||
| import matplotlib.pyplot | ||||
| import numpy | ||||
| import os | ||||
|  | @ -366,6 +368,21 @@ class PlotWidget(Image): | |||
|     image_output_file = StringProperty('') | ||||
|     raw_data_output_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): | ||||
|         super(PlotWidget, self).__init__(**kwargs) | ||||
|  | @ -381,6 +398,34 @@ class PlotWidget(Image): | |||
|         self.image_data = None | ||||
|         self._image_raw_data = 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): | ||||
|  | @ -390,6 +435,7 @@ class PlotWidget(Image): | |||
|         self.texture = None | ||||
|         self.image_output_file = '' | ||||
|         self.raw_data_output_file = '' | ||||
|         self.do_update() | ||||
| 
 | ||||
| 
 | ||||
|     def do_update(self): | ||||
|  | @ -417,30 +463,44 @@ class PlotWidget(Image): | |||
| 
 | ||||
| 
 | ||||
|     def to_image_data(self): | ||||
|         if not self.data.any(): | ||||
|             return | ||||
|         #Logger.debug('self.data: ' + str(self.data)) | ||||
|         #Logger.debug('self.data shape: ' + str(self.data.shape)) | ||||
|         # Add in polygons for hilightning particular temperature ranges of interest. | ||||
|         plot_args = [] | ||||
|         t = None | ||||
|         time_max = 60 | ||||
|         temp_max = 80 | ||||
|         handles = [] | ||||
|         if self.data.any(): | ||||
|             data = numpy.copy(self.data) | ||||
|             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) | ||||
|         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(): | ||||
|             reference_data = numpy.copy(self.reference_profile) | ||||
|             reference_data = reference_data.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 | ||||
|             if t: | ||||
|                 t2 = numpy.add(t2, t[0][0]) | ||||
|             #Logger.debug('PlotWidget: reference profile t: ' + str(t2)) | ||||
|             #Logger.debug('PlotWidget: reference profile temp: ' + str(reference_temperature)) | ||||
|         #Logger.debug('PlotWidget: time: ' + str(t[0])) | ||||
|         #Logger.debug('PlotWidget: temperature: ' + str(temperature[0])) | ||||
|         if reference_data is not None and reference_data.any(): | ||||
|             self.plot_axes.plot(t[0], temperature[0], 'b', t2[0], reference_temperature[0], 'r') | ||||
|         else: | ||||
|             self.plot_axes.plot(t[0], temperature[0], 'b') | ||||
|             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(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() | ||||
|         self.figure.savefig(image_data, format = 'png') | ||||
|         image_data.seek(0) | ||||
|  | @ -487,6 +547,7 @@ class PlotWidget(Image): | |||
|     def on_reference_profile_file(self, *args, **kwargs): | ||||
|         Logger.debug('PlotWidget: on_reference_profile_file ' + str(self.reference_profile_file)) | ||||
|         self.load_reference_profile() | ||||
|         self.do_update() | ||||
| 
 | ||||
| 
 | ||||
|     def load_reference_profile(self): | ||||
|  | @ -496,6 +557,7 @@ class PlotWidget(Image): | |||
|                                                delimiter=',') | ||||
|         Logger.debug('PlotWidget: reference_profile: ' + str(self.reference_profile)) | ||||
| 
 | ||||
| 
 | ||||
| class YesNoModalView(Popup): | ||||
| 
 | ||||
|     def process(self, result, *args, **kwargs): | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue