[GRASS-user] Merge spatially connected features

Hi all,
I have a large river network dataset (lines). Now I’d to assign unique categories to each group of connected lines that have an attribute in common.

For example, my rivers are categorized based on some kind of stream order. I want to group all rivers that belong to stream order 2 and are spatially connected; each group should get a unique category value. I thought that I could first extract all rivers with a particular attribute (e.g. stream order = 2) which will provide me some scattered pattern of lines. Then I need a spatial join tool to make subgroups of lines that are connected. How can I achieve the latter? Any idea?

Cheers,
Johannes

On 24/02/2020 10:45, Johannes Radinger wrote:

Hi all,
I have a large river network dataset (lines). Now I'd to assign unique categories to each group of connected lines that have an attribute in common.

For example, my rivers are categorized based on some kind of stream order. I want to group all rivers that belong to stream order 2 and are spatially connected; each group should get a unique category value. I thought that I could first extract all rivers with a particular attribute (e.g. stream order = 2) which will provide me some scattered pattern of lines. Then I need a spatial join tool to make subgroups of lines that are connected. How can I achieve the latter? Any idea?

Here's a procedure that might work for you. Somewhat clunky, but I think it gets what you want.

It's based on the v.build.polylines module to connect all touching stream reaches. First extract each order from the stream vector into a new vector. Then build polylines. Patch them all together. Now you have a polyline vector with a single cat value for each set of original stream reaches that had the same order and that were touching.

Finally, with v.distance you can upload that cat value to the original streams.

# Get a list of stream orders
ORDERS=`v.db.select -c streams group=strahler column=strahler`
echo $ORDERS
#1 2 3 4 5 6
# How many stream segments in original
v.info -t streams | grep lines
# lines=1420

# Now loop thru list of stream orders and extract stream segments for each order
for o in $ORDERS; do
v.extract input=streams output=streams_${o} where="strahler=${o}"
# Create polyline for each stream order
# Line "connects" all touching stream segments
v.build.polylines input=streams_${o} output=streams_${o}_polyline type=line cat=first
done

# Patch stream order polylines together
POLYLINES=`g.list vect pattern="streams*polyline" separator=comma`
echo $POLYLINES
v.patch input=$POLYLINES output=streams_polylines
v.info -t streams_polylines | grep lines
# lines=738

# Add a new column to the original streams for new ID value
v.db.addcolumn map=streams column="merged_id INTEGER"
# And use v.distance to update that column from cat values in polylines vector
v.distance from=streams to=streams_polylines upload=cat column=merged_id

HTH

Cheers,
Johannes

_______________________________________________
grass-user mailing list
grass-user@lists.osgeo.org
https://lists.osgeo.org/mailman/listinfo/grass-user

--
Micha Silver
Ben Gurion Univ.
Sde Boker, Remote Sensing Lab
cell: +972-523-665918
https://orcid.org/0000-0002-1128-1325

Hi Micha, hi all,

sorry for my late response...however, just today I managed to try your approach of building polylines to connect "touching stream lines"...but...

On 24.02.20 16:48, Micha Silver wrote:

On 24/02/2020 10:45, Johannes Radinger wrote:

Hi all,
I have a large river network dataset (lines). Now I'd to assign unique categories to each group of connected lines that have an attribute in common.

For example, my rivers are categorized based on some kind of stream order. I want to group all rivers that belong to stream order 2 and are spatially connected; each group should get a unique category value. I thought that I could first extract all rivers with a particular attribute (e.g. stream order = 2) which will provide me some scattered pattern of lines. Then I need a spatial join tool to make subgroups of lines that are connected. How can I achieve the latter? Any idea?

Here's a procedure that might work for you. Somewhat clunky, but I think it gets what you want.

It's based on the v.build.polylines module to connect all touching stream reaches. First extract each order from the stream vector into a new vector. Then build polylines. Patch them all together. Now you have a polyline vector with a single cat value for each set of original stream reaches that had the same order and that were touching.

Unfortunately, the v.build.polylines tool does not work here as it does not connect multiple (intersecting) lines like in a river network. For example, I tried to build polylines from the stream network of the NC dataset. The suggested approach should result that each sub-network (i.e. river network that is not connected to another one) should get its own ID/cat...however, v.build.polylines results in a stream sub-network that consists of multiple cats:

v.clean --overwrite input=streams@PERMANENT output=streams_break tool=break
v.build.polylines --overwrite input=streams_break@test output=streams_poly cats=first type=line
d.vect -c map=streams_poly

So is there any other way to join all lines that are touching...This would be something similar to v.dissolve but based on lines rather than on polygons.

Any ideas for a simple work around?

cheers,

Johannes

Finally, with v.distance you can upload that cat value to the original streams.

# Get a list of stream orders
ORDERS=`v.db.select -c streams group=strahler column=strahler`
echo $ORDERS
#1 2 3 4 5 6
# How many stream segments in original
v.info -t streams | grep lines
# lines=1420

# Now loop thru list of stream orders and extract stream segments for each order
for o in $ORDERS; do
v.extract input=streams output=streams_${o} where="strahler=${o}"
# Create polyline for each stream order
# Line "connects" all touching stream segments
v.build.polylines input=streams_${o} output=streams_${o}_polyline type=line cat=first
done

# Patch stream order polylines together
POLYLINES=`g.list vect pattern="streams*polyline" separator=comma`
echo $POLYLINES
v.patch input=$POLYLINES output=streams_polylines
v.info -t streams_polylines | grep lines
# lines=738

# Add a new column to the original streams for new ID value
v.db.addcolumn map=streams column="merged_id INTEGER"
# And use v.distance to update that column from cat values in polylines vector
v.distance from=streams to=streams_polylines upload=cat column=merged_id

HTH

Cheers,
Johannes

_______________________________________________
grass-user mailing list
grass-user@lists.osgeo.org
https://lists.osgeo.org/mailman/listinfo/grass-user

Hi Micha, hi all,

sorry for my late response…however, just today I managed to try your approach of building polylines to connect “touching stream lines”…but…

On 24.02.20 16:48, Micha Silver wrote:

On 24/02/2020 10:45, Johannes Radinger wrote:

Hi all,
I have a large river network dataset (lines). Now I’d to assign unique categories to each group of connected lines that have an attribute in common.

