1# -*- coding: utf-8 -*- 2 3""" 4*************************************************************************** 5 BarPlot.py 6 --------------------- 7 Date : March 2015 8 Copyright : (C) 2017 by Matteo Ghetta 9 Email : matteo dot ghetta at gmail dot com 10*************************************************************************** 11* * 12* This program is free software; you can redistribute it and/or modify * 13* it under the terms of the GNU General Public License as published by * 14* the Free Software Foundation; either version 2 of the License, or * 15* (at your option) any later version. * 16* * 17*************************************************************************** 18""" 19 20__author__ = 'Matteo Ghetta' 21__date__ = 'March 2017' 22__copyright__ = '(C) 2017, Matteo Ghetta' 23 24import warnings 25 26from qgis.core import (QgsProcessingException, 27 QgsProcessingParameterFeatureSource, 28 QgsProcessingParameterField, 29 QgsProcessingParameterEnum, 30 QgsProcessingParameterFileDestination, 31 QgsFeatureRequest) 32from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm 33from processing.tools import vector 34 35from qgis.PyQt.QtCore import QCoreApplication 36 37 38class BoxPlot(QgisAlgorithm): 39 INPUT = 'INPUT' 40 OUTPUT = 'OUTPUT' 41 NAME_FIELD = 'NAME_FIELD' 42 VALUE_FIELD = 'VALUE_FIELD' 43 MSD = 'MSD' 44 45 def group(self): 46 return self.tr('Plots') 47 48 def groupId(self): 49 return 'plots' 50 51 def __init__(self): 52 super().__init__() 53 54 def initAlgorithm(self, config=None): 55 self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, 56 self.tr('Input layer'))) 57 self.addParameter(QgsProcessingParameterField(self.NAME_FIELD, 58 self.tr('Category name field'), 59 parentLayerParameterName=self.INPUT, 60 type=QgsProcessingParameterField.Any)) 61 self.addParameter(QgsProcessingParameterField(self.VALUE_FIELD, 62 self.tr('Value field'), 63 parentLayerParameterName=self.INPUT, 64 type=QgsProcessingParameterField.Numeric)) 65 msd = [self.tr('Show Mean'), 66 self.tr('Show Standard Deviation'), 67 self.tr('Don\'t show Mean and Standard Deviation') 68 ] 69 self.addParameter(QgsProcessingParameterEnum( 70 self.MSD, 71 self.tr('Additional Statistic Lines'), 72 options=msd, defaultValue=0)) 73 74 self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT, self.tr('Box plot'), self.tr('HTML files (*.html)'))) 75 76 def name(self): 77 return 'boxplot' 78 79 def displayName(self): 80 return self.tr('Box plot') 81 82 def processAlgorithm(self, parameters, context, feedback): 83 try: 84 # importing plotly throws Python warnings from within the library - filter these out 85 with warnings.catch_warnings(): 86 warnings.filterwarnings("ignore", category=ResourceWarning) 87 warnings.filterwarnings("ignore", category=ImportWarning) 88 import plotly as plt 89 import plotly.graph_objs as go 90 except ImportError: 91 raise QgsProcessingException(QCoreApplication.translate('BoxPlot', 'This algorithm requires the Python “plotly” library. Please install this library and try again.')) 92 93 source = self.parameterAsSource(parameters, self.INPUT, context) 94 if source is None: 95 raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) 96 97 namefieldname = self.parameterAsString(parameters, self.NAME_FIELD, context) 98 valuefieldname = self.parameterAsString(parameters, self.VALUE_FIELD, context) 99 100 output = self.parameterAsFileOutput(parameters, self.OUTPUT, context) 101 102 values = vector.values(source, valuefieldname) 103 104 x_index = source.fields().lookupField(namefieldname) 105 x_var = vector.convert_nulls([i[namefieldname] for i in source.getFeatures(QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry).setSubsetOfAttributes([x_index]))], '<NULL>') 106 107 msdIndex = self.parameterAsEnum(parameters, self.MSD, context) 108 msd = True 109 110 if msdIndex == 1: 111 msd = 'sd' 112 elif msdIndex == 2: 113 msd = False 114 115 data = [go.Box( 116 x=x_var, 117 y=values[valuefieldname], 118 boxmean=msd)] 119 120 plt.offline.plot(data, filename=output, auto_open=False) 121 122 return {self.OUTPUT: output} 123