source: sasview/src/sas/qtgui/Perspectives/Fitting/ReportPageLogic.py @ 933f9e9

ESS_GUIESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since 933f9e9 was 30bc96eb, checked in by Piotr Rozyczko <rozyczko@…>, 6 years ago

Hardocoded width is only applicable to OSX

  • Property mode set to 100644
File size: 7.0 KB
Line 
1# -*- coding: utf-8 -*-
2import base64
3import datetime
4import re
5import sys
6import logging
7from io import BytesIO
8import urllib.parse
9
10from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
11
12from sas.qtgui.Plotting.Plotter import Plotter
13from sas.qtgui.Plotting.Plotter2D import Plotter2D
14from sas.qtgui.Plotting.PlotterData import Data1D
15from sas.qtgui.Plotting.PlotterData import Data2D
16
17import sas.qtgui.Utilities.GuiUtils as GuiUtils
18from sas.qtgui.Perspectives.Fitting import FittingUtilities
19
20class ReportPageLogic(object):
21    """
22    Logic for the Report Page functionality. Refactored from FittingWidget.
23    """
24    def __init__(self, parent=None, kernel_module=None, data=None, index=None, model=None):
25
26        self.parent = parent
27        self.kernel_module = kernel_module
28        self.data = data
29        self._index = index
30        self.model = model
31
32    @staticmethod
33    def cleanhtml(raw_html):
34        """Remove html tags from a document"""
35        cleanr = re.compile('<.*?>')
36        cleantext = re.sub(cleanr, '', raw_html)
37        return cleantext
38
39    def reportList(self):
40        """
41        Return the HTML version of the full report
42        """
43        if self.kernel_module is None:
44            report_txt = "No model defined"
45            report_html = HEADER % report_txt
46            images = []
47            return [report_html, report_txt, images]
48
49        # Get plot image from plotpanel
50        images = self.getImages()
51
52        imagesHTML = ""
53        if images is not None:
54            imagesHTML = self.buildPlotsForReport(images)
55
56        report_header = self.reportHeader()
57
58        report_parameters = self.reportParams()
59
60        report_html = report_header + report_parameters + imagesHTML
61
62        report_txt = self.cleanhtml(report_html)
63
64        report_list = [report_html, report_txt, images]
65
66        return report_list
67
68    def reportHeader(self):
69        """
70        Look at widget state and extract report header info
71        """
72        report = ""
73
74        title = self.data.name
75        current_time = datetime.datetime.now().strftime("%I:%M%p, %B %d, %Y")
76        filename = self.data.filename
77        modelname = self.kernel_module.id
78        if hasattr(self.data, 'xmin'):
79            qrange_min = self.data.xmin
80            qrange_max = self.data.xmax
81        else:
82            qrange_min = min(self.data.x)
83            qrange_max = max(self.data.x)
84        qrange = "min = {}, max = {}".format(qrange_min, qrange_max)
85
86        title = title + " [" + current_time + "]"
87        title_name = HEADER % title
88        report = title_name
89        report = report + CENTRE % "File name:{}\n".format(filename)
90        report = report + CENTRE % "Model name:{}\n".format(modelname)
91        report = report + CENTRE % "Q Range: {}\n".format(qrange)
92        chi2_repr = GuiUtils.formatNumber(self.parent.chi2, high=True)
93        report = report + CENTRE % "Chi2/Npts:{}\n".format(chi2_repr)
94
95        return report
96
97    def buildPlotsForReport(self, images):
98        """ Convert Matplotlib figure 'fig' into a <img> tag for HTML use using base64 encoding. """
99        html = FEET_1 % self.data.filename
100
101        for fig in images:
102            canvas = FigureCanvas(fig)
103            png_output = BytesIO()
104            canvas.print_png(png_output)
105            data = png_output.getvalue()
106            data64 = base64.b64encode(data)
107            data_to_print = urllib.parse.quote(data64)
108            feet=FEET_2
109            if sys.platform == "darwin":  # Mac
110                feet = FEET_3
111            html += feet.format(data_to_print)
112            html += ELINE
113            del canvas
114        return html
115
116    def reportParams(self):
117        """
118        Look at widget state and extract parameters
119        """
120        pars = FittingUtilities.getStandardParam(self.model)
121        if pars is None:
122            return ""
123
124        report = ""
125        plus_minus = " &#177; "
126        for value in pars:
127            try:
128                par_name = value[1]
129                par_fixed = not value[0]
130                par_value = value[2]
131                par_unit = value[7]
132                # Convert units for nice display
133                par_unit = GuiUtils.convertUnitToHTML(par_unit.strip())
134                if par_fixed:
135                    error = " (fixed)"
136                else:
137                    error = plus_minus + str(value[4][1])
138                param = par_name + " = " + par_value + error + " " + par_unit
139            except IndexError as ex:
140                # corrupted model. Complain and skip the line
141                logging.error("Error in parsing parameters: "+str(ex))
142                continue
143            report += CENTRE % param + "\n"
144
145        return report
146
147    def getImages(self):
148        """
149        Create MPL figures for the current fit
150        """
151        graphs = []
152        modelname = self.kernel_module.name
153        if not modelname or self._index is None:
154            return None
155        plots = GuiUtils.plotsFromModel(modelname, self._index)
156        # Call show on requested plots
157        # All same-type charts in one plot
158        for plot_set in plots:
159            if isinstance(plot_set, Data1D):
160                if 'residuals' in plot_set.title.lower():
161                    res_plot = Plotter(self, quickplot=True)
162                    res_plot.plot(plot_set)
163                    graphs.append(res_plot.figure)
164                    continue
165                if not 'new_plot' in locals():
166                    new_plot = Plotter(self, quickplot=True)
167                new_plot.plot(plot_set)
168            elif isinstance(plot_set, Data2D):
169                plot2D = Plotter2D(self, quickplot=True)
170                plot2D.item = self._index
171                plot2D.plot(plot_set)
172                graphs.append(plot2D.figure)
173
174            else:
175                msg = "Incorrect data type passed to Plotting"
176                raise AttributeError(msg)
177
178        if 'new_plot' in locals() and isinstance(new_plot.data, Data1D):
179            graphs.append(new_plot.figure)
180
181        return graphs
182
183
184# Simple html report template
185HEADER = "<html>\n"
186HEADER += "<head>\n"
187HEADER += "<meta http-equiv=Content-Type content='text/html; "
188HEADER += "charset=utf-8'> \n"
189HEADER += "<meta name=Generator >\n"
190HEADER += "</head>\n"
191HEADER += "<body lang=EN-US>\n"
192HEADER += "<div class=WordSection1>\n"
193HEADER += "<p class=MsoNormal><b><span ><center><font size='4' >"
194HEADER += "%s</font></center></span></center></b></p>"
195HEADER += "<p class=MsoNormal>&nbsp;</p>"
196PARA = "<p class=MsoNormal><font size='4' > %s \n"
197PARA += "</font></p>"
198CENTRE = "<p class=MsoNormal><center><font size='4' > %s \n"
199CENTRE += "</font></center></p>"
200FEET_1 = \
201"""
202<p class=MsoNormal>&nbsp;</p>
203<br>
204<p class=MsoNormal><b><span ><center> <font size='4' > Graph
205</font></span></center></b></p>
206<p class=MsoNormal>&nbsp;</p>
207<center>
208<br><font size='4' >Model Computation</font>
209<br><font size='4' >Data: "%s"</font><br>
210"""
211FEET_2 = \
212'''<img src="data:image/png;base64,{}"></img>
213'''
214FEET_3 = \
215'''<img width="540" src="data:image/png;base64,{}"></img>
216'''
217ELINE = """<p class=MsoNormal>&nbsp;</p>
218"""
219
Note: See TracBrowser for help on using the repository browser.