OSGeo Planet

gvSIG Team: gvSIG 2.3.1, a new gvSIG version with improvements oriented to cadastre

OSGeo Planet - 7 hours 54 min ago

After publishing gvSIG 2.3 scarcely a month ago, a gvSIG version with a lot of new features, we announce a new version, gvSIG 2.3.1, with a small group of novelties oriented to make the work tasks related to cadastral information easy. This version can be downloaded from the project website.

At this way, the new plugin for GML importing and generation has been included, with INSPIRE format for Cadastre. At least in Spain, the General Management for Cadastre uses a GML format (XML with geographic contents) to describe cadastral parcels in IT field. The cadastral parcel format that has been used, achieves with the INSPIRE cadastral parcel standard defined in INSPIRE Data Specification on Cadastral Parcels – Guidelines version 3.0.1.

The current plugin for cadastral searching has been updated too, improving some usability issues.

Taking advantage of this new version, several errors that have been detected by the gvSIG community have been fixed too, therefore we encourage users to update to this version.

Finally, we remind you that all the gvSIG 2.3 documentation for users as well as for developers is available online.

Filed under: community, development, english, gvSIG Desktop Tagged: gvSIG 2.3
Categories: OSGeo Planet

gvSIG Team: gvSIG 2.3.1, nueva versión de gvSIG Desktop con mejoras orientadas al Catastro

OSGeo Planet - 8 hours 1 min ago

Tras publicar hace escasamente un mes gvSIG 2.3, una versión de gvSIG plagada de novedades, anunciamos la publicación de una nueva versión gvSIG 2.3.1, disponible para descargar desde la web del proyecto, con un pequeño conjunto de novedades y orientada principalmente a facilitar las tareas de trabajo relacionadas con el uso del información catastral.

Así, se incluye el nuevo plugin para importación y generación de GML con formato INSPIRE para Catastro. Al menos en España la Dirección General del Catastro utiliza un formato GML (XML con contenido geográfico) para describir informáticamente las parcelas catastrales. El formato de parcela catastral utilizado cumple el estándar INSPIRE cadastral parcel definido en INSPIRE Data Specification on Cadastral Parcels – Guidelines version 3.0.1.

También se ha actualizado el plugin de Búsqueda Catastral, mejorando ciertos aspectos de usabilidad.

Aprovechando la salida de esta nueva versión se han solventado algunos errores detectados por la comunidad gvSIG, por lo que animamos a los usuarios a actualizarse a esta versión.

Por último os recordamos que toda la documentación, tanto de usuario como de desarrollo, de gvSIG 2.3 está ya accesible online.

Filed under: community, development, gvSIG Desktop, spanish Tagged: gvSIG 2.3
Categories: OSGeo Planet

Free and Open Source GIS Ramblings: More icons & symbols for QGIS

OSGeo Planet - Sun, 2016-10-23 11:36

The possibility to easily share plugins with other users and discover plugins written by other community members has been a powerful feature of QGIS for many years.

The QGIS Resources Sharing plugin is meant to enable the same sharing for map design resources. It allows you to share collections of resources, including but not limited to SVGs, symbols, styles, color ramps, and processing scripts.

Using the Resource Sharing plugin is like using the Plugin Manager. Once installed, you are presented with a list of available resource collections for download. You will find that there are already some really nice collections, including nautical symbols, Mapbox Maki Icons, and my Google-like OSM road style.


By pressing Install, the resource collection is downloaded and you can have a look at the content using the Open folder button. In case of the Mapbox Maki Icon collection, it contains a folder of SVGs:


Using the new icons is as simple as opening the layer styling settings and selecting the Mapbox Maki Icons collection in the SVG group list:


Similarly, if you download the OSM Spatialite Googlemaps collection, its road line symbols are added to your existing list of available line symbols:


By pressing the Open Library button, you get to the Style Manager where you can browse through all installed symbols and delete, rename, or categorize them.


The Resource Sharing plugin was developed by Akbar Gumbira during this year’s Google Summer of Code. The full documentation, including instructions for how to share your own symbols with the community, is available at www.akbargumbira.com/qgis_resources_sharing.

Categories: OSGeo Planet

From GIS to Remote Sensing: Minor Update: Semi-Automatic Classification Plugin v. 5.1.5

OSGeo Planet - Sat, 2016-10-22 10:15
This post is about a minor update for the Semi-Automatic Classification Plugin for QGIS, version 5.1.5.

Following the changelog:-added option for maximum result number in Landsat, Sentinel-2, and ASTER
Categories: OSGeo Planet

gvSIG Team: ¿Quieres saber cómo puedes contribuir con tus desarrollos en gvSIG?

OSGeo Planet - Fri, 2016-10-21 12:41


Está disponible la documentación que indica la forma de contribución al desarrollo de gvSIG. Si estás desarrollando sobre gvSIG y quieres que tú trabajo esté accesible para toda la comunidad te recomendamos que te leas esta guía:


Más allá de la aportación de parches al código, básicamente hay dos modos de contribuir con un plugin, y desde ya te recomendamos que siempre empieces por el primero -muy simple- y a partir de ahí puedas ir profundizando en la “calidad” de las contribuciones.

El modo más simple es el que etiquetamos como plugins de la “comunidad”. Tú aporte estará disponible desde el “Administrador de complementos” (por instalación desde URL). Simplemente quieres compartir tú desarrollo…y lo compartes.

Y a partir de ahí puedes plantearte que el plugin se etiquete como “oficial”. Aquí ya hay unas exigencias o requisitos a cumplir, que en función del grado en que se aborden conllevan a su vez a una serie de compromisos por nuestra parte en cuanto a evolución y mantenimiento del plugin aportado.

En cualquier caso, la regla principal que todos los desarrolladores de gvSIG deben tener en mente es: “Lo que no compartes, se pierde”.

Filed under: community, development, gvSIG Desktop, spanish Tagged: complementos, contribuciones, desarrollo, documentación, plugins
Categories: OSGeo Planet

Paul Ramsey: Geomatiqué 2016 Keynote

OSGeo Planet - Fri, 2016-10-21 09:05

This week I had the pleasure of presenting the morning keynote at Geomatiqué 2016 in Montreal. I’ve been thinking a lot recently about symbiosis of technology and culture: how new technology is generating new norms to go along with it. We humans are enormously adaptable, so princples that were sacrosanct to one generation become unknown to the next, and back again.

Geomatiqué 2016 Keynote

On the chopping block for our generation: privacy.

Not that privacy is any human absolute. I doubt a hunter gatherer had a lot of personal space and privacy: the smaller the group, the more fevered the gossip-mill. On the other hand, the abolition of privacy within the context of an industrial-sized polity will truly be something new under the sun. It could be fine, in its way; it could also be Nineteen Eighty-Four realized.

Anyways, the talk is mostly a survey of technology trends, with some philosophizing at the end. Unfortunately, no video at this event, but if you’d like me to deliver this talk to your organization, drop me a line.

Categories: OSGeo Planet

GIS for Thought: Crowdsourced City Extents

OSGeo Planet - Thu, 2016-10-20 08:00

Following up from my Glasgow Regions Mapped Update.

Alasdair Rae recently started a crowdsourcing project for four cities in the UK: London, Birmingham, Manchester, and Glasgow. Original page. Write up of the results. The post was however very popular and resulted in responses from around the world.

Since the project was created with the excellent code from Nick Martinelli, the data can be downloaded by anyone.

So I created a breakdown of the number of responses in 1 km grids for each city that received at least 5 responses.

The full album, ordered by country name and then city name can be found:


Highlights Glasgow

The west end is the true Glasgow.


Very inclusive.


Much larger and inclusive than Manchester.


The M25 provides a very handy limiting barrier.


Far reaching urban sprawl.

New York

Probably some selection bias, with crowd sourcing more popular in Brooklyn.



All cities.

Categories: OSGeo Planet

Jackie Ng: Announcing: mapguide-react-layout 0.6.1

OSGeo Planet - Wed, 2016-10-19 12:14
This is a quick release to fix the viewer so that it can load maps that contain raster layers.

Categories: OSGeo Planet

gvSIG Team: Retransmisión en directo de las 8as Jornadas de Latinoamérica y Caribe de gvSIG

OSGeo Planet - Wed, 2016-10-19 07:31

