Skip to content

Commit f587ae5

Browse files
authored
Merge pull request #4150 from alexbruy/processing-graphs
[processing] improve graphs
2 parents 35d9b83 + 1d68c16 commit f587ae5

File tree

7 files changed

+71
-111
lines changed

7 files changed

+71
-111
lines changed

python/plugins/processing/algs/qgis/BarPlot.py

+5-10
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525

2626
__revision__ = '$Format:%H$'
2727

28-
import matplotlib.pyplot as plt
29-
import matplotlib.pylab as lab
28+
import plotly as plt
29+
import plotly.graph_objs as go
3030
import numpy as np
3131

3232
from processing.core.parameters import ParameterTable
@@ -69,13 +69,8 @@ def processAlgorithm(self, feedback):
6969
output = self.getOutputValue(self.OUTPUT)
7070

7171
values = vector.values(layer, namefieldname, valuefieldname)
72-
plt.close()
7372

7473
ind = np.arange(len(values[namefieldname]))
75-
width = 0.8
76-
plt.bar(ind, values[valuefieldname], width, color='r')
77-
plt.xticks(ind, values[namefieldname], rotation=45)
78-
plotFilename = output + '.png'
79-
lab.savefig(plotFilename)
80-
with open(output, 'w') as f:
81-
f.write('<html><img src="' + plotFilename + '"/></html>')
74+
data = [go.Bar(x=ind,
75+
y=values[valuefieldname])]
76+
plt.offline.plot(data, filename=output, auto_open=False)

python/plugins/processing/algs/qgis/MeanAndStdDevPlot.py

+23-25
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,8 @@
2525

2626
__revision__ = '$Format:%H$'
2727

28-
import matplotlib.pyplot as plt
29-
import matplotlib.pylab as lab
30-
import numpy as np
28+
import plotly as plt
29+
import plotly.graph_objs as go
3130

3231
from processing.core.GeoAlgorithm import GeoAlgorithm
3332
from processing.core.parameters import ParameterTable
@@ -43,8 +42,7 @@ class MeanAndStdDevPlot(GeoAlgorithm):
4342
INPUT = 'INPUT'
4443
OUTPUT = 'OUTPUT'
4544
NAME_FIELD = 'NAME_FIELD'
46-
MEAN_FIELD = 'MEAN_FIELD'
47-
STDDEV_FIELD = 'STDDEV_FIELD'
45+
VALUE_FIELD = 'VALUE_FIELD'
4846

4947
def defineCharacteristics(self):
5048
self.name, self.i18n_name = self.trAlgorithm('Mean and standard deviation plot')
@@ -55,33 +53,33 @@ def defineCharacteristics(self):
5553
self.addParameter(ParameterTableField(self.NAME_FIELD,
5654
self.tr('Category name field'), self.INPUT,
5755
ParameterTableField.DATA_TYPE_ANY))
58-
self.addParameter(ParameterTableField(self.MEAN_FIELD,
59-
self.tr('Mean field'), self.INPUT))
60-
self.addParameter(ParameterTableField(self.STDDEV_FIELD,
61-
self.tr('StdDev field'), self.INPUT))
56+
self.addParameter(ParameterTableField(self.VALUE_FIELD,
57+
self.tr('Value field'), self.INPUT))
6258

6359
self.addOutput(OutputHTML(self.OUTPUT, self.tr('Plot')))
6460

6561
def processAlgorithm(self, feedback):
6662
layer = dataobjects.getObjectFromUri(
6763
self.getParameterValue(self.INPUT))
6864
namefieldname = self.getParameterValue(self.NAME_FIELD)
69-
meanfieldname = self.getParameterValue(self.MEAN_FIELD)
70-
stddevfieldname = self.getParameterValue(self.STDDEV_FIELD)
65+
valuefieldname = self.getParameterValue(self.VALUE_FIELD)
7166

7267
output = self.getOutputValue(self.OUTPUT)
7368

74-
values = vector.values(layer, namefieldname, meanfieldname, stddevfieldname)
75-
plt.close()
76-
ind = np.arange(len(values[namefieldname]))
77-
width = 0.8
78-
plt.bar(ind, values[meanfieldname], width, color='r',
79-
yerr=values[stddevfieldname],
80-
error_kw=dict(ecolor='yellow'),
81-
)
82-
83-
plt.xticks(ind, values[namefieldname], rotation=45)
84-
plotFilename = output + '.png'
85-
lab.savefig(plotFilename)
86-
with open(output, 'w') as f:
87-
f.write('<html><img src="' + plotFilename + '"/></html>')
69+
values = vector.values(layer, namefieldname, valuefieldname)
70+
71+
d = {}
72+
for i in range(len(values[namefieldname])):
73+
v = values[namefieldname][i]
74+
if v not in d:
75+
d[v] = [values[valuefieldname][i]]
76+
else:
77+
d[v].append(values[valuefieldname][i])
78+
79+
data = []
80+
for k, v in d.items():
81+
data.append(go.Box(y=list(v),
82+
boxmean='sd',
83+
name=k
84+
))
85+
plt.offline.plot(data, filename=output, auto_open=False)

