diff --git a/pyglance/glance/gui_controller.py b/pyglance/glance/gui_controller.py index 30d165680644aab7d1f5785ca1e81a4ba4f58c0c..afb6345742a751dabf85b24da6c0068e4f7c21c7 100644 --- a/pyglance/glance/gui_controller.py +++ b/pyglance/glance/gui_controller.py @@ -247,7 +247,7 @@ class GlanceGUIController (object) : the user asked for a display of the global file attributes """ - # TODO, actually send the attrs + # get the global attrs displayed for the user self.stats.sendGlobalAttrs( ) def userRequestsPlot (self) : diff --git a/pyglance/glance/gui_model.py b/pyglance/glance/gui_model.py index 1d172716a20ee95e1b660b36a7617fa5d4536770..281eb061390ecfbef33e9709455e742ea3e08bcc 100644 --- a/pyglance/glance/gui_model.py +++ b/pyglance/glance/gui_model.py @@ -622,7 +622,20 @@ class GlanceGUIModel (object) : toReturn.data[toReturn.data > self.fileSettings[filePrefix][GlanceGUIModel.MAX_RANGE]] = toReturn.fill_value return toReturn - + + def get_global_attributes (self, filePrefix, ) : + """ + get the dictionary of global attributes present in the file corresponding to filePrefix + + If that file is not loaded, None will be returned + """ + + temp_file = self.fileData[filePrefix].file if filePrefix in self.fileData else None + temp_file_obj = temp_file.file_object if temp_file is not None else None + to_return = temp_file_obj.get_global_attributes(caseInsensitive=False,) if temp_file_obj is not None else None + + return to_return + def getUnitsText (self, filePrefix, variableName) : """ get the text describing the units of the variable if the variable exists and that diff --git a/pyglance/glance/gui_statsprovider.py b/pyglance/glance/gui_statsprovider.py index 692461b6d4f5c73247652d5552ced1690e6b9ce5..b58c72b4cbdd10326a859c9e6153aada2411485e 100644 --- a/pyglance/glance/gui_statsprovider.py +++ b/pyglance/glance/gui_statsprovider.py @@ -15,7 +15,7 @@ import glance.stats as stats import glance.data as dataobjects import glance.constants as constants -from glance.report import GUI_STATS_REPORT_TEMPLATE +from glance.report import GUI_STATS_REPORT_TEMPLATE, GUI_G_ATTRS_REPORT_TEMPLATE from glance.gui_constants import A_CONST, B_CONST import logging @@ -78,13 +78,13 @@ class GlanceGUIStats (object) : # if we only have one file, just make stats for that one if aDataObject is None and bDataObject is not None: - return self.sendStatsInfoSingle(bVarName, bDataObject) + return self._sendStatsInfoSingle(bVarName, bDataObject) if aDataObject is not None and bDataObject is None: - return self.sendStatsInfoSingle(aVarName, aDataObject) + return self._sendStatsInfoSingle(aVarName, aDataObject) - return self.sendStatsInfoPair(aVarName, bVarName, aDataObject, bDataObject) + return self._sendStatsInfoPair(aVarName, bVarName, aDataObject, bDataObject) - def sendStatsInfoPair(self, aVarName, bVarName, aDataObject, bDataObject): + def _sendStatsInfoPair(self, aVarName, bVarName, aDataObject, bDataObject): """ send data listeners statistics information for the currently selected variables @@ -115,7 +115,7 @@ class GlanceGUIStats (object) : for listener in self.statsListeners : listener.displayStatsData(aVarName, bVarName, renderedText) - def sendStatsInfoSingle(self, varName, dataObject): + def _sendStatsInfoSingle(self, varName, dataObject): """ send data listeners statistics information for the currently selected variable @@ -143,8 +143,62 @@ class GlanceGUIStats (object) : Send information on the global attributes to our listeners """ - print ("*** TODO send global attr info!") - + # get global attributes if we can + aGlobalAttrs = self.dataModel.get_global_attributes(A_CONST,) + bGlobalAttrs = self.dataModel.get_global_attributes(B_CONST,) + + # pack up our data based on which files we have present + packedData = None + if aGlobalAttrs is None and bGlobalAttrs is not None: + packedData = self._packGlobalAttrsSingle(constants.B_FILE_TITLE_KEY, bGlobalAttrs,) + elif aGlobalAttrs is not None and bGlobalAttrs is None: + packedData = self._packGlobalAttrsSingle(constants.A_FILE_TITLE_KEY, aGlobalAttrs,) + elif aGlobalAttrs is not None and bGlobalAttrs is not None : + packedData = self._packGlobalAttrsPair(aGlobalAttrs, bGlobalAttrs,) + + # only try to show stuff if we have stuff to show! + if packedData is not None : + + # use a mako template to render an html verion of the global attributes for display + templateLookup = TemplateLookup(directories=[resource_filename(__name__, ".")]) + guiTemplate = Template(resource_string(__name__, GUI_G_ATTRS_REPORT_TEMPLATE), lookup=templateLookup) + renderedText = guiTemplate.render(**packedData) + + # tell my listeners to show the global attribute data we've collected + for listener in self.statsListeners: + listener.displayGlobalAttributes(renderedText, ) + + def _packGlobalAttrsSingle (self, fileKey, globalAttrsDict) : + """ + pack up a single file's global attributes data + """ + + # pack our data up the way the report expects it + tmpAttrs = { + fileKey: globalAttrsDict, + } + packedData = { + constants.ATTRS_INFO_DICT_KEY: tmpAttrs, + } + + return packedData + + def _packGlobalAttrsPair (self, aAttrsDict, bAttrsDict,) : + """ + pack up global file attributes for both our files + """ + + # pack our data up the way the report expects it + tmpAttrs = { + constants.A_FILE_TITLE_KEY: aAttrsDict, + constants.B_FILE_TITLE_KEY: bAttrsDict, + } + packedData = { + constants.ATTRS_INFO_DICT_KEY: tmpAttrs, + } + + return packedData + def sendRawData (self, fileID) : """ Send raw data information to our listeners @@ -160,4 +214,3 @@ class GlanceGUIStats (object) : # tell my listeners to show the stats data we've collected for listener in self.statsListeners : listener.displayVarData (varName, fileID, dataObject) - diff --git a/pyglance/glance/gui_view.py b/pyglance/glance/gui_view.py index b4ab63a812554f4631ae71ac480084bb7fff3a11..53979be2ce8bca823d6d2a38a969b6b2e36e37c8 100644 --- a/pyglance/glance/gui_view.py +++ b/pyglance/glance/gui_view.py @@ -163,14 +163,10 @@ class GlanceGUIView (QWidget) : # we will use this to remember were the user wanted to load files from last # Future, can we remember this between program runs? something like preferences? self.lastFilePath = './' - - # hang on to stats windows so they don't vanish - self.statsWindows = { } - self.statsCounter = 1 - - # hang on to data display windows - self.dataShowWindows = { } - self.dataShowCounter = 1 + + # hang on to the non-modal info windows we create + self.infoWindows = { } + self.infoWindowsCounter = 0 def _build_data_tab (self) : """ @@ -228,9 +224,9 @@ class GlanceGUIView (QWidget) : currentRow += 1 # set up a button that shows the global attributes - #self.gAttrsButton = QPushButton("Global Attrs.") - #self.gAttrsButton.clicked.connect(self.reportDisplayGlobalAttrsClicked) # TODO - #layoutToUse.addWidget(self.gAttrsButton, currentRow, 0, 1, 1) + self.gAttrsButton = QPushButton("Global Attrs.") + self.gAttrsButton.clicked.connect(self.reportDisplayGlobalAttrsClicked) + layoutToUse.addWidget(self.gAttrsButton, currentRow, 0, 1, 1) # set up a button that shows the numerical data self.rawDataButton = QPushButton("Show Data") @@ -874,14 +870,35 @@ class GlanceGUIView (QWidget) : display this to the user """ - tempID = self.statsCounter - self.statsCounter += self.statsCounter + 1 - - # I don't like this solution, but it would allow me to show multiple sets of stats at a time - self.statsWindows[tempID] = StatisticsDisplayWindow(tempID, - aVariableName, variable_name_b=bVariableName, - statsTextToDisplay=statsAnalysis, stored_in=self.statsWindows) - + tempID = self.infoWindowsCounter + self.infoWindowsCounter += 1 + + # build the window title + tempTitle = "Statistics Information for " + str(aVariableName) + if (bVariableName is not None) and (bVariableName != aVariableName): + tempTitle += " / " + str(bVariableName) + tempTitle += " data" + + # pop open a new window and hang on to it + self.infoWindows[tempID] = TextReportDisplayWindow(tempID, + tempTitle, + reportTextToDisplay=statsAnalysis, + stored_in=self.infoWindows) + + def displayGlobalAttributes(self, gAttrsReportTxt) : + """ + given an html report about the global attributes, display that to the user + """ + + tempID = self.infoWindowsCounter + self.infoWindowsCounter += 1 + + # pop open a new window and hang on to it + self.infoWindows[tempID] = TextReportDisplayWindow(tempID, + "Global Attributes", + reportTextToDisplay=gAttrsReportTxt, + stored_in=self.infoWindows) + def displayVarData (self, variableName, fileDescriptor, variableDataObject) : """ given variable data, pop a window to show it to the user @@ -894,17 +911,16 @@ class GlanceGUIView (QWidget) : newData.data = numpy.array([variableDataObject.data.item()]) variableDataObject = newData - if len(variableDataObject.data.shape) > 0 and len(variableDataObject.data.shape) <= 2 : - tempID = self.dataShowCounter - self.dataShowCounter += 1 + tempID = self.infoWindowsCounter + self.infoWindowsCounter += 1 - # not the best solution ever, but it works for now - self.dataShowWindows[tempID] = RawDataDisplayWindow(tempID, - variableDataObject, variableName, - file_descriptor=fileDescriptor, - stored_in=self.dataShowWindows) + # pop open a new window and hang on to it + self.infoWindows[tempID] = RawDataDisplayWindow(tempID, + variableDataObject, variableName, + file_descriptor=fileDescriptor, + stored_in=self.infoWindows) else: LOG.debug("Unable to display data for variable " + variableName + " because it's shape of " @@ -1109,56 +1125,51 @@ class GlanceGUIView (QWidget) : if objectToRegister not in self.userUpdateListeners : self.userUpdateListeners.append(objectToRegister) -class StatisticsDisplayWindow (QWidget) : +class TextReportDisplayWindow(QWidget): """ - This class represents a window that displays a statistics comparison between two variables. + This class represents a window that displays a text report of some kind. This window is intended to be displayed in a non-modal manner. """ - - def __init__ (self, id_number, variable_name_a, variable_name_b=None, - statsTextToDisplay="", stored_in=None, parent=None) : + + def __init__ (self, id_number, windowTitleTxt, + reportTextToDisplay="", stored_in=None, parent=None): """ set up a window to display stats """ - + QWidget.__init__(self, parent) - - self.id = id_number + + self.id = id_number self.stored = stored_in - - # build and set the window title - tempTitle = "Statistics Information for " + str(variable_name_a) - if (variable_name_b is not None) and (variable_name_b != variable_name_a) : - tempTitle = tempTitle + " / " + str(variable_name_b) - tempTitle = tempTitle + " data" - self.setWindowTitle(tempTitle) - - # create the layout and set up some of the overall record keeping + + self.setWindowTitle(windowTitleTxt) + + # create the layout and arrange things in it layoutToUse = QGridLayout() - - # set up the box that shows the stats + + # set up the box that shows the report self.statsText = QTextEdit() - self.statsText.setHtml(statsTextToDisplay) + self.statsText.setHtml(reportTextToDisplay) self.statsText.setReadOnly(True) layoutToUse.addWidget(self.statsText, 1, 1) - + # set up the overall window geometry self.setLayout(layoutToUse) self.setGeometry(400, 400, 500, 500) - + self.show() - - def closeEvent (self, event) : + + def closeEvent (self, event): """ we need to clean some stuff up when the window wants to close """ - - if self.stored is not None : + + if self.stored is not None: pass # FUTURE, right now if I remove the reference to this window in the parent object on MacOS I get a segfault # so for the moment, I'm going to have to leak these windows to avoid crashing my application! - #del self.stored[self.id] - + # del self.stored[self.id] + event.accept() class NumpyArrayTableModel (QAbstractTableModel) : diff --git a/pyglance/glance/report-guigattrs.txt b/pyglance/glance/report-guigattrs.txt new file mode 100644 index 0000000000000000000000000000000000000000..15b547ebc1efd6f7b740bbc18428436ca58a6a2a --- /dev/null +++ b/pyglance/glance/report-guigattrs.txt @@ -0,0 +1,31 @@ +<%doc> +This Mako template is intended to create a global attribute report page for +the Glance GUI. + +Created by Eva Schiffer Aug 2021. +Copyright (c) 2021 University of Wisconsin SSEC. All rights reserved. +</%doc> + +<%! + import glance.constants as constants +%> + +<%inherit file="report-base.txt"/> + +## replace our basic title with this +<%block name="title"> + Global Attributes +</%block> + +## we don't need a second label on the section +<%block name="attrsTitle"> +</%block> + +<%block name="htmlContent"> + + <h2>${self.title()}</h2> + + ${self.attrsInfo()} + +</%block> + diff --git a/pyglance/glance/report.py b/pyglance/glance/report.py index aa76310a41eca6a3eeb3ed518a1e4fb4aeae7819..244830c79e8a04d2322b11507fe1c07c23ff59dc 100644 --- a/pyglance/glance/report.py +++ b/pyglance/glance/report.py @@ -46,6 +46,7 @@ INSPECT_VAR_REPORT_TEMPLATE = 'report-inspectvariable.txt' CONCISE_REPORT_TEMPLATE = 'report-concise.txt' DOC_REPORT_TEMPLATE = 'report-doc.txt' GUI_STATS_REPORT_TEMPLATE = 'report-guistats.txt' +GUI_G_ATTRS_REPORT_TEMPLATE = 'report-guigattrs.txt' # make and save an html page using a mako template, put all the data you need # in the template into the kwargs