Las sesiones de ponencias de las 8as Jornadas de Latinoamérica y Caribe de gvSIG, que se celebrarán mañana día 20 de octubre en Montevideo (Uruguay), van a ser retransmitidas en directo a través de internet.

La retransmisión se realizará a través del portal de Vera tv desde el siguiente enlace directo.


Podéis consultar toda la información sobre el programa en la web de las jornadas.

Si no podéis acudir podréis seguir las presentaciones en directo.

Y si deseáis acudir, y aún no os habéis registrado, podéis hacerlo desde el mismo portal del evento. Hay aforo limitado. ¡No esperéis al final!


Filed under: community, events, spanish Tagged: 8as Jornadas LAC
Categories: OSGeo Planet

gvSIG Team: Extensión de GML Catastro: Importa y genera un GML INSPIRE que pase la Validación

OSGeo Planet - Tue, 2016-10-18 09:01

Desde la Asociación gvSIG hemos realizado un desarrollo que os puede interesar alrededor del nuevo uso de GML INSPIRE en el Catastro.

El objetivo de la extensión es el poder generar ficheros GML INSPIRE que puedan pasar la Validación Gráfica Alternativa en la Sede Electrónica del Catastro.

Para ello hemos creado la extensión “GMLCatastro” que nos permitirá esto y más.

Funcionalidades y características
  • El único requisito que tienen que cumplir estar parcelas antes de ser exportadas es de al menos contener dos campos localId y nameSpace. Donde localId debe de ser un nombre diferente para cada parcela, o el de la Ref Catastral para parcelas ya existentes. El campo nameSpace se asignará automáticamente al exportarlo para parcelas de nueva creación.
  • Importar ficheros DXF de descarga masiva del Catastro o Municipios completos, asignándoles su correspondiente Referencia Catastral, dejando las parcelas listas para trabajar y en formato correcto para su exportación.


  • Herramienta de Extraer Parcelas de capas como la anterior, quedando en formato localId y nameSpace en su Tabla de Atributos. Tiene de objetivo generar capas que puedan luego ser exportadas a GML.


  • No es una característica exclusiva de esta extensión, pero recordar que podremos hacer uso de todas las herramientas de Edición de geometrías y Snapping



  • Exportador a GML INSPIRE integrado en el exportador de gvSIG, ya sea de una o varias parcelas, seleccionadas o todas las de la capa. La herramientas de Exportación se encuentra al hacer click derecho – Exportar sobre cualquier capa seleccionada en nuestra Vista.


  • Detección automática en la exportación de duplicados en el campo localId que generarían un Negativo en la validación. Nos ofrece la posibilidad automáticamente de generar un identificador único.
  • Soporte de geometrías usadas en el Catastro: Multipolígonos con parcelas separadas, huecos internos, etc.
  • Posibilidad de abrir ficheros GML INSPIRE y Extraerlos en el formato comentado anteriormente preparado para su edición.
  • Creación de un fichero por parcela.
  • Manual PDF integrado en gvSIG con los pasos a seguir desde la Descarga del Catastro, su edición en gvSIG, hasta su subida para la Validación. Podéis descargarlo de aquí para echarle un vistazo.


En resumen, generación de ficheros GML INSPIRE que pasen la validación:


Guía rápida

Para su instalación será necesario:

  • Disponer de gvSIG 2.3
  • Descargar la extensión “GMLCatastro” desde el Administrador de Complementos (por ahora disponible en el repositorio remoto, próximamente vendrá con la instalación). Instalar y reiniciar gvSIG.


Para acceder a la herramienta presionar sobre el siguiente icono una vez tengamos una Vista abierta:


La herramienta de Exportar ya se encontrará integrada en gvSIG, teniendo que hacer click derecho sobre una capa y seleccionando Exportar.

Lo principal a tener en cuenta es:

  • Una Vista con la proyección a usar
  • Una capa de polígonos con los campos localId y nameSpace

Para ver su uso general os animo a visualizar el siguiente vídeo, es un resumen del uso de la aplicación (activar los subtítulos para ver los comentarios):

Además recordar que también tenemos otros desarrollos como el Buscador de Referencias Catastrales.


Para concluir solo añadir que esta herramienta se encuentra en desarrollo, esperamos aumentar su funcionalidad y desarrollo del manual. Cualquier aportación sobre errores que encontréis o mejoras que os puedan ser útiles durante el uso de la herramienta será bien recibida, os podéis poner en contacto con nosotros en las Listas de Usuarios o Desarrolladores o comentar en este mismo post.

Filed under: gvSIG Desktop, spanish
Categories: OSGeo Planet

gvSIG Team: ¿Cómo crear tú propia versión de gvSIG portable?

OSGeo Planet - Mon, 2016-10-17 12:41


A través de la lista de usuarios de gvSIG se nos ha solicitado la posibilidad de hacer una versión portable de gvSIG Desktop más ligera, con menos extensiones. En determinados casos esto puede ser muy útil, ya que cualquier extensión está siempre disponible para instalar por el administrador de complementos con conexión a Internet; en otros casos, sin embargo, puede haber usuarios con dificultades para tener acceso a la red y, por ello, prefieren una versión más completa -como la que actualmente hay disponible para descargar en la web del proyecto-. La decisión de definir qué extensiones debe tener una portable puede ser muy variada, pues al fin y al cabo depende de las necesidades de cada usuario.

Por eso creo que puede ser interesante un post que nos indique los pasos a seguir para generar nuestra propia portable, aligerando si se necesita la versión actual.

– ¿Fácil?

– Muy, muy fácil.

Tan fácil como borrar todo aquello que no necesitemos.

¿Y qué podemos borrar?

Básicamente 3 cosas:

  • Extensiones instaladas por defecto.
  • Extensiones no instaladas pero disponibles en la distribución.
  • Bibliotecas de símbolos.

Partimos de que hemos descargado la versión de gvSIG Portable para Ubuntu, la hemos descomprimido y ahora queremos eliminar aquello “que nos sobra”. Los pasos son similares para cualquier portable, tan sólo cambia el nombre de la carpeta inicial que en este caso es “gvSIG-desktop-2.3.0-2447-final-lin_ubuntu_16.04-x86_64” y, por ejemplo, para windows 64 bits sería “gvSIG-desktop-2.3.0-2447-final-win-x86_64“.

Vamos a ver dónde podemos borrar:

Extensiones instaladas por defecto

En este post vamos a partir de la última versión publicada de gvSIG (gvSIG 2.3). Aparecen ubicadas en la carpeta:


Borra todas aquellas que no necesites (y no borres ninguna extensión básica del sistema). El nombre de las carpetas permite identificar con facilidad la funcionalidad del plugin. Por ejemplo, podría borrar carpetas como “org.gvsig.busquedacatastral.app.mainplugin” (que es un buscador de Catastro para España), o la carpeta “org.gvsig.seismic.app.mainplugin” (que permite cargar formatos de sísmica) o “org.gvsig.animation3d.app” (que permite generar animaciones 3D). Uno de los paquetes más pesados es el de “org.gvsig.r.app.mainplugin” que contiene la librería estadística “R”…si no la necesitas, es la carpeta que debes borrar.

Extensiones no instaladas pero disponibles en la distribución

En toda distribución de gvSIG hay varias extensiones que no vienen instaladas por defecto, pero que se pueden instalar desde el “Administrador de complementos” sin conexión a Internet. Estas extensiones se pueden encontrar en la carpeta:


Aquí podemos borrar las extensiones que no vayamos a necesitar que estén disponibles en nuestra portable…incluso todas.

Bibliotecas de símbolos

Las bibliotecas de símbolos se encuentran en la carpeta:


Si queremos dejar la simbología mínima podemos borrar todas las carpetas menos la de “gvSIG Basic” o bien dejar aquellas que nos interesen y borrar el resto.

Una vez finalizado el borrado comprimimos en un zip la carpeta de gvSIG (en el ejemplo “gvSIG-desktop-2.3.0-2447-final-lin_ubuntu_16.04-x86_64”) y ya tenemos nuestro gvSIG Portable personalizado.

Filed under: gvSIG Desktop, spanish Tagged: adaptación, personalización, portable
Categories: OSGeo Planet

Jackie Ng: Announcing: mapguide-react-layout 0.6

OSGeo Planet - Mon, 2016-10-17 11:59
Previously, I mentioned a series of blocking issues (in the process of porting over the Aqua Fusion template) that I needed to clear before I can safely put out a new release of mapguide-react-layout. Well, those roadblocks have been cleared, so here's a new release.