python/plugins/processing/algs/qgis/PolarPlot.py

+8-18
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,15 @@
2525

2626
__revision__ = '$Format:%H$'
2727

28-
import matplotlib.pyplot as plt
29-
import matplotlib.pylab as lab
30-
from matplotlib.pyplot import figure
28+
import plotly as plt
29+
import plotly.graph_objs as go
3130
import numpy as np
3231

3332
from processing.core.GeoAlgorithm import GeoAlgorithm
3433
from processing.core.parameters import ParameterTable
3534
from processing.core.parameters import ParameterTableField
3635
from processing.core.outputs import OutputHTML
37-
from processing.tools import vector
38-
from processing.tools import dataobjects
36+
from processing.tools import dataobjects, vector
3937

4038

4139
class PolarPlot(GeoAlgorithm):
@@ -66,16 +64,8 @@ def processAlgorithm(self, feedback):
6664

6765
output = self.getOutputValue(self.OUTPUT)
6866

69-
values = vector.values(layer, namefieldname, valuefieldname)
70-
plt.close()
71-
fig = figure(figsize=(8, 8))
72-
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8], polar=True)
73-
N = len(values[valuefieldname])
74-
theta = np.arange(0.0, 2 * np.pi, 2 * np.pi / N)
75-
radii = values[valuefieldname]
76-
width = 2 * np.pi / N
77-
ax.bar(theta, radii, width=width, bottom=0.0)
78-
plotFilename = output + '.png'
79-
lab.savefig(plotFilename)
80-
with open(output, 'w') as f:
81-
f.write('<html><img src="' + plotFilename + '"/></html>')
67+
values = vector.values(layer, valuefieldname)
68+
69+
data = [go.Area(r=values[valuefieldname],
70+
t=np.degrees(np.arange(0.0, 2 * np.pi, 2 * np.pi / len(values[valuefieldname]))))]
71+
plt.offline.plot(data, filename=output, auto_open=False)

python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py

+9-11
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,10 @@
2828
import os
2929

3030
try:
31-
import matplotlib.pyplot
32-
assert matplotlib # NOQA silence pyflakes
33-
hasMatplotlib = True
31+
import plotly
32+
hasPlotly = True
3433
except:
35-
hasMatplotlib = False
34+
hasPlotly = False
3635

3736
from qgis.PyQt.QtGui import QIcon
3837

@@ -259,21 +258,20 @@ def __init__(self):
259258
FixGeometry(), ExecuteSQL(), FindProjection()
260259
]
261260

262-
if hasMatplotlib:
261+
if hasPlotly:
263262
from .VectorLayerHistogram import VectorLayerHistogram
264263
from .RasterLayerHistogram import RasterLayerHistogram
265264
from .VectorLayerScatterplot import VectorLayerScatterplot
266265
from .MeanAndStdDevPlot import MeanAndStdDevPlot
267266
from .BarPlot import BarPlot
268267
from .PolarPlot import PolarPlot
269268

270-
self.alglist.extend([
271-
VectorLayerHistogram(), RasterLayerHistogram(),
272-
VectorLayerScatterplot(), MeanAndStdDevPlot(), BarPlot(),
273-
PolarPlot(),
274-
])
269+
self.alglist.extend([VectorLayerHistogram(), RasterLayerHistogram(),
270+
VectorLayerScatterplot(), MeanAndStdDevPlot(),
271+
BarPlot(), PolarPlot()])
275272

276-
self.externalAlgs = [] # to store algs added by 3rd party plugins as scripts
273+
# to store algs added by 3rd party plugins as scripts
274+
self.externalAlgs = []
277275

278276
folder = os.path.join(os.path.dirname(__file__), 'scripts')
279277
scripts = ScriptUtils.loadFromFolder(folder)

python/plugins/processing/algs/qgis/RasterLayerHistogram.py

+10-27
Original file line numberDiff line numberDiff line change
@@ -27,27 +27,21 @@
2727

2828
__revision__ = '$Format:%H$'
2929

30-
import matplotlib.pyplot as plt
31-
import matplotlib.pylab as lab
32-
33-
from qgis.PyQt.QtCore import QVariant
34-
from qgis.core import QgsField
30+
import plotly as plt
31+
import plotly.graph_objs as go
3532

3633
from processing.core.GeoAlgorithm import GeoAlgorithm
3734
from processing.core.parameters import ParameterNumber
3835
from processing.core.parameters import ParameterRaster
39-
from processing.core.outputs import OutputTable
4036
from processing.core.outputs import OutputHTML
41-
from processing.tools import dataobjects
42-
from processing.tools import raster
37+
from processing.tools import dataobjects, raster
4338

4439

4540
class RasterLayerHistogram(GeoAlgorithm):
4641

4742
INPUT = 'INPUT'
48-
PLOT = 'PLOT'
49-
TABLE = 'TABLE'
5043
BINS = 'BINS'
44+
PLOT = 'PLOT'
5145

