Related Plugins and Tags

QGIS Planet

QGIS Print Layouts Graphs and Charts – campaign deadline extended!

If you’re a regular reader of this blog, it won’t surprise you to hear that we’re very excited about adding rich charting and graph functionality to QGIS’ Print Layout designer! Alongside our friends at Faunalia, we’re currently running a crowd funding campaign to make this a reality.

So, while the required funds weren’t raised within our original April 30 deadline, we’ve decided to extend this campaign by an additional 30 days in the hopes that the users and organisations from the wider QGIS community will jump onboard and pledge the remaining required funds.

This missing feature is a large gap in QGIS printing capabilities, so we’re counting on you to show your support and spread the word to your local user groups, QGIS users, and any organisations you know of who rely on QGIS and would love to see its inbuilt reporting capabilities levelled up!

QGIS (and SLYR!), now with Hash Lines support

Thanks to an anonymous corporate sponsor, we’ve recently had the opportunity to add a new Hashed Line symbol type for QGIS 3.8. This allows for a repeating line segment to be drawn over the length of a feature, with a line-sub symbol used to render each individual segment.

There’s tons of options available for customising the appearance and placement of line hashes. We based the feature heavily off QGIS’ existing “Marker Line” support, so you can create hashed lines placed at set intervals, on line vertices, or at the start/end/middle of lines. There’s options to offset the lines, and tweak the rotation angle of individual hashes too. Added to QGIS’ rich support for “data defined” symbol properties, this allows for a huge range of new symbol effects.

E.g. using a data defined hash length which increases over the length of a feature gives us this effect:

Or, when using a complex line sub-symbol for rendering each hash, we can get something like this:

Or even go completely “meta” and use a hashed line sub symbol for the hash line itself!

With the right combination of symbol settings and QGIS draw effects you can even emulate a calligraphic pen effect:

Or a chunky green highlighter!

This same corporate sponsor also funded a change which results in a huge improvement to the appearance of both rotated hashed lines and marker lines. Previously, when marker or hash lines were rendered, the symbol angles were determined by taking the exact line orientation at the position of the symbol. This often leads to undesirable rendering effects, where little “bumps” or corners in lines which occur at the position of the symbol cause the marker or hash line to be oriented at a very different angle to what the eye expects to see.

With this improvement, the angle is instead calculated by averaging the line over a specified distance either side of the symbol. E.g. averaging the line angle over 4mm means we take the points along the line 2mm from either side of the symbol placement, and use these instead to calculate the line angle for that symbol. This has the effect of smoothing (or removing) any tiny local deviations from the overall line direction, resulting in much nicer visual orientation of marker or hash lines.

It’s easiest to show the difference visually. Here’s a before image, showing arrow markers following a line feature. Pay specific attention to the 3rd and last arrow, which seem completely random oriented due to the little shifts in line direction:

With new smoothing logic this is much improved:

The difference is even more noticeable for hashed lines. Here’s the before:

…and the after:

Suffice to say, cartographers will definitely appreciate the result!

Lastly, we’ve taken this new hash line feature as an opportunity to implement automatic conversion of ESRI hash line symbols within our SLYR ESRI to QGIS conversion tool. Read more about SLYR here, and how you can purchase this tool for .style, .lyr and .mxd document conversion.

QGIS Print Layouts Graphs and Charts crowdfund launched!

Ever wished QGIS had a way to insert dynamic, feature rich charts and graphs directly inside print layouts? If so, our latest crowdfunding campaign has you covered! This missing feature is a large gap in QGIS printing capabilities, so we’re planning on filling that gap by exposing the powerful QGIS “Data Plotly” plugin to allow these charts to be embedded inside your layouts, and allow them to be created and modified in a simple, interactive style.

If you’re not aware of the existing capabilities of the DataPlotly plugin, here’s a quick screencast which should get you excited about the possibilities here…

QGIS is already a reporting powerhouse, and we believe that linking DataPlotly with QGIS print layouts will boost the current functionality up an order of magnitude! To make it possible we need 8600€ pledged before 30 April 2019. North Road is collaborating on this campaign with our friends at Faunalia, and development work will be shared between the two consultancy firms.

You can help make this a reality by supporting the campaign or by sharing the page and increasing exposure to the campaign. Full details about the planned functionality and how to contribute are available at the campaign page.

Happy birthday OSGeo!

On February 4, 2006 OSGeo held its first meeting in Chicago, with 25 participants representing 18 groups and over 20 different Open Source GIS projects, and 39 others participating via Internet Relay Chat. During the meeting, participants made important decisions in the formation and organization of the foundation, including the name, structure and purpose. The consensus reached in Chicago opened the way for the establishment of a productive and representative foundation.

Today we are happy to announce that the we have meanwhile over 32,800 unique subscribers in the huge list of over 290 OSGeo mailing lists!

And: check out the web site of the OSGeo foundation.

1. More to come this year!

… see here for the growing list of events

The post Happy birthday OSGeo! appeared first on GFOSS Blog | GRASS GIS and OSGeo News.

Announcing our SLYR (MXD to QGIS) funding drive!

One product which North Road had the chance to develop last year, and which we are super-proud of, is our SLYR ESRI style to QGIS conversion tool. If you haven’t heard of it before, this tool allows automatic conversion of ESRI .style database files to their equivalent QGIS symbology equivalent. It works well for the most part, and now we’re keen to take this to the next stage.

The good news is that North Road have been conducting extensive research and development over the past 12 months, and we’re pleased to announce our plans for extending SLYR to support ESRI LYR and MXD documents. The LYR and MXD formats are proprietary ESRI-only formats, with no public specifications allowing their use. This is a huge issue for organisations who want to move from an ESRI environment to the open geospatial world, yet are held back by hundreds (or thousands!) of existing ESRI MXD map documents and layer styles which they currently cannot utilise outside of the ESRI software ecosystem. Furthermore, many providers of spatial data only include ESRI specific layer formatting files with their data supplies. This leaves users with no means of utilising these official, pre-defined styles in non-ESRI tools.