For example, my rivers are categorized based on some kind of stream order. I want to group all rivers that belong to stream order 2 and are spatially connected; each group should get a unique category value. I thought that I could first extract all rivers with a particular attribute (e.g. stream order = 2) which will provide me some scattered pattern of lines. Then I need a spatial join tool to make subgroups of lines that are connected. How can I achieve the latter? Any idea?

Here’s a procedure that might work for you. Somewhat clunky, but I think it gets what you want.

It’s based on the v.build.polylines module to connect all touching stream reaches. First extract each order from the stream vector into a new vector. Then build polylines. Patch them all together. Now you have a polyline vector with a single cat value for each set of original stream reaches that had the same order and that were touching.

Unfortunately, the v.build.polylines tool does not work as it only does not connect multiple (intersecting) lines like in a river network. As an example I tried to build polylines from the stream network of the NC dataset. Yous suggested approach should result that each sub-network (i.e. river network that is not connected to another one) should get its own ID/cat…however, v.build.polylines results in a connected stream network that consists of multiple cats:

v.clean --overwrite input=streams@PERMANENT output=streams_break tool=break
v.build.polylines --overwrite input=streams_break@test output=streams_poly cats=first type=line
d.vect -c map=streams_poly

So what would be needed here is some kind of tool that connects all touching lines and assigns a common category value, similar to the v.dissolve tool for polygon features. I can imagine that such a task might be not that uncommon also in another context? Any suggestions how to achieve this in GRASS?

A workaround that came into my mind was to create buffers around lines in order to make areas out of lines. Subsequently these touching areas can be merged using v.dissolve and the information about the common category can be queried using v.distance. Nevertheless, a rather cumbersome way to just assign a common category value to all lines that are touching…

Any further ideas?

cheers,

Johannes

Finally, with v.distance you can upload that cat value to the original streams.

Get a list of stream orders

ORDERS=v.db.select -c streams group=strahler column=strahler
echo $ORDERS
#1 2 3 4 5 6

How many stream segments in original

v.info -t streams | grep lines

lines=1420

Now loop thru list of stream orders and extract stream segments for each order

for o in $ORDERS; do
v.extract input=streams output=streams_${o} where=“strahler=${o}”

Create polyline for each stream order

Line “connects” all touching stream segments

v.build.polylines input=streams_${o} output=streams_${o}_polyline type=line cat=first
done

Patch stream order polylines together

POLYLINES=g.list vect pattern="streams*polyline" separator=comma
echo $POLYLINES
v.patch input=$POLYLINES output=streams_polylines
v.info -t streams_polylines | grep lines

lines=738

Add a new column to the original streams for new ID value

v.db.addcolumn map=streams column=“merged_id INTEGER”

And use v.distance to update that column from cat values in polylines vector

v.distance from=streams to=streams_polylines upload=cat column=merged_id

HTH

Cheers,
Johannes


grass-user mailing list
grass-user@lists.osgeo.org
https://lists.osgeo.org/mailman/listinfo/grass-user

On 3/5/20 10:47 AM, Johannes Radinger wrote:

Hi Micha, hi all,

sorry for my late response...however, just today I managed to try your approach of building polylines to connect "touching stream lines"...but...

On 24.02.20 16:48, Micha Silver wrote:

On 24/02/2020 10:45, Johannes Radinger wrote:

Hi all,
I have a large river network dataset (lines). Now I'd to assign unique categories to each group of connected lines that have an attribute in common.

For example, my rivers are categorized based on some kind of stream order. I want to group all rivers that belong to stream order 2 and are spatially connected; each group should get a unique category value. I thought that I could first extract all rivers with a particular attribute (e.g. stream order = 2) which will provide me some scattered pattern of lines. Then I need a spatial join tool to make subgroups of lines that are connected. How can I achieve the latter? Any idea?

Here's a procedure that might work for you. Somewhat clunky, but I think it gets what you want.

It's based on the v.build.polylines module to connect all touching stream reaches. First extract each order from the stream vector into a new vector. Then build polylines. Patch them all together. Now you have a polyline vector with a single cat value for each set of original stream reaches that had the same order and that were touching.

Unfortunately, the v.build.polylines tool does not work as it only does not connect multiple (intersecting) lines like in a river network. As an example I tried to build polylines from the stream network of the NC dataset. Yous suggested approach should result that each sub-network (i.e. river network that is not connected to another one) should get its own ID/cat...however, v.build.polylines results in a connected stream network that consists of multiple cats:

Maybe I misunderstood your question. The steps I tried use a stream_order column to group stream segments, then apply a new attribute "merged_id" to those stream orders that touch. i.e. that connect to the same confluence point.

Here's what I get using the nc_basic_spm mapset:

r.watershed elev=elevation accum=nc_facc drain=nc_fdir bas=nc_bas stream=nc_str thresh=1000
r.stream.order stream_rast=nc_str direct=nc_fdir elev=elevation accum=nc_facc stream_vect=nc_streams
ORDERS=`v.db.select -c nc_streams group=strahler column=strahler`
echo $ORDERS

# Create a new stream vector for each stream order

for o in $ORDERS; do

 v\.extract input=nc\_streams output=streams\_$\{o\} where="strahler=$\{o\}"

 \# Give each polyline it's own cat value

 v\.build\.polylines input=streams\_$\{o\} output=streams\_$\{o\}\_polyline type=line cat=first

done

# patch the stream orders back together

POLYLINES=`g.list vect pattern="streams*polyline" separator=comma`

v.patch input=$POLYLINES output=streams_polylines

v.db.addcolumn map=streams column="merged_id INTEGER"

# And use v.distance to update that merged_id column from cat values in polylines vector
v.distance from=streams to=streams_polylines upload=cat column=merged_id
v.db.addcolumn map=nc_streams column="merged_id INTEGER"
v.distance from=nc_streams to=streams_polylines upload=cat column=merged_id

Now, all stream reaches that have the same order and are "touching" have the same merged_id. See the attached image.

If that's not your purpose, then just ignore...

v.clean --overwrite input=streams@PERMANENT output=streams_break tool=break
v.build.polylines --overwrite input=streams_break@test output=streams_poly cats=first type=line
d.vect -c map=streams_poly

