Add files via upload

This commit is contained in:
2024-06-28 12:23:19 +02:00
committed by GitHub
parent 9bb1112132
commit 0bec1cd9f4
29 changed files with 14571 additions and 0 deletions
+51
View File
@@ -0,0 +1,51 @@
import rasterio
import numpy as np
from scipy.stats import pearsonr
import matplotlib.pyplot as plt
def read_raster_data(raster_path, target_width, target_height):
with rasterio.open(raster_path) as raster:
data = raster.read(1, masked=True) # Reads the first band
if data.shape != (target_height, target_width):
data = data[:target_height, :target_width]
if raster.nodata is not None:
data = data.filled(np.nan) # Fill masked values with NaN
return data
def flatten_data(data):
return data.flatten()
def calculate_correlation(data1, data2):
mask = ~np.isnan(data1) & ~np.isnan(data2)
filtered_data1 = data1[mask]
filtered_data2 = data2[mask]
correlation, _ = pearsonr(filtered_data1, filtered_data2)
return correlation, filtered_data1, filtered_data2 # Return the filtered data for plotting
def plot_correlation(data1, data2, correlation, file_path):
plt.scatter(data1, data2, alpha=0.5)
plt.xlim(0,7)
#plt.title(f'Correlation: {correlation:.2f}')
plt.xlabel('Raster 1 Values')
plt.ylabel('Raster 2 Values')
plt.savefig(file_path, dpi=300)
plt.close()
if __name__ == "__main__":
raster_path1 = 'friction surface.tif'
raster_path2 = 'ghsl.tif'
save_path = 'plot.png'
# Common dimensions
target_width = 275 # Choose based on your requirements
target_height = 254
data1 = flatten_data(read_raster_data(raster_path1, target_width, target_height))
data2 = flatten_data(read_raster_data(raster_path2, target_width, target_height))
correlation, filtered_data1, filtered_data2 = calculate_correlation(data1, data2)
plot_correlation(filtered_data1, filtered_data2, correlation, save_path)
+94
View File
@@ -0,0 +1,94 @@
import rasterio
import numpy as np
from scipy.stats import pearsonr
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
def read_raster_data(raster_path, target_width, target_height):
with rasterio.open(raster_path) as raster:
data = raster.read(1, masked=True) # Reads the first band
if data.shape != (target_height, target_width):
data = data[:target_height, :target_width]
if raster.nodata is not None:
data = data.filled(np.nan) # Fill masked values with NaN
return data
def flatten_data(data):
return data.flatten()
def calculate_correlation(data1, data2):
mask = ~np.isnan(data1) & ~np.isnan(data2)
filtered_data1 = data1[mask]
filtered_data2 = data2[mask]
correlation, _ = pearsonr(filtered_data1, filtered_data2)
return correlation, filtered_data1, filtered_data2
def exponential_func(x, a, b):
return a * np.exp(-b * x)
def plot_max_values_scatter(data1, data2, file_path):
# Group data by 0.01 increments
bins = np.arange(0, np.nanmax(data1) + 0.001, 0.001)
digitized = np.digitize(data1, bins)
# Calculate the maximum of raster 2 values for each bin
max_values_per_bin = []
for i in range(1, len(bins)):
filtered_data2 = data2[digitized == i]
if filtered_data2.size > 0: # Check if the array is not empty
max_value = np.nanmax(filtered_data2)
else:
max_value = np.nan # Set to NaN if no data is present in the bin
max_values_per_bin.append(max_value)
# Compute the indices of non-NaN values for max_values_per_bin
non_nan_indices = ~np.isnan(max_values_per_bin)
# Use these indices to filter both bins and max_values_per_bin
max_values_per_bin = np.array(max_values_per_bin)[non_nan_indices]
# Adjust the bin values to be the center of each bin for plotting
bin_centers = bins[:-1] + 0.0005
bin_centers = bin_centers[non_nan_indices]
# Remove outliers based on a threshold (e.g., 3 standard deviations from the mean)
threshold = np.nanmean(max_values_per_bin) + 3 * np.nanstd(max_values_per_bin)
outliers_mask = max_values_per_bin <= threshold
max_values_per_bin = max_values_per_bin[outliers_mask]
bin_centers = bin_centers[outliers_mask]
# Fit an exponential decrease to the scatter plot
popt, pcov = curve_fit(exponential_func, bin_centers, max_values_per_bin)
# Plot
plt.scatter(bin_centers, max_values_per_bin, alpha=0.5, label='Data')
plt.plot(bin_centers, exponential_func(bin_centers, *popt), 'r-', label='Exponential Fit')
# Update labels to reflect the new bin size
plt.xlabel('Population density in [%]')
plt.ylabel('Friction surface in [min/km]')
"""plt.xlim(0,0.1)
plt.ylim(0,0.1)"""
plt.legend()
plt.savefig(file_path, dpi=300)
plt.close()
if __name__ == "__main__":
raster_path2 = 'friction surface.tif'
raster_path1 = 'ghsl.tif'
save_path = 'plot_grouped_scatter_with_exponential_fit.png'
# Common dimensions
target_width = 275
target_height = 254
# Read and process the raster data
data1 = flatten_data(read_raster_data(raster_path1, target_width, target_height))
data2 = flatten_data(read_raster_data(raster_path2, target_width, target_height))
# Calculate correlation
correlation, filtered_data1, filtered_data2 = calculate_correlation(data1, data2)
# Plot the maximum values of raster 2 for each group in raster 1
plot_max_values_scatter(filtered_data1, filtered_data2, save_path)
+186
View File
@@ -0,0 +1,186 @@
from qgis.PyQt.QtCore import QCoreApplication, QVariant
from qgis.core import (QgsProcessing,
QgsFeatureSink,
QgsProcessingException,
QgsProcessingAlgorithm,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsProcessingParameterString,
QgsProcessingParameterEnum,
QgsFeature,
QgsField,
QgsGeometry,
QgsVectorLayer,
QgsProject,
QgsProcessingContext)
from qgis import processing
import requests
import geopandas as gpd
class FetchGeoBoundaryAlgorithm(QgsProcessingAlgorithm):
INPUT = 'INPUT'
OUTPUT = 'OUTPUT'
RELEASE_TYPE = 'RELEASE_TYPE'
COUNTRY_CODE = 'COUNTRY_CODE'
BOUNDARY_TYPE = 'BOUNDARY_TYPE'
def tr(self, string):
return QCoreApplication.translate('Processing', string)
def createInstance(self):
return FetchGeoBoundaryAlgorithm()
def name(self):
return 'fetchgeoboundary'
def displayName(self):
return self.tr('Fetch geoBoundaries')
def group(self):
return self.tr('geoBoundaries')
def groupId(self):
return 'geoboundaryscripts'
def shortHelpString(self):
return self.tr("Fetches geoBoundaries and adds them. This is an unofficial tool by Joaquin Gottlebe. \n More information: https://www.geoboundaries.org/index.html")
def initAlgorithm(self, config=None):
self.addParameter(
QgsProcessingParameterString(
self.COUNTRY_CODE,
self.tr('Country Code ISO-3'),
defaultValue='DEU'
)
)
self.addParameter(
QgsProcessingParameterEnum(
self.BOUNDARY_TYPE,
self.tr('Boundary Type'),
options=['ADM0','ADM1','ADM2','ADM3','ADM4','ADM5'],
defaultValue=0
)
)
self.addParameter(
QgsProcessingParameterEnum(
self.RELEASE_TYPE,
self.tr('Release Type'),
options=['gbOpen','gbHumanitarian','gbAuthorative'],
defaultValue='gbOpen'
)
)
self.addParameter(
QgsProcessingParameterFeatureSink(
self.OUTPUT,
self.tr('Output layer')
)
)
def processAlgorithm(self, parameters, context, feedback):
release_type_index = self.parameterAsEnum(parameters, self.RELEASE_TYPE, context)
release_types = ['gbOpen', 'gbHumanitarian', 'gbAuthorative']
release_type = release_types[release_type_index]
country_code = self.parameterAsString(parameters, self.COUNTRY_CODE, context)
boundary_type_index = self.parameterAsEnum(parameters, self.BOUNDARY_TYPE, context)
boundary_types = ['ADM0','ADM1','ADM2','ADM3','ADM4','ADM5']
boundary_type = boundary_types[boundary_type_index]
results = self.fetch_geoboundary(release_type, country_code, boundary_type, feedback)
if not results:
raise QgsProcessingException('Failed to fetch geoBoundary')
total_features = sum(len(result['gdf']) for result in results)
processed_features = 0
layer_name = f"{country_code}_{boundary_type}_{release_type}_geoBoundaries"
vector_layer = QgsVectorLayer("Polygon?crs=epsg:4326", layer_name, "memory")
pr = vector_layer.dataProvider()
for result in results:
gdf = result['gdf']
metadata = result['metadata']
if gdf.empty:
feedback.reportError("Loaded GeoDataFrame is empty.")
continue
for index, row in gdf.iterrows():
if feedback.isCanceled():
break
# Debugging type and attribute
if not hasattr(row['geometry'], 'wkt'):
feedback.reportError(f"Unexpected type for geometry: {type(row['geometry'])}. Expected shapely geometry object.")
continue # Skip this iteration if the geometry type is unexpected
# Assuming row['geometry'] is a shapely.geometry object as expected
feat = QgsFeature()
try:
feat.setGeometry(QgsGeometry.fromWkt(row['geometry'].wkt))
except Exception as e:
feedback.reportError(f"Error setting geometry from WKT: {e}")
continue # Skip this iteration if there was an error setting the geometry
# Add additional feature settings and add feature to the provider as necessary
pr.addFeature(feat)
vector_layer.updateExtents()
QgsProject.instance().addMapLayer(vector_layer)
feedback.pushInfo("GeoBoundary layer added to the project.")
return {self.OUTPUT: vector_layer.id()}
def fetch_geoboundary(self, release_type, country_code, boundary_type, feedback):
api_url = f"https://www.geoboundaries.org/api/current/{release_type}/{country_code}/{boundary_type}/"
try:
response = requests.get(api_url)
if response.status_code != 200:
print(f"Failed to fetch data: HTTP Status Code {response.status_code}")
return None
data = response.json()
results = []
if not isinstance(data, list):
data = [data]
total_countries = len(data)
processed_countries = 0
for country_data in data:
if feedback.isCanceled():
return None
if 'gjDownloadURL' not in country_data:
feedback.reportError("'gjDownloadURL' not found in the response for" + country_data.get('boundaryISO', 'an unknown country'))
continue
geojson_url = country_data['gjDownloadURL']
gdf = gpd.read_file(geojson_url)
if gdf.empty:
feedback.reportError("Loaded GeoDataFrame is empty.")
continue
metadata = {key: country_data.get(key, '') for key in country_data}
results.append({'gdf': gdf, 'metadata' : metadata})
processed_countries += 1
feedback.setProgress(int((processed_countries / total_countries) * 100))
return results
except requests.RequestException as e:
feedback.reportError(f"Request error: {e}")
except Exception as e:
feedback.reportError(f"An unexpected error occurred: {e}")
return None
+316
View File
@@ -0,0 +1,316 @@
from matplotlib.colors import Normalize
import matplotlib.pyplot as plt
from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (QgsProcessing,
QgsProcessingException,
QgsProcessingAlgorithm,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterField,
QgsProcessingParameterFileDestination,
QgsProcessingParameterNumber,
QgsProcessingParameterString,
QgsProcessingParameterBoolean,
QgsProcessingParameterEnum)
from qgis import processing
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
class matplotlibBar(QgsProcessingAlgorithm):
INPUT = 'INPUT'
ATTRIBUTE_CAT = 'ATTRIBUTE_CAT'
ATTRIBUTE_VAL = 'ATTRIBUTE_VAL'
SORTING_OPTION = 'SORTING_OPTION'
ATTRIBUTE_COLOR = 'ATTRIBUTE_COLOR'
COLOR_MAP = 'COLOR_MAP'
SHOW_LEGEND = 'SHOW_LEGEND'
LEGEND_TITLE = 'LEGEND_TITLE'
PLOT_OUTPUT = 'PLOT_OUTPUT'
FIG_WIDTH = 'FIG_WIDTH'
FIG_HEIGHT = 'FIG_HEIGHT'
ALPHA = 'ALPHA'
COLOR = 'COLOR'
SHOW_GRID = 'SHOW_GRID'
PLOT_TITLE = 'PLOT_TITLE'
X_LABEL = 'X_LABEL'
Y_LABEL = 'Y_LABEL'
X_TICK_ROTATION = 'X_TICK_ROTATION'
X_TICK_ALIGNMENT = 'X_TICK_ALIGNMENT'
def tr(self, string):
return QCoreApplication.translate('Processing', string)
def createInstance(self):
return matplotlibBar()
def name(self):
return 'Bar Plot'
def displayName(self):
return self.tr('Bar Plot')
def group(self):
return self.tr('matplotlib vector')
def groupId(self):
return 'matplotlib vector'
def shortHelpString(self):
return self.tr("Generates a Bar Plot for a category attribute and a value attribute and colors them depending another attribute from an input layer.")
def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterFeatureSource(
self.INPUT,
self.tr('Input layer'),
[QgsProcessing.TypeVectorAnyGeometry]
)
)
self.addParameter(QgsProcessingParameterField(
self.ATTRIBUTE_CAT,
self.tr('Category Attribute'),
None,
self.INPUT,
QgsProcessingParameterField.Any
)
)
self.addParameter(QgsProcessingParameterField(
self.ATTRIBUTE_VAL,
self.tr('Value Attribute'),
None,
self.INPUT,
QgsProcessingParameterField.Numeric
)
)
sorting_options = [
('NO_SORTING', ('No Sorting')),
('ASCENDING', ('Ascending')),
('DESCENDING', ('Descending'))
]
self.addParameter(QgsProcessingParameterEnum(
self.SORTING_OPTION,
self.tr('Sorting Option'),
options=[option[1] for option in sorting_options],
defaultValue=0,
allowMultiple=False
)
)
self.addParameter(QgsProcessingParameterFileDestination(
'PLOT_OUTPUT',
self.tr('Plot Output File'),
'PNG Files (*.png)'
)
)
self.addParameter(QgsProcessingParameterNumber(
self.FIG_WIDTH,
self.tr('Figure Width'),
QgsProcessingParameterNumber.Double,
10
)
)
self.addParameter(QgsProcessingParameterNumber(
self.FIG_HEIGHT,
self.tr('Figure Height'),
QgsProcessingParameterNumber.Double,
6
)
)
self.addParameter(QgsProcessingParameterNumber(
self.ALPHA,
self.tr('Alpha Transparency'),
QgsProcessingParameterNumber.Double,
0.7
)
)
self.addParameter(QgsProcessingParameterString(
self.COLOR,
self.tr('Color'),
defaultValue='blue'
)
)
self.addParameter(QgsProcessingParameterBoolean(
self.SHOW_GRID,
self.tr('Show Grid'),
defaultValue=True
)
)
self.addParameter(QgsProcessingParameterString(
self.PLOT_TITLE,
self.tr('Plot Title'),
defaultValue=' '
)
)
self.addParameter(QgsProcessingParameterString(
self.X_LABEL,
self.tr('X-axis Label (Categories)'),
defaultValue=' '
)
)
self.addParameter(QgsProcessingParameterString(
self.Y_LABEL,
self.tr('Y-axis Label (Values)'),
defaultValue=' '
)
)
self.addParameter(QgsProcessingParameterNumber(
self.X_TICK_ROTATION,
self.tr('X-axis Tick Label Rotation'),
QgsProcessingParameterNumber.Integer,
defaultValue=45
)
)
self.addParameter(QgsProcessingParameterString(
self.X_TICK_ALIGNMENT,
self.tr('X-axis Tick Label Alignment'),
defaultValue='right'
)
)
self.addParameter(QgsProcessingParameterField(
self.ATTRIBUTE_COLOR,
self.tr('Color Attribute'),
None,
self.INPUT,
QgsProcessingParameterField.Any,
optional=True
)
)
self.addParameter(QgsProcessingParameterString(
self.COLOR_MAP,
self.tr('Color Map'),
defaultValue='viridis',
)
)
self.addParameter(QgsProcessingParameterBoolean(
'SHOW_LEGEND',
self.tr('Show Legend'),
defaultValue=True,
)
)
self.addParameter(QgsProcessingParameterString(
self.LEGEND_TITLE,
self.tr('Legend Title'),
optional=True,
defaultValue=' '
)
)
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
cat_attribute_name = self.parameterAsString(
parameters, self.ATTRIBUTE_CAT, context)
val_attribute_name = self.parameterAsString(
parameters, self.ATTRIBUTE_VAL, context)
color_attribute_name = self.parameterAsString(
parameters, self.ATTRIBUTE_COLOR, context)
color_map_name = self.parameterAsString(
parameters, self.COLOR_MAP, context)
plot_output_path = self.parameterAsFileOutput(
parameters, 'PLOT_OUTPUT', context)
fig_width = self.parameterAsDouble(parameters, self.FIG_WIDTH, context)
fig_height = self.parameterAsDouble(
parameters, self.FIG_HEIGHT, context)
alpha = self.parameterAsDouble(parameters, self.ALPHA, context)
color = self.parameterAsString(parameters, self.COLOR, context)
show_grid = self.parameterAsBool(parameters, self.SHOW_GRID, context)
plot_title = self.parameterAsString(
parameters, self.PLOT_TITLE, context)
x_label = self.parameterAsString(parameters, self.X_LABEL, context)
y_label = self.parameterAsString(parameters, self.Y_LABEL, context)
x_tick_rotation = self.parameterAsInt(
parameters, self.X_TICK_ROTATION, context)
x_tick_alignment = self.parameterAsString(
parameters, self.X_TICK_ALIGNMENT, context)
show_legend = self.parameterAsBool(parameters, self.SHOW_LEGEND, context)
legend_title = self.parameterAsString(
parameters, self.LEGEND_TITLE, context)
sorting_option = self.parameterAsEnum(
parameters, self.SORTING_OPTION, context)
categories, values, color_values = [], [], []
for feature in source.getFeatures():
cat_value = feature[cat_attribute_name]
val_value = feature[val_attribute_name]
if cat_value is not None and val_value is not None:
categories.append(str(cat_value))
values.append(float(val_value))
if color_attribute_name:
color_value = feature[color_attribute_name] if feature[color_attribute_name] is not None else "Default"
color_values.append(color_value)
if sorting_option == 1:
sorted_indices = sorted(
range(len(values)), key=lambda i: values[i])
elif sorting_option == 2:
sorted_indices = sorted(
range(len(values)), key=lambda i: values[i], reverse=True)
else:
sorted_indices = range(len(values))
sorted_categories = [categories[i] for i in sorted_indices]
sorted_values = [values[i] for i in sorted_indices]
if color_attribute_name:
color_values = [color_values[i] for i in sorted_indices]
plt.figure(figsize=(fig_width, fig_height))
if color_attribute_name:
unique_colors = list(set(color_values))
colormap = plt.cm.get_cmap(color_map_name, len(unique_colors))
norm = Normalize(vmin=0, vmax=len(unique_colors)-1)
color_map = {color: colormap(norm(i))
for i, color in enumerate(unique_colors)}
bar_colors = [color_map[value] for value in color_values]
for i, (cat, val) in enumerate(zip(sorted_categories, sorted_values)):
plt.bar(cat, val, color=bar_colors[i], label=color_values[i]
if i == 0 or color_values[i] != color_values[i-1] else "")
if show_legend:
handles, labels = plt.gca().get_legend_handles_labels()
by_label = dict(zip(labels, handles))
plt.legend(by_label.values(), by_label.keys(), title=legend_title)
else:
plt.bar(sorted_categories, sorted_values, color=color, alpha=alpha)
if color_attribute_name and len(color_values) != len(categories):
raise QgsProcessingException(
self.tr('Mismatch in the number of categories and color values.'))
if not categories or not values:
raise QgsProcessingException(
self.tr("No valid data found. Please check the selected attributes."))
if not legend_title.strip():
legend_title = color_attribute_name if color_attribute_name else 'Legend'
plt.title(plot_title if plot_title else 'Value Distribution by Category')
plt.xlabel(x_label if x_label else 'Category')
plt.ylabel(y_label if y_label else 'Value')
if show_grid:
plt.grid(True)
else:
plt.grid(False)
plt.xticks(rotation=x_tick_rotation, ha=x_tick_alignment)
plt.tight_layout()
try:
plt.savefig(plot_output_path)
plt.close()
return {}
except Exception as e:
feedback.reportError(str(e))
return {}
+113
View File
@@ -0,0 +1,113 @@
from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (QgsProcessing,
QgsFeatureSink,
QgsProcessingException,
QgsProcessingAlgorithm,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsProcessingParameterField,
QgsProcessingParameterFileDestination,
QgsProcessingParameterNumber,
QgsProcessingParameterString,
QgsProcessingParameterBoolean)
from qgis import processing
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
class matplotlibHist(QgsProcessingAlgorithm):
INPUT = 'INPUT'
ATTRIBUTE = 'ATTRIBUTE'
MAX_VALUE = 'MAX_VALUE'
PLOT_OUTPUT = 'PLOT_OUTPUT'
FIG_WIDTH = 'FIG_WIDTH'
FIG_HEIGHT = 'FIG_HEIGHT'
BINS = 'BINS'
ALPHA = 'ALPHA'
COLOR = 'COLOR'
SHOW_GRID = 'SHOW_GRID'
PLOT_TITLE = 'PLOT_TITLE'
X_LABEL = 'X_LABEL'
Y_LABEL = 'Y_LABEL'
def tr(self, string):
return QCoreApplication.translate('Processing', string)
def createInstance(self):
return matplotlibHist()
def name(self):
return 'Histogram'
def displayName(self):
return self.tr('Histogram')
def group(self):
return self.tr('matplotlib vector')
def groupId(self):
return 'matplotlib vector'
def shortHelpString(self):
return self.tr("Generates a histogram plot for a selected numeric attribute from an input layer.")
def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,self.tr('Input layer'),[QgsProcessing.TypeVectorAnyGeometry]))
self.addParameter(QgsProcessingParameterField(self.ATTRIBUTE,self.tr('Attribute'),None,self.INPUT,QgsProcessingParameterField.Any))
self.addParameter(QgsProcessingParameterNumber(self.MAX_VALUE, self.tr('Maximum Value'), QgsProcessingParameterNumber.Double, None, optional=True))
self.addParameter(QgsProcessingParameterFileDestination('PLOT_OUTPUT',self.tr('Plot Output File'),'PNG Files (*.png)'))
self.addParameter(QgsProcessingParameterNumber(self.FIG_WIDTH,self.tr('Figure Width'), QgsProcessingParameterNumber.Double, 10))
self.addParameter(QgsProcessingParameterNumber(self.FIG_HEIGHT,self.tr('Figure Height'), QgsProcessingParameterNumber.Double, 6))
self.addParameter(QgsProcessingParameterNumber(self.BINS, self.tr('Number of Bins'), QgsProcessingParameterNumber.Integer, 30 ))
self.addParameter(QgsProcessingParameterNumber(self.ALPHA,self.tr('Alpha Transparency'), QgsProcessingParameterNumber.Double, 0.7))
self.addParameter(QgsProcessingParameterString(self.COLOR,self.tr('Color'), defaultValue='blue'))
self.addParameter(QgsProcessingParameterBoolean(self.SHOW_GRID,self.tr('Show Grid'), defaultValue=True))
self.addParameter(QgsProcessingParameterString(self.PLOT_TITLE, self.tr('Plot Title'), defaultValue=' '))
self.addParameter(QgsProcessingParameterString(self.X_LABEL, self.tr('X-axis Label'), defaultValue=' '))
self.addParameter(QgsProcessingParameterString(self.Y_LABEL, self.tr('Y-axis Label'), defaultValue='Frequency'))
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
attribute_name = self.parameterAsString(parameters, self.ATTRIBUTE, context)
attribute_values = []
max_value = self.parameterAsDouble(parameters, self.MAX_VALUE, context) if parameters[self.MAX_VALUE] is not None else max(attribute_values)
plot_output_path = self.parameterAsFileOutput(parameters, 'PLOT_OUTPUT', context)
fig_width = self.parameterAsDouble(parameters, self.FIG_WIDTH, context)
fig_height = self.parameterAsDouble(parameters, self.FIG_HEIGHT, context)
bins = self.parameterAsInt(parameters, self.BINS, context)
alpha = self.parameterAsDouble(parameters, self.ALPHA, context)
color = self.parameterAsString(parameters, self.COLOR, context)
show_grid = self.parameterAsBool(parameters, self.SHOW_GRID, context)
plot_title = self.parameterAsString(parameters, self.PLOT_TITLE, context)
x_label = self.parameterAsString(parameters, self.X_LABEL, context)
y_label = self.parameterAsString(parameters, self.Y_LABEL, context)
for feature in source.getFeatures():
attribute_value = feature[attribute_name]
if attribute_value is not None:
attribute_values.append(attribute_value)
if not attribute_values:
raise QgsProcessingException(self.tr("No attribute values found. Please check the selected attribute."))
try:
plt.figure(figsize=(fig_width,fig_height))
plt.hist(attribute_values, bins=bins,alpha=alpha, color=color, range=(min(attribute_values), max_value))
plt.title(plot_title if plot_title else 'Value Distribution by Category')
plt.xlabel(x_label if x_label else ' ')
plt.ylabel(y_label if y_label else 'Frequence')
if show_grid:
plt.grid(True)
else:
plt.grid(False)
plt.savefig(plot_output_path)
plt.close()
return {}
except Exception as e:
feedback.reportError(str(e))
return {}
+256
View File
@@ -0,0 +1,256 @@
import math
import matplotlib.pyplot as plt
from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (QgsProcessing,
QgsProcessingAlgorithm,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFileDestination,
QgsProcessingParameterField,
QgsProcessingParameterString,
QgsProcessingParameterNumber,
QgsProcessingParameterBoolean)
import numpy as np
from scipy.optimize import curve_fit
import matplotlib
matplotlib.use('Agg')
class matplotlibExp(QgsProcessingAlgorithm):
INPUT = 'INPUT'
OUTPUT = 'OUTPUT'
X_VALUES = 'X_VALUES'
Y_VALUES = 'Y_VALUES'
X_MAX = 'X_MAX'
Y_MAX = 'Y_MAX'
B = 'B'
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 matplotlibExp()
def name(self):
return 'Exponential fit'
def displayName(self):
return self.tr('Exponential fit')
def group(self):
return self.tr('matplotlib vector')
def groupId(self):
return 'matplotlib vector'
def shortHelpString(self):
return self.tr("Generates a exponential fit 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(
QgsProcessingParameterNumber(
self.B,
self.tr('b'),
type = QgsProcessingParameterNumber.Double,
optional=True
)
)
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=' '
)
)
@staticmethod
def exponential_decay(x, a, b, c):
return a * np.exp(b * x) + c
@staticmethod
def exponential_decay_no_offset(x,a,b):
return a * np.exp(b * x)
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)
b = self.parameterAsDouble(parameters, self.B, 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"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}")
grouped_data = {}
for x, y in zip(x_values, y_values):
if x not in grouped_data:
grouped_data[x] = [y]
else:
grouped_data[x].append(y)
max_y_values = {x: max(y_list) for x, y_list in grouped_data.items()}
x_values_np = np.array(sorted(max_y_values.keys()))
y_values_np = np.array([max_y_values[x] for x in x_values_np])
positive_filter = y_values_np > 0
x_values_positive = x_values_np[positive_filter]
y_values_positive = y_values_np[positive_filter]
if np.any(y_values_positive.min() <= 0):
feedback.reportError("Negative values in y field")
return {}
initial_guess = [np.max(y_values_positive), b] # Assuming a starts at the max values, b is negative, c is zero
try:
popt, pcov = curve_fit(
matplotlibExp.exponential_decay_no_offset,
x_values_positive,
y_values_positive,
p0=initial_guess,
)
a_fit, b_fit = popt
x_axis = np.linspace(x_values_positive.min(), x_values_positive.max(),500)
y_fit = matplotlibExp.exponential_decay_no_offset(x_axis, a_fit, b_fit)
feedback.pushInfo(f"Inital guess: {initial_guess}")
feedback.pushInfo(f"Fit parameters: {popt}")
except RuntimeError as e:
feedback.reportError(f"Error during curve fitting: {e}")
return{}
try:
plt.scatter(x_values_positive, y_values_positive)
plt.plot(x_axis, y_fit, color=color, label='Fit Line')
plt.xlim(x_values_positive.min(), x_max if x_max is not None else x_values_positive.max())
plt.ylim(y_values_positive.min(), y_max if y_max is not None else y_values_positive.max())
plt.title(title)
plt.xlabel(x_label)
plt.ylabel(y_label)
plt.legend()
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 {}
+216
View File
@@ -0,0 +1,216 @@
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 {}
+39
View File
@@ -0,0 +1,39 @@
import rasterio
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
def read_raster_data(raster_path):
with rasterio.open(raster_path) as raster:
data = raster.read(1, masked=True)
if raster.nodata is not None:
data = data.filled(np.nan)
return data
def flatten_data(data):
return data.flatten()
# Replace 'traveltime.tif' with the path to your actual raster file
x_axis = flatten_data(read_raster_data('traveltime.tif'))
# Filter out NaN values
x_axis = x_axis[~np.isnan(x_axis)]
mean = np.mean(x_axis)
sd = np.std(x_axis)
# Plot histogram
plt.hist(x_axis, bins=50, density=True, alpha=0.6, color='g', range=(mean-3*sd, mean+3*sd))
xmin, xmax = plt.xlim()
plt.xlim(0,5)
plt.xlabel("Travel time in [h]")
plt.ylabel("Quantaty in percentage")
x = np.linspace(xmin, xmax, 100)
# Calculate and plot the 0.85 quantile
quantile_90 = np.quantile(x_axis, 0.90)
plt.axvline(x=quantile_90, color='r', linestyle='--', label='90%')
plt.legend()
plt.savefig("traveltimedistribution.png", dpi=300) # Save the plot
+26
View File
@@ -0,0 +1,26 @@
import sys
def clean_file(input_path):
try:
output_path = input_path.replace('.', '_clean.')
with open(input_path, 'r', encoding='utf-8', errors='ignore') as file:
file_content = file.read()
clean_content = file_content.replace('\x00', '')
with open(output_path, 'w', encoding='utf-8') as clean_file:
clean_file.write(clean_content)
print('Null bytes removed from file:', input_path)
except Exception as e:
print(f'Error processing file {input_path}: {e}')
sys.exit(1)
if __name__ == '__main__':
if len(sys.argv) < 2:
print('Usage: python removenullbytes.py <file_path>')
sys.exit(1)
else:
input_path = sys.argv[1]
clean_file(input_path)