Skip to content

Commit

Permalink
GRASS: add -t flag to export temp data (#284)
Browse files Browse the repository at this point in the history
* QGIS: import temp and control data into map window
  • Loading branch information
pesekon2 authored Nov 16, 2023
1 parent 04ca756 commit ab7dee9
Show file tree
Hide file tree
Showing 15 changed files with 279 additions and 520 deletions.
6 changes: 5 additions & 1 deletion bin/base/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def __init__(self, label, section_arguments=()):
),
'channel_properties': Argument('Channel properties table'),
'preparation_only': Argument('Do the data preparation only'),
'generate_temporary': Argument('Generate also temporary data'),
}


Expand All @@ -64,5 +65,8 @@ def __init__(self, label, section_arguments=()):
'Computation options',
('output', 'max_time_step', 'total_time')
),
Section('Advanced', ()) # TODO: Add ('preparation_only',))
Section(
'Advanced',
('generate_temporary', )
) # TODO: Add ('preparation_only',))
]
5 changes: 5 additions & 0 deletions bin/grass/r.smoderp2d/r.smoderp2d.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
# % key: d
# % description: Perform data preparation only and exit
# %end
# %flag
# % key: t
# % description: Export temporary data
# %end
# %option G_OPT_R_ELEV
# % description: Input surface raster
# % guisection: Data preparation
Expand Down Expand Up @@ -128,6 +132,7 @@

if __name__ == "__main__":
options, flags = gs.parser()
options['t'] = flags['t']

try:
runner = GrassGisRunner()
Expand Down
88 changes: 68 additions & 20 deletions bin/qgis/smoderp2d-plugin/smoderp_2D_dockwidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import QFileDialog, QProgressBar, QMenu

from qgis.core import QgsProviderRegistry, QgsMapLayerProxyModel, \
QgsRasterLayer, QgsTask, QgsApplication, Qgis, QgsProject, \
QgsRasterBandStats, QgsSingleBandPseudoColorRenderer, QgsGradientColorRamp
from qgis.core import (
QgsProviderRegistry, QgsMapLayerProxyModel, QgsRasterLayer, QgsTask,
QgsApplication, Qgis, QgsProject, QgsRasterBandStats,
QgsSingleBandPseudoColorRenderer, QgsGradientColorRamp, QgsVectorLayer
)
from qgis.utils import iface
from qgis.gui import QgsMapLayerComboBox, QgsFieldComboBox

Expand Down Expand Up @@ -146,6 +148,7 @@ def __init__(self, parent=None):
self.table_stream_shape_code_comboBox = QgsFieldComboBox()
self.table_stream_shape_comboBox = QgsMapLayerComboBox()
self.table_stream_shape_toolButton = QtWidgets.QToolButton()
self.generate_temporary_checkBox = QtWidgets.QCheckBox()
self.run_button = QtWidgets.QPushButton(self.dockWidgetContents)

# set default values
Expand Down Expand Up @@ -188,12 +191,17 @@ def retranslateUi(self):
self.__class__.__name__, arguments[argument_id].label
)
)
section_tab_layout.addWidget(argument_label)

# create empty layout for the specific widget
argument_widget = QtWidgets.QWidget()
argument_widget_layout = QtWidgets.QHBoxLayout()
argument_widget.setLayout(argument_widget_layout)

if section.label != 'Advanced':
section_tab_layout.addWidget(argument_label)
else:
# so far, all Advanced tab widgets should be horizontal
argument_widget_layout.addWidget(argument_label)
section_tab_layout.addWidget(argument_widget)

self.arguments.update({argument_id: argument_widget_layout})
Expand Down Expand Up @@ -242,6 +250,10 @@ def set_widgets(self):
self.arguments['channel_properties'].addWidget(
self.table_stream_shape_toolButton
)
self.arguments['generate_temporary'].insertWidget(
0, self.generate_temporary_checkBox
) # checkbox should be before label
self.arguments['generate_temporary'].addStretch()

def closeEvent(self, event):
self.closingPlugin.emit()
Expand Down Expand Up @@ -374,7 +386,9 @@ def OnRunButton(self):
# Get input parameters
self._getInputParams()

smoderp_task = SmoderpTask(self._input_params, self._input_maps, self._grass_bin_path)
smoderp_task = SmoderpTask(
self._input_params, self._input_maps, self._grass_bin_path
)

# prepare the progress bar
self.progress_bar = QProgressBar()
Expand Down Expand Up @@ -424,26 +438,59 @@ def _layerColorRamp(layer):
return renderer

def computationFinished(self):
# show results
def import_group_layers(group, outdir, ext='asc', show=False):
for map_path in glob.glob(os.path.join(outdir, f'*.{ext}')):
if ext == 'asc':
# raster
layer = QgsRasterLayer(
map_path,
os.path.basename(os.path.splitext(map_path)[0])
)