So what would be needed here is some kind of tool that connects all touching lines and assigns a common category value, similar to the v.dissolve tool for polygon features. I can imagine that such a task might be not that uncommon also in another context? Any suggestions how to achieve this in GRASS?

A workaround that came into my mind was to create buffers around lines in order to make areas out of lines. Subsequently these touching areas can be merged using v.dissolve and the information about the common category can be queried using v.distance. Nevertheless, a rather cumbersome way to just assign a common category value to all lines that are touching...

Any further ideas?

cheers,

Johannes

Cheers,
Johannes

_______________________________________________
grass-user mailing list
grass-user@lists.osgeo.org <mailto:grass-user@lists.osgeo.org>
https://lists.osgeo.org/mailman/listinfo/grass-user

--
Micha Silver
Ben Gurion Univ.
Sde Boker, Remote Sensing Lab
cell: +972-523-665918

(attachments)

merged_id.png

So...no also with GRASS-user as recipient...

On 05.03.20 16:21, Micha Silver wrote:

On 3/5/20 10:47 AM, Johannes Radinger wrote:

Hi Micha, hi all,

sorry for my late response...however, just today I managed to try your approach of building polylines to connect "touching stream lines"...but...

On 24.02.20 16:48, Micha Silver wrote:

On 24/02/2020 10:45, Johannes Radinger wrote:

Hi all,
I have a large river network dataset (lines). Now I'd to assign unique categories to each group of connected lines that have an attribute in common.

For example, my rivers are categorized based on some kind of stream order. I want to group all rivers that belong to stream order 2 and are spatially connected; each group should get a unique category value. I thought that I could first extract all rivers with a particular attribute (e.g. stream order = 2) which will provide me some scattered pattern of lines. Then I need a spatial join tool to make subgroups of lines that are connected. How can I achieve the latter? Any idea?

Here's a procedure that might work for you. Somewhat clunky, but I think it gets what you want.

It's based on the v.build.polylines module to connect all touching stream reaches. First extract each order from the stream vector into a new vector. Then build polylines. Patch them all together. Now you have a polyline vector with a single cat value for each set of original stream reaches that had the same order and that were touching.

Unfortunately, the v.build.polylines tool does not work as it only does not connect multiple (intersecting) lines like in a river network. As an example I tried to build polylines from the stream network of the NC dataset. Yous suggested approach should result that each sub-network (i.e. river network that is not connected to another one) should get its own ID/cat...however, v.build.polylines results in a connected stream network that consists of multiple cats:

Maybe I misunderstood your question. The steps I tried use a stream_order column to group stream segments, then apply a new attribute "merged_id" to those stream orders that touch. i.e. that connect to the same confluence point.

Here's what I get using the nc_basic_spm mapset:

r.watershed elev=elevation accum=nc_facc drain=nc_fdir bas=nc_bas stream=nc_str thresh=1000
r.stream.order stream_rast=nc_str direct=nc_fdir elev=elevation accum=nc_facc stream_vect=nc_streams
ORDERS=`v.db.select -c nc_streams group=strahler column=strahler`
echo $ORDERS

# Create a new stream vector for each stream order

for o in $ORDERS; do

v\.extract input=nc\_streams output=streams\_$\{o\} where=&quot;strahler=$\{o\}&quot;

\# Give each polyline it&#39;s own cat value

v\.build\.polylines input=streams\_$\{o\} output=streams\_$\{o\}\_polyline type=line cat=first

done

# patch the stream orders back together

POLYLINES=`g.list vect pattern="streams*polyline" separator=comma`

v.patch input=$POLYLINES output=streams_polylines

v.db.addcolumn map=streams column="merged_id INTEGER"

# And use v.distance to update that merged_id column from cat values in polylines vector
v.distance from=streams to=streams_polylines upload=cat column=merged_id
v.db.addcolumn map=nc_streams column="merged_id INTEGER"
v.distance from=nc_streams to=streams_polylines upload=cat column=merged_id

Now, all stream reaches that have the same order and are "touching" have the same merged_id. See the attached image.

If that's not your purpose, then just ignore...

Micha thank you for your help and of course, you're fully correct! Merging lines that belong to the same stream order works in this case well...but this is because of the definition of the Strahler ordering system, where there is only one "touching node" (i.e. river junction) of two rivers of the same stream order (i.e. when two 2nd order streams meet, the become a 3rd order stream). Thus your solution works because of this specifics and might not work if streams are grouped based on a different (ordering) system.

I was already thinking of the next step (beyond simple Strahler): As mentioned in my initial post I am dealing with "some kind" of stream order. It is similar to grouped stream orders (e.g. stream order 1-2 = "headwater streams"). I tried to somehow reproduce my situation based on your example of the NC dataset. What I basically did was to reassign a new stream order "99" to all former 1st and 2nd order streams. Then I did exactly what you did in your example, and of course I don't unique merged_ids for the subnetworks of touching lines (see attached Figs) that all belong the the same "order" 99 (the original strahler order 3 works of course, see Fig.)...So is there a more general way (as said something like v.dissolve but for lines/networks?):

#####################
g.region raster=elevation

r.watershed --o elev=elevation accum=nc_facc drain=nc_fdir bas=nc_bas stream=nc_str thresh=1000
r.stream.order stream_rast=nc_str direct=nc_fdir elev=elevation accum=nc_facc stream_vect=nc_streams

#ORDERS=`v.db.select -c nc_streams group=strahler column=strahler`
#echo $ORDERS

# Regroup orders 1-2 (to 99)
v.db.addcolumn map=nc_streams@test2 columns="strahler_groups INTEGER"
v.db.update map=nc_streams column=strahler_groups query_column=strahler
v.db.update map=nc_streams column=strahler_groups value=99 where="strahler=1 OR strahler=2"

NEWORDERS=`v.db.select -c nc_streams group=strahler_groups column=strahler_groups`
echo $NEWORDERS

# Create a new stream vector for each stream order
for o in $NEWORDERS; do
v.extract input=nc_streams output=streams_${o} where="strahler_groups=${o}"
# Give each polyline it's own cat value
v.build.polylines input=streams_${o} output=streams_${o}_polyline type=line cat=first
done

d.vect -c map=streams_99_polyline@test2
#################

