Skip to content

Commit

Permalink
Merge pull request #29 from JakubCha/update_library
Browse files Browse the repository at this point in the history
ExactExtract package update information
  • Loading branch information
JakubCha authored Oct 9, 2024
2 parents 27be45b + 0d0e77a commit 0299114
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 52 deletions.
18 changes: 14 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,23 @@ There is also option to modify custom functions defined by user earlier. In orde
## Installation
In current version of the plugin there i 1 required and 1 optional package:
In current version of the plugin there is 1 required and 1 optional package:
- [**REQUIRED**] From PyPi repository: `pip install exactextract`
- [**OPTIONAL**] Installed through OSGeo4W setup utility (or `pip install pandas`):
- pandas
>**Note:** pandas is required only if user wants to export result to CSV (non-geospatial output)
If `exactextract` package is not installed, plugin will try to install it by itself.
### Update exactextract
If there's need to update `exactextract` user should close QGIS, open OSGeo4WShell and write:
`pip install exactextract --upgrade`
### Automatic
This plugin comes with automatic installation module which installs `exactextract` to QGIS user `profile` directory.
### Manual
User might also install library by himself using `OSGeo4W Shell` command: `pip install exactextract`
## Update `exactextract`
#### Plugin was installed automatically
Similar to `Manual` installation step input command: `pip install exactextract --upgrade`
#### Plugin was installed with `OSGeo4W Shell`
1. Close QGIS.
2. Go to `C:\Users\<Username>\AppData\Roaming\QGIS\QGIS3\profiles\<profile name>\python\plugins\python3.9`
and remove directories with `exactextract` in name.
3. Open QGIS and let plugin install the package using `Automatic` method.
34 changes: 17 additions & 17 deletions zonal_exact/help.md
Original file line number Diff line number Diff line change
@@ -1,75 +1,75 @@
# Help
## Help
This is a tool for the QGIS that allows to aggregate/summarize values of the raster over polygonal (vector) areas using exactextract library. This library allows to treat pixel cells as partially covered by polygons using weighting according to the extent of cover. If you want to know more about the library working in the backend of this plugin it's highly recommend to visit its [github repository](https://github.com/isciences/exactextract/tree/master).
<br />

## Input
### Input
<br />

### Values
#### Values

`Values` input for zonal statistics are raster layers with values that will be aggregated using zones inside polygons. `Values` raster may have multiple bands. In such case statistics are calculated for each band separately and put in result in separate columns.
It's possible to calculate zonal statistics for multiple rasters. In such case statistics are calculated for each band separately and put in result in separate columns.

### Weights
#### Weights

`Weights` is a raster layer with weighting values. The weighting raster does not need to have the same resolution and extent as the value raster, but the resolutions of the two rasters must be integer multiples of each other, and any difference between the grid origin points must be an integer multiple of the smallest cell size.

### Vector
#### Vector

`Vector` is a vector layer with polygon geometry. For each polygon in this layer `exactextract` computes the area of each raster cell that is covered and aggregates the values of these raster cells.

### ID Column
#### ID Column

`Vector` layer need to have unique, numerical column that's used as identifier of polygons based on which calculated statistics can be joined to.
<br />
<br />

## Parameters
### Parameters
<br />

### Output statistics column prefix
#### Output statistics column prefix

Prefix for result column names.

### Number of subtasks
#### Number of subtasks

Plugin allows to divide calculation to multiple **threads** (subtasks) to speed up calculation of big input data. In case of small input data usage of multiple threads will slow down calculation due to overhead needed to configure and start threads.
It's up to user to decide whether usage of subtasks is profitable.
*Plugin developer suggestion is to start using subtasks with more than 100 000 polygons*

> **Note:** Use QGIS parallel engine to create threads
### Processing strategy
#### Processing strategy

Plugin allows to choose what strategy should `exactextract` library use.

#### The "feature sequential" strategy
##### The "feature sequential" strategy
In the `feature-sequential` strategy (the default), `exactextract` iterates over the features one at atime, reads the corresponding pixels from each raster, and computes the summary operations.
This strategy is the most efficient from a memory consumption perspective. The entire vector dataset does not need to be read into memory at once, and statistics for each feature can be flushed to disk before the next feature is read. However, this strategy may be inefficient if the order of features causes the same raster blocks to be read and decompressed multiple times.
#### The "raster sequential" strategy
##### The "raster sequential" strategy
In the `raster-sequential` strategy, `exactextract` iterates over chunks of the raster, finds corresponding features from the vector layer, and updates the summary operations. This guarantees that raster pixels are read only once, which can be useful if network access or compression make the read process slow. However, this strategy requires all vector features and their associated statistics to be kept in memory for the duration of processing. It also causes features spanning multiple chunks to be visited multiple times, which is inefficient.