Here's a summary of the cool stuff since the first official release.

Aqua Template

The first of 5 fusion templates have been ported across.

Here's how the road blocks were cleared

1. Task Pane / Selection Panel / Legend does not play nice with Modal Dialogs

It turns out that all we really needed to do was have each modal dialog containee component support the notion of a maximum height and overflow:scroll its inner content if that height is exceeded. As these modal dialogs are of a known height, we know what max height that will have to be applied to each top-level component that is to be housed inside a modal dialog

2. We sort of need InvokeScript support as that is what the original templates use to show the Task Pane / Selection Panel / Legend / etc. 

I've decided to nip this one in the bud and just hard code into the template 3 toggling buttons that you can see on the top-right hand corner of the screenshot. If you close any of the affected modals, you can hit the respective button to bring it back.

3. Flyout menus don't play nice either

This one looked to be hard, but thankfully the react-flyout component I've chosen allowed for my workaround to (ahem) work with minimal amount of legwork.

The key was to introduce a new top-level FlyoutRegion component which all flyout menus render into (regardless of what toolbar they come from). As this FlyoutRegion component is top-level, the flyout menus rendered inside do not have a direct parent-child relationship with the toggling button (from whatever toolbar it may originate from), therefore it is not subject to being caught up in any toolbar CSS overflow shenanigans.

The only catch with this is that all the flyout menus will always render to the top left corner (I'm guessing this wasn't a usage scenario envisioned by the react-flyout author). So as a minor hack I've introduced new redux actions to dispatch the opening/closing of flyout menus, which the FlyoutRegion listens on, and the flyout menu buttons dispatch such actions when clicked, also flowing back DOM element dimensions (of the toggling button), so the listening FlyoutRegion component knows exactly where to position the flyout menu to be rendered.

This isn't perfect, as this animation shows

But it's a small (and acceptable) price to pay for what is now mostly functional flyout menus.

Application Definition (aka. Flexible Layout) support

As porting across the Aqua template would imply, the viewer now accepts Application Definition resource ids in addition to Web Layout resource ids. Please note that currently only certain templates can accept Web Layouts and others only accept Application Definitions. You can find out which template supports what in this document.

This support is not 100% yet, and so you will invariably find error placeholders for un-implemented widgets strewn across various toolbars and menus like so.

If you hover your mouse over these items, you can see what the viewer currently doesn't support or map across yet.

So when you encounter such buttons, the only practical thing to do at the moment is to remove such buttons from your Application Definition. The error placeholder mechanism is a nice and easy way to identify such unsupported elements.

If your Application Definition has external base layers defined, this release will recognize the following base layer types:

  • OpenStreetMap: Mapnik/CycleMap/TransportMap
  • Stamen: Toner/Terrain/Watercolor

Better Startup

The initial release of mapguide-react-layout wasn't really graceful about any errors that occur during the process of initialization. All you had was a white screen of nothingness to tell you that something went wrong. So naturally in the interest of providing a good out-of-the-box experience, this was something that needed to be rectified.

If there's a problem on startup, we'll show it to you now. For example, the MapGuide Server isn't running or reachable.

Another common silent error is loading a map with an EPSG code not known to proj4js (ie. Anything not EPSG:4326 or EPSG:3857). Now for such EPSG codes that aren't known to proj4js on startup, we'll automatically fetch the appropriate proj4js definition from https://epsg.io, register it with proj4js and continue on our merry way.

More OpenLayers goodies baked in

The base map viewer component now has these extra OL controls baked in.

An overview map

A rotation reset button that's shown when you rotate the map. You can rotate the map by holding ALT+SHIFT and dragging the map to rotate it.

And lots more!

All is covered in the associated release notes for this release.

Categories: OSGeo Planet

gvSIG Team: Some improvements in access data in gvSIG 2.4

OSGeo Planet - Mon, 2016-10-17 09:48

Hi everyone

I’m going to talk a few things about data access that has changed in the new version 2.4 (some of them already appeared in the 2.3, but now are consolidated in 2.4)

At first, they are changes that shouldn’t affect on the already existing developments, because all of them are about improvements or additions over the old versions.

I’m going to talk about:

  • Automatic dispose of resources when we hit the end in an iteration over a FeatureSet.
  • Obtain a “List” with the features of one “store”, with a filter or without it.
  • Create a layer with the filtered data of one table.
  • Create a filter for a DB that will be independent from itself.

We are going to be seeing this things.

Dispose of resources in a FeatureSet.

This feature already appear in the last builds of gvSIG 2.3. In several classes of the DAL library, it was given support to the Java interface ”Iterable”. This allow us to build code in more comfortable way. Instead of:

try { FeatureSet set = store.getFeatureSet(); Iterator it = set.iterator(); while( it.hasNext() ) { Feature feature = (Feature) it.next(); ... } } finally { DisposeUtils.disposeQuietly(it); DisposeUtils.disposeQuietly(set); }

Now we could make something like this:

for(Feature feature : store.getFeatureSet() ) { ... }

In this way, the resources associated to the iterator and the set are disposed automatically when it reaches the end of the iteration. To do this, what has be done is when it’s called the method hasNext from the iterator and has been reached the end of the iteration, inside of this method the resources are disposed.

We should be careful with this code constructions when we are going to exit the loop before to reach the end of the iteration, with a break or a returrn,

Obtain a “List” of features

This feature also appeared in the last builds of gvSIG 2.3. It has been added the following methods to the FeatureStore:

public List<Feature> getFeatures(FeatureQuery query, int pageSize); public List<Feature> getFeatures();

Until now, the only way to access to the store featuers was through the method getFeatureSet and then iterating over them. With the addition of this two methods now we can obtain directly a ”List” of features, allowing us to a random access over the store features. We should be careful with the use of this method. To obtain this list of features we use FeaturePagingHelper, so we don’t load all the features in memory. It uses a “paging” (size by default 500 elements) and the pages are being loaded and unloaded automatically depending on how they are being requested from the interface ”List”. A real random access over all the list could lead to an overflow in the data access and a significant loss of performance. This method is designed to give support to show results of a search over the user data, for example in a JList or JTable, since is relatively easy create a TableModel or a ListModel based on a “List<Feature>”. Usually the performance of a JTable and a JList will be acceptable even with a hundred of thousands of records.

An important consideration. Once is obtained a ”List”, if we try to edit or end the edition through the store from where it has been obtained it, it can produce some errors. In the 2.4 version we should not change the edition mode of a store once we have obtained a ”List”. We will try to fix this issue in future releases.

Create a layer with the filtered data of one table

This is not a truly improvement in the data access library, but because in some way is related to the data access and a interesting improvement, that’s why I’m going to explain it here.

It has been added to the VectorLayer interface this methods:

public FeatureQuery getBaseQuery(); public void addBaseFilter(Evaluator filter); public void addBaseFilter(String filter);

The addBaseFilter methods allow us to add a filter that will be applied when it’s needed to obtain a FeatureSet used for drawing layer elements.

This allow us with an easy way through code to add filtered information from layers to a view that is going to be visualize. Starting with the same table is possible to have different layers with different data visualizations.

Create a filter for a DB that will be independent from itself.

I’m going to take more time explaining this topic, because in my experience, usually it takes time to understand.

The way to filter data in gvSIG 2 is through the ”addFilter” method or a ”setFilter” from a ”FeatureQuery”. A filter is a class that the interface ”Evaluator” has implemented.

Suppose that we have a table with a geometry field and we want filter the features with lines that intersects with a given area.

The implementation should be something like this:

public class IntersectsGeometryEvaluator extends AbstractEvaluator { private String geometryColumnName; private Geometry areaOfInterest; IntersectsGeometryEvaluator(Geometry areaOfInterest, String geometryColumnName) { this.areaOfInterest = areaOfInterest; this.geometryColumnName = geometryColumnName; } @Override public Object evaluate(EvaluatorData data) throws EvaluatorException { try { Geometry geometryColumn = (Geometry) data.getDataValue(geometryColumnName); if (geometryColumn == null) { return false; } return geometryColumn.intersects(this.areaOfInterest); } catch (Exception e) { return false; } } @Override public String getName() { return "intersects with geometry"; } } ... Geometry areaOfInterest = ... FeatureQuery query = store.createFeatureQuery(); query.setFilter(new IntersectsGeometryEvaluator(areaOfInterest,"the_geom")); FeatureSet set = store.getFeatureSet(query); ...