Thank you very much!

Cheers,

Johannes

v.clean --overwrite input=streams@PERMANENT output=streams_break tool=break
v.build.polylines --overwrite input=streams_break@test output=streams_poly cats=first type=line
d.vect -c map=streams_poly

So what would be needed here is some kind of tool that connects all touching lines and assigns a common category value, similar to the v.dissolve tool for polygon features. I can imagine that such a task might be not that uncommon also in another context? Any suggestions how to achieve this in GRASS?

A workaround that came into my mind was to create buffers around lines in order to make areas out of lines. Subsequently these touching areas can be merged using v.dissolve and the information about the common category can be queried using v.distance. Nevertheless, a rather cumbersome way to just assign a common category value to all lines that are touching...

Any further ideas?

cheers,

Johannes

Cheers,
Johannes

_______________________________________________
grass-user mailing list
grass-user@lists.osgeo.org <mailto:grass-user@lists.osgeo.org>
https://lists.osgeo.org/mailman/listinfo/grass-user

(attachments)

merged_id_ORDER99.png
merged_id_ORDER3.png

Hi Johannes,

IIUC, what you want to do is an operation that involves topological relations of vector geometries (connected lines) and a common attribute. There is no easy common recipe for this.

Just a suggestion:
for each stream order:
extract all lines with this stream order (v.extract)
identify connected lines (v.net + v.net.components)
update a new attribute of the original lines with the comp attribute of the output of v.net.components plus some offset to separate different stream orders

HTH,

Markus M

On Tue, Mar 10, 2020 at 5:20 PM Johannes Radinger <johannesradinger@gmail.com> wrote:

So…no also with GRASS-user as recipient…

On 05.03.20 16:21, Micha Silver wrote:

On 3/5/20 10:47 AM, Johannes Radinger wrote:

Hi Micha, hi all,

sorry for my late response…however, just today I managed to try
your approach of building polylines to connect “touching stream
lines”…but…

On 24.02.20 16:48, Micha Silver wrote:

On 24/02/2020 10:45, Johannes Radinger wrote:

Hi all,
I have a large river network dataset (lines). Now I’d to assign
unique categories to each group of connected lines that have an
attribute in common.

For example, my rivers are categorized based on some kind of stream
order. I want to group all rivers that belong to stream order 2 and
are spatially connected; each group should get a unique category
value. I thought that I could first extract all rivers with a
particular attribute (e.g. stream order = 2) which will provide me
some scattered pattern of lines. Then I need a spatial join tool to
make subgroups of lines that are connected. How can I achieve the
latter? Any idea?

Here’s a procedure that might work for you. Somewhat clunky, but I
think it gets what you want.

It’s based on the v.build.polylines module to connect all touching
stream reaches. First extract each order from the stream vector into
a new vector. Then build polylines. Patch them all together. Now you
have a polyline vector with a single cat value for each set of
original stream reaches that had the same order and that were touching.

Unfortunately, the v.build.polylines tool does not work as it only
does not connect multiple (intersecting) lines like in a river
network. As an example I tried to build polylines from the stream
network of the NC dataset. Yous suggested approach should result that
each sub-network (i.e. river network that is not connected to another
one) should get its own ID/cat…however, v.build.polylines results
in a connected stream network that consists of multiple cats:

Maybe I misunderstood your question. The steps I tried use a
stream_order column to group stream segments, then apply a new
attribute “merged_id” to those stream orders that touch. i.e. that
connect to the same confluence point.

Here’s what I get using the nc_basic_spm mapset:

r.watershed elev=elevation accum=nc_facc drain=nc_fdir bas=nc_bas
stream=nc_str thresh=1000
r.stream.order stream_rast=nc_str direct=nc_fdir elev=elevation
accum=nc_facc stream_vect=nc_streams
ORDERS=v.db.select -c nc_streams group=strahler column=strahler
echo $ORDERS

Create a new stream vector for each stream order

for o in $ORDERS; do

v.extract input=nc_streams output=streams_${o} where=“strahler=${o}”

Give each polyline it’s own cat value

v.build.polylines input=streams_${o} output=streams_${o}_polyline
type=line cat=first

done

patch the stream orders back together

POLYLINES=g.list vect pattern="streams*polyline" separator=comma

v.patch input=$POLYLINES output=streams_polylines

v.db.addcolumn map=streams column=“merged_id INTEGER”

And use v.distance to update that merged_id column from cat values

in polylines vector
v.distance from=streams to=streams_polylines upload=cat column=merged_id
v.db.addcolumn map=nc_streams column=“merged_id INTEGER”
v.distance from=nc_streams to=streams_polylines upload=cat
column=merged_id

Now, all stream reaches that have the same order and are “touching”
have the same merged_id. See the attached image.

If that’s not your purpose, then just ignore…

Micha thank you for your help and of course, you’re fully correct!
Merging lines that belong to the same stream order works in this case
well…but this is because of the definition of the Strahler ordering
system, where there is only one “touching node” (i.e. river junction) of
two rivers of the same stream order (i.e. when two 2nd order streams
meet, the become a 3rd order stream). Thus your solution works because
of this specifics and might not work if streams are grouped based on a
different (ordering) system.

I was already thinking of the next step (beyond simple Strahler): As
mentioned in my initial post I am dealing with “some kind” of stream
order. It is similar to grouped stream orders (e.g. stream order 1-2 =
“headwater streams”). I tried to somehow reproduce my situation based on
your example of the NC dataset. What I basically did was to reassign a
new stream order “99” to all former 1st and 2nd order streams. Then I
did exactly what you did in your example, and of course I don’t unique
merged_ids for the subnetworks of touching lines (see attached Figs)
that all belong the the same “order” 99 (the original strahler order 3
works of course, see Fig.)…So is there a more general way (as said
something like v.dissolve but for lines/networks?):

#####################
g.region raster=elevation

r.watershed --o elev=elevation accum=nc_facc drain=nc_fdir bas=nc_bas
stream=nc_str thresh=1000
r.stream.order stream_rast=nc_str direct=nc_fdir elev=elevation
accum=nc_facc stream_vect=nc_streams

#ORDERS=v.db.select -c nc_streams group=strahler column=strahler
#echo $ORDERS