More about processing strategy and performance caveats can be read at the dedicated `exactextract` [documentation](https://github.com/isciences/exactextract/blob/master/python/doc/performance.rst)

### Output File Path
#### Output File Path

Path to the output file that result will be written to.
In current version of the plugin possible outputs are **geospatial** (e.g. *geopackage* - .gpkg) formats that are supported with every OGR supported driver or **CSV**.

## Statistics
### Statistics
Description of statistics possible to use in tool is available in `exactextract` library [documentation](https://github.com/isciences/exactextract/blob/master/python/doc/operations.rst)
<br />


### Aggregates
#### Aggregates

Statistics that aggregate values from `Values` raster in `Vector` to single value for each input polygon.

### Arrays
#### Arrays

Statistics that returns array of raster values for each polygon in `Vector`.

### Custom Function
#### Custom Function

Write custom Python code to define extra, additional features for raster zonal statistics. Custom functions should accept raster `values` and `coverage` attributes.
> **Example:** Calculate 90th percentile of raster values:
Expand Down
19 changes: 19 additions & 0 deletions zonal_exact/library.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
## About
This plugin use [exactextract](https://github.com/isciences/exactextract/tree/master) library. It's an external package that's not shipped with QGIS by default.
<br />

## Installation
### Automatic
This plugin comes with automatic installation module which installs `exactextract` to QGIS user `profile` directory.
### Manual
User might also install library by himself using `OSGeo4W Shell` command: `pip install exactextract`
<br />

## Update
### Plugin was installed automatically
Similar to `Manual` installation step input command: `pip install exactextract --upgrade`
### Plugin was installed with `OSGeo4W Shell`
1. Close QGIS.
2. Go to `C:\Users\<Username>\AppData\Roaming\QGIS\QGIS3\profiles\<profile name>\python\plugins\python3.9`
and remove directories with `exactextract` in name.
3. Open QGIS and let plugin install the package using `Automatic` method.
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ def are_packages_importable() -> bool:
return False

return True


def check_pip_installed() -> bool:
try:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Deepness - Packages Installer Dialog</string>
<string>Zonal Exact - Packages Installer Dialog</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
Expand Down
69 changes: 40 additions & 29 deletions zonal_exact/task_classes.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from pathlib import Path
from typing import List, Dict

from exactextract import exact_extract

from qgis.core import (
Expand Down Expand Up @@ -57,6 +58,7 @@ def __init__(
self.result_list: List = result_list

self.completed_succesfully = False
self.error_message = None

def run(self):
"""
Expand All @@ -69,35 +71,42 @@ def run(self):
def task_progress_update(frac: float, message: str):
self.setProgress(int(frac * 100))

if self.geospatial_output:
result_stats = exact_extract(
vec=self.polygon_layer,
rast=self.rasters,
weights=self.weights,
ops=self.stats,
include_cols=list(self.include_cols.keys()),
progress=task_progress_update,
include_geom=True,
output="qgis",
strategy=self.strategy,
)
else:
import pandas as pd # noqa

result_stats = exact_extract(
vec=self.polygon_layer,
rast=self.rasters,
weights=self.weights,
ops=self.stats,
include_cols=self.include_cols,
progress=task_progress_update,
output="pandas",
strategy=self.strategy,
)
self.result_list.append(result_stats)

self.completed_succesfully = True
return True
try:
if self.geospatial_output:
result_stats = exact_extract(
vec=self.polygon_layer,
rast=self.rasters,
weights=self.weights,
ops=self.stats,
include_cols=list(self.include_cols.keys()),
progress=task_progress_update,
include_geom=True,
output="qgis",
strategy=self.strategy,
)
else:
import pandas as pd # noqa

result_stats = exact_extract(
vec=self.polygon_layer,
rast=self.rasters,
weights=self.weights,
ops=self.stats,
include_cols=self.include_cols,
progress=task_progress_update,
output="pandas",
strategy=self.strategy,
)
self.result_list.append(result_stats)

self.completed_succesfully = True
return True
except TypeError as ex:
self.completed_succesfully = False
self.error_message = f"Error in task: {self.description}, {ex}. Probably there's an old version of exactextract installed. Follow the instructions in 'Library' tab to update the exactextract library."
QgsMessageLog.logMessage(self.error_message)
return False


def finished(self, result: bool):
"""
Expand All @@ -107,6 +116,8 @@ def finished(self, result: bool):
result (bool): The result of the task. True if the task was successful otherwise False.
"""
message = f"Finished task: {self.description}, result: {'Successful' if result else 'Failed'}"
if self.error_message is not None:
message += f"\nError: {self.error_message}"
self.taskChanged.emit(message)


Expand Down
4 changes: 4 additions & 0 deletions zonal_exact/zonal_exact_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,13 @@ def __init__(
self.setupUi(self)
self.populate_comboboxes()
self.mRasterLayersList.setup(self.project)

self.helpTextBrowser.setSearchPaths([os.path.dirname(__file__)])
self.helpTextBrowser.setSource(QtCore.QUrl("help.md"))
self.helpTextBrowser.setOpenExternalLinks(True)
self.libraryTextBrowser.setSearchPaths([os.path.dirname(__file__)])
self.libraryTextBrowser.setSource(QtCore.QUrl("library.md"))
self.libraryTextBrowser.setOpenExternalLinks(True)

self.set_id_field()

Expand Down
15 changes: 15 additions & 0 deletions zonal_exact/zonal_exact_dialog_base.ui
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,21 @@ p, li { white-space: pre-wrap; }
</item>
</layout>
</widget>
<widget class="QWidget" name="LibraryTab">
<attribute name="title">
<string>Library</string>
</attribute>
<widget class="QTextBrowser" name="libraryTextBrowser">
<property name="geometry">
<rect>
<x>9</x>
<y>9</y>
<width>584</width>
<height>676</height>
</rect>
</property>
</widget>
</widget>
</widget>
</item>
</layout>
Expand Down

0 comments on commit 0299114

Please sign in to comment.