# set symbology
layer.setRenderer(self._layerColorRamp(layer))
else:
# vector
layer = QgsVectorLayer(
map_path,
os.path.basename(os.path.splitext(map_path)[0])
)

# add layer into group
QgsProject.instance().addMapLayer(layer, False)
node = group.addLayer(layer)
node.setExpanded(False)
node.setItemVisibilityChecked(show is True)
show = False

# show main results
root = QgsProject.instance().layerTreeRoot()
group = root.insertGroup(0, self._result_group_name)

outdir = self.main_output_lineEdit.text().strip()
first = True
for map_path in glob.glob(os.path.join(outdir, '*.asc')):
layer = QgsRasterLayer(
map_path, os.path.basename(os.path.splitext(map_path)[0])
)

# set symbology
layer.setRenderer(self._layerColorRamp(layer))
import_group_layers(group, outdir, show=True)

# import control results
ctrl_group = group.addGroup('control')
ctrl_group.setExpanded(False)
ctrl_group.setItemVisibilityChecked(False)
import_group_layers(ctrl_group, os.path.join(outdir, 'control'))

# import control points
ctrl_group = group.addGroup('control_point')
ctrl_group.setExpanded(False)
ctrl_group.setItemVisibilityChecked(False)
import_group_layers(
ctrl_group, os.path.join(outdir, 'control_point'), 'csv'
)

# add layer into group
QgsProject.instance().addMapLayer(layer, False)
node = group.addLayer(layer)
node.setExpanded(False)
node.setItemVisibilityChecked(first is True)
first = False
if self._input_params['t'] is True:
# import temp results
temp_group = group.addGroup('temp')
temp_group.setExpanded(False)
temp_group.setItemVisibilityChecked(False)
import_group_layers(temp_group, os.path.join(outdir, 'temp'))
import_group_layers(temp_group, os.path.join(outdir, 'temp'), 'gml')

# QGIS bug: group must be collapsed and then expanded
group.setExpanded(False)
Expand Down Expand Up @@ -474,6 +521,7 @@ def _getInputParams(self):
self.table_stream_shape_comboBox.currentText(),
'streams_channel_type_fieldname':
self.table_stream_shape_code_comboBox.currentText(),
't': bool(self.generate_temporary_checkBox.checkState()),
'output': self.main_output_lineEdit.text().strip()
}

Expand Down
16 changes: 2 additions & 14 deletions smoderp2d/providers/arcgis/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,7 @@ def output_filepath(self, name):
:param name: layer name to be saved
:return: full path to the dataset
"""
item = self._data_target.get(name)
if item is None or item not in ("temp", "control", "core"):
raise ProviderError(
"Unable to define target in output_filepath: {}".format(name)
)

path = Globals.get_outdir()
# 'core' datasets don't have directory, only the geodatabase
if item in ("temp", "control"):
path = os.path.join(path, item)

path = os.path.join(path, 'data.gdb', name)

path = os.path.join(BaseWriter.output_filepath(self, name, dirname_only=True), 'data.gdb', name)
Logger.debug('File path: {}'.format(path))

return path
Expand All @@ -75,7 +63,7 @@ def _write_raster(self, array, file_output):

arcpy.RasterToASCII_conversion(
raster,
file_output
file_output + self._raster_extension
)


Expand Down
4 changes: 2 additions & 2 deletions smoderp2d/providers/arcgis/data_preparation.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,12 +365,12 @@ def _stream_direction(self, stream, dem_aoi):

# extract elevation for the stream segment vertices
arcpy.ddd.InterpolateShape(
dem_aoi, stream, self.storage.output_filepath("stream_z"), "", "",
dem_aoi, stream, self.storage.output_filepath("stream_aoi_z"), "", "",
"CONFLATE_NEAREST", "VERTICES_ONLY"
)
shape_fieldname = "SHAPE@"

with arcpy.da.SearchCursor(self.storage.output_filepath("stream_z"), [shape_fieldname, segment_id_fieldname]) as segments:
with arcpy.da.SearchCursor(self.storage.output_filepath("stream_aoi_z"), [shape_fieldname, segment_id_fieldname]) as segments:
for row in segments:
startpt = row[0].firstPoint
endpt = row[0].lastPoint
Expand Down
36 changes: 23 additions & 13 deletions smoderp2d/providers/base/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ def __getitem__(cls, key):


class BaseWriter(object):
_raster_extension = '.asc'

def __init__(self):
self._data_target = None

Expand All @@ -58,22 +60,30 @@ def set_data_layers(self, data):
"""
self._data_target = data