Regroup orders 1-2 (to 99)

v.db.addcolumn map=nc_streams@test2 columns=“strahler_groups INTEGER”
v.db.update map=nc_streams column=strahler_groups query_column=strahler
v.db.update map=nc_streams column=strahler_groups value=99
where=“strahler=1 OR strahler=2”

NEWORDERS=v.db.select -c nc_streams group=strahler_groups column=strahler_groups
echo $NEWORDERS

Create a new stream vector for each stream order

for o in $NEWORDERS; do
v.extract input=nc_streams output=streams_${o}
where=“strahler_groups=${o}”

Give each polyline it’s own cat value

v.build.polylines input=streams_${o} output=streams_${o}_polyline
type=line cat=first
done

d.vect -c map=streams_99_polyline@test2
#################

Thank you very much!

Cheers,

Johannes

v.clean --overwrite input=streams@PERMANENT output=streams_break
tool=break
v.build.polylines --overwrite input=streams_break@test
output=streams_poly cats=first type=line
d.vect -c map=streams_poly

So what would be needed here is some kind of tool that connects all
touching lines and assigns a common category value, similar to the
v.dissolve tool for polygon features. I can imagine that such a task
might be not that uncommon also in another context? Any suggestions
how to achieve this in GRASS?

A workaround that came into my mind was to create buffers around
lines in order to make areas out of lines. Subsequently these
touching areas can be merged using v.dissolve and the information
about the common category can be queried using v.distance.
Nevertheless, a rather cumbersome way to just assign a common
category value to all lines that are touching…

Any further ideas?

cheers,

Johannes

Cheers,
Johannes


grass-user mailing list
grass-user@lists.osgeo.org mailto:[grass-user@lists.osgeo.org](mailto:grass-user@lists.osgeo.org)
https://lists.osgeo.org/mailman/listinfo/grass-user


grass-user mailing list
grass-user@lists.osgeo.org
https://lists.osgeo.org/mailman/listinfo/grass-user

Thank you Markus,
indeed your approach looks like what I need…The hint with v.net.components was the part that I was missing; I’ll try as soon as possible and will report back on how this works.
cheers,
Johannes

On Wed, Mar 11, 2020 at 10:16 PM Markus Metz <markus.metz.giswork@gmail.com> wrote:

Hi Johannes,

IIUC, what you want to do is an operation that involves topological relations of vector geometries (connected lines) and a common attribute. There is no easy common recipe for this.

Just a suggestion:
for each stream order:
extract all lines with this stream order (v.extract)
identify connected lines (v.net + v.net.components)
update a new attribute of the original lines with the comp attribute of the output of v.net.components plus some offset to separate different stream orders

HTH,

Markus M

On Tue, Mar 10, 2020 at 5:20 PM Johannes Radinger <johannesradinger@gmail.com> wrote:

So…no also with GRASS-user as recipient…

On 05.03.20 16:21, Micha Silver wrote:

On 3/5/20 10:47 AM, Johannes Radinger wrote:

Hi Micha, hi all,

sorry for my late response…however, just today I managed to try
your approach of building polylines to connect “touching stream
lines”…but…

On 24.02.20 16:48, Micha Silver wrote:

On 24/02/2020 10:45, Johannes Radinger wrote:

Hi all,
I have a large river network dataset (lines). Now I’d to assign
unique categories to each group of connected lines that have an
attribute in common.

For example, my rivers are categorized based on some kind of stream
order. I want to group all rivers that belong to stream order 2 and
are spatially connected; each group should get a unique category
value. I thought that I could first extract all rivers with a
particular attribute (e.g. stream order = 2) which will provide me
some scattered pattern of lines. Then I need a spatial join tool to
make subgroups of lines that are connected. How can I achieve the
latter? Any idea?

Here’s a procedure that might work for you. Somewhat clunky, but I
think it gets what you want.

It’s based on the v.build.polylines module to connect all touching
stream reaches. First extract each order from the stream vector into
a new vector. Then build polylines. Patch them all together. Now you
have a polyline vector with a single cat value for each set of
original stream reaches that had the same order and that were touching.

Unfortunately, the v.build.polylines tool does not work as it only
does not connect multiple (intersecting) lines like in a river
network. As an example I tried to build polylines from the stream
network of the NC dataset. Yous suggested approach should result that
each sub-network (i.e. river network that is not connected to another
one) should get its own ID/cat…however, v.build.polylines results
in a connected stream network that consists of multiple cats:

Maybe I misunderstood your question. The steps I tried use a
stream_order column to group stream segments, then apply a new
attribute “merged_id” to those stream orders that touch. i.e. that
connect to the same confluence point.

Here’s what I get using the nc_basic_spm mapset:

r.watershed elev=elevation accum=nc_facc drain=nc_fdir bas=nc_bas
stream=nc_str thresh=1000
r.stream.order stream_rast=nc_str direct=nc_fdir elev=elevation
accum=nc_facc stream_vect=nc_streams
ORDERS=v.db.select -c nc_streams group=strahler column=strahler
echo $ORDERS

Create a new stream vector for each stream order

for o in $ORDERS; do

v.extract input=nc_streams output=streams_${o} where=“strahler=${o}”

Give each polyline it’s own cat value

v.build.polylines input=streams_${o} output=streams_${o}_polyline
type=line cat=first

done

patch the stream orders back together

POLYLINES=g.list vect pattern="streams*polyline" separator=comma

v.patch input=$POLYLINES output=streams_polylines

v.db.addcolumn map=streams column=“merged_id INTEGER”

And use v.distance to update that merged_id column from cat values

in polylines vector
v.distance from=streams to=streams_polylines upload=cat column=merged_id
v.db.addcolumn map=nc_streams column=“merged_id INTEGER”
v.distance from=nc_streams to=streams_polylines upload=cat
column=merged_id

Now, all stream reaches that have the same order and are “touching”
have the same merged_id. See the attached image.

If that’s not your purpose, then just ignore…

Micha thank you for your help and of course, you’re fully correct!
Merging lines that belong to the same stream order works in this case
well…but this is because of the definition of the Strahler ordering
system, where there is only one “touching node” (i.e. river junction) of
two rivers of the same stream order (i.e. when two 2nd order streams
meet, the become a 3rd order stream). Thus your solution works because
of this specifics and might not work if streams are grouped based on a
different (ordering) system.