Thereby we would obtain a set of features filtered with the condition that we are interested.

Even that this works with all data sources (shapes, dxf or DB tables), it wouldn’t be optimal for a DB. If we let the code like that, it will get all the table records associated with the store, bring them to local and filter them in local. If the table is big and the DB has support for spatial indexes, this will be very inefficient.

How should we do it ?

The ”Evaluator” interface has a method called ”getSQL”. In the example, we didn’t implement it. This method should return the ”where” part of the ”SQL” clause that do something similar to our Java code. It’s not precisely that they are identical, but at least it should return the same or more records (never less) than our Java code filter. When we apply this filter over a data source that supports SQL conditions like ”where”, the data access library will take care of it and return this records. If the filter is applied over a data source that doesn’t have support for it, for example a shape file, the parameter returned from ”getSQL” it will be ignored. If it supports a SQL type filter, the data access library will create a query from the DB with this condition and then will filter the obtained records with our evaluator. With this way to work, it will be not necessary get all the table data records and we will keep available all the filter potential from our Java code.

We could have a ”getSQL” method like this:

@Override public String getSQL() { return MessageFormat.format( "ST_intersects( ST_GeomFromText(''{0}'',{1}), {2} )", this.areaOfInterest.convertToWKT(), this.srsid, this.geometryColumnName ); }

This method will return the condition part that we will put in the ”where” clause. It will allow us filter it with the interested condition.

If we take a closer look we could find a few problems..

  • We need a“srsid” to rebuild the geometry from the DB server starting with aWKT. This shouldn’t be big a problem, we just have to set our evaluator in which projection are our geometries. Usually we will use a IProjection object, this object is the usual return from any artifact in gvSIG when we ask for a projection. Here we required the data base SRS identifier, not a projection object.
  • The syntax used to make to query is so OGC.. What if the DB that we are accessing doesn’t accept this type of syntax?

To solve this problems in gvSIG 2.4 it has been introduced the concept of ”ExpressionBuilder” linked to a data source FeatureStore. We can ask to the store, with whitch we are working, for a ”ExpressionBuilder” appropriate for itself and use it to create the condition that we need. Let see an example:

public class IntersectsGeometryEvaluator extends AbstractEvaluator { private String geometryColumnName; private Geometry areaOfInterest; private IProjection projection; private ExpressionBuilder builder; IntersectsGeometryEvaluator( Geometry areaOfInterest, String geometryColumnName, IProjection projection, ExpressionBuilder builder ) { this.areaOfInterest = areaOfInterest; this.geometryColumnName = geometryColumnName; this.proyeccion = projection; this.builder = builder; } @Override public Object evaluate(EvaluatorData data) throws EvaluatorException { try { Geometry geometryColumn = (Geometry) data.getDataValue(geometryColumnName); if (geometryColumn == null) { return false; } return geometryColumn.intersects(this.areaOfInterest); } catch (Exception e) { return false; } } @Override public String getName() { return "intersects with geometry"; } @Override public String getSQL() { String condition = this.builder.set( this.builder.ST_Intersects( this.builder.geometry(this.areaOfInterest, this.projection), this.builder.column(this.geometryColumnName) ) ).toString(); return condition; } } ... Geometry areaOfInterest = ... FeatureQuery query = store.createFeatureQuery(); query.setFilter(new IntersectsGeometryEvaluator( areaOfInterest, "the_geom", projection, store.createExpressionBuilder() ) ); FeatureSet set = store.getFeatureSet(query); ...

I’m going to explain the changes..

First of all, our evaluator, in addition to receive a geometry with an area on which we want the filter, and the column name which we want to filter, it will receive an object “Iprojection” with the projection in which are our geometries, and a ”ExpressionBuilder” that we have obtained through the ”store” that we are working with. We will save this new two parameters in our class properties like we did with the previous two parameters. The rest of the changes are already in the ”getSQL” method. Now there isn’t SQL code in our method. Instead it’s called a builder to build the SQL code. This builder will take care of:

this.builder.geometry(this.areaOfInterest, this.projection)

.. build this SQL code necessary for our geometry with its projection in our format, to be translated correctly to the format of the DB associated with the store that we are working with. We shouldn’t be worried about its type, WKT or some other format, or if the IProjection has this or other code in this DB. The builder will take care of it for us. The same as it take care to translate:

this.builder.ST_Intersects( this.builder.column("a") this.builder.column("b") )

to the appropriate syntax for our DB. For example. If we are working over a PostgreSQL+PostGIS, it will generate something like:


But If our “store” is stored in a SQLServer data base, it will generate something like:


It will take care of this job and letting our code free to handle different SQL dialects.

(Thanks to Oscar for the translation)


Filed under: gvSIG Desktop
Categories: OSGeo Planet

gvSIG Team: Algunas mejoras en el acceso a datos en gvSIG 2.4

OSGeo Planet - Mon, 2016-10-17 09:42

(English version here)

Hola a todos.
Voy a comentar sobre dos o tres cosas que han cambiado en el acceso a datos en la versión 2.4 (alguna ya apareció en la 2.3, pero se consolidan en la versión 2.4).

En principio son cambios que no deberían afectar a los desarrollos ya existentes ya que en general se tratan de mejoras o adiciones sobre lo que ya había en versiones anteriores.

Voy a contar sobre:

  • Liberación de recursos automaticamente al llegar al final de  una iteración sobre un FeatureSet.
  • Obtener un “List” con las features de un “store”, filtrando o  sin filtrar.
  • Crear una capa con los datos de una tabla filtrados.
  • Crear un filtro para BBDD que sea independiente de esta.

Vamos a ir viendo estas cosas.

Liberación de recursos de un FeatureSet.

Esta funcionalidad ya apareció en los últimos builds de gvSIG 2.3. En varias clases de la librería de DAL se dio soporte al interface de java “Iterable”. Esto permite realizar construcciones de código mas cómodas. En lugar de tener que hacer:

  try {     FeatureSet set = store.getFeatureSet();     Iterator it = set.iterator();     while( it.hasNext() ) {       Feature feature = (Feature) it.next();       ...     }   } finally {     DisposeUtils.disposeQuietly(it);     DisposeUtils.disposeQuietly(set);   }

Ahora podríamos hacer algo como:

  for(Feature feature : store.getFeatureSet() ) {     ...   }

De forma que los recursos asociados al iterador y al set se liberarán de forma automatica al llegar al final de la iteración. Para hacer esto lo que se ha hecho es que cuando se ejecuta el método hasNext del iterador, y se ha alcanzado el final de la iteración, dentro de este método se liberan los recursos automaticamente.

Tendremos que tener cuidado con estas construcciones cuando vayamos a salir del bucle  antes de llegar al final de la iteración, con un break o un return, siendo recomendable seguir utilizando para esos casos la forma de acceso anterior.

Obtener un “List” de features

Esta funcionalidad también apareció en los últimos builds de gvSIG 2.3. Se han añadido los siguientes métodos al FeatureStore:

  public List<Feature> getFeatures(FeatureQuery query, int pageSize);   public List<Feature> getFeatures();

Hasta ahora la única forma de acceder a las features de un store era a través del método getFeatureSet, y luego iterando sobre ellas. Con la introducción de estos dos métodos podemos obtener un “List” de features directamente permitiéndonos un acceso aleatorio sobre las features de un store. Hay que tener cuidado al usar este método. Para obtener la lista de features se utiliza un FeaturePagingHelper, de forma que no se cargan en memoria todas las features del store. Se utiliza un “paginado” (por defecto de 500 elementos) y se van cargando y descargando paginas automaticamente según se van solicitando estas a través del interface de “List”. Un acceso aleatorio real sobre la lista puede llevar a una sobrecarga en el acceso a datos y una perdida de rendimiento considerable. Este método esta pensado para dar un soporte a mostrar el resultado de una búsqueda sobre datos al usuario, por ejemplo en un JList o un JTable, ya que es relativamente simple crear un TableModel o un ListModel basado en un “List<Feature>”. Normalmente los rendimientos del JTable y JList serán aceptables aun con unos cientos de miles de registros.