In order for us to continue development of the SLYR tool and unlock use of LYR and MXD formats outside of ESRI tools, we are conducting a funding campaign. Sponsors of the campaign will receive access to the tools as they are developed and gain access to official support channels covering their use. At the conclusion of this drive we’ll be releasing all the tools and specifications under a free, open-source license.

You can read the full details of the campaign here, including pricing to become a project sponsor and gain access to the tools as they develop. As a campaign launch promo, we’re offering the first 10 sponsors a super-special discounted rate (as a reward for jumping on the development early).

The mockup below shows what the end goal is: seamless, fully integrated, automatic conversion of MXD and LYR files directly within the QGIS desktop application!

Call for testing: GRASS GIS with Python 3

Please help us testing the Python3 support in the yet unreleased GRASS GIS trunk (i.e., version “grass77” which will be released as “grass78” in the near future).

1. Why Python 3?

Python 2 is end-of-life (EOL); the current Python 2.7 will retire in 11 months from today (see https://pythonclock.org). We want to follow the “Moving to require Python 3” and complete the change to Python 3. And we need a broader community testing.

2. Download and test!

Packages are available at time:

3. Instructions for testing

4. Problems found? Please report them to us

Problems and bugs can be reported in the GRASS GIS trac. Code changes are welcome!

Thanks for testing grass77!

The post Call for testing: GRASS GIS with Python 3 appeared first on GFOSS Blog | GRASS GIS and OSGeo News.

GRASS GIS 7.6.0 released

We are pleased to announce the GRASS GIS 7.6.0 release

What’s new in a nutshell

After almost 1 year of development the new stable release GRASS GIS 7.6.0 is available. Efforts have concentrated on making the user experience even better, providing many new useful additional functionalities to modules and further improving the graphical user interface. Furthermore, ZSTD has been added a new raster compression method which is an improvement over ZLIB’s deflate method, providing both faster and higher compression than ZLIB. Also a new raster map type has been added: GRASS virtual raster (VRT) which is a virtual mosaic of the list of input raster maps. In addition, support for PROJ v. 5 has been implemented. An overview of the new features in the 7.6 release series is available at new features in GRASS GIS 7.6.

Binaries/Installer download:

Source code download:

More details:

See also our detailed announcement:

First time users may explore the first steps tutorial after installation.

About GRASS GIS

The Geographic Resources Analysis Support System (https://grass.osgeo.org/), commonly referred to as GRASS GIS, is an Open Source Geographic Information System providing powerful raster, vector and geospatial processing capabilities in a single integrated software suite. GRASS GIS includes tools for spatial modeling, visualization of raster and vector data, management and analysis of geospatial data, and the processing of satellite and aerial imagery. It also provides the capability to produce sophisticated presentation graphics and hardcopy maps. GRASS GIS has been translated into about twenty languages and supports a huge array of data formats. It can be used either as a stand-alone application or as backend for other software packages such as QGIS and R geostatistics. It is distributed freely under the terms of the GNU General Public License (GPL). GRASS GIS is a founding member of the Open Source Geospatial Foundation (OSGeo).

The GRASS Development Team, January 2019

The post GRASS GIS 7.6.0 released appeared first on GFOSS Blog | GRASS GIS and OSGeo News.

On custom layout checks in QGIS 3.6, and how they can do your work for you!

Recently, we had the opportunity to implement an exciting new feature within QGIS. An enterprise with a large number of QGIS installs was looking for a way to control the outputs which staff were creating from the software, and enforce a set of predefined policies. The policies were designed to ensure that maps created in QGIS’ print layout designer would meet a set of minimum standards, e.g.:

  • Layouts must include a “Copyright 2019 by XXX” label somewhere on the page
  • All maps must have a linked scale bar
  • No layers from certain blacklisted sources (e.g. Google Maps tiles) are permitted
  • Required attribution text for other layers must be included somewhere on the layout

Instead of just making a set of written policies and hoping that staff correctly follow them, it was instead decided that the checks should be performed automatically by QGIS itself. If any of the checks failed (indicating that the map wasn’t complying to the policies), the layout export would be blocked and the user would be advised what they needed to change in their map to make it compliant.

The result of this work is a brand new API for implementing custom “validity checks” within QGIS. Out of the box, QGIS 3.6 ships with two in-built validity checks. These are:

  • A check to warn users when a layout includes a scale bar which isn’t linked to a map
  • A check to warn users if a map overview in a layout isn’t linked to a map (e.g. if the linked map has been deleted)

All QGIS 3.6 users will see a friendly warning if either of these conditions are met, advising them of the potential issue.

 

The exciting stuff comes in custom, in-house checks. These are written in PyQGIS, so they can be deployed through in-house plugins or startup scripts. Let’s explore some examples to see how these work.

A basic check looks something like this:

from qgis.core import check

@check.register(type=QgsAbstractValidityCheck.TypeLayoutCheck)
def my_layout_check(context, feedback):
  results = ...
  return results

Checks are created using the @check.register decorator. This takes a single argument, the check type. For now, only layout checks are implemented, so this should be set to QgsAbstractValidityCheck.TypeLayoutCheck. The check function is given two arguments, a QgsValidityCheckContext argument, and a feedback argument. We can safely ignore the feedback option for now, but the context argument is important. This context contains information useful for the check to run — in the case of layout checks, the context contains a reference to the layout being checked. The check function should return a list of QgsValidityCheckResult objects, or an empty list if the check was passed successfully with no warnings or errors.

Here’s a more complete example. This one throws a warning whenever a layout map item is set to the web mercator (EPSG:3875) projection:

@check.register(type=QgsAbstractValidityCheck.TypeLayoutCheck)
def layout_map_crs_choice_check(context, feedback):
  layout = context.layout
  results = []
  for i in layout.items():
    if isinstance(i, QgsLayoutItemMap) and i.crs().authid() == 'EPSG:3857':
      res = QgsValidityCheckResult()
      res.type = QgsValidityCheckResult.Warning
      res.title='Map projection is misleading'
      res.detailedDescription='The projection for the map item {} is set to Web Mercator (EPSG:3857) which misrepresents areas and shapes. Consider using an appropriate local projection instead.'.format(i.displayName())
      results.append(res)

  return results

Here, our check loops through all the items in the layout being tested, looking for QgsLayoutItemMap instances. It then checks the CRS for each map, and if that CRS is ‘EPSG:3857’, a warning result is returned. The warning includes a friendly message for users advising them why the check failed.

In this example our check is returning results with a QgsValidityCheckResult.Warning type. Warning results are shown to users, but they don’t prevent users from proceeding and continuing to export their layout.

Checks can also return “critical” results. If any critical results are obtained, then the actual export itself is blocked. The user is still shown the messages generated by the check so that they know how to resolve the issue, but they can’t proceed with the export until they’ve fixed their layout. Here’s an example of a check which returns critical results, preventing layout export if there’s no “Copyright 2019 North Road” labels included on their layout:

@check.register(type=QgsAbstractValidityCheck.TypeLayoutCheck)
def layout_map_crs_choice_check(context, feedback):
  layout = context.layout
  for i in layout.items():
    if isinstance(i, QgsLayoutItemLabel) and 'Copyright 2019 North Road' in i.currentText():
      return

  # did not find copyright text, block layout export
  res = QgsValidityCheckResult()
  res.type = QgsValidityCheckResult.Critical
  res.title = 'Missing copyright label'
  res.detailedDescription = 'Layout has no "Copyright" label. Please add a label containing the text "Copyright 2019 North Road".'
  return [res]

If we try to export a layout with the copyright notice, we now get this error:

Notice how the OK button is disabled, and users are forced to fix the error before they can export their layouts.

Here’s a final example. This one runs through all the layers included within maps in the layout, and if any of them come from a “blacklisted” source, the user is not permitted to proceed with the export:

@check.register(type=QgsAbstractValidityCheck.TypeLayoutCheck)
def layout_map_crs_choice_check(context, feedback):
  layout = context.layout
  for i in layout.items():
    if isinstance(i, QgsLayoutItemMap):
      for l in i.layersToRender():
        # check if layer source is blacklisted
        if 'mt1.google.com' in l.source():
          res = QgsValidityCheckResult()
          res.type = QgsValidityCheckResult.Critical
          res.title = 'Blacklisted layer source'
          res.detailedDescription = 'This layout includes a Google maps layer ("{}"), which is in violation of their Terms of Service.'.format(l.name())
          return [res]

Of course, all checks are run each time — so if a layout fails multiple checks, the user will see a summary of ALL failed checks, and can click on each in turn to see the detailed description of the failure.

So there we go — when QGIS 3.6 is released in late February 2019, you’ll  have access to this API and can start making QGIS automatically enforce your organisation policies for you! The really neat thing is that this doesn’t only apply to large organisations. Even if you’re a one-person shop using QGIS, you could write your own checks to  make QGIS “remind” you when you’ve forgotten to include something in your products. It’d even be possible to hook into one of the available Python spell checking libraries to write a spelling check! With any luck, this should lead to better quality outputs and less back and forth with your clients.

North Road are leading experts in customising the QGIS application for enterprise installs. If you’d like to discuss how you can deploy in-house customisation like this within your organisation, contact us for further details!

GRASS GIS 7.4.4 released: QGIS friendship release

We are pleased to announce the GRASS GIS 7.4.4 release

What’s new in a nutshell

The new update release GRASS GIS 7.4.4 is release with a few bugfixes and the addition of r.mapcalc.simple esp. for QGIS integration. An overview of the new features in the 7.4 release series is available at New Features in GRASS GIS 7.4.

As a stable release series, 7.4.x enjoys long-term support.

Binaries/Installer download:

Source code download:

More details:

See also our detailed announcement:

About GRASS GIS

The Geographic Resources Analysis Support System (https://grass.osgeo.org/), commonly referred to as GRASS GIS, is an Open Source Geographic Information System providing powerful raster, vector and geospatial processing capabilities in a single integrated software suite. GRASS GIS includes tools for spatial modeling, visualization of raster and vector data, management and analysis of geospatial data, and the processing of satellite and aerial imagery. It also provides the capability to produce sophisticated presentation graphics and hardcopy maps. GRASS GIS has been translated into about twenty languages and supports a huge array of data formats. It can be used either as a stand-alone application or as backend for other software packages such as QGIS and R geostatistics. It is distributed freely under the terms of the GNU General Public License (GPL). GRASS GIS is a founding member of the Open Source Geospatial Foundation (OSGeo).

The GRASS Development Team, January 2019

The post GRASS GIS 7.4.4 released: QGIS friendship release appeared first on GFOSS Blog | GRASS GIS and OSGeo News.

Thoughts on “FOSS4G/SOTM Oceania 2018”, and the PyQGIS API improvements which it caused

Last week the first official “FOSS4G/SOTM Oceania” conference was held at Melbourne University. This was a fantastic event, and there’s simply no way I can extend sufficient thanks to all the organisers and volunteers who put this event together. They did a brilliant job, and their efforts are even more impressive considering it was the inaugural event!

Upfront — this is not a recap of the conference (I’m sure someone else is working on a much more detailed write up of the event!), just some musings I’ve had following my experiences assisting Nathan Woodrow deliver an introductory Python for QGIS workshop he put together for the conference. In short, we both found that delivering this workshop to a group of PyQGIS newcomers was a great way for us to identify “pain points” in the PyQGIS API and areas where we need to improve. The good news is that as a direct result of the experiences during this workshop the API has been improved and streamlined! Let’s explore how:

Part of Nathan’s workshop (notes are available here) focused on a hands-on example of creating a custom QGIS “Processing” script. I’ve found that preparing workshops is guaranteed to expose a bunch of rare and tricky software bugs, and this was no exception! Unfortunately the workshop was scheduled just before the QGIS 3.4.2 patch release which fixed these bugs, but at least they’re fixed now and we can move on…

The bulk of Nathan’s example algorithm is contained within the following block (where “distance” is the length of line segments we want to chop our features up into):

for input_feature in enumerate(features):
    geom = feature.geometry().constGet()
    if isinstance(geom, QgsLineString):
        continue
    first_part = geom.geometryN(0)
    start = 0
    end = distance
    length = first_part.length()

    while start < length:
        new_geom = first_part.curveSubstring(start,end)

        output_feature = input_feature
        output_feature.setGeometry(QgsGeometry(new_geom))
        sink.addFeature(output_feature)

        start += distance
        end += distance

There’s a lot here, but really the guts of this algorithm breaks down to one line:

new_geom = first_part.curveSubstring(start,end)

Basically, a new geometry is created for each trimmed section in the output layer by calling the “curveSubstring” method on the input geometry and passing it a start and end distance along the input line. This returns the portion of that input LineString (or CircularString, or CompoundCurve) between those distances. The PyQGIS API nicely hides the details here – you can safely call this one method and be confident that regardless of the input geometry type the result will be correct.

Unfortunately, while calling the “curveSubstring” method is elegant, all the code surrounding this call is not so elegant. As a (mostly) full-time QGIS developer myself, I tend to look over oddities in the API. It’s easy to justify ugly API as just “how it’s always been”, and over time it’s natural to develop a type of blind spot to these issues.

Let’s start with the first ugly part of this code:

geom = input_feature.geometry().constGet()
if isinstance(geom, QgsLineString):
    continue
first_part = geom.geometryN(0)
# chop first_part into sections of desired length
...

This is rather… confusing… logic to follow. Here the script is fetching the geometry of the input feature, checking if it’s a LineString, and if it IS, then it skips that feature and continues to the next. Wait… what? It’s skipping features with LineString geometries?

Well, yes. The algorithm was written specifically for one workshop, which was using a MultiLineString layer as the demo layer. The script takes a huge shortcut here and says “if the input feature isn’t a MultiLineString, ignore it — we only know how to deal with multi-part geometries”. Immediately following this logic there’s a call to geometryN( 0 ), which returns just the first part of the MultiLineString geometry.

There’s two issues here — one is that the script just plain won’t work for LineString inputs, and the second is that it ignores everything BUT the first part in the geometry. While it would be possible to fix the script and add a check for the input geometry type, put in logic to loop over all the parts of a multi-part input, etc, that’s instantly going to add a LOT of complexity or duplicate code here.

Fortunately, this was the perfect excuse to improve the PyQGIS API itself so that this kind of operation is simpler in future! Nathan and I had a debrief/brainstorm after the workshop, and as a result a new “parts iterator” has been implemented and merged to QGIS master. It’ll be available from version 3.6 on. Using the new iterator, we can simplify the script:

geom = input_feature.geometry()
for part in geom.parts():
    # chop part into sections of desired length
    ...

Win! This is simultaneously more readable, more Pythonic, and automatically works for both LineString and MultiLineString inputs (and in the case of MultiLineStrings, we now correctly handle all parts).

Here’s another pain-point. Looking at the block:

new_geom = part.curveSubstring(start,end)
output_feature = input_feature
output_feature.setGeometry(QgsGeometry(new_geom))

At first glance this looks reasonable – we use curveSubstring to get the portion of the curve, then make a copy of the input_feature as output_feature (this ensures that the features output by the algorithm maintain all the attributes from the input features), and finally set the geometry of the output_feature to be the newly calculated curve portion. The ugliness here comes in this line:

output_feature.setGeometry(QgsGeometry(new_geom))

What’s that extra QgsGeometry(…) call doing here? Without getting too sidetracked into the QGIS geometry API internals, QgsFeature.setGeometry requires a QgsGeometry argument, not the QgsAbstractGeometry subclass which is returned by curveSubstring.

This is a prime example of a “paper-cut” style issue in the PyQGIS API. Experienced developers know and understand the reasons behind this, but for newcomers to PyQGIS, it’s an obscure complexity. Fortunately the solution here was simple — and after the workshop Nathan and I added a new overload to QgsFeature.setGeometry which accepts a QgsAbstractGeometry argument. So in QGIS 3.6 this line can be simplified to:

output_feature.setGeometry(new_geom)

Or, if you wanted to make things more concise, you could put the curveSubstring call directly in here:

output_feature = input_feature
output_feature.setGeometry(part.curveSubstring(start,end))

Let’s have a look at the simplified script for QGIS 3.6:

for input_feature in enumerate(features):
    geom = feature.geometry()
    for part in geom.parts():
        start = 0
        end = distance
        length = part.length()

        while start < length:
            output_feature = input_feature
            output_feature.setGeometry(part.curveSubstring(start,end))
            sink.addFeature(output_feature)

            start += distance
            end += distance

This is MUCH nicer, and will be much easier to explain in the next workshop! The good news is that Nathan has more niceness on the way which will further improve the process of writing QGIS Processing script algorithms. You can see some early prototypes of this work here:

So there we go. The process of writing and delivering a workshop helps to look past “API blind spots” and identify the ugly points and traps for those new to the API. As a direct result of this FOSS4G/SOTM Oceania 2018 Workshop, the QGIS 3.6 PyQGIS API will be easier to use, more readable, and less buggy! That’s a win all round!

GRASS GIS 7.4.2 released

We are pleased to announce the GRASS GIS 7.4.2 release

What’s new in a nutshell

After a bit more than four months of development the new update release GRASS GIS 7.4.2 is available. It provides more than 50 stability fixes and improvements compared to the previous stable version 7.4.1. An overview of the new features in the 7.4 release series is available at New Features in GRASS GIS 7.4.

Efforts have concentrated on making the user experience even better, providing many small, but useful additional functionalities to modules and further improving the graphical user interface. Segmentation now support extremely large raster maps. Dockerfile and Windows support received updates. Also the manual was improved. For a detailed overview, see the list of new features. As a stable release series, 7.4.x enjoys long-term support.

Binaries/Installer download:

Source code download:

More details:

See also our detailed announcement:

About GRASS GIS

The Geographic Resources Analysis Support System (https://grass.osgeo.org/), commonly referred to as GRASS GIS, is an Open Source Geographic Information System providing powerful raster, vector and geospatial processing capabilities in a single integrated software suite. GRASS GIS includes tools for spatial modeling, visualization of raster and vector data, management and analysis of geospatial data, and the processing of satellite and aerial imagery. It also provides the capability to produce sophisticated presentation graphics and hardcopy maps. GRASS GIS has been translated into about twenty languages and supports a huge array of data formats. It can be used either as a stand-alone application or as backend for other software packages such as QGIS and R geostatistics. It is distributed freely under the terms of the GNU General Public License (GPL). GRASS GIS is a founding member of the Open Source Geospatial Foundation (OSGeo).

The GRASS Development Team, October 2018

The post GRASS GIS 7.4.2 released appeared first on GFOSS Blog | GRASS GIS and OSGeo News.

French Ministry in charge of the ecological transition selected Oslandia

Ministère de la Transition Écologique et Solidaire Logo

The French ministry of the ecological transition  selected Oslandia for two of the three packages of its call for tender procedure dedicated to geomatic tools.  We are very proud to dedicate our team to one of the strongest support of geomatics and Open Source in France for the next 2 to 4 years.

First package is dedicated to expert studies covering spatial databases, software, components, protocols, norms and standards in the geomatics fields.

Second package provides support and development for QGIS,  the spatial cartridge PostGIS of PostgreSQL and their components. We are really happy to continue a common work already engaged in the previous contract.

This is again another proof that we face a major tendency of open source investment, where geomatics components are currently among the most dynamic and strongest open source projects. This is also a confirmation that actors are now integrating deeply the economic rationale of open source contribution inside their politics.

Edit Features “In Place” crowdfund — made it to QGIS 3.4!

Well, thanks to the resounding success of our QGIS edit-in-place crowdfunding campaign, we’ve been frantically smashing away at our keyboards in an attempt to reward the QGIS community by sneaking this feature in a whole 4 months earlier than originally promised! And, we’re very proud to announce, that this exciting new feature has been implemented and will be included in the upcoming QGIS 3.4 release (due late October 2018). So go ahead — grab one of the nightly pre-release of QGIS 3.4 and checkout the results.

This wouldn’t have been possible without the rapid response to the campaign and the generosity of our wonderful backers:

(In addition to these backers, we’ve also received numerous anonymous donations to this feature from many other individuals — while we can’t list you all publicly, you’re also in our thanks!)

 

Keep an eye on this blog for other upcoming QGIS crowdfunding campaigns targeted at QGIS 3.6 and beyond… we’ve got lots more exciting work planned for these releases!

 

Edit Features “In Place” crowdfund — target reached!

Well, the final pledges have been tallied and we’re very proud to announce that our latest crowd funding campaign has been a roaring success!

We’ve been completely blown away by the response to this campaign. Thanks to some incredibly generous backers and donors, we’ve been able to hit the campaign target with plenty of time to spare. As a result, we’ll be pushing hard to reward the generosity of the community by trying to sneak this feature in for the upcoming QGIS 3.4 release (instead of the originally promised 3.6 release)! You can read more about what we’re adding at the campaign page.

We’d like to take this opportunity to extend our heartfelt thanks to all the backers who have pledged to support this project:

In addition to these backers, we’ve also received numerous anonymous donations to this feature from many other individuals — while we can’t list you all publicly, you’re also in our thanks!

Stay tuned for more updates to come as work proceeds on this feature…

Edit Features “In Place” Using QGIS Spatial Operations crowdfund launched!

We’ve just launched a new QGIS crowd funding campaign which we’re super-excited about! This time, we’re addressing what we see as the major shortcoming within QGIS vector layer editing tools, and bridging the gap between the vast power of QGIS’ Processing algorithms and easy-to-use operations which modify layer features “in place”. Here’s a quick sneak preview of what we have planned:

 

QGIS is already a vector editing powerhouse, and we believe that this improvement will boost the current functionality up an order of magnitude! To make it possible we need 6500€ pledged before 30 September 2018.

This is also our first crowdfunding campaign in which we’re running a “dual funding” approach, which we think should make things friendly and easy for both corporate backers and end user contributions alike. Read more about this at the full campaign page.

You can help make this a reality by supporting the campaign or by sharing the page and increasing exposure to the campaign. Updates to follow!

 

Celebrating 35 years of GRASS GIS!

Today marks 35 years of GRASS GIS development – with frequent releases the project keeps pushing the limits in terms of geospatial data processing quality and performance.

GRASS (Geographic Resources Analysis Support System) is a free and open source Geographic Information System (GIS) software suite used for geospatial data management and analysis, image processing, graphics and map production, spatial modeling, and 3D visualization. Since the major GRASS GIS 7 version, it also comes with a feature rich engine for space-time cubes useful for time series processing of Landsat and Copernicus Sentinel satellite data and more. GRASS GIS can be either used as a desktop application or as a backend for other software packages such as QGIS and R. Furthermore, it is frequently used on HPC and cloud infrastructures for massive parallelized data processing.

Brief history
In 1982, under the direction of Bill Goran at the U.S. Army Corps of Engineers Construction Engineering Research Laboratory (CERL), two GIS development efforts were undertaken. First, Lloyd Van Warren, a University of Illinois engineering student, began development on a new computer program that allowed analysis of mapped data.  Second, Jim Westervelt (CERL) developed a GIS package called “LAGRID – the Landscape Architecture Gridcell analysis system” as his master’s thesis. Thirty five years ago, on 29 July 1983, the user manual for this new system titled “GIS Version 1 Reference Manual” was first published by J. Westervelt and M. O’Shea. With the technical guidance of Michael Shapiro (CERL), the software continued its development at the U.S. Army Corps of Engineers Construction Engineering Research Laboratory (USA/CERL) in Champaign, Illinois; and after further expansion version 1.0 was released in 1985 under the name Geographic Resources Analysis Support System (GRASS). The GRASS GIS community was established the same year with the first annual user meeting and the launch of GRASSnet, one of the internet’s early mailing lists. The user community expanded to a larger audience in 1991 with the “Grasshopper” mailing list and the introduction of the World Wide Web. The users’ and programmers’ mailing lists archives for these early years are still available online.
In the mid 1990s the development transferred from USA/CERL to The Open GRASS Consortium (a group who would later generalize to become today’s Open Geospatial Consortium — the OGC). The project coordination eventually shifted to the international development team made up of governmental and academic researchers and university scientists. Reflecting this shift to a project run by the users, for the users, in 1999 GRASS GIS was released under the terms of the GNU General Public License (GPL). A detailed history of GRASS GIS can be found at https://grass.osgeo.org/history/.

Where to next?
The development on GRASS GIS continues with more energy and interest than ever. Parallel to the long-term maintenance of the GRASS 7.4 stable series, effort is well underway on the new upcoming cutting-edge 7.6 release, which will bring many new features, enhancements, and cleanups. As in the past, the GRASS GIS community is open to any contribution, be it in the form of programming, documentation, testing, and financial sponsorship. Please contact us!

About GRASS GIS

The Geographic Resources Analysis Support System (https://grass.osgeo.org/), commonly referred to as GRASS GIS, is an Open Source Geographic Information System providing powerful raster, vector and geospatial processing capabilities in a single integrated software suite. GRASS GIS includes tools for spatial modeling, visualization of raster and vector data, management and analysis of geospatial data, and the processing of satellite and aerial imagery. It also provides the capability to produce sophisticated presentation graphics and hardcopy maps. GRASS GIS has been translated into about twenty languages and supports a huge array of data formats. It can be used either as a stand-alone application or as backend for other software packages such as QGIS and R geostatistics. It is distributed freely under the terms of the GNU General Public License (GPL). GRASS GIS is a founding member of the Open Source Geospatial Foundation (OSGeo).

The GRASS Development Team, July 2018

The post Celebrating 35 years of GRASS GIS! appeared first on GFOSS Blog | GRASS GIS and OSGeo News.

Drill down (cascading) forms in QGIS crowdfund – final stretch!

Update: donations are now closed, with the outcome of the campaign pending!

We’re nearing the final hours of our crowd funding campaign to implement a drill-down (cascading) field support within QGIS forms, and thanks to numerous generous backers we’re very close to hitting the funding goal! This is a really exciting new feature which would help add greater flexibility and power to QGIS feature forms, but in order to implement it for QGIS 3.2 we need to hit the funding target by 11 May 2018.

As a result, we’re dropping the minimum contribution amount and throwing open the campaign for payments of any amount. These smaller payment will be treated as direct donations to the campaign, so unlike the standard campaign backing these are payable up front. In the case that the campaign IS NOT successful, the donations will not be refunded and will instead be reinvested back into the QGIS (via bug fixing and maintenance efforts). Of course, if you’d prefer to pledge using the standard crowdfunding “no payment if campaign unsuccessful” model you’re more than welcome to! (Full details are available on the campaign page).

Donations closed – outcome pending!

Full details are available on the campaign page.

PDAL 1.7 packaged for Fedora including vertical datums and grids

Cologne city shown as colorized 3D point cloud (data source: openNRW Germany)In order to simplify the installation of the latest PDAL release (Point Data Abstraction Library, https://pdal.io/, version 1.7.0 1.7.2) on Fedora, I have created an updated set of RPM packages, again including the vertical datums and grids available from OSGeo (i.e., .gtx files from here).

The installation is as simple as this (the repository is located at Fedora’s COPR):

# enable extra repos to satisfy dependencies
sudo dnf copr enable neteler/pdal-hexer
sudo dnf copr enable neteler/points2grid
sudo dnf copr enable neteler/laszip

# install minimal dependencies
sudo dnf install hexer
sudo dnf install points2grid

# enable and install PDAL
sudo dnf copr enable neteler/pdal
sudo dnf install PDAL PDAL-vdatums

# run it
pdal-config --version
pdal --help

Enjoy!

The post PDAL 1.7 packaged for Fedora including vertical datums and grids appeared first on GFOSS Blog | GRASS GIS and OSGeo News.

Drill-down (cascading) forms in QGIS crowdfund launched!

We’ve just launched a new crowd funding campaign to implement a drill-down (cascading) field support within QGIS forms. Full details are available on the campaign page.

This is a really exciting new feature which would help add greater flexibility and power to QGIS feature forms! To make it possible we need 3500€ pledged before 11 May 2018. You can help make this a reality by supporting the campaign or by sharing the page and increasing exposure to the campaign. Updates to follow!

Implementing an in-house “New Project Wizard” for QGIS

Recently, we were required to implement a custom “New Project Wizard” for use in a client’s internal QGIS installation. The goal here was that users would be required to fill out certain metadata fields whenever they created a new QGIS project.

Fortunately, the PyQGIS (and underlying Qt) libraries makes this possibly, and relatively straightforward to do. Qt has a powerful API for creating multi-page “wizard” type dialogs, via the QWizard and QWizardPage classes. Let’s have a quick look at writing a custom wizard using these classes, and finally we’ll hook it into the QGIS interface using some PyQGIS magic.

We’ll start super simple, creating a single page wizard with no settings. To do this we first create a Page1 subclass of QWizardPage, a ProjectWizard subclass of QWizard, and a simple runNewProjectWizard function which launches the wizard. (The code below is designed for QGIS 3.0, but will run with only small modifications on QGIS 2.x):


class Page1(QWizardPage):

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setTitle('General Properties')
        self.setSubTitle('Enter general properties for this project.')


class ProjectWizard(QWizard):
    
    def __init__(self, parent=None):
        super().__init__(parent)
        
        self.addPage(Page1(self))
        self.setWindowTitle("New Project")


def runNewProjectWizard():
    d=ProjectWizard()
    d.exec()

If this code is executed in the QGIS Python console, you’ll see something like this:

Not too fancy (or functional) yet, but still not bad for 20 lines of code! We can instantly make this a bit nicer by inserting a custom logo into the widget. This is done by calling setPixmap inside the ProjectWizard constructor.


class ProjectWizard(QWizard):
    
    def __init__(self, parent=None):
        super().__init__(parent)
        
        self.addPage(Page1(self))
        self.setWindowTitle("New Project")

        logo_image = QImage('path_to_logo.png')
        self.setPixmap(QWizard.LogoPixmap, QPixmap.fromImage(logo_image))

That’s a bit nicer. QWizard has HEAPS of options for tweaking the wizards — best to read about those over at the Qt documentation. Our next step is to start adding some settings to this wizard. We’ll keep things easy for now and just insert a number of text input boxes (QLineEdits) into Page1:


class Page1(QWizardPage):

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setTitle('General Properties')
        self.setSubTitle('Enter general properties for this project.')

        # create some widgets
        self.project_number_line_edit = QLineEdit()
        self.project_title_line_edit = QLineEdit()
        self.author_line_edit = QLineEdit()        
        
        # set the page layout
        layout = QGridLayout()
        layout.addWidget(QLabel('Project Number'),0,0)
        layout.addWidget(self.project_number_line_edit,0,1)
        layout.addWidget(QLabel('Title'),1,0)
        layout.addWidget(self.project_title_line_edit,1,1)
        layout.addWidget(QLabel('Author'),2,0)
        layout.addWidget(self.author_line_edit,2,1)
        self.setLayout(layout)

There’s nothing particularly new here, especially if you’ve used Qt widgets before. We make a number of QLineEdit widgets, and then create a grid layout containing these widgets and accompanying labels (QLabels). Here’s the result if we run our wizard now:

So now there’s the option to enter a project number, title and author. The next step is to force users to populate these fields before they can complete the wizard. Fortunately, QWizardPage has us covered here and we can use the registerField() function to do this. By calling registerField, we make the wizard aware of the settings we’ve added on this page, allowing us to retrieve their values when the wizard completes. We can also use registerField to automatically force their population by appending a * to the end of the field names. Just like this…

class Page1(QWizardPage):
    def __init__(self, parent=None):
        super().__init__(parent)
        ...
        self.registerField('number*',self.project_number_line_edit)
        self.registerField('title*',self.project_title_line_edit)
        self.registerField('author*',self.author_line_edit)

If we ran the wizard now, we’d be forced to enter something for project number, title and author before the Finish button becomes enabled. Neat! By registering the fields, we’ve also allowed their values to be retrieved after the wizard completes. Let’s alter runNewProjectWizard to retrieve these values and do something with them:

def runNewProjectWizard():
   d=ProjectWizard()
   d.exec()

   # Set the project title
   title=d.field('title')
   QgsProject.instance().setTitle(d.field('title'))

   # Create expression variables for the author and project number
   number=d.field('number')
   QgsExpressionContextUtils.setProjectVariable(QgsProject.instance(),'project_number', number)
   author=d.field('author')
   QgsExpressionContextUtils.setProjectVariable(QgsProject.instance(),'project_author', author)
 

Here, we set the project title directly and create expression variables for the project number and author. This allows their use within QGIS expressions via the @project_number and @project_author variables. Accordingly, they can be embedded into print layout templates so that layout elements are automatically populated with the corresponding author and project number. Nifty!

Ok, let’s beef up our wizard by adding a second page, asking the user to select a sensible projection (coordinate reference system) for their project. Thanks to improvements in QGIS 3.0, it’s super-easy to embed a powerful pre-made projection selector widget into your scripts, which even includes a handy preview of the area of the world that the projection is valid for.


class Page2(QWizardPage):

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setTitle('Project Coordinate System')
        self.setSubTitle('Choosing an appropriate projection is important to ensure accurate distance and area measurements.')
        
        self.proj_selector = QgsProjectionSelectionTreeWidget()
        layout = QVBoxLayout()
        layout.addWidget(self.proj_selector)
        self.setLayout(layout)
        
        self.registerField('crs',self.proj_selector)
        self.proj_selector.crsSelected.connect(self.crs_selected)
        
    def crs_selected(self):
        self.setField('crs',self.proj_selector.crs())
        self.completeChanged.emit()
        
    def isComplete(self):
        return self.proj_selector.crs().isValid()

There’s a lot happening here. First, we subclass QWizardPage to create a second page in our widget. Then, just like before, we add some widgets to this page and set the page’s layout. In this case we are using the standard QgsProjectionSelectionTreeWidget to give users a projection choice. Again, we let the wizard know about our new setting by a call to registerField. However, since QWizard has no knowledge about how to handle a QgsProjectionSelectionTreeWidget, there’s a bit more to do here. So we make a connection to the projection selector’s crsSelected signal, hooking it up to a function which sets the wizard’s “crs” field value to the widget’s selected CRS. Here, we also emit the completeChanged signal, which indicates that the wizard page should re-validate the current settings. Lastly, we override QWizardPage’s isComplete method, checking that there’s a valid CRS selection in the selector widget. If we run the wizard now we’ll be forced to choose a valid CRS from the widget before the wizard allows us to proceed:

Lastly, we need to adapt runNewProjectWizard to also handle the projection setting:


def runNewProjectWizard():
    d=ProjectWizard()
    d.exec()

    # Set the project crs
    crs=d.field('crs')
    QgsProject.instance().setCrs(crs)

    # Set the project title
    title=d.field('title')
    ...

Great! A fully functional New Project wizard. The final piece of the puzzle is triggering this wizard when a user creates a new project within QGIS. To do this, we hook into the iface.newProjectCreated signal. By connecting to this signal, our code will be called whenever the user creates a new project (after all the logic for saving and closing the current project has been performed). It’s as simple as this:


iface.newProjectCreated.connect(runNewProjectWizard)

Now, whenever a new project is made, our wizard is triggered – forcing users to populate the required fields and setting up the project accordingly!

There’s one last little bit to do – we also need to prevent users cancelling or closing the wizard before completing it. That’s done by changing a couple of settings in the ProjectWizard constructor, and by overriding the default reject method (which prevents closing the dialog by pressing escape).


class ProjectWizard(QWizard):
    
    def __init__(self, parent=None):
        super().__init__(parent)
        ...
        self.setOption(QWizard.NoCancelButton, True)
        self.setWindowFlags(self.windowFlags() | QtCore.Qt.CustomizeWindowHint)
        self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.WindowCloseButtonHint)

    def reject(self):
        pass

Here’s the full version of our code, ready for copying and pasting into the QGIS Python console:


icon_path = '/home/nyall/nr_logo.png'

class ProjectWizard(QWizard):
    
    def __init__(self, parent=None):
        super().__init__(parent)
        
        self.addPage(Page1(self))
        self.addPage(Page2(self))
        self.setWindowTitle("New Project")
        
        logo_image=QImage('path_to_logo.png')
        self.setPixmap(QWizard.LogoPixmap, QPixmap.fromImage(logo_image))
        
        self.setOption(QWizard.NoCancelButton, True)
        self.setWindowFlags(self.windowFlags() | QtCore.Qt.CustomizeWindowHint)
        self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.WindowCloseButtonHint)
    def reject(self):
        pass
class Page1(QWizardPage):
    
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setTitle('General Properties')
        self.setSubTitle('Enter general properties for this project.')

        # create some widgets
        self.project_number_line_edit = QLineEdit()
        self.project_title_line_edit = QLineEdit()
        self.author_line_edit = QLineEdit()        
        
        # set the page layout
        layout = QGridLayout()
        layout.addWidget(QLabel('Project Number'),0,0)
        layout.addWidget(self.project_number_line_edit,0,1)
        layout.addWidget(QLabel('Title'),1,0)
        layout.addWidget(self.project_title_line_edit,1,1)
        layout.addWidget(QLabel('Author'),2,0)
        layout.addWidget(self.author_line_edit,2,1)
        self.setLayout(layout)
        
        self.registerField('number*',self.project_number_line_edit)
        self.registerField('title*',self.project_title_line_edit)
        self.registerField('author*',self.author_line_edit)
 
 
class Page2(QWizardPage):
    
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setTitle('Project Coordinate System')
        self.setSubTitle('Choosing an appropriate projection is important to ensure accurate distance and area measurements.')
        
        self.proj_selector = QgsProjectionSelectionTreeWidget()
        layout = QVBoxLayout()
        layout.addWidget(self.proj_selector)
        self.setLayout(layout)
        
        self.registerField('crs',self.proj_selector)
        self.proj_selector.crsSelected.connect(self.crs_selected)
        
    def crs_selected(self):
        self.setField('crs',self.proj_selector.crs())
        self.completeChanged.emit()
        
    def isComplete(self):
        return self.proj_selector.crs().isValid()
 
        
def runNewProjectWizard():
    d=ProjectWizard()
    d.exec()
    
    # Set the project crs
    crs=d.field('crs')
    QgsProject.instance().setCrs(crs)
    
    # Set the project title
    title=d.field('title')
    QgsProject.instance().setTitle(d.field('title'))

    # Create expression variables for the author and project number
    number=d.field('number')
    QgsExpressionContextUtils.setProjectVariable(QgsProject.instance(),'project_number', number)
    author=d.field('author')
    QgsExpressionContextUtils.setProjectVariable(QgsProject.instance(),'project_author', author)
    
    
iface.newProjectCreated.connect(runNewProjectWizard)

  • <<
  • Page 3 of 9 ( 169 posts )
  • >>
  • osgeo

Back to Top

Sustaining Members