5246
def defineCharacteristics(self):
5347
self.name, self.i18n_name = self.trAlgorithm('Raster layer histogram')
@@ -59,33 +53,22 @@ def defineCharacteristics(self):
5953
self.tr('Number of bins'), 2, None, 10))
6054

6155
self.addOutput(OutputHTML(self.PLOT, self.tr('Histogram')))
62-
self.addOutput(OutputTable(self.TABLE, self.tr('Table')))
6356

6457
def processAlgorithm(self, feedback):
6558
layer = dataobjects.getObjectFromUri(
6659
self.getParameterValue(self.INPUT))
6760
nbins = self.getParameterValue(self.BINS)
6861

69-
outputplot = self.getOutputValue(self.PLOT)
70-
outputtable = self.getOutputFromName(self.TABLE)
62+
output = self.getOutputValue(self.PLOT)
7163

64+
# ALERT: this is potentially blocking if the layer is too big
7265
values = raster.scanraster(layer, feedback)
7366

74-
# ALERT: this is potentially blocking if the layer is too big
75-
plt.close()
7667
valueslist = []
7768
for v in values:
7869
if v is not None:
7970
valueslist.append(v)
80-
(n, bins, values) = plt.hist(valueslist, nbins)
81-
82-
fields = [QgsField('CENTER_VALUE', QVariant.Double),
83-
QgsField('NUM_ELEM', QVariant.Double)]
84-
writer = outputtable.getTableWriter(fields)
85-
for i in range(len(values)):
86-
writer.addRecord([str(bins[i]) + '-' + str(bins[i + 1]), n[i]])
87-
88-
plotFilename = outputplot + '.png'
89-
lab.savefig(plotFilename)
90-
with open(outputplot, 'w') as f:
91-
f.write('<html><img src="' + plotFilename + '"/></html>')
71+
72+
data = [go.Histogram(x=valueslist,
73+
nbinsx=nbins)]
74+
plt.offline.plot(data, filename=output, auto_open=False)

python/plugins/processing/algs/qgis/VectorLayerHistogram.py

+6-8
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525

2626
__revision__ = '$Format:%H$'
2727

28-
import matplotlib.pyplot as plt
29-
import matplotlib.pylab as lab
28+
import plotly as plt
29+
import plotly.graph_objs as go
3030

3131
from processing.core.GeoAlgorithm import GeoAlgorithm
3232
from processing.core.parameters import ParameterVector
@@ -66,9 +66,7 @@ def processAlgorithm(self, feedback):
6666
output = self.getOutputValue(self.OUTPUT)
6767

6868
values = vector.values(layer, fieldname)
69-
plt.close()
70-
plt.hist(values[fieldname], bins)
71-
plotFilename = output + '.png'
72-
lab.savefig(plotFilename)
73-
with open(output, 'w') as f:
74-
f.write('<html><img src="' + plotFilename + '"/></html>')
69+
70+
data = [go.Histogram(x=values[fieldname],
71+
nbinsx=bins)]
72+
plt.offline.plot(data, filename=output, auto_open=False)

python/plugins/processing/algs/qgis/VectorLayerScatterplot.py

+10-12
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525

2626
__revision__ = '$Format:%H$'
2727

28-
import matplotlib.pyplot as plt
29-
import matplotlib.pylab as lab
28+
import plotly as plt
29+
import plotly.graph_objs as go
3030

3131
from processing.core.GeoAlgorithm import GeoAlgorithm
3232
from processing.core.parameters import ParameterVector
@@ -51,10 +51,12 @@ def defineCharacteristics(self):
5151
self.addParameter(ParameterVector(self.INPUT,
5252
self.tr('Input layer')))
5353
self.addParameter(ParameterTableField(self.XFIELD,
54-
self.tr('X attribute'), self.INPUT,
54+
self.tr('X attribute'),
55+
self.INPUT,
5556
ParameterTableField.DATA_TYPE_NUMBER))
5657
self.addParameter(ParameterTableField(self.YFIELD,
57-
self.tr('Y attribute'), self.INPUT,
58+
self.tr('Y attribute'),
59+
self.INPUT,
5860
ParameterTableField.DATA_TYPE_NUMBER))
5961

6062
self.addOutput(OutputHTML(self.OUTPUT, self.tr('Scatterplot')))
@@ -68,11 +70,7 @@ def processAlgorithm(self, feedback):
6870
output = self.getOutputValue(self.OUTPUT)
6971

7072
values = vector.values(layer, xfieldname, yfieldname)
71-
plt.close()
72-
plt.scatter(values[xfieldname], values[yfieldname])
73-
plt.ylabel(yfieldname)
74-
plt.xlabel(xfieldname)
75-
plotFilename = output + '.png'
76-
lab.savefig(plotFilename)
77-
with open(output, 'w') as f:
78-
f.write('<html><img src="' + plotFilename + '"/></html>')
73+
data = [go.Scatter(x=values[xfieldname],
74+
y=values[yfieldname],
75+
mode='markers')]
76+
plt.offline.plot(data, filename=output, auto_open=False)

0 commit comments

Comments
 (0)