[GRASS-user] Merge spatially connected features

Markus Metz markus.metz.giswork at gmail.com
Thu Mar 12 14:48:33 PDT 2020


On Thu, Mar 12, 2020 at 12:34 PM Johannes Radinger <
johannesradinger at 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 at 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 at 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 at 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 at test2
>> > #################
>> >
>> > Thank you very much!
>> >
>> > Cheers,
>> >
>> > Johannes
>> >
>> > >
>> > >> v.clean --overwrite input=streams at PERMANENT output=streams_break
>> > >> tool=break
>> > >> v.build.polylines --overwrite input=streams_break at 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 at lists.osgeo.org <mailto:grass-user at lists.osgeo.org>
>> > >>>> https://lists.osgeo.org/mailman/listinfo/grass-user
>> > >>>
>> > _______________________________________________
>> > grass-user mailing list
>> > grass-user at lists.osgeo.org
>> > https://lists.osgeo.org/mailman/listinfo/grass-user
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osgeo.org/pipermail/grass-user/attachments/20200312/6f742823/attachment-0001.html>


More information about the grass-user mailing list