@staticmethod
def _raster_output_path(output, directory='core'):
"""Get output raster path.
def output_filepath(self, name, data_type=None, dirname_only=False):
"""
Get correct path to store dataset 'name'.
:param name: layer name to be saved
:param data_type: None to determine target subdirectory from self._data_target
:param dirname_only: True to return only path to parent directory
:param output: raster output name
:param directory: target directory (temp, control)
:return: full path to the dataset
"""
dir_name = os.path.join(Globals.outdir, directory) if directory != 'core' else Globals.outdir
if data_type is None:
data_type = self._data_target.get(name)
if data_type is None or data_type not in ("temp", "control", "core"):
raise ProviderError(
"Unable to define target in output_filepath: {}".format(name)
)

if not os.path.exists(dir_name):
os.makedirs(dir_name)
path = os.path.join(Globals.outdir, data_type) if data_type != 'core' else Globals.outdir
if not os.path.exists(path):
os.makedirs(path)
if dirname_only:
return path

return os.path.join(
dir_name,
output + '.asc'
)
return os.path.join(path, name)

@staticmethod
def _print_array_stats(arr, file_output):
Expand All @@ -100,7 +110,7 @@ def write_raster(self, array, output_name, data_type='core'):
:param output_name: output filename
:param data_type: directory where to write output file
"""
file_output = self._raster_output_path(output_name, data_type)
file_output = BaseWriter.output_filepath(self, output_name, data_type)

self._print_array_stats(
array, file_output
Expand Down
72 changes: 37 additions & 35 deletions smoderp2d/providers/base/data_preparation.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,38 +193,44 @@ def _get_rr_rc(r, c, mat_boundary):


class PrepareDataGISBase(PrepareDataBase):

# complete dictionary of datasets and their type
data_layers = {
'dem_slope_mask': 'temp',
'dem_polygon': 'temp',
'aoi': 'temp',
'aoi_polygon': 'core',
'aoi_mask': 'temp',
'dem_filled': 'temp',
'dem_flowdir': 'temp',
'dem_flowacc': 'temp',
'dem_slope': 'temp',
'dem_aspect': 'temp',
'dem_aoi': 'temp',
'dem_slope_aoi': 'temp',
'dem_flowdir_aoi': 'temp',
'dem_flowacc_aoi': 'temp',
'dem_aspect_aoi': 'temp',
'points_aoi': 'temp',
'soil_veg': 'temp',
'soilveg_aoi': 'temp',
'aoi_buffer': 'temp',
'stream_aoi': 'temp',
"stream_aoi_z": 'temp',
'stream_start': 'temp',
'stream_end': 'temp',
'stream_seg': 'temp',
'ratio_cell': 'temp',
'effect_cont': 'temp',
}

soilveg_fields = {
"k": None, "s": None, "n": None, "pi": None, "ppl": None,
"ret": None, "b": None, "x": None, "y": None, "tau": None, "v": None
}
def __init__(self, writter):
self.storage = writter

# complete dictionary of datasets and their type
self._data_layers = {
'dem_slope_mask': 'temp',
'dem_polygon': 'temp',
'aoi': 'temp',
'aoi_polygon': 'core',
'aoi_mask': 'temp',
'dem_filled': 'temp',
'dem_flowdir': 'temp',
'dem_flowacc': 'temp',
'dem_slope': 'temp',
'dem_aspect': 'temp',
'dem_aoi': 'temp',
'dem_slope_aoi': 'temp',
'dem_flowdir_aoi': 'temp',
'dem_flowacc_aoi': 'temp',
'dem_aspect_aoi': 'temp',
'points_aoi': 'temp',
'soil_veg': 'temp',
'soilveg_aoi': 'temp',
'aoi_buffer': 'temp',
'stream_aoi': 'temp',
"stream_z": 'temp',
'stream_start': 'temp',
'stream_end': 'temp',
'stream_seg': 'temp',
'ratio_cell': 'temp',
'effect_cont': 'temp',
}
# complete list of field names that are supposed not to be changed,
# e.g. in properties tables
self.fieldnames = {
Expand All @@ -247,13 +253,9 @@ def __init__(self, writter):
'channel_q365': 'q365'
}

self.soilveg_fields = {
"k": None, "s": None, "n": None, "pi": None, "ppl": None,
"ret": None, "b": None, "x": None, "y": None, "tau": None, "v": None
}
for sv in self.soilveg_fields.keys():
self._data_layers["soilveg_aoi_{}".format(sv)] = 'temp'
self.storage.set_data_layers(self._data_layers)
self.data_layers["soilveg_aoi_{}".format(sv)] = 'temp'
self.storage.set_data_layers(self.data_layers)

self.stream_shape_fields = [
self.fieldnames['channel_profile'],
Expand Down
2 changes: 1 addition & 1 deletion smoderp2d/providers/cmd/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def __init__(self):
def _write_raster(self, array, file_output):
"""See base method for description.
"""
np.savetxt(file_output, array, fmt='%.6e')
np.savetxt(file_output + self._raster_extension, array, fmt='%.6e')


class CmdArgumentParser(object):
Expand Down
Loading

0 comments on commit ab7dee9

Please sign in to comment.