[GRASS-user] Pygrass vector package: write geometric feature in a specific layer

Hello all,

I’m writing a GRASS module with pygrass to import data from a text file into a new vector map.
Those data have topological relationships: they are nodes and links of a sewer network. But those objects may have different types of attributes. For example a link could be a pipe or a pump.

Therefore I think that the use of vector layers is the right way to store those data.

With pygrass I managed to set DB links and import the attributes in different tables.
But the only way I’ve found to change the layer of geometric features is with .open(mode=‘w’, layer=X). This works well for one layer, but I’ve to write different objects in different layers.

I tried to close the map and re-open it with another layer, but if I pass mode=‘rw’, the map refuse to open because the layer not yet exist, and with mode=‘w’, it overwrite the existing map.

I know there is a way to create a new map for each layer and then use existing GRASS modules to “merge” them into a single map, but I feel that this is overly complex.

So my question is: Is there a way to decide which layer to write new objects, and change this layer during the import process?

I’m using grass70-svn with the following version of libgis:
libgis Revision: 62395
libgis Date: 2014-10-26 18:17:27

Thanks for you help.

Regards,

Laurent

Hi Laurent,

On Tue, Dec 2, 2014 at 4:41 PM, Laurent C. <lrntct@gmail.com> wrote:

With pygrass I managed to set DB links and import the attributes in
different tables.
But the only way I've found to change the layer of geometric features is
with .open(mode='w', layer=X). This works well for one layer, but I've to
write different objects in different layers.
I tried to close the map and re-open it with another layer, but if I pass
mode='rw', the map refuse to open because the layer not yet exist, and with
mode='w', it overwrite the existing map.

I didn't have the need to do this, so far, so probably I should
rewrite the write method to make it easier.
The first time that you open the map, you should create links and
table and save the link between the vector map and these tables, so
something like (note: this is pseudo-code, not tested! so use it as a
draft idea):

{{{
with VectorTopo('mymap', mode='w', overwrite=True) as vct:
    # create links
    lpipes = Link(layer=1, name='pipes', table=vct.name + 'pipes', key='cat')
    lpumps = Link(layer=2, name='pumps', table=vct.name + 'pumps', key='cat')

    # add the links to the vector map
    if lpipes not in vct.dblinks:
        vct.dblinks.add(lpipes)
    if lpumps not in vct.dblinks:
        vct.dblinks.add(lpumps)

    # create tables removing them if already created
    tpipes = lpipes.table()
    if tpipes.exist():
        tpipes.drop(force=True)
    tpipes.create([('cat', 'PRIMARY KEY'), ('col1', 'VARCHAR(8)'), etc...])
    tpumps = lpumps.table()
    if tpumps.exist():
        tpumps.drop(force=True)
    tpumps.create([('cat', 'PRIMARY KEY'), ('col1', 'VARCHAR(8)'), etc...])

    # write your pipes
    vct.table = tpipes
    for pipe, pipeattr in zip(pipes, pipesattrs):
        vct.write(pipe, attrs=pipeattr)

    # write the pumps
    vct.table = tpumps
    for pump, pumpattr in zip(pumps, pumpattrs):
        # you have to set the category for the second layer
        cats = Cats(pump.c_cats)
        cats.reset()
        cats.set(vct.nlines + 1, lpumps.layer)
        # finally write the pump
        vct.write(pump, attrs=pumpattr, set_cats=False)

}}}

On Wed, Dec 3, 2014 at 7:28 AM, Pietro <peter.zamb@gmail.com> wrote:

Hi Laurent,

On Tue, Dec 2, 2014 at 4:41 PM, Laurent C. <lrntct@gmail.com> wrote:

With pygrass I managed to set DB links and import the attributes in
different tables.
But the only way I've found to change the layer of geometric features is
with .open(mode='w', layer=X). This works well for one layer, but I've to
write different objects in different layers.
I tried to close the map and re-open it with another layer, but if I pass
mode='rw', the map refuse to open because the layer not yet exist, and with
mode='w', it overwrite the existing map.

I didn't have the need to do this, so far, so probably I should
rewrite the write method to make it easier.
The first time that you open the map, you should create links and
table and save the link between the vector map and these tables, so
something like (note: this is pseudo-code, not tested! so use it as a
draft idea):

How can you write a single feature with multiple links to different
layers? Your example assumes one link per feature. GRASS supports M:N
mapping of vector features to attributes: several features can have
the same category, thus the same attirbutes, and one feature can have
several categories, all in one layer or distributed across several
layers.

Markus M

