216 lines
6.7 KiB
Python
216 lines
6.7 KiB
Python
from qgis.PyQt.QtCore import QCoreApplication
|
|
from qgis.core import (QgsProcessing,
|
|
QgsProcessingAlgorithm,
|
|
QgsProcessingParameterFeatureSource,
|
|
QgsProcessingParameterFileDestination,
|
|
QgsProcessingParameterField,
|
|
QgsProcessingParameterString,
|
|
QgsProcessingParameterNumber,
|
|
QgsProcessingParameterBoolean)
|
|
|
|
import matplotlib
|
|
matplotlib.use('Agg')
|
|
import matplotlib.pyplot as plt
|
|
import math
|
|
|
|
class matplotlibScat(QgsProcessingAlgorithm):
|
|
|
|
INPUT = 'INPUT'
|
|
OUTPUT = 'OUTPUT'
|
|
X_VALUES = 'X_VALUES'
|
|
Y_VALUES = 'Y_VALUES'
|
|
X_MAX = 'X_MAX'
|
|
Y_MAX = 'Y_MAX'
|
|
FLIP_X = 'FLIP_X'
|
|
FLIP_Y = 'FLIP_Y'
|
|
COLOR = 'COLOR'
|
|
TITLE = 'TITLE'
|
|
X_LABEL = 'X_LABEL'
|
|
Y_LABEL = 'Y_LABEL'
|
|
|
|
|
|
def tr(self, string):
|
|
return QCoreApplication.translate('Processing', string)
|
|
|
|
def createInstance(self):
|
|
return matplotlibScat()
|
|
|
|
def name(self):
|
|
return 'Scatter Plot'
|
|
|
|
def displayName(self):
|
|
return self.tr('Scatter Plot')
|
|
|
|
def group(self):
|
|
return self.tr('matplotlib vector')
|
|
|
|
def groupId(self):
|
|
return 'matplotlib vector'
|
|
|
|
def shortHelpString(self):
|
|
return self.tr("Generates a scatter plot for two selected numeric attributes from an input layer.")
|
|
|
|
def initAlgorithm(self, config=None):
|
|
|
|
self.addParameter(
|
|
QgsProcessingParameterFeatureSource(
|
|
self.INPUT,
|
|
self.tr('Input layer'),
|
|
[QgsProcessing.TypeVectorAnyGeometry]
|
|
)
|
|
)
|
|
|
|
self.addParameter(QgsProcessingParameterFileDestination(
|
|
'OUTPUT',
|
|
self.tr('Plot Output File'),
|
|
'PNG Files (*.png)'
|
|
)
|
|
)
|
|
|
|
self.addParameter(
|
|
QgsProcessingParameterField(
|
|
self.X_VALUES,
|
|
self.tr('X Values'),
|
|
None,
|
|
self.INPUT,
|
|
QgsProcessingParameterField.Numeric
|
|
)
|
|
)
|
|
|
|
self.addParameter(
|
|
QgsProcessingParameterField(
|
|
self.Y_VALUES,
|
|
self.tr('Y Values'),
|
|
None,
|
|
self.INPUT,
|
|
QgsProcessingParameterField.Numeric
|
|
)
|
|
)
|
|
|
|
self.addParameter(
|
|
QgsProcessingParameterNumber(
|
|
self.X_MAX,
|
|
self.tr('X Max'),
|
|
type=QgsProcessingParameterNumber.Double,
|
|
optional=True
|
|
)
|
|
)
|
|
|
|
self.addParameter(
|
|
QgsProcessingParameterNumber(
|
|
self.Y_MAX,
|
|
self.tr('Y Max'),
|
|
type=QgsProcessingParameterNumber.Double,
|
|
optional=True
|
|
)
|
|
)
|
|
|
|
self.addParameter(
|
|
QgsProcessingParameterBoolean(
|
|
self.FLIP_X,
|
|
self.tr('Flip X Axis'),
|
|
defaultValue=False
|
|
)
|
|
)
|
|
|
|
self.addParameter(
|
|
QgsProcessingParameterBoolean(
|
|
self.FLIP_Y,
|
|
self.tr('Flip Y Axis'),
|
|
defaultValue=False
|
|
)
|
|
)
|
|
|
|
self.addParameter(
|
|
QgsProcessingParameterString(
|
|
self.COLOR,
|
|
self.tr('Color'),
|
|
defaultValue='blue'
|
|
)
|
|
)
|
|
|
|
self.addParameter(
|
|
QgsProcessingParameterString(
|
|
self.TITLE,
|
|
self.tr('Title'),
|
|
defaultValue=' '
|
|
)
|
|
)
|
|
|
|
self.addParameter(
|
|
QgsProcessingParameterString(
|
|
self.X_LABEL,
|
|
self.tr('X Label'),
|
|
defaultValue=' '
|
|
)
|
|
)
|
|
|
|
self.addParameter(
|
|
QgsProcessingParameterString(
|
|
self.Y_LABEL,
|
|
self.tr('Y Label'),
|
|
defaultValue=' '
|
|
)
|
|
)
|
|
|
|
def processAlgorithm(self, parameters, context, feedback):
|
|
|
|
source = self.parameterAsSource(parameters, self.INPUT, context)
|
|
x_field = self.parameterAsString(parameters, self.X_VALUES, context)
|
|
y_field = self.parameterAsString(parameters, self.Y_VALUES, context)
|
|
x_max = self.parameterAsDouble(parameters, self.X_MAX, context)
|
|
y_max = self.parameterAsDouble(parameters, self.Y_MAX, context)
|
|
flip_x = self.parameterAsBool(parameters, self.FLIP_X, context)
|
|
flip_y = self.parameterAsBool(parameters, self.FLIP_Y, context)
|
|
color = self.parameterAsString(parameters, self.COLOR, context)
|
|
title = self.parameterAsString(parameters, self.TITLE, context)
|
|
x_label = self.parameterAsString(parameters, self.X_LABEL, context)
|
|
y_label = self.parameterAsString(parameters, self.Y_LABEL, context)
|
|
output = self.parameterAsFileOutput(parameters, self.OUTPUT, context)
|
|
|
|
feedback.pushInfo(f"Source: {source}")
|
|
feedback.pushInfo(f"x_field: {x_field}")
|
|
feedback.pushInfo(f"y_field: {y_field}")
|
|
feedback.pushInfo(f"x_max: {x_max}")
|
|
feedback.pushInfo(f"y_max: {y_max}")
|
|
feedback.pushInfo(f"flip_x: {flip_x}")
|
|
feedback.pushInfo(f"flip_y: {flip_y}")
|
|
feedback.pushInfo(f"title: {title}")
|
|
feedback.pushInfo(f"x_label: {x_label}")
|
|
feedback.pushInfo(f"y_label: {y_label}")
|
|
feedback.pushInfo(f"output: {output}")
|
|
|
|
x_values = []
|
|
y_values = []
|
|
|
|
for feature in source.getFeatures():
|
|
try:
|
|
x = float(feature[x_field])
|
|
y = float(feature[y_field])
|
|
if not (math.isnan(x) or math.isnan(y)):
|
|
x_values.append(x)
|
|
y_values.append(y)
|
|
except Exception as e:
|
|
continue
|
|
|
|
feedback.pushInfo(f"x_values: {x_values}")
|
|
feedback.pushInfo(f"y_values: {y_values}")
|
|
|
|
try:
|
|
plt.scatter(x_values, y_values, color=color)
|
|
plt.xlim(0, x_max)
|
|
plt.ylim(0, y_max)
|
|
if flip_x:
|
|
plt.gca().invert_xaxis()
|
|
if flip_y:
|
|
plt.gca().invert_yaxis()
|
|
plt.title(title)
|
|
plt.xlabel(x_label)
|
|
plt.ylabel(y_label)
|
|
plt.savefig(output)
|
|
plt.close()
|
|
feedback.pushInfo(f"Scatter plot saved to {output}")
|
|
return {self.OUTPUT: output}
|
|
except Exception as e:
|
|
feedback.reportError(f"Error: {e}")
|
|
return {} |