The event attracted a diverse group of experts and novices from organizations as varied as NOAA, the World Bank, USAID, the American Red Cross, Deloitte, LockHeed Martin, the CDC and many others. As a new member of QGIS community myself, I was floored by the energy of the group and how quickly the project is evolving.
The day started with Jeff Johnson and Larry Shaffer setting the stage with presentations highlighting the history and evolution of QGIS from a shapefile viewer to full-fledged desktop application. Jeff went into detail about specific applications of QGIS, highlighting examples from NOAA and NASA. Larry picked it up from there and discussed the QGIS ecosystem and open source development community. He noted that plug-in development has been a long-time focus within the community and sees core development picking up steam in the coming year.
Next, Tim Sutton from the QGIS project steering committee joined remotely. Thanks to OpenGovHub’s fantastic conference abilities, Tim being in South Africa didn’t pose a challenge. Tim provided further context to Larry’s discussion on core and plugin development and the steering committee’s focus for 2014.
Later on, Gary Sherman joined remotely from Alaska and provided a brief history of QGIS development, including it’s origin as a shapefile viewer. Gary is also the author of the PyQGIS Programmer’s Guide on developing QGIS Plugins.
QGIS for Humanitarianism
Vivien Depardy and Yewondwossen Assefa of GFDDR then presented on the role QGIS (and GeoNode) plays in their emergency response and disaster recovery efforts. Larry provided context to their efforts, applauding their development model calling it a leading example of development.
After a quick lunch we split into two groups for hands-on workshops. Jeff Johnson led “Using QGIS with OpenGeo Suite” and Larry Shaffer led “How to Become a QGIS Developer”. I attended Jeff’s session, which provided a good opportunity to review the fantastic QGIS documentation with an experienced instructor. Jeff used the documentation as a starting point but added his tips and tricks along the way. He ended by showing us how to use the OpenGeo Explorer plugin to publish data to GeoServer.
My colleague, Eva Shon, attended Larry’s workshop. Larry’s goal was to get more developers involved on the QGIS project. As the only core developer in the United States, he’s especially interested in increasing the number of developers from North America. He shared an early draft of QGIS core developer documentation and virtual machine images he’s working on intended to help new developers get started more quickly.
Whether you were looking for an introduction to QGIS or were already active in the community, the day had something for everyone. The event ended with a happy hour and the only question left was when we’d do it again. To learn more about QGIS, download and install it using the OpenGeo Suite installer and check out documentation to see what it can do. Stay tuned for next QGIS U.S. User Group meetings being planned in Atlanta and Seattle.
The State of the Map US 2014 conference, a two-day conference covering all things OpenStreetMap, was held this past weekend in Washington DC. It was nice to attend as part of the Boundless contingent and meet — in person — tons of people whom I had only heretofore known via the internets.
Aside from the inspiration provided by the gorgeous weather and the cherry blossoms, there was also inspiration in abundance at the conference for cartographers. Every cartographer should become familiar with OpenStreetMap data if they aren’t already. It’s a bit of a bear to work with because it is in a different structure than we are normally used to (nodes and ways mean anything to you?) but you’ll see the benefits if you download a state-wide or city-wide extract from one of several sites (such as geofabrik or Metro Extracts) and start using it in your map-making medium of choice. The dataset provides a comprehensive collection of roads, buildings and building types, points of interest, and so on. And it’s free!
There were many talks I didn’t get to see because there were two concurrent tracks, but the ones that I attended focused heavily on tools that for using OpenStreetMap data, including GeoGit, TileMill, Esri, QGIS, and PostGIS. However, there were still some cartographic takeaways.
Kate Watkins, Seth Fitzsimmons and Alan McConchie told us that a great way to build a stylistically cohesive basemap is to focus on three main hues, along with variations on those hues.
In that same talk we saw some great examples of labels that break all the rules: the leading and kerning (that’s line spacing and character spacing, basically) are decreased to negative values and the halos are very large and black. Of course this is the opposite of what most texts will recommend but it just proves that breaking the rules once in a while can make for some neat cartographic effects.
Eric Theise showed us that applying some of the devices of experimental film to maps, such as perception distortion, can be a creative way to get people thinking. Eric and I were discussing this later on in the day when he mentioned that he thought it would be interesting to have a map that taunted you if you tried to click on a feature to find out more about it. Something like, “You’d like to know what this building is, wouldn’t you?!”
Kevin Bullock told a great story about a map of India that was produced in the 1800s with crude tools, took 70 years to complete, and astonishingly accurate despite these and other limitations. And you thought your map products took a long time to produce!
Our own Jeff Johnson rounded out the weekend with a more technical talk that examined the ways in which GeoGit could lead to a more distributed and decentralized architecture for OSM.
There was a lot more material covered, of course, and these points focused just on the cartography aspect of OpenStreetMap use. All the talks are now posted on the schedule part of the conference website so definitely take the time to watch them!
If you’re still curious about State of the Map, I recommend this great recap from Peter Batty which provides more details about the event and reviews other issues in the OpenStreetMap community including vector tiles, licensing, passive crowdsourcing, geocoding and more.
The release of OpenGeo Suite 4.0 added Catalogue Services for the Web (CSW) support to the impressive list of OGC services supported by the product. CSW is an open standard defined by the Open Geospatial Consortium (OGC) that makes it easier to search for and discover geospatial data in a machine-readable way. With CSW support, metadata about data and web services is more discoverable, making it easier to manage and advertise data as holdings grow. We explained how to install the CSW plugin and described the mechanics of how a CSW service works in a previous post, but this post will describe how to harvest metadata from GeoServer.
Because CSW can be automatically harvested, its easier to integrate new services into existing spatial data infrastructures. GeoServer offers a minimal implementation of the CSW specification that is limited when compared to implementations in more full-fledged catalogs. This is by design, as it is meant to be as lightweight as possible while still providing the capability to offer metadata about the contents of a GeoServer instance. This metadata can easily be consumed by a more complete CSW implementation that supports harvesting. While specific to GeoNetwork, the same workflow is possible with other servers such as pycsw or Esri GeoPortal Server.
The first step is to install OpenGeo Suite with the CSW plugin. For this post we used OpenGeo Suite 4.0.2 and the installation instructions from our previous post. Once the source catalog is installed, the next step is to download and install a catalog into which to harvest metadata. For this post we used GeoNetwork 2.10.2 and followed the detailed instructions in the documentation.
We installed both OpenGeo Suite and GeoNetwork on the same local machine so all links reference http://localhost. One important note is that since OpenGeo Suite and GeoNetwork use the same default port (8080), one must be changed if you intend to run them on the same machine. For this post we set OpenGeo Suite to run on port 9080 by following the documentation.
Once OpenGeo Suite is up and running, visit the GeoServer administration page at http://localhost:9080/geoserver. If the CSW plugin has been installed correctly, you’ll see a link to the capabilities document on the right hand side of the page. Copy this link as you’ll need it shortly.
Ensure that GeoNetwork is started and visit http://localhost:8080/geonetwork. Login with the “admin” account — by default the password for this account is “admin”. Once logged in, visit the “Administration” page and go to the “Harvesting Management” link about halfway down the page.
The harvesting page allows us to add a link to another CSW from which to harvest metadata. The goal here is to harvest from GeoServer. Start by clicking the “Add” button, then expand the “Type” drop down and select “Catalogue Services for the Web ISO Profile 2.0”.
This results in a form requesting information about the server from which to harvest. For this step we must fill out the following:
Set “Name” to “GeoServer CSW” and “Service URL” to the capabilities url we copied previously.
Uncheck “Use account” since in this case our CSW is not secured by a username and password.
Choose “Datasets” under the “CATEGORIES” list.
Once the service has been added, return to the harvesting page and select the “GeoServer CSW” service, then click the “Run” button. After a few seconds click the “Refresh” button. Upon success you should see the “Last run” timestamp updated.
Search & Discover
Once the harvest job has completed, GeoNetwork should have all the metadata provided by GeoServer. In this example, GeoServer is publishing a number of layers featuring Natural Earth data. Let’s examine one such layer: parks and protected areas.
Metadata from GeoServer such as title, abstract, and keywords have all been defined. Once GeoNetwork has harvested all this metadata it becomes possible to search using the form on the GeoNetwork home page. As expected, entering the search term “parks” returns on the appropriate layer.
Since the metadata returned by GeoServer provides information about other services, such as WMS, we can browse the data directly in GeoNetwork as well.
As with our first support story, this one comes from MassGIS, the official state agency assigned to the collection, storage, and dissemination of geographic data. When a layer has overlapping lines or polygons, we often want to control which ones are rendered on top and which ones are rendered below. The classic example is when we have a roads layer that contains overpasses that we want to appear above regular roads at ground level. MassGIS was dealing with a land-usage layer which required one type of polygon to be rendered with a solid color and other types to be rendered above with specific patterns.
The Aral Sea Example
We can simulate this problem by taking a layer that has both current and historical extents of bodies of water. In particular we’ll look at the Aral Sea, which shrunk considerably in the twentieth century. We’ll want to style the historical extents using hatching and then overlay the current lake in a plain blue style. What we don’t want is to have the historical bounds drawn over the modern lake.
You can test on your own GeoServer install with the data and SLDs in this ZIP.
Our first attempt at creating an SLD to draw the two polygons in the correct order is to use two rule statements: the first will match our historical layer (where attribute
type is equal to
historical) and the second will match the modern layer (where the attribute
type is equal to
modern). We expect this to draw the historical lakes first and then the modern lakes on top:
<sld:StyledLayerDescriptor version="1.0.0" xmlns:sld="http://www.opengis.net/sld"> <sld:NamedLayer> <sld:Name>Lakes</sld:Name> <UserStyle xmlns="http://www.opengis.net/sld"> <FeatureTypeStyle> <Rule> <Name>Historical area</Name> ... </Rule> <Rule> <Name>Modern area</Name> ... </Rule> </FeatureTypeStyle> </UserStyle> </sld:NamedLayer> </sld:StyledLayerDescriptor>
Unfortunately, this gives us the opposite effect: the historical area has been rendered above the modern area.
Since this ordering of the rules didn’t work, we can try switching them around in the SLD, putting the rule for modern lakes first and historical lakes second. If you test this in GeoServer, however, you will see that the image that we get back is not affected.
Since reordering rules in an SLD does not affect the output image, we had to provide another approach.
The answer to the problem is to use the rules in separate
<FeatureTypeStyle> sections of our SLD document:
<sld:StyledLayerDescriptor version="1.0.0" xmlns:sld="http://www.opengis.net/sld"> <sld:NamedLayer> <sld:Name>Lakes</sld:Name> <UserStyle xmlns="http://www.opengis.net/sld"> <FeatureTypeStyle> <Rule> <Name>Historical area</Name> ... </Rule> </FeatureTypeStyle> <FeatureTypeStyle> <Rule> <Name>Modern area</Name> ... </Rule> </FeatureTypeStyle> </UserStyle> </sld:NamedLayer> </sld:StyledLayerDescriptor>
Why does this work?
Our first approach did not work since rules inside a single
FeatureTypeStyle are applied to features as they arrive from the data source. GeoServer was drawing the modern Aral Sea first and the historical Aral Sea second simply because that is the order in which they were stored in the shapefile.
Even if the order had been correct, it would have been dangerous to rely on it for styling since that order could change at any time.
To reliably control the rendering order, therefore, we need the multiple
FeatureTypeStyle blocks. GeoServer will draw each of these independently and then merge them in the defined order as the last step.
Benjamin Trigona-Harany leads our global support team from our offices in Victoria, BC. Interested in support or training for your enterprise? Contact us to learn more.
The San Francisco Bay Area Bike Share Open Data Challenge is now underway, with entries due April 25, 2014. The idea is to use their open data on bike stations, bicycle traffic patterns, and weather to create an interesting visualization, map, or other product that adds value to the program.
Using open source mapping tools is a great way to explore the data and create winning entries for the contest. For those who are new to making maps out of open data, we’re here to help you get started. In this tutorial we’ll show you how to use QGIS, a popular mapping software product, to create a simple map out of the data. Build on this foundation to create your own contest entries and learn about data and geospatial technology along the way.
To get started, download all four data files from the contest website here. After you unzip the data you’ll see that it’s in CSV format. This is a comma delimited text file format that’s useful for spreadsheets and geospatial tables.
First, download and install QGIS. Then install the OpenLayers plugin, which simplifies adding some of the most common base layers, such as Google Maps or OSM, and makes it easier to visualize the bike station locations. You can install it by opening the Plugin Manager, selecting the Get more section and then searching for OpenLayers.
Now in the Plugins menu you should have a new entry where you can select the layers to add.
Adding bike share data
Add whichever basemap you like. In the following screenshots, you will see that we’ve added the Bing Road layer, which is less saturated than some of the others. A less saturated basemap helps to highlight the data that will be overlaid. You can zoom into San Francisco now or wait until the bike share data is added. To create the bike share data overlay, use the Add Delimited Text Layer button.
Add the station data file using the browse button. Use the x and y drop down selectors under Geometry definition to tell QGIS which fields have the latitude coordinates and which have the longitude coordinates. Latitude is y and longitude is x.
Your input should look like the screenshot above. Press OK. In the Coordinate Reference System Selector, type in “4326” in the Filter box and select WGS 84 in the box directly beneath it. Many — but not all — datasets in open data formats are in the WGS 84, or EPSG 4326, coordinate system.
The QGIS map should now look similar to the screenshot below. If it isn’t zoomed in properly, you can right-click the station_data layer in the Layers list and choose Zoom to Layer Extent.
Joining and analyzing bike share data
There is a lot of data in the other three tables to explore but they need to be joined to the station data first since the station data contains the geometry for displaying the data on the map, while the other tables are related to the station data geometry via its station_id field. Fields that can be used for joining are often described in files that come with the data. The README.txt file that came with this data follows this convention.
In this tutorial we’ll use the trip_data table to perform an analysis and display the results on the map. First the trip_data table needs to be added to QGIS. Click Add Delimited Text Layer again, browse to the trip_data table, and choose “No geometry” next to Geometry layer definition. Press ok. The table is added to the Layers list in QGIS. Right-click the table name in the Layers list and click Open Attribute Table. You can see the data has loaded correctly. Notice that the station_id is used in the Start Terminal and End Terminal fields.
The average duration of a trip from each station is a good first analysis. To get the average duration we have to total up the durations of each trip by Start Terminal. This could be done in a spreadsheet program, exported as a CSV file, and then added into QGIS using the steps described above for loading non-spatial tables. Alternatively, we are providing avg.py, a script created that will do the calculation within QGIS.
In the Processing menu under Options and configuration, expand Scripts and view the folder path. This is the folder path in which to save the Python script. Once the script is saved to that path, restart QGIS.
Open the Processing Toolbox by clicking Processing > Toolbox. It will appear on the right-hand side of the QGIS window. Expand Scripts, Boundless, and double-click “avg.” Fill out the dialog with the following, making sure to save the table as a CSV file in the path of your choosing.
Now you can join the output table with the station data layer in order to visualize the average duration (in seconds) of trips from each station. Double-click the station_data layer in the Layers list to bring up the Properties window. Choose Joins and click the green plus sign near the bottom of the window. Pick the table from the list that contains the average data and the field that has the station ID number. If you used the QGIS script, these will be “output_table” and “class.” The Target field is “station_id.”
Now you can look at the attribute table for the station_data to make sure the join worked properly. If it did, the fields from station_data are now in the table. (If the fields are added to the table but the cells are populated with NULL values, the wrong id field was used in the join process.)
To visualize the duration field, double click the station_data in the Layers list to open the Layer Properties and choose Style. Choose Graduated, output_table_avg for the column to style, and change the color in the color ramp as per your preference. Change the mode to Natural Breaks and press ok. (Choosing a mode that makes sense for the data and for the map is an important part of the analytical process. Here is more information on modes).
Zoom in to the denser section to see that data more clearly. Enlarge the circles by double clicking station_data, Style, click the change symbol button and change the size to 3. Click OK twice.
The trips in San Francisco appear to be shorter than the trips in Redwood City. Hopefully this tutorial on using QGIS with the Bay Area Bike Share open data provides a springboard for contest entrants. Good luck!
Interested in QGIS? Learn more at the first QGIS user group meetup in the United States on Friday, April 11!
We’re happy to welcome Matt Richards, our new web designer, to the team! Matt will be working from our brand new (and growing) DC office where he’ll be crafting interfaces and developing the user experience for hosted services like Mapmeter and other upcoming products.
Hi Matt. Welcome to Boundless! What were you doing before you joined us?
Most recently, I was at Cvent, a software-as-a-service company that has a platform for event management services. Think of it as Eventbrite for small-to-large businesses who host large events like conferences, meetings, company events, and tradeshows. Cvent manages and automates the more mundane aspects of logistics, marketing, and management for the entire event process.
While there, I worked as a web designer on the marketing team, so my projects were all public-facing. From landing pages, to new product announcements, to complete branding packages, my role was part visual design, part web development, and part creative guru. I led the design and development for Cvent’s most recent marketing project, the CrowdTorch website.
Before all of that though, I began my web design career at the ripe age of 16 in rural West Virginia.
You started a web design company prior to starting college?
There’s not a whole lot to do in West Virginia. <laughs> I stress that I lived in a very rural part of the state and wanted to do something cool out there. When I was younger, I ended getting into the competitive gaming scene. I designed graphics for gaming tournaments, leagues, and that sort of thing. From there I built up word-of-mouth referrals to build my client database, and I also did a lot of client work online.
Around the time I turned 16, I had enough of a client list and enough freelancers in my stable that I made an actual go of it. I registered as a business, began working with local and regional clients and had some pretty good successes along the way. I worked with developers — they do the programming and I would make it look cool. I built out websites, invitations, and collateral for gaming challenges. I was also building online networks for the competitive gaming scene. I became a well-known graphic designer within the gaming circle.
What excites you most about working on the new tools and products that Boundless is currently developing?
With an upcoming product that is taking on a new space in the market, I have the unique opportunity to design an interface and experience that isn’t really constrained by older, out-dated processes. This is really exciting as a designer — it means you can embrace the most recent design ideas and create a new user experience from the ground up. I’m really excited to start making what’ll hopefully be the best looking Boundless product to date.
What are your design resources and sources of inspiration?
Two pillars of the web design community are A List Apart and Smashing Magazine, both blogs I read regularly and find very useful. Some of the most interesting stuff I’ve seen recently has come out of Medium, specifically the Design/UX section. There’s a ton of other stuff scattered around though and I use sidebar.io and Panda to filter through the nonsense and find the best articles. I like to keep current.
What languages or programs are your main ways of working?
Do you have any experience with open source development?
I’m limited in this regard. I was exposed early on to the virtues of open source from my Dad, who was a passionate open source developer. I remember that he was always on Slashdot — this was back in the days when Slashdot was just the worst looking website around. <laughs> He was really passionate about using open source tools and was a big Linux advocate. I was very pro-Windows in those days, due mostly to my interest in gaming. I just didn’t have the appreciation for anything beyond the Windows gaming world back then. But now that I’m older I can see what my dad was excited about it. I’m really excited to be at a company that has open source values.
What do open source values means to you?
To me, it means the willingness to select tools and components that are the right ones for the task at hand. At proprietary companies, I see that there is more of a business decision process that leads development. That leads to tools and solutions being chosen based on political or cultural factors. Boundless seems to have a strong culture of embracing the best ideas and products and using the right tools for the job. An open source foundation provides a lot more flexibility and control.
What has been your favorite project to have worked on?
Professionally, my favorite project was the company career microsite for Cvent. I was able to go off-brand with colors and treatments, which was a satisfying technical and aesthetic challenge. There is a lot of video and photo assets that I incorporated into the site and I was able to make it more friendly and approachable than the typical branding was. It was immensely satisfying being able to stretch my design wings.
Another project that I really enjoyed working on was a the full brand build-out for CrowdTorch. I worked on the color, typography, icons, website design, and development. It was a really exciting project, because most what resulted was stuff that I conceptualized, designed, and eventually developed.
What’s an interesting facts about yourself (that you haven’t already said)?
When I was 15 years old, my family moved out to middle of nowhere: Thomas, West Virginia. Our parents decided to homeschool my two sisters and me. As part of that, we opened a music venue and cafe called The Purple Fiddle in an old general store. It was a bar/cafe/performing space in a small town. It was a much-needed venue for the area. The town had a population of about 250 people, and basically cafe was the highlight of the area’s entertainment.
For those of us not familiar with competitive online gaming, what are some popular trends right now?
There’s a growing industry known as “esports” that basically boils down to a bunch of gamers sitting in a room and playing video games — mostly Starcraft II, Defense of the Ancients 2, League of Legends, and Counter-Strike: Global Offensive. It doesn’t sound that competitive or interesting, but I assure you it is. At the largest tournaments, tens of millions of people tune in to watch gamers from all over the world compete for millions of dollars in prize money. The numbers can be staggering at times; the biggest live viewership was 32 million. In comparison, NBA games usually get under 2 million viewers. It’s a bit crazy to comprehend how much it’s grown, but the scene is exploding and I was happy to be a part of it during it’s early stages.
What other hobbies do you have?
I’m a creative at heart, so my hobbies are basically just other creative outlets. I’m a DSLR geek, so I take photography whenever the opportunity arises. Even though there’s not much on it yet, I do plan on posting more photography to my 500px profile. I’ve also made quite a few short films. Here’s a few videos I’ve been proud of: an indie-rock music video, a short film about finding yourself (won an award!), and a trailer for an utopian sci-fi film that never was finished.
At Boundless, we usually describe GeoGit not as an application itself, but as a library. We see it as a basic component of geospatial data management on top of which other applications can be built. While GeoGit currently has a command-line interface (CLI), adding new ways of interacting with GeoGit will increase the possibilities for creating new projects that rely on GeoGit to manage changes to geospatial data. We hope to see GeoGit as the core of an ecosystem of tools that solve a variety of problems.
We have started developing a Python library, the geogit-py library, to make it much easier to create GeoGit-based applications. Since Python is a widespread scripting language, this will allow other developers to incorporate GeoGit-based capabilities into many other applications. In fact, we are already using it to create a plugin to bring the versioning capabilities of GeoGit into QGIS.
Basic GeoGit Automation
The geogit-py library will also make it easier to automate tasks when working with a GeoGit repository, since all the great features of the Python language can be used alongside GeoGit methods. This represents a great feature for all GeoGit users, especially those that use it in a workflow that can be partially of fully automated.
Here are some examples to provide an idea of what using the library is like. A basic workflow should start with something like this:
# Create repo repo = Repository('path/to/repo/folder', init = True) # Configure repo.config(geogit.USER_NAME, 'myuser') repo.config(geogit.USER_EMAIL, 'firstname.lastname@example.org') # Add some data and create a snapshot repo.importshp('myshapefile.shp') repo.addandcommit('first import')
You can automate this first step and easily import a set of layers , creating a different snapshot for each one. Assuming that we have a set of shapefiles in a folder, the following code will do it.
for f in os.listdir(folder): if f.endswith('.shp'): path = os.path.join(folder, f) repo.importshp(path) repo.addandcommit('Imported ' + f)
In a normal GeoGit workflow, you export from a GeoGit repository, edit the exported data using the tool of your choice (i.e. a desktop GIS like QGIS), and then import the changed layer so GeoGit can compute the changes that have been introduced, which are later used to create a new snapshot.
With geogit-py, that approach is still possible, but you can also edit without exporting while directly modifying a feature. Internally, geogit-py still calls GeoGit import/export commands but wraps them to expose them in a more practical way. It is also more efficient, since it does not import/export the whole layer. Here’s an example.
# Take a feature and modify its geometry feature = repo.feature(geogit.HEAD, 'parks/1') geom = feature.geom attributes = feature.attributesnogeom newgeom = geom.buffer(5.0) # insert the modified geometry and create a new snapshot with the changes repo.insertfeature(feature.path, attributes, newgeom) repo.addandcommit('modified parks/1 (buffer computed)')
In this case we have computed a buffer, but you can modify the geometry as you like. Geometries are Shapely objects, so you can use all the methods in that powerful library to work with them. You can also modify the non-geometry attributes in the feature (though we haven’t done so in that example).
Working with GeoGit Branches
Working with branches is also rather simple:
# Create a branch at the current HEAD commit to work on it repo.createbranch(repo.head, 'mybranch', checkout = True) # [...] Perform some work on the branch, modifying the repo data and creating new commits # Bring changes to master branch (which might itself have changes) repo.checkout(geogit.MASTER) try: repo.merge('mybranch') print 'Merge correctly executed. No merge conflicts' except GeoGitConflictException, e: print 'Cannot merge. There are merge conflicts'
Although most of the functionality of GeoGit is already available through geogit-py, some features are not yet supported. Unsupported features mostly correspond to convenience options that can very easily be implemented, or replicated with a few lines of Python code.
A side effect of developing geogit-py is that it has helped us improve GeoGit itself. Several new features have been added to GeoGit commands to allow for a better integration, and some new commands have even been implemented. Using GeoGit from geogit-py has given us more insight into ways that GeoGit can be used by different applications and services, and has helped us shaping it and improving it.
A comprehensive test suite is included with geogit-py, which represents a real test suite for GeoGit itself, adding to the large collection of sets that GeoGit has. Moreover, we have plans to use geogit-py as part of our quality assurance, specifically for testing GeoGit and prototyping GeoGit use cases.
Soon we will release some of the projects that we are working on that rely on geogit-py. Stay tuned for further updates.
Over 50 people came together in Vienna last week for five days of working on open source geospatial software. This code sprint merged the annual “C tribe” sprint — PostGIS, MapServer, GDAL, PDAL, and others — with the regular sprints held by the QGIS and GRASS communities. As a result, the attendance was at a record level, and the opportunities for collaboration much greater.
PostGIS 2.1.2 & 2.0.5 Released
I attended to work on PostGIS development, as usual, and achieved my modest goal: closing all the remaining tickets and getting 2.1.2 and 2.0.5 released. These are both bug fix releases, so no new functionality is included, but there are some important issues in the 2.1 branch that were resolved with the 2.1.2 release.
More QGIS in Our Future
Wearing my OpenGeo Suite product manager hat, the sprint was an excellent opportunity to sit down and talk with leaders in the QGIS community about our plans for bundling QGIS with OpenGeo Suite. When OpenGeo Suite 4.1 is released later this year, it will include builds of QGIS for all our supported platforms (Windows, OSX, Linux). It will also have some specialized plugins for managing map composition and versioned editing within QGIS. Our own Victor Olaya is a QGIS community member and a developer of the the Processing framework (formerly Sextante) in QGIS. We’re looking forward to being a part of the QGIS community, in the same way that we are a part of the OpenLayers, GeoServer and PostGIS communities.
Five days is a long time to hunker down in a room slinging a code, and there were a lot of valuable side meetings: developers showed off some of their latest work (I saw some great 3D work from the PDAL’s Howard Butler and Oslandia’s Olivier Courtin); the QGIS community worked through important design decisions; and Tim Sutton and Anita Graser collected lots of interviews for the QGIS podcast.
The “beer track” (not run concurrently with the other tracks) was also great, thanks to Stephan Meißl’s organizing: some onsite events, a walk and dinner in downtown Vienna, and a dinner in the local neighborhood. Most importantly, opportunities to get to know developers from other communities and bring the whole open source geo community closer together.
Next year, the sprint will once again combine as many communities as possible (hopefully adding some!), this time in a North American venue (likely Philadelphia). I’ll certainly be in attendance. If you write open source geo software, I hope you will too.
NYC DoITT, the New York City Department of Information Technology and Telecommunications, oversees the use of existing and emerging technologies in government operations and delivers various services to city residents. Since we have an office in NYC, we’re particularly proud to support them as OpenGeo Suite customers.
Not long ago, they asked for ways to create styles based on the number of hours that had elapsed since a feature was created, a calculation that would otherwise have been impossible using a regular SLD. In a previous support story, we described using WPS in SLD to alter a geometry prior to rendering. While some rendering transforms — such as heatmaps and contour maps — are relatively well-known, GeoServer facilitates the use of Python or other scripting languages to help style data. By writing the logic in Python, NYC DoITT would be able to use the standard datetime module to style features. Below we’ll review how to use GeoScript to perform more advanced styling programmatically.
Before we start, we will need to install the right extensions to OpenGeo Suite, particularly the GeoServer Python scripting extension. On Linux, you can simply install the
geoserver-script package. On Windows, scripting is an option in the OpenGeo Suite installer.
On OSX, you will need to manually install the plugin by downloading the community build, selecting “Open Webapps Directory” from the menu, and dropping the
Once GeoScript is installed, we can add our Python scripts to the
scripts/functions directory in the GeoServer data directory. A simple test is to create a script named
random_colour.py that returns a random colour:
import random def run(value, args): return random.choice(["#000000", "#ff0000", "#00ff00", "#0000ff"])
We can then create an SLD that calls this function. The following SLD is based on the default
polygon style in GeoServer, with one line changed:
<?xml version="1.0" encoding="ISO-8859-1"?> <StyledLayerDescriptor version="1.0.0" xsi:schemaLocation="http://www.opengis.net/sld StyledLayerDescriptor.xsd" xmlns="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <NamedLayer> <Name>geoscript test</Name> <UserStyle> <FeatureTypeStyle> <Rule> <Name>random colour</Name> <PolygonSymbolizer> <Fill> <CssParameter name="fill"> <ogc:Function name='random_colour'/> </CssParameter> </Fill> <Stroke> <CssParameter name="stroke">#000000</CssParameter> <CssParameter name="stroke-width">1</CssParameter> </Stroke> </PolygonSymbolizer> </Rule> </FeatureTypeStyle> </UserStyle> </NamedLayer> </StyledLayerDescriptor>
Instead of referencing a fixed grey colour,
<ogc:Function name='random_colour'/> calls
random_colour.py and uses the evaluated value as the polygon fill colour. The Python code simply selects at random from a list of colors — in this case: #000000, #ff0000, #00ff00 and #0000ff — and then returns it.
We can test this new style with the default
opengeo:countries layer that ships with OpenGeo Suite. Every time a new request is made, the polygon colours should be randomly generated again.
To make our SLD functions more useful, we can style based on attribute values by passing arguments to the function. Let’s create a new Python script to manage the values of each colour by mapping the value of the
mapcolor9 attribute of the
opengeo:countries to a colour. We will call this script
colour_9.py and put it in the same scripts/functions directory:
def run(value, args): colour = args if colour == 1: return "#fbb4ae" if colour == 2: return "#b3cde3" if colour == 3: return "#ccebc5" if colour == 4: return "#decbe4" if colour == 5: return "#fed9a6" if colour == 6: return "#ffffcc" if colour == 7: return "#e5d8bd" if colour == 8: return "#fddaec" if colour == 9: return "#f2f2f2"
This will use the value of the first argument as the colour for the feature. Our SLD needs to call this function and pass the
mapcolor9 attribute as the argument:
<CssParameter name="fill"> <ogc:Function name='colour_9'> <ogc:PropertyName>mapcolor9</ogc:PropertyName> </ogc:Function> </CssParameter>
While this could be done in pure SLD, it can be easier to manage complex styling rules using scripts rather than XML.
Logging to geoserver.log
Any print statements in the Python script will appear in the GeoServer logs. Let’s modify our SLD to add a second argument:
<CssParameter name="fill"> <ogc:Function name='colour_9'> <ogc:PropertyName>mapcolor9</ogc:PropertyName> <ogc:PropertyName>name</ogc:PropertyName> </ogc:Function> </CssParameter>
Then let’s print out all our arguments from the script:
def run(value, args): print args colour = args …
We should now see lines like the following in
[2.0, Aruba] [6.0, Angola] [6.0, Anguilla] [1.0, Albania] [4.0, Aland] [1.0, Andorra] [3.0, United Arab Emirates] [2.0, Armenia] [5.0, Antigua and Barbuda] [3.0, Austria] [5.0, Azerbaijan] [5.0, Burundi] [1.0, Belgium] [2.0, Benin] [5.0, Burkina Faso] [1.0, Bulgaria] [1.0, Bahrain] …
Using feature geometries
Attentive readers will have noted that in addition to
args, our scripts have an additional
value parameter. This variable contains an instance of GeoScript’s
org.geotools.feature.simple.SimpleFeatureImpl. This means we have access to the feature’s geometry and, since these geometries are JTS objects, we can use methods such as
getArea() in our script:
def run(value, args): geom = value.getDefaultGeometry() print "%s: %f" % (args, geom.getArea()) …
The modified script above will simply record the area of each geometry in the GeoServer logs before styling it.
DoITT also identified scale-dependent styling as another use for GeoScript. Rather than writing filter functions in our SLD, we can instead pass our current scale as an argument to a new function and use this to format the label. Our script,
country_label.py, can use the current scale to decide which of the three possible labels to use:
def run(value, args): abbrev = args normal = args formal = args scale = args if scale > 10000000: return abbrev if scale < 5000000: return formal return normal
The three arguments are an abbreviated name, a regular name and a formal (long) name for each country. The corresponding SLD appears as:
<TextSymbolizer> <Label> <ogc:Function name='country_label'> <ogc:PropertyName>abbrev</ogc:PropertyName> <ogc:PropertyName>name</ogc:PropertyName> <ogc:PropertyName>formal_en</ogc:PropertyName> <ogc:Function name="env"> <ogc:Literal>wms_scale_denominator</ogc:Literal> </ogc:Function> </ogc:Function> </Label> <Font> <CssParameter name="font-family">DejaVuSans</CssParameter> <CssParameter name="font-size">10.0</CssParameter> <CssParameter name="font-style">normal</CssParameter> <CssParameter name="font-weight">normal</CssParameter> </Font> <LabelPlacement> <PointPlacement> <AnchorPoint> <AnchorPointX>0.5</AnchorPointX> <AnchorPointY>0.5</AnchorPointY> </AnchorPoint> </PointPlacement> </LabelPlacement> <Halo> <Radius>2.0</Radius> <Fill> <CssParameter name="fill">#FFFFFF</CssParameter> </Fill> </Halo> <Fill> <CssParameter name="fill">#000000</CssParameter> </Fill> </TextSymbolizer>
Once again, we could have written these rules directly into our SLD, but using GeoScript allows us to maintain complex styling more efficiently.
We might want to combine our scale-dependent rule with the area calculation so that we do not have instances of large countries with the abbreviated labels (as in the case of France being labelled Fr. in the image above):
def run(value, args): abbrev = args normal = args formal = args scale = args area = value.getDefaultGeometry().getArea() if scale > 10000000 and area < 5000: return abbrev if scale < 5000000: return formal return normal
Now, countries with a large area will use the country name rather than the abbreviations that we saw in the earlier example. Smaller countries, such as most of those in the Balkans, still have their names abbreviated.
Another use of GeoScript in SLDs is creating filter functions. To continue the example of using country names, we might want to find all countries whose formal designations are comprised of five or more separate words. In this case, Federal Republic of Germany would not be shown on our map, but Independent State of Papua New Guinea would.
Using Python, we can create a file called
long_names.py with this relatively simple calculation:
def run(value, args): formal = args if len(formal.split()) >= 5: return True return False
We can then use this filter in our SLD by adding a filter after our rule name:
<Rule> <Name>long country names</Name> <ogc:Filter> <ogc:PropertyIsEqualTo> <ogc:Function name="long_names"> <ogc:PropertyName>formal_en</ogc:PropertyName> </ogc:Function> <ogc:Literal>true</ogc:Literal> </ogc:PropertyIsEqualTo> </ogc:Filter> ... </Rule>
When the script returns
True, the feature will be displayed.
Benjamin Trigona-Harany leads our global support team from our offices in Victoria, BC. Interested in support or training for your enterprise? Contact us to learn more.