{{{
with VectorTopo('mymap', mode='w', overwrite=True) as vct:
    # create links
    lpipes = Link(layer=1, name='pipes', table=vct.name + 'pipes', key='cat')
    lpumps = Link(layer=2, name='pumps', table=vct.name + 'pumps', key='cat')

    # add the links to the vector map
    if lpipes not in vct.dblinks:
        vct.dblinks.add(lpipes)
    if lpumps not in vct.dblinks:
        vct.dblinks.add(lpumps)

    # create tables removing them if already created
    tpipes = lpipes.table()
    if tpipes.exist():
        tpipes.drop(force=True)
    tpipes.create([('cat', 'PRIMARY KEY'), ('col1', 'VARCHAR(8)'), etc...])
    tpumps = lpumps.table()
    if tpumps.exist():
        tpumps.drop(force=True)
    tpumps.create([('cat', 'PRIMARY KEY'), ('col1', 'VARCHAR(8)'), etc...])

    # write your pipes
    vct.table = tpipes
    for pipe, pipeattr in zip(pipes, pipesattrs):
        vct.write(pipe, attrs=pipeattr)

    # write the pumps
    vct.table = tpumps
    for pump, pumpattr in zip(pumps, pumpattrs):
        # you have to set the category for the second layer
        cats = Cats(pump.c_cats)
        cats.reset()
        cats.set(vct.nlines + 1, lpumps.layer)
        # finally write the pump
        vct.write(pump, attrs=pumpattr, set_cats=False)

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

2014-12-03 0:28 GMT-06:00 Pietro <peter.zamb@gmail.com>:

you have to set the category for the second layer

cats = Cats(pump.c_cats)
cats.reset()
cats.set(vct.nlines + 1, lpumps.layer)

finally write the pump

vct.write(pump, attrs=pumpattr, set_cats=False)

Hi Pietro,

Thanks for your answer, and for your work on pygrass.

It’s the use of Cats that I was missing. However when I tried that :

{{{
cats = Cats(new_conduit.c_cats)
cats.reset()
cats.set(new_vect_map.nlines + 1, lconduit.layer)
new_vect_map.write(new_conduit, attrs=dbline_content, set_cats=False)
}}}

I got the following error :

"cats.set(new_vect_map.nlines + 1, lconduit.layer)
AttributeError: ‘VectorTopo’ object has no attribute ‘nlines’ "

What ‘nlines’ is supposed to return?

I worked around by using a int variable incremented at each object. It worked fine.

Thanks again !

Regards,

Laurent

···

2014-12-03 0:28 GMT-06:00 Pietro <peter.zamb@gmail.com>:

Hi Laurent,

On Tue, Dec 2, 2014 at 4:41 PM, Laurent C. <lrntct@gmail.com> wrote:

With pygrass I managed to set DB links and import the attributes in
different tables.
But the only way I’ve found to change the layer of geometric features is
with .open(mode=‘w’, layer=X). This works well for one layer, but I’ve to
write different objects in different layers.
I tried to close the map and re-open it with another layer, but if I pass
mode=‘rw’, the map refuse to open because the layer not yet exist, and with
mode=‘w’, it overwrite the existing map.

I didn’t have the need to do this, so far, so probably I should
rewrite the write method to make it easier.
The first time that you open the map, you should create links and
table and save the link between the vector map and these tables, so
something like (note: this is pseudo-code, not tested! so use it as a
draft idea):

{{{
with VectorTopo(‘mymap’, mode=‘w’, overwrite=True) as vct:

create links

lpipes = Link(layer=1, name=‘pipes’, table=vct.name + ‘pipes’, key=‘cat’)
lpumps = Link(layer=2, name=‘pumps’, table=vct.name + ‘pumps’, key=‘cat’)

add the links to the vector map

if lpipes not in vct.dblinks:
vct.dblinks.add(lpipes)
if lpumps not in vct.dblinks:
vct.dblinks.add(lpumps)

create tables removing them if already created

tpipes = lpipes.table()
if tpipes.exist():
tpipes.drop(force=True)
tpipes.create([(‘cat’, ‘PRIMARY KEY’), (‘col1’, ‘VARCHAR(8)’), etc…])
tpumps = lpumps.table()
if tpumps.exist():
tpumps.drop(force=True)
tpumps.create([(‘cat’, ‘PRIMARY KEY’), (‘col1’, ‘VARCHAR(8)’), etc…])

write your pipes

vct.table = tpipes
for pipe, pipeattr in zip(pipes, pipesattrs):
vct.write(pipe, attrs=pipeattr)

write the pumps

vct.table = tpumps
for pump, pumpattr in zip(pumps, pumpattrs):

you have to set the category for the second layer

cats = Cats(pump.c_cats)
cats.reset()
cats.set(vct.nlines + 1, lpumps.layer)

finally write the pump

vct.write(pump, attrs=pumpattr, set_cats=False)

}}}

Hi Laurent,

sorry for the late reply.

On Wed, Dec 3, 2014 at 10:14 PM, Laurent C. <lrntct@gmail.com> wrote:

2014-12-03 0:28 GMT-06:00 Pietro <peter.zamb@gmail.com>:

        # you have to set the category for the second layer
        cats = Cats(pump.c_cats)
        cats.reset()
        cats.set(vct.nlines + 1, lpumps.layer)
        # finally write the pump
        vct.write(pump, attrs=pumpattr, set_cats=False)

Hi Pietro,

Thanks for your answer, and for your work on pygrass.
It's the use of Cats that I was missing. However when I tried that :
{{{
cats = Cats(new_conduit.c_cats)
cats.reset()
cats.set(new_vect_map.nlines + 1, lconduit.layer)
new_vect_map.write(new_conduit, attrs=dbline_content, set_cats=False)
}}}

I got the following error :
"cats.set(new_vect_map.nlines + 1, lconduit.layer)
AttributeError: 'VectorTopo' object has no attribute 'nlines' "

the attribute name was 'n_lines' sorry for the misspelling! and it is
the counter used when writing the geometry feature, basically it does
exactly the thing that you have done manually with the new counter.
However I should change the behavior of the write method to make it
more flexible.

If you have any cleaner ideas on how you would like to interact and
write geometry features may be we can implement it.

Best regards

Pietro