From 04e60d69c4418e484647ff35dd8d71c0c48d6f43 Mon Sep 17 00:00:00 2001 From: "(no author)" <(no author)@8a9318a1-56ba-4d59-b755-99d26321be01> Date: Mon, 21 Nov 2011 17:25:32 +0000 Subject: [PATCH] adding mako version dependancy to setup.py; added new stats provider and figure manager to remove those tasks from the model; used partial to simplify the a/b controls/methods in the view git-svn-id: https://svn.ssec.wisc.edu/repos/glance/trunk@154 8a9318a1-56ba-4d59-b755-99d26321be01 --- pyglance/glance/data.py | 22 +++ pyglance/glance/gui_controller.py | 17 ++- pyglance/glance/gui_figuremanager.py | 158 +++++++++++++++++++ pyglance/glance/gui_model.py | 217 ++++++--------------------- pyglance/glance/gui_statsprovider.py | 100 ++++++++++++ pyglance/glance/gui_view.py | 62 ++------ pyglance/setup.py | 4 +- 7 files changed, 351 insertions(+), 229 deletions(-) create mode 100644 pyglance/glance/gui_figuremanager.py create mode 100644 pyglance/glance/gui_statsprovider.py diff --git a/pyglance/glance/data.py b/pyglance/glance/data.py index b7c1793..b1c6e2e 100644 --- a/pyglance/glance/data.py +++ b/pyglance/glance/data.py @@ -293,6 +293,28 @@ class DiffInfoObject (object) : mismatch_pt_mask, outside_epsilon_mask) return diff_data_object + + @staticmethod + def verifyDataCompatability (aDataObject, bDataObject, aName, bName) : + """ + Confirm that the two data objects can minimally be compared. + + return None if they can be compared or a text message explaining why they cannot. + """ + # check the minimum comparison requirments + message = None + + # if either object does not exist, they can not be compared + if (aDataObject is None) or (bDataObject is None) : + message = ("Requested data was not available or did not exist.") + # check to see if the two variables have the same shape of data + elif aDataObject.data.shape != bDataObject.data.shape : + message = (aName + ' / ' + bName + ' ' + + 'could not be compared because the data for these variables does not match in shape ' + + 'between the two files (file A data shape: ' + str(aDataObject.data.shape) + '; file B data shape: ' + + str(bDataObject.data.shape) + ').') + + return message class FileInfo (object) : """ diff --git a/pyglance/glance/gui_controller.py b/pyglance/glance/gui_controller.py index d123eef..1e9dda3 100644 --- a/pyglance/glance/gui_controller.py +++ b/pyglance/glance/gui_controller.py @@ -15,8 +15,10 @@ if os.path.isdir(PYQT4_HAX): from PyQt4 import QtGui -import glance.gui_view as gui_view -import glance.gui_model as gui_model +import glance.gui_view as gui_view +import glance.gui_model as gui_model +import glance.gui_statsprovider as gui_stats +import glance.gui_figuremanager as gui_figs LOG = logging.getLogger(__name__) @@ -33,6 +35,8 @@ class GlanceGUIController (object) : self.view - the view object (see glance.gui_view) self.model - the model object (see glance.gui_model) + self.stats - the stats provider object (see glance.gui_statsprovider) + self.figs - the figure manager object (see glance.gui_figuremanager) self.qtApp - an application object, used to start QT """ @@ -45,10 +49,15 @@ class GlanceGUIController (object) : self.qtApp = QtGui.QApplication(sys.argv) self.view = gui_view.GlanceGUIView(version_string) self.model = gui_model.GlanceGUIModel() + self.stats = gui_stats.GlanceGUIStats(self.model) + self.figs = gui_figs.GlanceGUIFigures(self.model) # set things up to talk to each other self.model.registerErrorHandler(self) self.model.registerDataListener(self.view) + self.stats.registerErrorHandler(self) + self.stats.registerStatsListener(self.view) + self.figs.registerErrorHandler(self) self.view.registerUserUpdateListener(self) # force the initial info load from the model @@ -112,14 +121,14 @@ class GlanceGUIController (object) : the user has asked for stats information """ - self.model.sendStatsInfo() # TODO, should a different object handle this? + self.stats.sendStatsInfo() def userRequestsPlot (self) : """ the user has asked for a plot """ - self.model.spawnPlotWithCurrentInfo() + self.figs.spawnPlot() ################# end of methods to handle user input reporting ################# diff --git a/pyglance/glance/gui_figuremanager.py b/pyglance/glance/gui_figuremanager.py new file mode 100644 index 0000000..6c5501c --- /dev/null +++ b/pyglance/glance/gui_figuremanager.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" +This module manages creating figures for the Glance GUI. + +Created by evas Nov 2011. +Copyright (c) 2011 University of Wisconsin SSEC. All rights reserved. +""" + +# these first two lines must stay before the pylab import +import matplotlib +matplotlib.use('Qt4Agg') # use the Qt Anti-Grain Geometry rendering engine + +from pylab import * + +import matplotlib.cm as cm +import matplotlib.pyplot as plt +import matplotlib.colors as colors + +import logging +import numpy as np + +import glance.data as dataobjects +import glance.figures as figures +import glance.gui_model as model + +LOG = logging.getLogger(__name__) + +# the number of bins to use for histograms +DEFAULT_NUM_BINS = 50 + +class GlanceGUIFigures (object) : + """ + This class handles creating figures for the glance gui. + + (in future it may manage them more actively) + + it includes: + + self.dataModel - the GlanceGUIModel object that contains the main data + model for the GUI + self.errorHandlers - objects that want to be notified when there's a serious error + """ + + def __init__ (self, dataModelToSave) : + """ + create a figure manager, hanging on to the data model, for use in creating figures + """ + + self.dataModel = dataModelToSave + self.errorHandlers = [ ] + + def registerErrorHandler (self, objectToRegister) : + """ + add the given object to our list of error handlers + """ + + if objectToRegister not in self.errorHandlers : + self.errorHandlers.append(objectToRegister) + + def spawnPlot (self) : + """ + create a matplotlib plot using the current model information + """ + + imageType = self.dataModel.getImageType() + + LOG.info ("Preparing variable data for plotting...") + + # get Variable names + aVarName = self.dataModel.getVariableName("A") + bVarName = self.dataModel.getVariableName("B") + + # get Data objects + aDataObject = self.dataModel.getVariableData("A", aVarName) + bDataObject = self.dataModel.getVariableData("B", bVarName) + + # TODO, this ignores the fact that the "original" plots don't need two sets of data + message = dataobjects.DiffInfoObject.verifyDataCompatability (aDataObject, bDataObject, aVarName, bVarName) + + # if the data isn't valid, stop now + if message is not None : + for errorHandler in self.errorHandlers : + errorHandler.handleWarning(message) + # we can't make any images from this data, so just return + return + + # compare our data + diffData = dataobjects.DiffInfoObject(aDataObject, bDataObject, epsilonValue=self.dataModel.getEpsilon()) + + # get units text for display + aUnitsText = self.dataModel.getUnitsText("A", aVarName) + bUnitsText = self.dataModel.getUnitsText("B", bVarName) + + LOG.info("Spawning plot window: " + imageType) + + plt.ion() # make sure interactive plotting is on + + # create the plot + + if imageType == model.ORIGINAL_A : + + tempFigure = figures.create_simple_figure(aDataObject.data, aVarName + "\nin File A", + invalidMask=aDataObject.masks.missing_mask, colorMap=cm.jet, units=aUnitsText) + + elif imageType == model.ORIGINAL_B : + + tempFigure = figures.create_simple_figure(bDataObject.data, bVarName + "\nin File B", + invalidMask=bDataObject.masks.missing_mask, colorMap=cm.jet, units=bUnitsText) + + elif imageType == model.ABS_DIFF : + + tempFigure = figures.create_simple_figure(np.abs(diffData.diff_data_object.data), "Absolute value of difference\nin " + aVarName, + invalidMask=~diffData.diff_data_object.masks.valid_mask, colorMap=cm.jet, units=aUnitsText) + + elif imageType == model.RAW_DIFF : + + tempFigure = figures.create_simple_figure(diffData.diff_data_object.data, "Value of (Data File B - Data File A)\nfor " + aVarName, + invalidMask=~diffData.diff_data_object.masks.valid_mask, colorMap=cm.jet, units=aUnitsText) + + elif imageType == model.HISTOGRAM : + + rawDiffDataClean = diffData.diff_data_object.data[diffData.diff_data_object.masks.valid_mask] + tempFigure = figures.create_histogram(rawDiffDataClean, DEFAULT_NUM_BINS, "Difference in\n" + aVarName, + "Value of (B - A) at each data point", "Number of points with a given difference", units=aUnitsText) + + elif imageType == model.MISMATCH : + + mismatchMask = diffData.diff_data_object.masks.mismatch_mask + tempFigure = figures.create_simple_figure(aDataObject.data, "Areas of mismatch data\nin " + aVarName, + invalidMask=aDataObject.masks.missing_mask, tagData=mismatchMask, + colorMap=figures.MEDIUM_GRAY_COLOR_MAP, units=aUnitsText) + + elif imageType == model.SCATTER : + + tempCleanMask = aDataObject.masks.missing_mask | bDataObject.masks.missing_mask + aDataClean = aDataObject.data[~tempCleanMask] + bDataClean = bDataObject.data[~tempCleanMask] + cleanMismatchMask = diffData.diff_data_object.masks.mismatch_mask[~tempCleanMask] + figures.create_scatter_plot(aDataClean, bDataClean, "Value in File A vs Value in File B", + "File A Value in " + aVarName, + "File B Value in " + bVarName, + badMask=cleanMismatchMask, epsilon=self.dataModel.getEpsilon(), + units_x=aUnitsText, units_y=bUnitsText) + + elif imageType == model.HEX_PLOT : + + tempCleanMask = aDataObject.masks.missing_mask | bDataObject.masks.missing_mask + aDataClean = aDataObject.data[~tempCleanMask] + bDataClean = bDataObject.data[~tempCleanMask] + tempFigure = figures.create_hexbin_plot(aDataClean, bDataClean, + "Value in File A vs Value in File B", + "File A Value in " + aVarName, + "File B Value in " + bVarName, + epsilon=self.dataModel.getEpsilon(), + units_x=aUnitsText, units_y=bUnitsText) + + plt.draw() diff --git a/pyglance/glance/gui_model.py b/pyglance/glance/gui_model.py index 5ed31b8..fb5b52b 100644 --- a/pyglance/glance/gui_model.py +++ b/pyglance/glance/gui_model.py @@ -7,27 +7,11 @@ Created by evas Oct 2011. Copyright (c) 2011 University of Wisconsin SSEC. All rights reserved. """ -# these first two lines must stay before the pylab import -import matplotlib -matplotlib.use('Qt4Agg') # use the Qt Anti-Grain Geometry rendering engine - -from pylab import * - -import matplotlib.cm as cm -import matplotlib.pyplot as plt -import matplotlib.colors as colors - -from pkg_resources import resource_string, resource_filename -from mako.template import Template -from mako.lookup import TemplateLookup - -import sys, os.path, logging +import logging import numpy as np -import glance.data as dataobjects -import glance.figures as figures -import glance.io as io -import glance.stats as stats +import glance.data as dataobjects +import glance.io as io LOG = logging.getLogger(__name__) @@ -62,9 +46,6 @@ IMAGE_TYPES = [ORIGINAL_A, HEX_PLOT ] -# the number of bins to use for histograms -DEFAULT_NUM_BINS = 50 - class _FileModelData (object) : """ This object is meant to be used internally by the GUI model. The model is going to mess with the @@ -331,168 +312,62 @@ class GlanceGUIModel (object) : listener.updateEpsilon(self.epsilon) listener.updateImageTypes(self.imageType) - def _verifyDataCompatability (self, aDataObject, bDataObject, aName, bName) : + def getVariableName (self, filePrefix) : """ - Confirm that the two data objects can minimally be compared. - - return None if they can be compared or a text message explaining why they cannot. + get the name of the variable loaded for the given file prefix + or None if no variable is loaded """ + toReturn = None - # check the minimum comparison requirments - message = None - # if either object does not exist, they can not be compared - if (aDataObject is None) or (bDataObject is None) : - message = ("Data for requested files was not available. " + - "Please load or reload files and try again.") - # check to see if the two variables have the same shape of data - elif aDataObject.data.shape != bDataObject.data.shape : - message = (aName + ' / ' + bName + ' ' + - 'could not be compared because the data for these variables does not match in shape ' + - 'between the two files (file A data shape: ' + str(aDataObject.data.shape) + '; file B data shape: ' - + str(bDataObject.data.shape) + ').') + if filePrefix in self.fileData.keys() : + toReturn = self.fileData[filePrefix].variable - return message + return toReturn - def sendStatsInfo (self) : + def getVariableData (self, filePrefix, variableName) : """ - our data listeners should be sent statistics information for a comparison - of the currently selected variables (if possible) + get the data object for the variable of variableName associated with the file prefix + or None if that variable is not loaded - TODO, move this to some sort of report manager model object? + Note: this is not a copy, but the original object, so any manipulations + done to it will be reflected in the model """ + toReturn = None - tempVarA = self.fileData["A"].variable - tempVarB = self.fileData["B"].variable - aData = self.fileData["A"].var_data_cache[tempVarA] if tempVarA in self.fileData["A"].var_data_cache else None - bData = self.fileData["B"].var_data_cache[tempVarB] if tempVarB in self.fileData["B"].var_data_cache else None + if (filePrefix in self.fileData) and (variableName in self.fileData[filePrefix].var_data_cache) : + toReturn = self.fileData[filePrefix].var_data_cache[variableName] - # check the minimum validity of our data - message = self._verifyDataCompatability (aData, bData, tempVarA, tempVarB) - - # if the data isn't valid, stop now - if message is not None : - for errorHandler in self.errorHandlers : - errorHandler.handleWarning(message) - # we can't make any stats from this data, so just return - return - - LOG.info ("Constructing statistics") - - tempAnalysis = stats.StatisticalAnalysis.withDataObjects(aData, bData, epsilon=self.epsilon) - tempInfo = {'variable_name': tempVarA, - 'alternate_name_in_B': tempVarB} - kwargs = { 'runInfo': tempInfo, - 'statGroups': tempAnalysis.dictionary_form(), - } - - templateLookup = TemplateLookup(directories=[resource_filename(__name__, ".")]) - guiTemplate = Template(resource_string(__name__, "guistatsreport.txt"), lookup=templateLookup) - - renderedText = guiTemplate.render(**kwargs) - - # tell my listeners to show the stats data we've collected - for listener in self.dataListeners : - listener.displayStatsData(tempVarA, tempVarB, renderedText) # TODO, do we need a different set of data here? + return toReturn - def spawnPlotWithCurrentInfo (self) : + def getUnitsText (self, filePrefix, variableName) : """ - create a matplotlib plot using the current model information - - TODO, move this into some sort of figure manager model object/module? + get the text describing the units of the variable if the variable exists and that + attribute exists, otherwise return None """ - - LOG.debug ("Variable A cache entries: " + str(self.fileData["A"].var_data_cache.keys())) - LOG.debug ("Variable B cache entries: " + str(self.fileData["B"].var_data_cache.keys())) - - LOG.info ("Preparing variable data for plotting...") - - tempVarA = self.fileData["A"].variable - tempVarB = self.fileData["B"].variable - - # TODO, move to taking advantage of the whole data objects - aData = self.fileData["A"].var_data_cache[tempVarA] if tempVarA in self.fileData["A"].var_data_cache else None - bData = self.fileData["B"].var_data_cache[tempVarB] if tempVarB in self.fileData["B"].var_data_cache else None - - # TODO, this ignores the fact that the "original" plots don't need two sets of data - message = self._verifyDataCompatability (aData, bData, tempVarA, tempVarB) - - # if the data isn't valid, stop now - if message is not None : - for errorHandler in self.errorHandlers : - errorHandler.handleWarning(message) - # we can't make any images from this data, so just return - return - - # compare our data - diffData = dataobjects.DiffInfoObject(aData, bData, epsilonValue=self.epsilon) - - # pull the units information - aUnits = self.fileData["A"].file.file_object.get_attribute(self.fileData["A"].variable, io.UNITS_CONSTANT) - bUnits = self.fileData["B"].file.file_object.get_attribute(self.fileData["B"].variable, io.UNITS_CONSTANT) - - LOG.info("Spawning plot window: " + self.imageType) - - plt.ion() # make sure interactive plotting is on - - # create the plot - - if self.imageType == ORIGINAL_A : - - tempFigure = figures.create_simple_figure(aData.data, self.fileData["A"].variable + "\nin File A", - invalidMask=aData.masks.missing_mask, colorMap=cm.jet, units=aUnits) - - elif self.imageType == ORIGINAL_B : - - tempFigure = figures.create_simple_figure(bData.data, self.fileData["B"].variable + "\nin File B", - invalidMask=bData.masks.missing_mask, colorMap=cm.jet, units=bUnits) - - elif self.imageType == ABS_DIFF : - - tempFigure = figures.create_simple_figure(np.abs(diffData.diff_data_object.data), "Absolute value of difference\nin " + self.fileData["A"].variable, - invalidMask=~diffData.diff_data_object.masks.valid_mask, colorMap=cm.jet, units=aUnits) - - elif self.imageType == RAW_DIFF : - - tempFigure = figures.create_simple_figure(diffData.diff_data_object.data, "Value of (Data File B - Data File A)\nfor " + self.fileData["A"].variable, - invalidMask=~diffData.diff_data_object.masks.valid_mask, colorMap=cm.jet, units=aUnits) - - elif self.imageType == HISTOGRAM : - - rawDiffDataClean = diffData.diff_data_object.data[diffData.diff_data_object.masks.valid_mask] - tempFigure = figures.create_histogram(rawDiffDataClean, DEFAULT_NUM_BINS, "Difference in\n" + self.fileData["A"].variable, - "Value of (B - A) at each data point", "Number of points with a given difference", units=aUnits) - - elif self.imageType == MISMATCH : - - mismatchMask = diffData.diff_data_object.masks.mismatch_mask - tempFigure = figures.create_simple_figure(aData.data, "Areas of mismatch data\nin " + self.fileData["A"].variable, - invalidMask=aData.masks.missing_mask, tagData=mismatchMask, colorMap=figures.MEDIUM_GRAY_COLOR_MAP, units=aUnits) - - elif self.imageType == SCATTER : - - tempCleanMask = aData.masks.missing_mask | bData.masks.missing_mask - aDataClean = aData.data[~tempCleanMask] - bDataClean = bData.data[~tempCleanMask] - cleanMismatchMask = diffData.diff_data_object.masks.mismatch_mask[~tempCleanMask] - figures.create_scatter_plot(aDataClean, bDataClean, "Value in File A vs Value in File B", - "File A Value in " + self.fileData["A"].variable, - "File B Value in " + self.fileData["B"].variable, - badMask=cleanMismatchMask, epsilon=self.epsilon, - units_x=aUnits, units_y=bUnits) - - elif self.imageType == HEX_PLOT : - - tempCleanMask = aData.masks.missing_mask | bData.masks.missing_mask - aDataClean = aData.data[~tempCleanMask] - bDataClean = bData.data[~tempCleanMask] - tempFigure = figures.create_hexbin_plot(aDataClean, bDataClean, - "Value in File A vs Value in File B", - "File A Value in " + self.fileData["A"].variable, - "File B Value in " + self.fileData["B"].variable, - epsilon=self.epsilon, - units_x=aUnits, units_y=bUnits) - - plt.draw() + return self.fileData[filePrefix].file.file_object.get_attribute(variableName, io.UNITS_CONSTANT) + + def getEpsilon (self) : + """ + get the current value of epsilon + """ + return self.epsilon + + def getImageType (self) : + """ + get the text string describing the image type currently selected + + the return will correspond to one of the constants from this module: + + ORIGINAL_A, + ORIGINAL_B, + ABS_DIFF, + RAW_DIFF, + HISTOGRAM, + MISMATCH, + SCATTER, + HEX_PLOT + """ + return self.imageType def registerDataListener (self, objectToRegister) : """ diff --git a/pyglance/glance/gui_statsprovider.py b/pyglance/glance/gui_statsprovider.py new file mode 100644 index 0000000..f82b88b --- /dev/null +++ b/pyglance/glance/gui_statsprovider.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" +This module handles providing stats data to the rest of the Glance GUI. + +Created by evas Nov 2011. +Copyright (c) 2011 University of Wisconsin SSEC. All rights reserved. +""" + +from pkg_resources import resource_string, resource_filename +from mako.template import Template +from mako.lookup import TemplateLookup + +import glance.stats as stats +import glance.data as dataobjects + +import logging + +LOG = logging.getLogger(__name__) + +class GlanceGUIStats (object) : + """ + this class represents a model object that manages providing + statistics information to the Glance GUI + + it includes: + + self.dataModel - the GlanceGUIModel object that contains the main data + model for the GUI + self.statsListeners - objects that want to be notified when stats are calculated + self.errorHandlers - objects that want to be notified when there's a serious error + """ + + def __init__ (self, dataModelToSave) : + """ + create the gui stats object, hanging onto the dataModel given + """ + + self.dataModel = dataModelToSave + self.statsListeners = [ ] + self.errorHandlers = [ ] + + def registerStatsListener (self, objectToRegister) : + """ + add the given object to our list of stats listeners + """ + + if objectToRegister not in self.statsListeners : + self.statsListeners.append(objectToRegister) + + def registerErrorHandler (self, objectToRegister) : + """ + add the given object to our list of error handlers + """ + + if objectToRegister not in self.errorHandlers : + self.errorHandlers.append(objectToRegister) + + def sendStatsInfo (self) : + """ + our data listeners should be sent statistics information for a comparison + of the currently selected variables (if possible) + """ + + # get Variable names + aVarName = self.dataModel.getVariableName("A") + bVarName = self.dataModel.getVariableName("B") + + # get Data objects + aDataObject = self.dataModel.getVariableData("A", aVarName) + bDataObject = self.dataModel.getVariableData("B", bVarName) + + # check the minimum validity of our data + message = dataobjects.DiffInfoObject.verifyDataCompatability (aDataObject, bDataObject, aVarName, bVarName) + + # if the data isn't valid, stop now + if message is not None : + for errorHandler in self.errorHandlers : + errorHandler.handleWarning(message) + # we can't make any stats from this data, so just return + return + + LOG.info ("Constructing statistics") + + # do the statistical analysis and collect the data that will be needed to render it nicely + tempAnalysis = stats.StatisticalAnalysis.withDataObjects(aDataObject, bDataObject, epsilon=self.dataModel.getEpsilon()) + tempInfo = { 'variable_name': aVarName, + 'alternate_name_in_B': bVarName } + kwargs = { 'runInfo': tempInfo, + 'statGroups': tempAnalysis.dictionary_form() } + + # use a mako template to render an html verion of the stats for display + templateLookup = TemplateLookup(directories=[resource_filename(__name__, ".")]) + guiTemplate = Template(resource_string(__name__, "guistatsreport.txt"), lookup=templateLookup) + renderedText = guiTemplate.render(**kwargs) + + # tell my listeners to show the stats data we've collected + for listener in self.statsListeners : + listener.displayStatsData(aVarName, bVarName, renderedText) + diff --git a/pyglance/glance/gui_view.py b/pyglance/glance/gui_view.py index 7db22f7..9d0dd2e 100644 --- a/pyglance/glance/gui_view.py +++ b/pyglance/glance/gui_view.py @@ -15,6 +15,8 @@ if os.path.isdir(PYQT4_HAX): from PyQt4 import QtGui, QtCore +from functools import partial + LOG = logging.getLogger(__name__) """ @@ -100,10 +102,7 @@ class GlanceGUIView (QtGui.QWidget) : # set some tooltip text loadButton.setToolTip("Load a file: glance can handle NetCDF, HDF4, HDF5, and AERI files") # connect the button to an action - if file_prefix is "A" : - loadButton.clicked.connect(self.clickedALoad) - elif file_prefix is "B" : - loadButton.clicked.connect(self.clickedBLoad) + loadButton.clicked.connect(partial(self.selectFileToLoad, file_prefix=file_prefix)) self.widgetInfo[file_prefix]['load'] = loadButton grid_layout.addWidget(loadButton, currentRow, 4) @@ -113,10 +112,7 @@ class GlanceGUIView (QtGui.QWidget) : grid_layout.addWidget(QtGui.QLabel("variable name:"), currentRow, 1) variableSelection = QtGui.QComboBox() variableSelection.setDisabled(True) - if file_prefix is "A" : - variableSelection.activated.connect(self.selectedAVariable) - elif file_prefix is "B" : - variableSelection.activated.connect(self.selectedBVariable) + variableSelection.activated.connect(partial(self.reportVariableSelected, file_prefix=file_prefix)) self.widgetInfo[file_prefix]['variable'] = variableSelection grid_layout.addWidget(variableSelection, currentRow, 2, 1, 3) @@ -149,10 +145,7 @@ class GlanceGUIView (QtGui.QWidget) : # set up a check box to override the fill value loaded from the file overrideFillButton = QtGui.QCheckBox("override fill value") overrideFillButton.setDisabled(True) - if file_prefix is "A" : - overrideFillButton.stateChanged.connect(self.toggledAOverride) - elif file_prefix is "B" : - overrideFillButton.stateChanged.connect(self.toggledBOverride) + overrideFillButton.stateChanged.connect(partial(self.reportOverrideChange, file_prefix=file_prefix)) self.widgetInfo[file_prefix]['override'] = overrideFillButton grid_layout.addWidget(overrideFillButton, currentRow, 1) @@ -163,10 +156,7 @@ class GlanceGUIView (QtGui.QWidget) : tempValidator.setNotation(QtGui.QDoubleValidator.StandardNotation) fillValue.setValidator(tempValidator) fillValue.setDisabled(True) - if file_prefix is "A" : - fillValue.editingFinished.connect(self.fillValueEditedA) - elif file_prefix is "B" : - fillValue.editingFinished.connect(self.fillValueEditedB) + fillValue.editingFinished.connect(partial(self.fillValueChanged, file_prefix=file_prefix)) self.widgetInfo[file_prefix]['fillValue'] = fillValue grid_layout.addWidget(fillValue, currentRow+1, 2, 1, 3) @@ -227,15 +217,7 @@ class GlanceGUIView (QtGui.QWidget) : ################# start methods related to user input ################# - def clickedALoad (self) : - - self.selectFileToLoad ("A") - - def clickedBLoad (self) : - - self.selectFileToLoad ("B") - - def selectFileToLoad (self, file_prefix) : + def selectFileToLoad (self, file_prefix=None) : """ when the load button is pressed, let the user pick a file to load """ @@ -252,15 +234,7 @@ class GlanceGUIView (QtGui.QWidget) : for listener in self.userUpdateListeners : listener.newFileSelected(file_prefix, tempFilePath) - def selectedAVariable (self) : - - self.reportVariableSelected("A") - - def selectedBVariable (self) : - - self.reportVariableSelected("B") - - def reportVariableSelected (self, file_prefix) : + def reportVariableSelected (self, file_prefix=None) : """ when a variable is selected for one of the files, report it to any user update listeners """ @@ -271,15 +245,7 @@ class GlanceGUIView (QtGui.QWidget) : for listener in self.userUpdateListeners : listener.userSelectedVariable(file_prefix, selectionText) - def toggledAOverride (self) : - - self.reportOverrideChange("A") - - def toggledBOverride (self) : - - self.reportOverrideChange("B") - - def reportOverrideChange (self, file_prefix) : + def reportOverrideChange (self, file_prefix=None) : """ when the user checks or unchecks one of the override checkboxes, report it to user update listeners """ @@ -295,15 +261,7 @@ class GlanceGUIView (QtGui.QWidget) : for listener in self.userUpdateListeners : listener.userChangedOverload(file_prefix, shouldDoOverride) - def fillValueEditedA (self) : - - self.fillValueChanged("A") - - def fillValueEditedB (self) : - - self.fillValueChanged("B") - - def fillValueChanged (self, file_prefix) : + def fillValueChanged (self, file_prefix=None) : """ when the user edits a fill value, report it to user update listeners """ diff --git a/pyglance/setup.py b/pyglance/setup.py index b372998..fa1c232 100644 --- a/pyglance/setup.py +++ b/pyglance/setup.py @@ -22,11 +22,11 @@ easy_install -d $HOME/Library/Python -vi http://larch.ssec.wisc.edu/eggs/repos g from setuptools import setup, find_packages setup( name="glance", - version="0.2.7.01", + version="0.2.7.02", zip_safe = False, entry_points = { 'console_scripts': [ 'glance = glance.compare:main' ] }, packages = ['glance'], #find_packages('.'), - install_requires=[ 'numpy', 'matplotlib' ], + install_requires=[ 'numpy', 'matplotlib', 'mako>=0.4.1' ], package_data = {'': ['*.txt', '*.gif']} ) -- GitLab