Maybe this is a bit off-topic, but I just spent quite some time on this and I need to write it down so I can look it up again later :)

These are instructions for Ubuntu running Postgres 8.4. By default, Postgres ships without PL/Python so we need to get it first:

sudo apt-get install postgresql-plpython-8.4

Next, we need to create the language for our database. I’m using PgAdmin3. From there, I ran:

CREATE PROCEDURAL LANGUAGE 'plpython' HANDLER plpython_call_handler;

This should have been it. Let’s try with a simple function:

CREATE FUNCTION replace_e_to_a(text) RETURNS text AS
'
import re
Text1 = re.sub(''e'', ''a'',args[0])
return Text1
'
LANGUAGE 'plpython';

SELECT replace_e_to_a('Meee');

… should return ‘Maaa’.

Now for the juicy part: Let’s create an INSERT trigger function!

First, let’s have a look at the corresponding table structure. We have two tables “user_data” and “user_keywords”. “user_data” is the table that’s being filled with information from external functions. “user_keywords” has to be kept up-to-date. It is supposed to count the appearance of keywords on a per-user base.

user_data                                   user_keywords
user_id, event_id, keywords                 user_id, keyword,   count
1,       1,        'music,rock'             1,       'music',   2
1,       2,        'music,classic'          1,       'rock',    1
                                            1,       'classic', 1

First, the keyword list has to be split. Then a row has to be inserted for new keywords (compare insert_plan) and the counter has to be increased for existing keywords (update_plan).

The values that are about to be inserted can be accessed via TD[“new”][“column_name”].

CREATE FUNCTION update_keyword_count() RETURNS trigger AS '

keywords = TD["new"]["keywords"]
user = TD["new"]["user_id"]

insert_plan = plpy.prepare("INSERT INTO user_keywords (keyword, count, user_id) VALUES ($1, $2, $3)", ["text", "int", "int"])

update_plan = plpy.prepare("UPDATE user_keywords SET count = $3 WHERE user_id = $1 AND keyword = $2", ["int", "text", "int"])

for keyword in keywords.split(","):
  select_cnt_rows = plpy.prepare("SELECT count(*) AS cnt FROM user_keywords WHERE user_id = $1 AND keyword = $2", ["int", "text"])
  cnt_rows = plpy.execute(select_cnt_rows, [user, keyword])

  select_plan = plpy.prepare("SELECT count AS cnt FROM user_keywords WHERE user_id = $1 AND keyword = $2", ["int", "text"])
  results = plpy.execute(select_plan, [user, keyword])

  if cnt_rows[0]["cnt"] == 0:
   rv = plpy.execute(insert_plan, [keyword, 1, user])
  else:
   rv = plpy.execute(update_plan, [user, keyword, results[0]["cnt"]+1])

' LANGUAGE plpython;

Now, we need to wire it up by defining the trigger:

CREATE TRIGGER update_keywords
BEFORE INSERT ON user_data
FORE EACH ROW
EXECUTE PROCEDURE update_keyword_count();

… Wasn’t that bad ;)

Interesting news from the gispython.org community mailing list: There is a new Python library out there called PyKML.

PyKML allows parsing and authoring of KML documents based on the lxml.objectify API which provides Pythonic access to XML documents.

Nathan from woostuff.wordpress.com has compiled a descriptive comparison of MapInfo and QGIS. He presents the up and downsides of QGIS compared to one of the major commercial GIS around. 

The QGIS community presents two new case studies:

QGIS and GRASS applied to paleontological survey in Western Portugal by André Mano
QGIS as major GIS software in the Laboratory on Experimental and Applied Geography by Jakub Trojan

GeoServer has always been good at simply publishing database tables. But anything more complex (e.g. pre-filtering data in a table, joining two tables together, or generating values on the fly) could be painful. With Geoserver 2.1 one can finally create a layer directly from an SQL query.

"Create New SQL View" interface

Even dynamic queries are possible, e.g.

select gid, state_name, the_geom from pgstates where persons between %low% and %high%

To select for example all states with 2 to 5 millions inhabitants, the following parameters can be added to the normal GetMap request:

&viewparams=low:2000000;high:5000000

Find more information on SQL layers in Geoserver 2.1 documentation.

Globe plugin had it’s first big presentation at FOSS4G 2010:

(This video is part of a series of videos titled “Comparison of Open Source Virtual Globes”.)

Where to download Globe plugin

The globe plugin is a C++ plugin based on the threading branch and can be
downloaded from
http://github.com/sourcepole/qgis/tree/threading-globe

How to install QGIS Globe

To install Globe plugin, you can use Marco Bernasocchi’s install script. Thanks Marco!

Sourcepole (the developers of Globe plugin) promise that as soon as the threading branch is merged into trunk, globe should make its way into trunk as well.

Creating high-resolution output with QGIS can be tricky. “Save as image” saves the current map extent and creates a world file, but the output size cannot be specified directly. It simply saves the currently visible map. Most of the time this resolution will not be satisfactory.

Using “Print Composer” enables you to create full-grown maps including legend, scale bar, text annotations, north arrow, attribute table, decorations, etc. You are free to chose any size/resolution for the output image. Unfortunately, this way you will not get a world file.

That’s where the third possibility comes in handy:  Using QGIS from command line to create a snapshot of a map. This way, you can create images of any size and with corresponding world file. The work-flow can be divided into the following steps:

  1. Create and design your project: Add layers and styles.
  2. Zoom to the desired zoom level.
  3. Write down the extent of the map window. Use coordinates in the project’s projection. (You can skip this step and don’t specify –extent option. The project will be restored in it’s original saved state if you do so.)
  4. Close the project
  5. Go to command line and run
C:\...>qgis --project myproject.qgs --snapshot image.png
            --width 1500 --height 1000 --extent xmin,ymin,xmax,ymax

QGIS will start, load the project, create the snapshot, and close again. That’s it!

Things to be aware of: QGIS will start, load the project, set the given extent (if specified), enlarge the map canvas and then take the snapshot. As a consequence, the extent given doesn’t match the extent of the resulting image. The image will have a bigger extent and contain surrounding areas.

Together with the new labeling tools this can be a fast and (semi-)automatic way to create nice looking high-resolution map images and corresponding world files from QGIS projects.

A great enhancement has been added to “Delimited Text” plugin today. It allows the use of a geometry column formatted as well known text (WKT), as an alternative to using x and y columns to define point features.

Requirements

To view a delimited text file as layer, the text file must contain:

  1. A delimited header row of field names. This must be the first line in the text file.
  2. The header row must contain an X and Y field or a Well Known Text (WKT) field. These fields can have any name.
  3. The WKT field must be in standard format.

Example of a valid text file with a WKT field

id|wkt
1|POINT(172.0702250 -43.6031036)
2|POINT(172.0702250 -43.6031036)
3|POINT(172.1543206 -43.5731302)
4|POINT(171.9282585 -43.5493308)
5|POINT(171.8827359 -43.5875983)

Update: Tim has posted a video tutorial: Video tutorial #2: Delimited Text Plugin

QGIS 1.6 is now officially released. Read the announcement on QGIS blog for information on new features or go directly to the download page.

Update: The QGIS manual has also been brought up-to-date.