I was already thinking of the next step (beyond simple Strahler): As
mentioned in my initial post I am dealing with “some kind” of stream
order. It is similar to grouped stream orders (e.g. stream order 1-2 =
“headwater streams”). I tried to somehow reproduce my situation based on
your example of the NC dataset. What I basically did was to reassign a
new stream order “99” to all former 1st and 2nd order streams. Then I
did exactly what you did in your example, and of course I don’t unique
merged_ids for the subnetworks of touching lines (see attached Figs)
that all belong the the same “order” 99 (the original strahler order 3
works of course, see Fig.)…So is there a more general way (as said
something like v.dissolve but for lines/networks?):

#####################
g.region raster=elevation

r.watershed --o elev=elevation accum=nc_facc drain=nc_fdir bas=nc_bas
stream=nc_str thresh=1000
r.stream.order stream_rast=nc_str direct=nc_fdir elev=elevation
accum=nc_facc stream_vect=nc_streams

#ORDERS=v.db.select -c nc_streams group=strahler column=strahler
#echo $ORDERS

Regroup orders 1-2 (to 99)

v.db.addcolumn map=nc_streams@test2 columns=“strahler_groups INTEGER”
v.db.update map=nc_streams column=strahler_groups query_column=strahler
v.db.update map=nc_streams column=strahler_groups value=99
where=“strahler=1 OR strahler=2”

NEWORDERS=v.db.select -c nc_streams group=strahler_groups column=strahler_groups
echo $NEWORDERS

Create a new stream vector for each stream order

for o in $NEWORDERS; do
v.extract input=nc_streams output=streams_${o}
where=“strahler_groups=${o}”

Give each polyline it’s own cat value

v.build.polylines input=streams_${o} output=streams_${o}_polyline
type=line cat=first
done

d.vect -c map=streams_99_polyline@test2
#################

Thank you very much!

Cheers,

Johannes

v.clean --overwrite input=streams@PERMANENT output=streams_break
tool=break
v.build.polylines --overwrite input=streams_break@test
output=streams_poly cats=first type=line
d.vect -c map=streams_poly

So what would be needed here is some kind of tool that connects all
touching lines and assigns a common category value, similar to the
v.dissolve tool for polygon features. I can imagine that such a task
might be not that uncommon also in another context? Any suggestions
how to achieve this in GRASS?

A workaround that came into my mind was to create buffers around
lines in order to make areas out of lines. Subsequently these
touching areas can be merged using v.dissolve and the information
about the common category can be queried using v.distance.
Nevertheless, a rather cumbersome way to just assign a common
category value to all lines that are touching…

Any further ideas?

cheers,

Johannes

Cheers,
Johannes


grass-user mailing list
grass-user@lists.osgeo.org mailto:[grass-user@lists.osgeo.org](mailto:grass-user@lists.osgeo.org)
https://lists.osgeo.org/mailman/listinfo/grass-user


grass-user mailing list
grass-user@lists.osgeo.org
https://lists.osgeo.org/mailman/listinfo/grass-user

On Thu, Mar 12, 2020 at 12:34 PM Johannes Radinger <johannesradinger@gmail.com> wrote:

Thank you Markus,

indeed your approach looks like what I need…The hint with v.net.components was the part that I was missing;

Note that v.net.components does not need a network prepared with v.net, you can use the extract of all lines with the same stream order as it is.

Markus M

I’ll try as soon as possible and will report back on how this works.
cheers,
Johannes

On Wed, Mar 11, 2020 at 10:16 PM Markus Metz <markus.metz.giswork@gmail.com> wrote:

Hi Johannes,

IIUC, what you want to do is an operation that involves topological relations of vector geometries (connected lines) and a common attribute. There is no easy common recipe for this.

Just a suggestion:
for each stream order:
extract all lines with this stream order (v.extract)
identify connected lines (v.net + v.net.components)
update a new attribute of the original lines with the comp attribute of the output of v.net.components plus some offset to separate different stream orders

HTH,

Markus M

On Tue, Mar 10, 2020 at 5:20 PM Johannes Radinger <johannesradinger@gmail.com> wrote:

So…no also with GRASS-user as recipient…

On 05.03.20 16:21, Micha Silver wrote:

On 3/5/20 10:47 AM, Johannes Radinger wrote:

Hi Micha, hi all,

sorry for my late response…however, just today I managed to try
your approach of building polylines to connect “touching stream
lines”…but…

On 24.02.20 16:48, Micha Silver wrote:

On 24/02/2020 10:45, Johannes Radinger wrote:

Hi all,
I have a large river network dataset (lines). Now I’d to assign
unique categories to each group of connected lines that have an
attribute in common.

For example, my rivers are categorized based on some kind of stream
order. I want to group all rivers that belong to stream order 2 and
are spatially connected; each group should get a unique category
value. I thought that I could first extract all rivers with a
particular attribute (e.g. stream order = 2) which will provide me
some scattered pattern of lines. Then I need a spatial join tool to
make subgroups of lines that are connected. How can I achieve the
latter? Any idea?

Here’s a procedure that might work for you. Somewhat clunky, but I
think it gets what you want.

It’s based on the v.build.polylines module to connect all touching
stream reaches. First extract each order from the stream vector into
a new vector. Then build polylines. Patch them all together. Now you
have a polyline vector with a single cat value for each set of
original stream reaches that had the same order and that were touching.

Unfortunately, the v.build.polylines tool does not work as it only
does not connect multiple (intersecting) lines like in a river
network. As an example I tried to build polylines from the stream
network of the NC dataset. Yous suggested approach should result that
each sub-network (i.e. river network that is not connected to another
one) should get its own ID/cat…however, v.build.polylines results
in a connected stream network that consists of multiple cats:

Maybe I misunderstood your question. The steps I tried use a
stream_order column to group stream segments, then apply a new
attribute “merged_id” to those stream orders that touch. i.e. that
connect to the same confluence point.

Here’s what I get using the nc_basic_spm mapset:

r.watershed elev=elevation accum=nc_facc drain=nc_fdir bas=nc_bas
stream=nc_str thresh=1000
r.stream.order stream_rast=nc_str direct=nc_fdir elev=elevation
accum=nc_facc stream_vect=nc_streams
ORDERS=v.db.select -c nc_streams group=strahler column=strahler
echo $ORDERS

Create a new stream vector for each stream order

for o in $ORDERS; do

v.extract input=nc_streams output=streams_${o} where=“strahler=${o}”

Give each polyline it’s own cat value

v.build.polylines input=streams_${o} output=streams_${o}_polyline
type=line cat=first

done

patch the stream orders back together

POLYLINES=g.list vect pattern="streams*polyline" separator=comma

v.patch input=$POLYLINES output=streams_polylines

v.db.addcolumn map=streams column=“merged_id INTEGER”

And use v.distance to update that merged_id column from cat values

in polylines vector
v.distance from=streams to=streams_polylines upload=cat column=merged_id
v.db.addcolumn map=nc_streams column=“merged_id INTEGER”
v.distance from=nc_streams to=streams_polylines upload=cat
column=merged_id

Now, all stream reaches that have the same order and are “touching”
have the same merged_id. See the attached image.

If that’s not your purpose, then just ignore…

Micha thank you for your help and of course, you’re fully correct!
Merging lines that belong to the same stream order works in this case
well…but this is because of the definition of the Strahler ordering
system, where there is only one “touching node” (i.e. river junction) of
two rivers of the same stream order (i.e. when two 2nd order streams
meet, the become a 3rd order stream). Thus your solution works because
of this specifics and might not work if streams are grouped based on a
different (ordering) system.

I was already thinking of the next step (beyond simple Strahler): As
mentioned in my initial post I am dealing with “some kind” of stream
order. It is similar to grouped stream orders (e.g. stream order 1-2 =
“headwater streams”). I tried to somehow reproduce my situation based on
your example of the NC dataset. What I basically did was to reassign a
new stream order “99” to all former 1st and 2nd order streams. Then I
did exactly what you did in your example, and of course I don’t unique
merged_ids for the subnetworks of touching lines (see attached Figs)
that all belong the the same “order” 99 (the original strahler order 3
works of course, see Fig.)…So is there a more general way (as said
something like v.dissolve but for lines/networks?):

#####################
g.region raster=elevation

r.watershed --o elev=elevation accum=nc_facc drain=nc_fdir bas=nc_bas
stream=nc_str thresh=1000
r.stream.order stream_rast=nc_str direct=nc_fdir elev=elevation
accum=nc_facc stream_vect=nc_streams

#ORDERS=v.db.select -c nc_streams group=strahler column=strahler
#echo $ORDERS

Regroup orders 1-2 (to 99)

v.db.addcolumn map=nc_streams@test2 columns=“strahler_groups INTEGER”
v.db.update map=nc_streams column=strahler_groups query_column=strahler
v.db.update map=nc_streams column=strahler_groups value=99
where=“strahler=1 OR strahler=2”

NEWORDERS=v.db.select -c nc_streams group=strahler_groups column=strahler_groups
echo $NEWORDERS

Create a new stream vector for each stream order

for o in $NEWORDERS; do
v.extract input=nc_streams output=streams_${o}
where=“strahler_groups=${o}”

Give each polyline it’s own cat value

v.build.polylines input=streams_${o} output=streams_${o}_polyline
type=line cat=first
done

d.vect -c map=streams_99_polyline@test2
#################

Thank you very much!

Cheers,

Johannes

v.clean --overwrite input=streams@PERMANENT output=streams_break
tool=break
v.build.polylines --overwrite input=streams_break@test
output=streams_poly cats=first type=line
d.vect -c map=streams_poly

So what would be needed here is some kind of tool that connects all
touching lines and assigns a common category value, similar to the
v.dissolve tool for polygon features. I can imagine that such a task
might be not that uncommon also in another context? Any suggestions
how to achieve this in GRASS?

A workaround that came into my mind was to create buffers around
lines in order to make areas out of lines. Subsequently these
touching areas can be merged using v.dissolve and the information
about the common category can be queried using v.distance.
Nevertheless, a rather cumbersome way to just assign a common
category value to all lines that are touching…

Any further ideas?

cheers,

Johannes

Cheers,
Johannes


grass-user mailing list
grass-user@lists.osgeo.org mailto:[grass-user@lists.osgeo.org](mailto:grass-user@lists.osgeo.org)
https://lists.osgeo.org/mailman/listinfo/grass-user


grass-user mailing list
grass-user@lists.osgeo.org
https://lists.osgeo.org/mailman/listinfo/grass-user

On Thu, Mar 12, 2020 at 10:48 PM Markus Metz <markus.metz.giswork@gmail.com> wrote:

On Thu, Mar 12, 2020 at 12:34 PM Johannes Radinger <johannesradinger@gmail.com> wrote:

Thank you Markus,

indeed your approach looks like what I need…The hint with v.net.components was the part that I was missing;

Note that v.net.components does not need a network prepared with v.net, you can use the extract of all lines with the same stream order as it is.

I just tested your suggested approach using v.net.components (without running v.net before)…works really smoothly and very fast and I get to the desired results of extracting subnets. Thanks a lot Markus for this hint!

/Johannes

Markus M

I’ll try as soon as possible and will report back on how this works.
cheers,
Johannes

On Wed, Mar 11, 2020 at 10:16 PM Markus Metz <markus.metz.giswork@gmail.com> wrote:

Hi Johannes,

IIUC, what you want to do is an operation that involves topological relations of vector geometries (connected lines) and a common attribute. There is no easy common recipe for this.

Just a suggestion:
for each stream order:
extract all lines with this stream order (v.extract)
identify connected lines (v.net + v.net.components)
update a new attribute of the original lines with the comp attribute of the output of v.net.components plus some offset to separate different stream orders

HTH,

Markus M

On Tue, Mar 10, 2020 at 5:20 PM Johannes Radinger <johannesradinger@gmail.com> wrote:

So…no also with GRASS-user as recipient…

On 05.03.20 16:21, Micha Silver wrote:

On 3/5/20 10:47 AM, Johannes Radinger wrote:

Hi Micha, hi all,

sorry for my late response…however, just today I managed to try
your approach of building polylines to connect “touching stream
lines”…but…