Una consideración importante. Si una vez obtenido el “List” intentamos entrar en edición o terminar edición en el store a partir del que lo hemos obtenido se pueden producir errores. En la versión 2.4 no debe cambiarse el modo de edición del store una vez se ha obtenido el “List”. Intentaremos subsanar este problema en próximas revisiones.

Crear una capa con los datos de una tabla filtrados.

Esto no es una mejora propiamente dicha de las librería de acceso a datos, pero como de alguna manera esta relacionado con el acceso a datos y es una mejora muy interesante lo voy a comentar aquí.

Se ha añadido al interface VectorLayer los métodos:

    public FeatureQuery getBaseQuery();     public void addBaseFilter(Evaluator filter);     public void addBaseFilter(String filter);

Los métodos addBaseFilter nos permiten añadir un filtro que sera aplicado cada vez que se precise obtener un FeatureSet para pintar los elementos de la capa.

Esto nos permite de forma cómoda añadir por código capas a una vista filtrando la información que se va a visualizar y a partir de una misma tabla tener varias capas con “vistas” distintas de los datos.

Crear un filtro para BBDD que sea independiente de esta.

Me voy a entretener un poco mas en la descripción de esto ya que mi experiencia es que suele costar entenderlo.

La forma de filtrar datos en gvSIG 2 es a través del método “addFilter” o “setFilter” de un “FeatureQuery”. Un filtro no es mas que una clase que implementa el interface   “Evaluator”. Vemos lo con un ejemplo:

Supongamos que tenemos una tabla con un campo geometría y quisiemos filtrar por las lineas de la tabla cuyo campo geometría intersecta con una determinada área.

Implementaríamos algo como:

public class  IntersectsGeometryEvaluator extends AbstractEvaluator {     private String geometryColumnName;     private Geometry areaOfInterest;     IntersectsGeometryEvaluator(Geometry areaOfInterest, String geometryColumnName) {         this.areaOfInterest = areaOfInterest;         this.geometryColumnName = geometryColumnName;     }     @Override     public Object evaluate(EvaluatorData data) throws EvaluatorException {         try {         Geometry geometryColumn = (Geometry) data.getDataValue(geometryColumnName);             if (geometryColumn == null) {                 return false;             }         return geometryColumn.intersects(this.areaOfInterest);         } catch (Exception e) {             return false;         }     }     @Override     public String getName() {         return "intersects with geometry";     } }   ...   Geometry areaOfInterest = ...   FeatureQuery query = store.createFeatureQuery();   query.setFilter(new IntersectsGeometryEvaluator(areaOfInterest,"the_geom"));   FeatureSet set = store.getFeatureSet(query);   ...

De esta forma obtendríamos un conjunto de features filtrado por la condición que nos

Ahora bien, aunque esto funcionaria con todas las fuentes de datos, shapes, dxf, o tablas en una BBDD, no seria óptimo cuando estemos atacando a una BBDD. Si lo dejamos tal cual, se traería a local todos los registros de la tabla asociada al store y los filtraría en local. Si la tabla es grande y la BBDD tiene soporta para índices espaciales, esto seria muy ineficiente.

¿ Como habría que hacerlo ?

El interface “Evaluator” tiene un método “getSQL”. En el ejemplo, no hemos implementado este método. Este método debería devolver la parte “where” de una sentencia SQL que realice una función “similar” a la de nuestro código java. No es preciso que sean idénticas, pero si que devuelva al menos los mismos o mas registros que los que filtraría nuestro código java (nunca menos). Cuando apliquemos ese filtro contra una fuente de datos que soporte condiciones tipo “where” de SQL, la librería de acceso a datos se encargara de hacérselas llegar. Si el filtro se aplica a una fuente de datos que no lo soporta, por ejemplo un shape, simplemente se ignorara el valor devuelto por “getSQL”. Si soporta el filtrado estilo SQL, la librería de acceso a datos montara la consulta a la BBDD con esa condición y luego filtrara los registros obtenidos con nuestro evaluador. De esta forma no sera necesario traerse todos los registros de la tabla y seguiremos disponiendo de toda la potencia de filtro de nuestro código java.
Podríamos tener un método “getSQL” algo como:

  @Override   public String getSQL() {       return MessageFormat.format(           "ST_intersects( ST_GeomFromText(''{0}'',{1}), {2} )",           this.areaOfInterest.convertToWKT(),           this.srsid,           this.geometryColumnName       );   }

De forma que este método nos devolvería la parte de condición que pondríamos en el “where” que nos permitiría filtrar por la condición que nos interesa.

Si nos fijamos un poco podemos observar un par de problemas…

  • Precisamos un “srsid” para reconstruir la geometría en el servidor de BBDD a partir del  WKT. Esto no debería tener grandes problemas, simplemente tendríamos que pasarle al   evaluador en que proyección están nuestras geometrías… pero lo normal es que le pasemos  un IProjection, que es lo que nos devuelve cualquier artefacto de gvSIG cuando le preguntamos  por su proyección. UUhmmm… Aquí requeriríamos el identificador de SRS de la BBDD, no un objeto proyección.
  • La sintaxis que he utilizado para realizar la consulta es muy OGC…
    ¿ Y si la BBDD a la que estamos accediendo no acepta esa sintaxis ?

Para solucionar estos problemas en gvSIG 2.4 se ha introducido el concepto de “ExpressionBuilder” ligado a una fuente de datos, un FeatureStore.
Podemos pedirle al store contra el que estamos trabajando un “ExpressionBuilder” adecuado para él, y utilizarlo para componer la condición que nos interesa. Veamos como seria en nuestro ejemplo:

public class  IntersectsGeometryEvaluator extends AbstractEvaluator {   private String geometryColumnName;   private Geometry areaOfInterest;   private IProjection projection;   private ExpressionBuilder builder;   IntersectsGeometryEvaluator(       Geometry areaOfInterest,       String geometryColumnName,       IProjection projection,       ExpressionBuilder builder     ) {       this.areaOfInterest = areaOfInterest;       this.geometryColumnName = geometryColumnName;       this.proyeccion = projection;       this.builder = builder;   }   @Override   public Object evaluate(EvaluatorData data) throws EvaluatorException {       try {         Geometry geometryColumn = (Geometry) data.getDataValue(geometryColumnName);         if (geometryColumn == null) {             return false;         }         return geometryColumn.intersects(this.areaOfInterest);       } catch (Exception e) {       return false;       }   }   @Override   public String getName() {       return "intersects with geometry";   }   @Override   public String getSQL() {     String condition = this.builder.set(         this.builder.ST_Intersects(           this.builder.geometry(this.areaOfInterest, this.projection),           this.builder.column(this.geometryColumnName)         )     ).toString();     return condition;   } }   ...   Geometry areaOfInterest = ...   FeatureQuery query = store.createFeatureQuery();   query.setFilter(new IntersectsGeometryEvaluator(         areaOfInterest,         "the_geom",         projection,         store.createExpressionBuilder()       )   );   FeatureSet set = store.getFeatureSet(query);   ...

Voy comentando los cambios…

Lo primero, nuestro evaluador, además de recibir la geometría con el área sobre la que queremos filtrar, y el nombre de la columna por la que queremos filtrar, recibirá el objeto “IProjection” con la proyección en la que están nuestras geometrías, y un “ExpressionBuilder” que habremos obtenido a partir del “store” sobre el que estamos trabajando. Estos dos nuevos parámetros nos los guardaremos en propiedades de la clase igual que hicimos con los dos anteriores. El resto de cambios están ya en el método “getSQL”. Ahora ya no hay código SQL en nuestro método. En su lugar se llama al builder para construir el código SQL. Este se encarga en:

  this.builder.geometry(this.areaOfInterest, this.projection)

De construir el código SQL necesario para que nuestra geometría con su proyección en
nuestro formato sea trasladada correctamente al formato de la BBDD asociada al store con el que estamos trabajando. No tendremos que preocuparnos de si hemos de convertir a WKT o a algún otro formato o si el IProjection tiene este o aquel código en esa BBDD. Eso ya lo hace el builder por nosotros. Igual que se encarga de trasladar:

  this.builder.ST_Intersects(     this.builder.column("a")     this.builder.column("b")   )

A la sintaxis adecuada para nuestra BBDD. Por ejemplo, si estamos trabajando sobre una
tabla de PostgreSQL+PostGIS, generaría algo como:


Pero si nuestro “store” esta almacenado en una BBDD de SQLServer generaría algo como:


Encargándose él de hacer ese trabajo, y dejando nuestro código libre de tener que encargarse de gestionar los distintos dialectos de SQL.

Filed under: gvSIG Association, gvSIG Desktop, gvSIG development, spanish
Categories: OSGeo Planet

Nyall Dawson: Speeding up your PyQGIS scripts

OSGeo Planet - Mon, 2016-10-17 04:07

I’ve recently spent some time optimising the performance of various QGIS plugins and algorithms, and I’ve noticed that there’s a few common performance traps which developers fall into when fetching features from a vector layer. In this post I’m going to explore these traps, what makes them slow, and how to avoid them.

As a bit of background, features are fetched from a vector layer in QGIS using a QgsFeatureRequest object. Common use is something like this:

request = QgsFeatureRequest() for feature in vector_layer.getFeatures(request): # do something

This code would iterate over all the features in layer. Filtering the features is done by tweaking the QgsFeatureRequest, such as:

request = QgsFeatureRequest().setFilterFid(1001) feature_1001 = next(vector_layer.getFeatures(request))

In this case calling getFeatures(request) just returns the single feature with an ID of 1001 (which is why we shortcut and use next(…) here instead of iterating over the results).

Now, here’s the trap: calling getFeatures is expensive. If you call it on a vector layer, QGIS will be required to setup an new connection to the data store (the layer provider), create some query to return data, and parse each result as it is returned from the provider. This can be slow, especially if you’re working with some type of remote layer, such as a PostGIS table over a VPN connection. This brings us to our first trap:

Trap #1: Minimise the calls to getFeatures()

A common task in PyQGIS code is to take a list of feature IDs and then request those features from the layer. A see a lot of older code which does this using something like:

for id in some_list_of_feature_ids: request = QgsFeatureRequest().setFilterFid(id) feature = next(vector_layer.getFeatures(request)) # do something with the feature

Why is this a bad idea? Well, remember that every time you call getFeatures() QGIS needs to do a whole bunch of things before it can start giving you the matching features. In this case, the code is calling getFeatures() once for every feature ID in the list. So if the list had 100 features, that means QGIS is having to create a connection to the data source, set up and prepare a query to match a single feature, wait for the provider to process that, and then finally parse the single feature result. That’s a lot of wasted processing!

If the code is rewritten to take the call to getFeatures() outside of the loop, then the result is:

request = QgsFeatureRequest().setFilterFids(some_list_of_feature_ids) for feature in vector_layer.getFeatures(request): # do something with the feature

Now there’s just a single call to getFeatures() here. QGIS optimises this request by using a single connection to the data source, preparing the query just once, and fetching the results in appropriately sized batches. The difference is huge, especially if you’re dealing with a large number of features.

Trap #2: Use QgsFeatureRequest filters appropriately

Here’s another common mistake I see in PyQGIS code. I often see this one when an author is trying to do something with all the selected features in a layer:

for feature in vector_layer.getFeatures(): if not feature.id() in vector_layer.selectedFeaturesIds(): continue # do something with the feature

What’s happening here is that the code is iterating over all the features in the layer, and then skipping over any which aren’t in the list of selected features. See the problem here? This code iterates over EVERY feature in the layer. If you’re layer has 10 million features, we are fetching every one of these from the data source, going through all the work of parsing it into a QGIS feature, and then promptly discarding it if it’s not in our list of selected features. It’s very inefficient, especially if fetching features is slow (such as when connecting to a remote database source).

Instead, this code should use the setFilterFids() method for QgsFeatureRequest:

request = QgsFeatureRequest().setFilterFids(vector_layer.selectedFeaturesIds()) for feature in vector_layer.getFeatures(request): # do something with the feature

Now, QGIS will only fetch features from the provider with matching feature IDs from the list. Instead of fetching and processing every feature in the layer, only the actual selected features will be fetched. It’s not uncommon to see operations which previously took many minutes (or hours!) drop down to a few seconds after applying this fix.

Another variant of this trap uses expressions to test the returned features:

filter_expression = QgsExpression('my_field &gt; 20') for feature in vector_layer.getFeatures(): if not filter_expression.evaluate(feature): continue # do something with the feature

Again, this code is fetching every single feature from the layer and then discarding it if it doesn’t match the “my_field > 20” filter expression. By rewriting this to:

request = QgsFeatureRequest().setFilterExpression('my_field &gt; 20') for feature in vector_layer.getFeatures(request): # do something with the feature

we hand over the bulk of the filtering to the data source itself. Recent QGIS versions intelligently translate the filter into a format which can be applied directly at the provider, meaning that any relevant indexes and other optimisations can be applied by the provider itself. In this case the rewritten code means that ONLY the features matching the ‘my_field > 20’ criteria are fetched from the provider – there’s no time wasted messing around with features we don’t need.


Trap #3: Only request values you need

The last trap I often see is that more values are requested from the layer then are actually required. Let’s take the code:

my_sum = 0 for feature in vector_layer.getFeatures(request): my_sum += feature['value']

In this case there’s no way we can optimise the filters applied, since we need to process every feature in the layer. But – this code is still inefficient. By default QGIS will fetch all the details for a feature from the provider. This includes all attribute values and the feature’s geometry. That’s a lot of processing – QGIS needs to transform the values from their original format into a format usable by QGIS, and the feature’s geometry needs to be parsed from it’s original type and rebuilt as a QgsGeometry object. In our sample code above we aren’t doing anything with the geometry, and we are only using a single attribute from the layer. By calling setFlags( QgsFeatureRequest.NoGeometry ) and setSubsetOfAttributes() we can tell QGIS that we don’t need the geometry, and we only require a single attribute’s value:

my_sum = 0 request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry).setSubsetOfAttributes(['value'], vector_layer.fields() ) for feature in vector_layer.getFeatures(request): my_sum += feature['value']

None of the unnecessary geometry parsing will occur, and only the ‘value’ attribute will be fetched and populated in the features. This cuts down both on the processing required AND the amount of data transfer between the layer’s provider and QGIS. It’s a significant improvement if you’re dealing with larger layers.


Optimising your feature requests is one of the easiest ways to speed up your PyQGIS script! It’s worth spending some time looking over all your uses of getFeatures() to see whether you can cut down on what you’re requesting – the results can often be mind blowing!

Categories: OSGeo Planet

portailSIG: Python: GeoPandas ou le Pandas spatial

OSGeo Planet - Sun, 2016-10-16 19:00
Niveau Intermédiaire Logiciels utilisés Python 2.7.x ou Python 3.x
Pandas (module Python)
GeoPandas (module Python)
Plateforme Windows | Mac | Linux | FreeBSD

Dans le monde géomatique, il y a ceux qui préfèrent les boutons, les menus, les pointer-cliquer, ou glisser-déplacer, le tout dans une jolie interface graphique (les SIGs quoi) et ceux qui préfèrent autre chose, comme la programmation directe et moi, malheureusement ou heureusement, je suis tombé dedans quand j’étais petit...

Parmi les nombreux modules Python existants, il y en a un qui me séduit de plus en plus, c’est GeoPandas (vu sommairement dans Python à finalité géospatiale: pourquoi débuter avec le module ogr alors qu’il existe des alternatives plus simples et plus didactiques ?) de Kelsey Jordahl, car il permet de pratiquement tout faire (attributs, géométries, jointures, etc.). Comme son nom l’indique, il est intrinsèquement lié à Pandas, mais force est de constater que la plupart des géomaticiens qui utilisent Python dans leurs logiciels SIG ne connaissent pas ce dernier module et pourtant...

Créé il y a relativement peu de temps, Pandas connaît un développement accéléré au point de devenir aujourd’hui l’un des principaux modules Python pour traiter les données de tout type ("Big Data", "Machine Learning", scientifique, économique, sociologique ...). Il s’appuie sur NumPy et permet de manipuler de grands volumes de données, structurées de manière simple et intuitive sous forme de tableaux.

Les exemples/tutoriels/videos sur Pandas sont innombrables sur Internet ainsi que des livres, aussi je me limiterai ici à une simple présentation de la structure des données pour passer ensuite à GeoPandas.


Figure modifiée de Cheat Sheet: The pandas DataFrame Object ( Dr. Stephen Sauchi Le)

Le type de base est la Serie (Pandas Series) qui peut être considérée comme un tableau de données à une dimension (grossièrement équivalent à une liste). L’extension en deux dimensions est un DataFrame (Pandas DataFrame). C’est un simple tableau dont les séries constituent les colonnes. Les index sont:

- index de colonne (df.columns()): les noms des colonnes (généralement des chaînes de caractères);
- index de ligne (df.index()): nombres entiers (numéros des lignes), chaînes de caractères, DatetimeIndex ou PeriodIndex pour les séries temporelles (time series).

C’est l’équivalent d’une matrice NumPy dont chaque colonne (Serie) est de même type (n’importe quel type de données, objets Python, nombres, dates, textes, binaires) et qui peut contenir des valeurs manquantes. C’est aussi l’équivalent des Data Frame de R (il y a aussi moyen de travailler avec des données selon 3 dimensions ou plus avec les Pandas Panels, mais le sujet ne sera pas abordé ici).

Cette manière de représenter les données oblige à changer quelque peu les habitudes de programmation. On travaille sur des colonnes, des lignes ou des cellules au lieu de parcourir l’ensemble des données avec des boucles et/ou des boucles imbriquées. Par exemple, pour modifier toutes les valeurs d'une colonne on utilisera pandas.Series.map(fonction).

Pandas permet nativement:

Cette librairie n'est pas isolée, car un grand nombre de modules se sont développes autour de sa structure pour offrir des traitements supplémentaires. C'est l'Ecosystème Pandas. Il est de plus, tout à fait possible d'utiliser Pandas avec une multitude d'autres librairies Python.  Autant dire que ses possibilités deviennent presque infinies, d'où son succès actuel.

"Essentially, you can think of pandas as a Numpy "on steroids" with a focus on real-world data. It encapsulates and wraps around much of the low-level functionality of numpy, scipy and matplotlib, exposing it to the end-user in a much friendlier way." (tiré de Brief introduction to the Python stack for scientific computing)


Figure réalisée avec GeoPandas (Delaunay, Voronoï) en s'inspirant de Origami Panda Print

Le monde géospatial ne pouvait pas rester en reste d'où la création de GeoPandas qui est une extension geospatiale de Pandas. Elle rajoute les GeoSeries (géométries, en bleu clair) et les GeoDataFrames ou DataFrames avec une colonne GeoSerie aux structures de Pandas (GeoPandas: Data Structures). Le résultat final est une structure où tous les traitements de Pandas sont possibles sur les colonnes oranges (attributs, Panda Series) et les traitements géomatiques sur la colonne bleu clair (geospatial, Geopandas GeoSerie). En pratique une GeoSerie est constituée de géométries Shapely.  Une ligne d'un GeoDataFrame contient donc les attributs et la géométrie d'un élément.

GeoPandas utilise donc Shapely (pour les traitements géométriques), mais aussi Fiona (pour l'importation/exportation des données géospatiales), pyproj (pour le traitement des projections), éventuellement Rtree (facultatif, pour implémenter les index spatiaux) et matplotlib et descartes pour les graphismes. Hormis Rtree, tous ces modules doivent être préalablement installés, Pandas y compris, bien évidemment. Le tout est particulièrement bien adapté aux Jupyter/IPython notebooks (voir Les notebooks IPython comme outil de travail dans le domaine géospatial ou le plaisir de partager, de collaborer et de communiquer) sur le Portail).

Quelques principes

Ouvrir et sauvegarder un fichier shapefile (ou autre) est enfantin et a été vu dans Python à finalité géospatiale: pourquoi débuter avec le module ogr alors qu'il existe des alternatives plus simples et plus didactiques ?  

Le fichier shapefile d'origine


Transformation en GeoDataFrame import geopandas as gpd # Création d'un GeoDataFrame gdf = gpd.read_file("test_portail.shp") gdf.head()

Quelques manipulation avec Pandas

À ce stade il est possible de modifier la table (ajout/suppression d'un champ par exemple), d'appliquer toutes les fonctions de Pandas pour ajouter/manipuler les attributs, de traiter l'ensemble d'une colonne (somme, moyenne, ...) ou de plusieurs colonnes (corrélations, ...)

  • Ajout d'un nouveau champ, soit avec une fonction de Pandas soit avec une fonction de GeoPandas (ici):
gdf["surface"] = gdf['geometry'].area gdf.head(2) # 2 premières lignes

  • Quelques statistiques basiques:


gdf[['Zn','Pb']].cov() # covariance


À tout moment il y a la possibilité de sauver le GeoDataFrame résultant


Je vous laisse découvrir Pandas pour tous les traitements possibles (une multitude), car ce qui nous intéresse ici ce sont les traitements géomatiques.

Quelques manipulations géométriques avec GeoPandas

Je vais vous montrer ici comment convertir ce GeoDataFrame en 4 fichiers shapefiles tout en gardant les attributs en illustrant les manières de procéder (je repars du fichier original):

  • la transformation de polygones en points se fera avec la fonction centroid de GeoPandas;
  • la transformation de polygones en lignes se fera avec Shapely et la commande map de GeoPandas et les fonctions lambda puisque la commande native n'existe pas et qu'il est nécessaire d'appliquer la fonction à chaque élément de la GeoSerie;
  • la transformation de lignes en points se fera de la même manière, mais le résultat aura évidemment plus de lignes.

Je vais sans doute être un peu long pour certains, mais il faut bien comprendre ici les manipulations géométriques sous peine d’être perdu dans la suite.

  • Transformation du GeoDataFrame en fichier shapefile de type point
# copie du GeoDataFrame original points = gdf.copy() points.geometry = points['geometry'].centroid  # même crs que l'original points.crs = gdf.crs # sauvetage du fichier shapefile points.to_file('centroid_portail.shp') points.head()

  • Transformation du GeoDataFrame en shapefile de type polylignes. Ici il est nécessaire d'utiliser une fonction extérieure puis d'utiliser la fonction map
from shapely.geometry import LineString # la fonction de transformation de polygones en polylignes linear = gdf.copy() def convert(geom):     return LineString(list(geom.exterior.coords)) # application de la fonction à toutes les lignes de la colonne geometry linear.geometry= linear.geometry.map(convert, linear['geometry']) # ou directement avec les fonctions lambdas linear.geometry= linear.geometry.map(lambda x: LineString(list(x.exterior.coords))) linear.crs = gdf.crs linear.head()

  • Extraction des noeuds des polylignes: ici il faut extraire les noeuds des lignes (LineString) de linear et créer un nouveau GeoDataFrame
col = linear.columns.tolist()[0:4] print col [u'POLY_NUM_B', u'Pb', u'Zn', 'geometry'] # création d'un nouveau GeoDataFrame avec ces colonnes noeuds = gpd.GeoDataFrame(columns=col) # extraction des noeuds à partir des lignes présentes dans linear et des valeurs d'attributs et intégration dans le nouveau GeoDataFrame for index, row in linear.iterrows():     for j in list(row['geometry'].coords):         noeuds = noeuds.append({'POLY_NUM_B': int(row['POLY_NUM_B']), 'Pb':row['Pb'],'Zn':row['Zn'], 'geometry':Point(j) },ignore_index=True) noeuds.crs = {'init' :'epsg:31370'} # autre manière de spécifier les coordonnées

Comme je veux être sûr que mes valeurs soient de type entier, je le spécifie:

noeuds['POLY_NUM_B'] = noeuds['POLY_NUM_B'].astype('int') noeuds['Pb'] = noeuds['Pb'].astype('int') noeuds['Zn'] = noeuds['Zn'].astype('int') # affichage des éléments 8 à 16 noeuds[8:16]

  • je crée maintenant un buffer autour de ces points
buffer = df.copy() buffer.geometry = buffer['geometry'].buffer(5) etc.
  • Résultat

En pratique

1) Une des plus belles illustrations de la puissance de GeoPandas m'a été apportée suite à une de mes réponses sur GIS Stack Exchange. La question posée était "More Efficient Spatial join in Python without QGIS, ArcGIS, PostGIS, etc". J'ai répondu avec une solution classique de boucles imbriquées en parcourant les 2 fichiers shapefiles (ma réponse) à comparer avec la réponse avec GeoPandas qui illustre les jointures spatiales (GeoPandas: spatial joins)

points = geopandas.GeoDataFrame.from_file('points.shp') # or geojson etc polys = geopandas.GeoDataFrame.from_file('polys.shp') pointInPoly = gpd.sjoin(points, polys, how='left',op='within')

Et vous obtiendrez un GeoDataFrame avec tous les points de 'points.shp' qui sont dans les polygones de 'polys.shp'.

2) Transformer un fichier csv ou Excel en GeoDataFrame est très facile:

import pandas as pd # transformation du fichier csv en Pandas DataFrame points = pd.read_csv("strati.csv") #transformation en GeoDataFrame from shapely.geometry import Point geometrie = [Point(xy) for xy in zip(points.x, points.y)] # colonnes du DataFrame résultants points = gpd.GeoDataFrame(points,geometry=geometrie) # ou directement points = pd.read_csv("strati.csv") points['geometry'] = points.apply(lambda p: Point(p.x, p.y), axis=1)

3) fusionner 2 ou plusieurs shapefiles, quelque soit le nombre et le type de champs, pourvu que le type de géométrie soit le même:

a = gpd.GeoDataFrame.from_file("shape1.shp") b = gpd.GeoDataFrame.from_file("shape2.shp") import pandas as pd result = pd.concat([a,b],axis=0) result.to_file("merged.shp")

4) un cas pratique auquel j'ai été confronté. J'ai un fichier shapefile reprenant les affleurements géologiques d'une carte (lignes) et un fichier csv avec leurs descriptions et je voudrai extraire les valeurs de schistosité de chacun d'entre eux pour créer un nouveau fichier shapefile de type point:

import geopandas as gpd import pandas as pd import re affl = gpd.GeoDataFrame.from_file("aff.shp") affl.head(2)


Traitement du fichier csv

affleurs = "schisto.csv" # je choisis les colonnes que je veux importer u_cols = ['IDENT','desc'] affleurs = pd.read_csv(aff, sep='\t', names=u_cols) regex = re.compile("S1.\d{1,2}\W*\d{1,3}") # je saute la partie du script pour chercher le regex et le résultat est affleurs.head(2) # les 2 premiers éléments


Je joins les 2 DataFrames sur base du champ 'IDENT' et je modifie la géométrie

df2 = gpd.GeoDataFrame( pd.merge(affl, affleurs, on='IDENT')) df2['geometry'] = df2['geometry'].representative_point() df2.head(2)



4) Pour le reste je vous renvoie (le choix n'est pas exhaustif):

- aux exemples de Geopandas (notebooks Jupyter/IPython):

- à mes réponses ou à celles d'autres personnes sur GIS Stack Exchange ou Stack Overflow:

- à des exemples de combinaisons avec d'autres librairies:


Contrairement à la plupart des tutoriels, je n'ai pas développé ici les fonctionnalités graphiques de la librairie puisque j'utilise un logiciel SIG pour visualiser les résultats. GeoPandas est encore jeune, mais ses possibilités sont déjà énormes, si vous aimez programmer, bien entendu. Dans mon cas, les traitements sont beaucoup plus rapides qu'avec QGIS pour ce que je veux faire (je ne dois pas utiliser PyQGIS, PyGRASS et leurs contraintes pour travailler sur des fichiers shapefiles. Tant que la colonne geometry d'un GeoDataFrame demeure inchangée, il y a moyen de faire ce que l'on veut avec les attributs).

Du fait que la librairie utilise Fiona, elle est sujette aux mêmes restrictions (pas d'accès direct aux bases de données spatiales par exemple), mais il est possible de contourner cet aspect avec d'autres modules plus adéquats. De part sa jeunesse elle est encore sujette à des erreurs non rédhibitoires (voir GeoPandas commits).

Signalons aussi OSMnx, pour le traitement des couches OpenStreetMap avec Pandas et  GeoRasters qui se veut l'équivalent de GeoPandas pour les rasters.

Tous les traitements présentés ont été effectués sur Mac OS X, Linux ou Windows avec les versions 0.1.x, 0.2.0 et 0.2.1 de GeoPandas et les versions 0.18.x puis 0.19.0 de Pandas.

Site officiel : Using geopandas on Windows
Site officiel : Pandas DataFrame Notes (PDF)
Site officiel : DataFrame et Matrice
Site officiel : DataFrame et Graphes
Site officiel : Le pandas c’est bon, mangez en
Site officiel : Introduction à Pandas

Creative Commons License
licence Creative Commons Paternité-Pas d'Utilisation Commerciale-Pas de Modification 2.0 France

Categories: OSGeo Planet

From GIS to Remote Sensing: How to identify Sentinel-2 granule zones using a shapefile

OSGeo Planet - Sun, 2016-10-16 16:03
The identification of Sentinel-2 granule zones can be useful for searching Sentinel-2 images using the Semi-Automatic Classification Plugin (SCP).
It is possible to download a shapefile containing the Sentinel-2 zones.

Categories: OSGeo Planet

GeoTools Team: GeoTools 15.2 Released

OSGeo Planet - Sat, 2016-10-15 21:53
The GeoTools team is pleased to announce GeoTools 15.2.
This release is also available from our Maven repository. This release is made in conjunction with GeoWebCache 1.9.2 and GeoServer 2.9.2. We would like to thank those who have contributed fixes and features to this release.

GeoTools 15.2 is the latest stable release of the 15.x series and is recommended for all new projects.

Security considerations:
  • The library now defaults to using PreventLocalEntityResolver for improved security. For more details (and how to disable this behavior) please see the GeoTools user guide.
Features and Improvements:
  • Styling improvements include support for SE 1.1 external marks (with mark index)
  • Parsing hints can now be provided for WMS and WFS clients (entity resolver hint and and DTD disabling hint provided).
  • Overview policy parameter now available for ImageMosaic.
  • Support for integrated water column climatological time in NetCDF files
  • ImagePyramid support for multiple coverages 
      Bug Fixes:
      • SLD graphics now correctly handle mix of mark and external graphic choosing the first one supported.
      • External marks with mark index fixes for both copying and SE 1.1 parsing.
      For more information please see the release notes (15.2 | 15.1 | 15.0 | RC1 | Beta 2 | Beta 1 | M0 ).
      About GeoTools 15 What's new in GeoTools 15:
      Categories: OSGeo Planet

      GeoSolutions: Presto disponibile il profilo DCAT-AP_IT per CKAN

      OSGeo Planet - Sat, 2016-10-15 11:31


      Dear Reader,

      We apologize in advance, but this post is for our italian readers (hence in Italian only) to announce that we have reached an agreement for the implementation of the DCAT-AP_IT Metadata Profile leveraging on the CKAN Open Data product.

      Siamo lieti di annunciare che il team di sviluppo di GeoSolutions si appresta ad implementare una estensione per il prodotto Open Source CKAN per la implementazione del profilo di metadati DCAT-AP_IT; lo sviluppo è sostenuta dalla Provincia di Bolzano/Sud Tirol e dalla Provincia di Trento in uno sforzo congiunto e verrà rilasciato gratuitamente con licenza Open Source.

      GeoSolutions ha sviluppato (o partecipato allo sviluppo) nel corso degli anni una serie impressionante di portali dedicati per la fruizione di dati geospaziali e statistici (sia Open che non) per vari enti in tutto il mondo utilizzando e customizzando il prodotto Open Source CKAN. Solo per citarne alcuni:

      Il nostro team di sviluppo ha guadagnato una esperienza senza eguali nella installazione, configurazione e customizzazione di CKAN che garantisce la qualità dello sviluppo che andremo a produrre. E' nostro obiettivo mettere questa estensione a disposizione gratuitamente su GitHub, così come prassi per la nostra azienda dove la filosofia Open Source viene praticata in modo corretto e responsabile e non per un mero risparmio di costi.

      Invitiamo tutti coloro che sono interessati a partecipare allo sforzo per lo sviluppo di questa estensione o che fossero interessati ad utilizzare questa estensione ad seguire il nostro blog o iscriversi alla nostra newsletter; raccomandiamo di visionare anche i nostri pacchetti di supporto professionale GeoSolutions Enterprise Support Services nel caso si volesse usufruire di un supporto attento e qualificato per la messa in produzione di questa estensione. Allo stesso modo vi invitiamo a visionare le informazioni sugli altri nostri prodotti Open Source quali GeoServerMapstore e GeoNetwork. The GeoSolutions team,
      Categories: OSGeo Planet
      Syndicate content