When viewing TMS layers in QGIS, as well as in any other GIS, the background map may be blurred if the current map scale does not match the scale of the tiles. The reason for this is a feature of TMS, namely the use of a fixed set of so-called “zoom levels”: tiles are generated only for certain scales defined by the data provider.
So to get a sharp image, you should only use the scales that correspond to the zoom levels of the selected TMS service. For OpenStreetMap, the formula for calculating the scale for each zoom level can be found on this page, and a similar approach can be used for other services.
Some time ago I added a special widget to QGIS to select a map scale from a given set. Later, it became possible to edit this list and define a set of scales on a global level as well as on a project level. So if your project uses TMS layers, you can create your own list of scales and switch between them. At the same time, you still have the option of using any intermediate scale values.
Another option is to install the Tile Map Scale plugin. This plugin allows you to easily connect popular TMS layers (remember about ToS!). It also monitors map scale changes and automatically sets the nearest correct TMS scale. Note that you will not be able to use intermediate scale values in this case.
Finally, QGIS has a built-in widget for changing the scale according to the layer’s scale list. It can be found in “View → Panels → Tile scale” or from the toolbar context menu.
We all face problems from time to time. Here are a few recent ones from my personal collection.
QGIS and SpatiaLite
Those who build QGIS themselves know that not so long ago there was a move to use external spatialindex and SpatiaLite instead of internal bundled copies. The former has been completely removed, but SpatiaLite is still there because it is either missing or too old in some distributions (namely Debian Squeeze, as well as Ubuntu Lucid, Maverick, Natty and Oneiric). The problem occurs when building QGIS with an external version of the library.
For historical reasons, the SpatiaLite can be compiled in two different ways:
as a loadable extension module for the system version of SQLite
as a standalone all-in-one library that combines the SQLite engine with the spatial capabilities of SpatiaLite
So. If you have SpatiaLite built as an all-in-one library, you can kiss SpatiaLite support in QGIS goodbye. You will not be able to create a new layer or open an existing one. What spices things up is that both configuration and compilation go smoothly: no missing files, no errors. The solution is to rebuild SpatiaLite as a loadable module and then rebuild QGIS. However, at this point you may face another problem.
SpatiaLite and dynamic linker
If the configure script constantly fails to find SQLite, GEOS and PROJ.4 when building a loadable SpatiaLite module on Linux, even though all these libraries are installed and have the correct version number, it is likely that your distribution has a policy of using unmodified source code (i.e., sources are only patched when absolutely necessary).
It should help to run configure as shown below
LDFLAGS=-ldl ./configure
PyQt4 and a new style of signal-slot connections
Since PyQt 4.5 there is a “new” style of signal-slot connection available in addition to the old style (more details). The new style is more Pythonic, and it is highly recommended to use it instead of the old style. The only thing is… if the interface was generated in Qt Designer and then converted to code using pyuic4, and the new style signal-slot connections are used in the code, then when you try to disconnect the signal from the slot, you may get a message that the operation cannot be performed. The situation has been clarified after contacting the developers:
PyQt allows connections to be made to any Python callable.
With old style connections a proxy slot is created under the covers whenever a callable is used (as opposed to when SLOT() is used to refer to a C++ slot). Therefore, in your example, a proxy is always created for the connection to Dialog.reject even though that refers to the object that wraps the C++ slot (as there is no Python reimplementation of reject()).
New style connections are a bit smarter in that they treat slot objects that refer to a wrapped C++ slot and objects that refer to some real Python code differently – a proxy is only created in the latter case.
So the rule is that if you make a connection old style then you must disconnect old style as well and the same for new style. You also need to be aware that pyuic4 uses old style connections.
It’s actually a bug, but they won’t fix it.
I accept that this is a bug, but I don’t want to fix it. The reason is that the changes required to the old style support code would be quite significant and I don’t think the risk to the stability of that code is worth it at this stage of the life of PyQt4 particularly as the workaround is straightforward.
The mentioned workaround is to create a dummy slot that simply calls the corresponding slot of the parent object. I.e., if you wanted to disconnect the reject() slot of a dialogue from the rejected() signal, using the old style, it was enough to write
Mayeul Kauffmann has done a great job comparing different ways to use OpenStreetMap (OSM) data in QGIS. He has also written a detailed guide on how to use OSM data to create beautiful, high-quality maps with routing support.
Here is a video demonstrating the use of QGIS and osm2postgresql.
QGIS allows you to save a default raster band combination, standard deviation and contrast enhancement algorithm for rasters.
But it seems that not many people use this feature. At least no one noticed that although the band combination and standard deviation can be saved, they are of no use because the saved values are not applied when the raster is loaded. There were also other problems (for example, when the default band combination is set to 5-4-3, in the raster properties dialogue we still see 1-2-3) that no one reported.
All this has been around for a long time, somewhere since r13582 or even earlier. And only in r15256 were all these problems finally solved.
I’ll try to explain why you might need it all this settings and how to use them.
Imagine you have a vector layer containing polygons, both single- and multipart. Your task is to get vertices of each geometry, including all rings and parts. Here is how it can be done using GDAL and Python.
Let’s start with simplest case — singlepart polygons. In that case everything is straightforward — we need to find out the number of vertices, iterate over them and get their coordinates. The code will look like this:
defdump_geometry(geom):
print "Exterior ring" ring = geom.GetGeometryRef(0)
for i in range(ring.GetPointCount()):
print i, ring.GetX(i), ring.GetY(i)
A polygon with “holes” is considered as a set of “rings”: one outer ring defining the polygon boundary and several inner rings describing the “holes”. The outer ring always comes first. Thus, the algorithm will transform as follows: loop over all rings; if it is the first iteration — this is an outer ring, otherwise — inner ring; extract vertices from the ring and output their coordinates.
defdump_geometry(geom):
nRings = geom.GetGeometryCount()
for i in range(nRings):
ring = geom.GetGeometryRef(i)
if i ==0:
print "Exterior ring"else:
print "Interior ring", i
for j in range(ring.GetPointCount()):
print j, ring.GetX(j), ring.GetY(j)
Handling multipart polygons is more complicated: they can be either singlepart polygons or contain “holes”, “islands”, or even “holes” and “islands” at the same time. Let’s try to figure out how to deal with them. A polygon consisting of several “islands” can be considered as a set of independent polygons. In turn, each of those polygons can have one or more rings. So what we have now:
if the polygon is a singlepart polygon and contains only one ring, we extract its vertices immediately
if the number of rings in polygon is greater than 1 — we loop through the rings and extract vertices from them
if the polygon is a multipart polygon — loop through the parts and for each for part perform checks starting from the step 1
So, this is a classical recursion and the final function will look like this:
defdump_geometry(geom, file):
geomType = geom.GetGeometryType() # geometry type# singlepart polygonif geomType == ogr.wkbPolygon or geomType == ogr.wkbPolygon25D:
nRings = geom.GetGeometryCount() # number of rings print "Rings", nRings
if nRings ==1: # there are no "holes" in the polygons print "Exterior ring" ring = geom.GetGeometryRef(0)
for i in range(ring.GetPointCount()):
print i, ring.GetX(i), ring.GetY(i)
else: # polygon with "holes"for i in range(nRings):
ring = geom.GetGeometryRef(i)
if i ==0:
print "Exterior ring"else:
print "Interior ring", i
for j in range(ring.GetPointCount()):
print j, ring.GetX(j), ring.GetY(j)
# multipart polygonelif geomType == ogr.wkbMultiPolygon or geomType == ogr.wkbMultiPolygon25D:
for i in range(geom.GetGeometryCount()):
subGeom = geom.GetGeometryRef(i) # for each polygon part dump_geometry(subGeom) # recursively call dump_geometry() function
The code is a bit bloated, but my aim was to demonstrate a possible way of approaching the task, not to come up with an ideal solution.
A bit more about Cyrillic and other non-ASCII characters in matplotlib. I decided to create a more comprehensive example to show how to output Cyrillic (or any other non-ASCII) characters in different parts of the plot. Actually, there is nothing complex here; you just need to find the time and read the manual, which is quite good, by the way. But as not everyone likes to read manuals… Anyway, here is the code:
#!/usr/bin/env python# -*- coding: utf-8 -*-from pylab import*import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
plt.rcParams["text.usetex"] =Falsefp = fm.FontProperties(fname="/home/alex/devel/mpl_cyr/CharisSILR.ttf")
plt.text(0.5, 0.5, u"довільний текст", fontproperties=fp)
# create some data to use for the plotx = arange(0.0, 3.0, 0.01)
y1 = sin(2* pi * x)
y2 = cos(2* pi * x)
# the main axes is subplot(111) by defaultplot(x, y1, label=u"Синусоїда")
plot(x, y2, label=u"Косинусоїда")
xlabel(u"Підпис вісі X", fontproperties=fp)
ylabel(u"Підпис вісі Y", fontproperties=fp)
title(u"Назва графіка", fontproperties=fp)
legend(prop=fp)
show()
There is a wonderful Python library — matplotlib. It is a plotting library that supports a wide range of plot types and is designed to emulate MATLAB commands and behaviour. The library is easy to learn; to draw a simple plot, you literally need two commands. I have used this library in my Statist plugin for QGIS and in another GIS project. To make installation of matplotlib more convenient for inexperienced users, I recently packaged it for OSGeo4W.
Sometimes, I needed to display non-ASCII (namely Cyrillic) characters on matplotlib plots. And there was a problem: such text was drawn as empty squares. Reading manuals, googling, and asking on the mailing list led to two solutions that I would like to share with you.
Method 1: the almighty TeX
matplotlib can use LaTeX to display both plain text and mathematical symbols. Moreover, a limited subset of TeX and the corresponding parser, fonts, and renderer are built into the library, so for this subset, you do not even need to have a full TeX installation. Unfortunately, this TeX subset only contains mathematical characters and letters of the Greek alphabet. In all other cases, an external LaTeX installation is required. To use LaTeX for text rendering, we should set the option
text.usetex: True
in the rc-file. This can be done either globally, by editing the rc-file once, or as needed at runtime. Below is an example of run-time initialisation:
Now we can output Cyrillic (or any other non-ASCII characters)
xlabel(u"Вісь Х: довжина, см")
The big disadvantage of this method is that the user needs to have LaTeX installed.
Method 2: unicode + fonts
matplotlib uses its own font rendering engine with full Unicode support. Therefore, we can explicitly specify a font that contains the required character sets and render the text using that font. Here is a small example:
# -*- coding: utf-8 -*-import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
plt.rcParams["text.usetex"] =Falsefp = fm.FontProperties(fname="/home/alex/.fonts/academy.ttf")
plt.text(0.5, 0.5, u"кириличний текст", fontproperties=fp)
plt.show()
There is also a disadvantage — the required font may not be available on the target system or may be in a different directory, so the font has to be stored in the same directory as your program. But in my opinion, this is much better than having LaTeX as a dependency.