On 24.02.20 16:48, Micha Silver wrote:

On 24/02/2020 10:45, Johannes Radinger wrote:

Hi all,
I have a large river network dataset (lines). Now I’d to assign
unique categories to each group of connected lines that have an
attribute in common.

For example, my rivers are categorized based on some kind of stream
order. I want to group all rivers that belong to stream order 2 and
are spatially connected; each group should get a unique category
value. I thought that I could first extract all rivers with a
particular attribute (e.g. stream order = 2) which will provide me
some scattered pattern of lines. Then I need a spatial join tool to
make subgroups of lines that are connected. How can I achieve the
latter? Any idea?

Here’s a procedure that might work for you. Somewhat clunky, but I
think it gets what you want.

It’s based on the v.build.polylines module to connect all touching
stream reaches. First extract each order from the stream vector into
a new vector. Then build polylines. Patch them all together. Now you
have a polyline vector with a single cat value for each set of
original stream reaches that had the same order and that were touching.

Unfortunately, the v.build.polylines tool does not work as it only
does not connect multiple (intersecting) lines like in a river
network. As an example I tried to build polylines from the stream
network of the NC dataset. Yous suggested approach should result that
each sub-network (i.e. river network that is not connected to another
one) should get its own ID/cat…however, v.build.polylines results
in a connected stream network that consists of multiple cats:

Maybe I misunderstood your question. The steps I tried use a
stream_order column to group stream segments, then apply a new
attribute “merged_id” to those stream orders that touch. i.e. that
connect to the same confluence point.

Here’s what I get using the nc_basic_spm mapset:

r.watershed elev=elevation accum=nc_facc drain=nc_fdir bas=nc_bas
stream=nc_str thresh=1000
r.stream.order stream_rast=nc_str direct=nc_fdir elev=elevation
accum=nc_facc stream_vect=nc_streams
ORDERS=v.db.select -c nc_streams group=strahler column=strahler
echo $ORDERS

Create a new stream vector for each stream order

for o in $ORDERS; do

v.extract input=nc_streams output=streams_${o} where=“strahler=${o}”

Give each polyline it’s own cat value

v.build.polylines input=streams_${o} output=streams_${o}_polyline
type=line cat=first

done

patch the stream orders back together

POLYLINES=g.list vect pattern="streams*polyline" separator=comma

v.patch input=$POLYLINES output=streams_polylines

v.db.addcolumn map=streams column=“merged_id INTEGER”

And use v.distance to update that merged_id column from cat values

in polylines vector
v.distance from=streams to=streams_polylines upload=cat column=merged_id
v.db.addcolumn map=nc_streams column=“merged_id INTEGER”
v.distance from=nc_streams to=streams_polylines upload=cat
column=merged_id

Now, all stream reaches that have the same order and are “touching”
have the same merged_id. See the attached image.

If that’s not your purpose, then just ignore…

Micha thank you for your help and of course, you’re fully correct!
Merging lines that belong to the same stream order works in this case
well…but this is because of the definition of the Strahler ordering
system, where there is only one “touching node” (i.e. river junction) of
two rivers of the same stream order (i.e. when two 2nd order streams
meet, the become a 3rd order stream). Thus your solution works because
of this specifics and might not work if streams are grouped based on a
different (ordering) system.

I was already thinking of the next step (beyond simple Strahler): As
mentioned in my initial post I am dealing with “some kind” of stream
order. It is similar to grouped stream orders (e.g. stream order 1-2 =
“headwater streams”). I tried to somehow reproduce my situation based on
your example of the NC dataset. What I basically did was to reassign a
new stream order “99” to all former 1st and 2nd order streams. Then I
did exactly what you did in your example, and of course I don’t unique
merged_ids for the subnetworks of touching lines (see attached Figs)
that all belong the the same “order” 99 (the original strahler order 3
works of course, see Fig.)…So is there a more general way (as said
something like v.dissolve but for lines/networks?):

#####################
g.region raster=elevation

r.watershed --o elev=elevation accum=nc_facc drain=nc_fdir bas=nc_bas
stream=nc_str thresh=1000
r.stream.order stream_rast=nc_str direct=nc_fdir elev=elevation
accum=nc_facc stream_vect=nc_streams

#ORDERS=v.db.select -c nc_streams group=strahler column=strahler
#echo $ORDERS

Regroup orders 1-2 (to 99)

v.db.addcolumn map=nc_streams@test2 columns=“strahler_groups INTEGER”
v.db.update map=nc_streams column=strahler_groups query_column=strahler
v.db.update map=nc_streams column=strahler_groups value=99
where=“strahler=1 OR strahler=2”

NEWORDERS=v.db.select -c nc_streams group=strahler_groups column=strahler_groups
echo $NEWORDERS

Create a new stream vector for each stream order

for o in $NEWORDERS; do
v.extract input=nc_streams output=streams_${o}
where=“strahler_groups=${o}”

Give each polyline it’s own cat value

v.build.polylines input=streams_${o} output=streams_${o}_polyline
type=line cat=first
done

d.vect -c map=streams_99_polyline@test2
#################

Thank you very much!

Cheers,

Johannes

v.clean --overwrite input=streams@PERMANENT output=streams_break
tool=break
v.build.polylines --overwrite input=streams_break@test
output=streams_poly cats=first type=line
d.vect -c map=streams_poly

So what would be needed here is some kind of tool that connects all
touching lines and assigns a common category value, similar to the
v.dissolve tool for polygon features. I can imagine that such a task
might be not that uncommon also in another context? Any suggestions
how to achieve this in GRASS?

A workaround that came into my mind was to create buffers around
lines in order to make areas out of lines. Subsequently these
touching areas can be merged using v.dissolve and the information
about the common category can be queried using v.distance.
Nevertheless, a rather cumbersome way to just assign a common
category value to all lines that are touching…

Any further ideas?

cheers,

Johannes

Cheers,
Johannes


grass-user mailing list
grass-user@lists.osgeo.org mailto:[grass-user@lists.osgeo.org](mailto:grass-user@lists.osgeo.org)
https://lists.osgeo.org/mailman/listinfo/grass-user


grass-user mailing list
grass-user@lists.osgeo.org
https://lists.osgeo.org/mailman/listinfo/grass-user