diff --git a/drawio-diagramms/Workflow.drawio b/drawio-diagramms/Workflow.drawio new file mode 100644 index 0000000..3cb36c0 --- /dev/null +++ b/drawio-diagramms/Workflow.drawio @@ -0,0 +1,239 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/drawio-diagramms/analysisworkflow.drawio b/drawio-diagramms/analysisworkflow.drawio new file mode 100644 index 0000000..fff3177 --- /dev/null +++ b/drawio-diagramms/analysisworkflow.drawio @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/drawio-diagramms/bordersworkflow.drawio b/drawio-diagramms/bordersworkflow.drawio new file mode 100644 index 0000000..9b9c856 --- /dev/null +++ b/drawio-diagramms/bordersworkflow.drawio @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/drawio-diagramms/facilitiesworkflow.drawio b/drawio-diagramms/facilitiesworkflow.drawio new file mode 100644 index 0000000..c85c6e5 --- /dev/null +++ b/drawio-diagramms/facilitiesworkflow.drawio @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/drawio-diagramms/frictionsurfaceworkflow.drawio b/drawio-diagramms/frictionsurfaceworkflow.drawio new file mode 100644 index 0000000..5c32f15 --- /dev/null +++ b/drawio-diagramms/frictionsurfaceworkflow.drawio @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/drawio-diagramms/icanalysisworkflow.drawio b/drawio-diagramms/icanalysisworkflow.drawio new file mode 100644 index 0000000..0829e2d --- /dev/null +++ b/drawio-diagramms/icanalysisworkflow.drawio @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/drawio-diagramms/indcomworkflow.drawio b/drawio-diagramms/indcomworkflow.drawio new file mode 100644 index 0000000..54140b9 --- /dev/null +++ b/drawio-diagramms/indcomworkflow.drawio @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/drawio-diagramms/overviewworkflow.drawio b/drawio-diagramms/overviewworkflow.drawio new file mode 100644 index 0000000..61fe55f --- /dev/null +++ b/drawio-diagramms/overviewworkflow.drawio @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/drawio-diagramms/roadsworkflow.drawio b/drawio-diagramms/roadsworkflow.drawio new file mode 100644 index 0000000..bb9e1bb --- /dev/null +++ b/drawio-diagramms/roadsworkflow.drawio @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/drawio-diagramms/studyareaworkflow.drawio b/drawio-diagramms/studyareaworkflow.drawio new file mode 100644 index 0000000..2295e14 --- /dev/null +++ b/drawio-diagramms/studyareaworkflow.drawio @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/drawio-diagramms/traveltimeworkflow 2.drawio b/drawio-diagramms/traveltimeworkflow 2.drawio new file mode 100644 index 0000000..c056e6a --- /dev/null +++ b/drawio-diagramms/traveltimeworkflow 2.drawio @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/drawio-diagramms/traveltimeworkflow.drawio b/drawio-diagramms/traveltimeworkflow.drawio new file mode 100644 index 0000000..c056e6a --- /dev/null +++ b/drawio-diagramms/traveltimeworkflow.drawio @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/python-scripts/correlation.py b/python-scripts/correlation.py new file mode 100644 index 0000000..5c26200 --- /dev/null +++ b/python-scripts/correlation.py @@ -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) + diff --git a/python-scripts/correlation_grouped.py b/python-scripts/correlation_grouped.py new file mode 100644 index 0000000..c714932 --- /dev/null +++ b/python-scripts/correlation_grouped.py @@ -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) diff --git a/python-scripts/geoBoundariesAPI.py b/python-scripts/geoBoundariesAPI.py new file mode 100644 index 0000000..fa8b730 --- /dev/null +++ b/python-scripts/geoBoundariesAPI.py @@ -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 \ No newline at end of file diff --git a/python-scripts/matplotlibBar.py b/python-scripts/matplotlibBar.py new file mode 100644 index 0000000..5421e6c --- /dev/null +++ b/python-scripts/matplotlibBar.py @@ -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 {} diff --git a/python-scripts/matplotlibHist.py b/python-scripts/matplotlibHist.py new file mode 100644 index 0000000..48573af --- /dev/null +++ b/python-scripts/matplotlibHist.py @@ -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 {} \ No newline at end of file diff --git a/python-scripts/matplotlibLin.py b/python-scripts/matplotlibLin.py new file mode 100644 index 0000000..dd17c79 --- /dev/null +++ b/python-scripts/matplotlibLin.py @@ -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 {} diff --git a/python-scripts/matplotlibScat.py b/python-scripts/matplotlibScat.py new file mode 100644 index 0000000..02343e3 --- /dev/null +++ b/python-scripts/matplotlibScat.py @@ -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 {} \ No newline at end of file diff --git a/python-scripts/normal.py b/python-scripts/normal.py new file mode 100644 index 0000000..4562244 --- /dev/null +++ b/python-scripts/normal.py @@ -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 diff --git a/python-scripts/removenullbytes.py b/python-scripts/removenullbytes.py new file mode 100644 index 0000000..a8ce5be --- /dev/null +++ b/python-scripts/removenullbytes.py @@ -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 ') + sys.exit(1) + else: + input_path = sys.argv[1] + clean_file(input_path) diff --git a/qgis-models/Analysis.model3 b/qgis-models/Analysis.model3 new file mode 100644 index 0000000..bb393ab --- /dev/null +++ b/qgis-models/Analysis.model3 @@ -0,0 +1,2838 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/qgis-models/facilities.model3 b/qgis-models/facilities.model3 new file mode 100644 index 0000000..36b0b54 --- /dev/null +++ b/qgis-models/facilities.model3 @@ -0,0 +1,3137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/qgis-models/friction.model3 b/qgis-models/friction.model3 new file mode 100644 index 0000000..1eec0e8 --- /dev/null +++ b/qgis-models/friction.model3 @@ -0,0 +1,500 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/qgis-models/ghsl.model3 b/qgis-models/ghsl.model3 new file mode 100644 index 0000000..af0c09b --- /dev/null +++ b/qgis-models/ghsl.model3 @@ -0,0 +1,695 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/qgis-models/mapbiomas.model3 b/qgis-models/mapbiomas.model3 new file mode 100644 index 0000000..03e5381 --- /dev/null +++ b/qgis-models/mapbiomas.model3 @@ -0,0 +1,445 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/qgis-models/region.model3 b/qgis-models/region.model3 new file mode 100644 index 0000000..27d6ade --- /dev/null +++ b/qgis-models/region.model3 @@ -0,0 +1,3086 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/qgis-models/roads.model3 b/qgis-models/roads.model3 new file mode 100644 index 0000000..929b8c7 --- /dev/null +++ b/qgis-models/roads.model3 @@ -0,0 +1,747 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/qgis-models/traveltime.model3 b/qgis-models/traveltime.model3 new file mode 100644 index 0000000..4ced480 --- /dev/null +++ b/qgis-models/traveltime.model3 @@ -0,0 +1,475 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +