How to compute distance of two geographical coordinates? - python

I read this question and implemented the accepted answer in Python (see below). It works in principle, but the results are consistently about 30% higher than expected (Czech Republic) - is that the expected accuracy of this algorithm?
To verify the algorithm, I used BoundingBox to get a bounding box with a known diagonal distance (building, two cities) and used the output coordinates as input for "my" algorithm.
Where is the problem?
my implementation?
the algorithm itself?
Python?
testing?
My implementation:
R= 6371 #km
dLat = math.radians(lat2-lat1)
dLon = math.radians(lon2-lon1)
lat1 = math.radians(lat1)
lat2 = math.radians(lat2)
a= math.sin(dLat/2)*math.sin(dLat/2) + math.sin(dLon/2) * math.sin(dLon/2) * math.cos(lat1) * math.cos(lat2)
c= 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
d = R * c;
return d

No, the algorithm is not supposed to have an error of that magnitude. The link specifies that you can expect around a 0.3% error.
I can not reproduce your results with your code, so I believe the error is with your testing.
Here's some testing data from a site with the distance between and coordinates of Prague and Brno in decimal degrees format:
lat_prague, long_prague = 50.0833, 14.4667
lat_brno, long_brno = 49.2000, 16.6333
expected_km = 184.21
Here are the testing results:
>>> def calc(lat1,lon1, lat2,lon2):
# ... your code ...
>>> calc(lat_prague,long_prague,lat_brno,long_brno)
184.34019283649852
>>> calc(lat_prague,long_prague,lat_brno,long_brno) / expected_km
1.0007067631317437
A wild guess: for locations in the Czech Republic, the error you're getting seems in the right order of magnitude for with mixing up latitude and longitude:
>>> calc(long_prague,lat_prague,long_brno,lat_brno)
258.8286271447481
>>> calc(long_prague,lat_prague,long_brno,lat_brno) / expected_km
1.405073704710646
This is apparently a known confusion. A coordinate specified as only a pair of numbers is ambiguous (for instance: both BoundingBox and the reference for the distance above use (long, lat), and the algorithm uses the ordering lat, long). When you come across the ambiguous format with an unfamiliar data source without a formal specification, you'll just have to sanity-check. Sites like Wikipedia will tell you unambiguously that Prague lies at "50°05′N 14°25′E" -- that is, very roughly, around 50 degrees latitude (north-south) and 14 degrees longitude (east-west).

Related

find if an device is in perpendicular to the current location from ariel view / map view

A device is traveling from source to destination and has support for GPS,
we are able to locate the nearest signal using (current loc - static fixed traffic signals array)
here D1 is nearest, but we want to select D2 as it is facing our direction,
my approach is to find the perpendicular to the current location if a signal is perpendicular, then select that one, but I can't figure out how to, thought of using another value attached to each signal called angle, which is the angle from the north ie 180 deg in our case and somehow calculate the angle of the andriod from the north and compare it. if it is opposite (180 - south , 0 - north) select that one.
using gmaps API to find the direction from source to destination and converting the string(Encoded Polyline) to lat log using python decode polyline function.)
How can I implement the above solution, is it functional, or do I have any other options
I was able to only find out this code, but it is for the angle between a straight line to the x-axis
I think math.atan2(x, y) also provides an angle, right?
import math
def calculate_initial_compass_bearing(pointA, pointB):
"""
Calculates the bearing between two points.
The formulae used is the following:
θ = atan2(sin(Δlong).cos(lat2),
cos(lat1).sin(lat2) − sin(lat1).cos(lat2).cos(Δlong))
:Parameters:
- `pointA: The tuple representing the latitude/longitude for the
first point. Latitude and longitude must be in decimal degrees
- `pointB: The tuple representing the latitude/longitude for the
second point. Latitude and longitude must be in decimal degrees
:Returns:
The bearing in degrees
:Returns Type:
float
"""
if (type(pointA) != tuple) or (type(pointB) != tuple):
raise TypeError("Only tuples are supported as arguments")
lat1 = math.radians(pointA[0])
lat2 = math.radians(pointB[0])
diffLong = math.radians(pointB[1] - pointA[1])
x = math.sin(diffLong) * math.cos(lat2)
y = math.cos(lat1) * math.sin(lat2) - (math.sin(lat1)
* math.cos(lat2) * math.cos(diffLong))
initial_bearing = math.atan2(x, y)
#print(initial_bearing)
# Now we have the initial bearing but math.atan2 return values
# from -180° to + 180° which is not what we want for a compass bearing
# The solution is to normalize the initial bearing as shown below
initial_bearing = math.degrees(initial_bearing)
compass_bearing = (initial_bearing + 360) % 360
return compass_bearing
You're assuming the phone is installed straight forward and not at an angle. That isn't a good assumption. My phone is rarely straight forwared, its usually thrown in the center console in whatever way it lands. Or sitting on the passenger seat, same thing. A better idea would be to look at the heading the last time their speed was non-zero- that will show the direction they were going in. Of course if they made a last minute lane change it could be a bit off, but it will be more accurate.

Python nearest neighbour - coordinates

I wanted to check I was using scipy's KD tree correctly because it appears slower than a simple bruteforce.
I had three questions regarding this:
Q1.
If I create the following test data:
nplen = 1000000
# WGS84 lat/long
point = [51.349,-0.19]
# This contains WGS84 lat/long
points = np.ndarray.tolist(np.column_stack(
[np.round(np.random.randn(nplen)+51,5),
np.round(np.random.randn(nplen),5)]))
And create three functions:
def kd_test(points,point):
""" KD Tree"""
return points[spatial.KDTree(points).query(point)[1]]
def ckd_test(points,point):
""" C implementation of KD Tree"""
return points[spatial.cKDTree(points).query(point)[1]]
def closest_math(points,point):
""" Simple angle"""
return (min((hypot(x2-point[1],y2-point[0]),y2,x2) for y2,x2 in points))[1:3]
I would expect the cKD tree to be the fastest, however - running this:
print("Co-ordinate: ", f(points,point))
print("Index: ", points.index(list(f(points,point))))
%timeit f(points,point)
Result times - the simple bruteforce method is faster:
closest_math: 1 loops, best of 3: 3.59 s per loop
ckd_test: 1 loops, best of 3: 13.5 s per loop
kd_test: 1 loops, best of 3: 30.9 s per loop
Is this because I am using it wrong - somehow?
Q2.
I would assume that the even to get the ranking (rather than distance) of closest points one still needs to project the data. However, it seems that the projected and un-projected points give me the same nearest neighbour:
def proj_list(points,
inproj = Proj(init='epsg:4326'),
outproj = Proj(init='epsg:27700')):
""" Projected geo coordinates"""
return [list(transform(inproj,outproj,x,y)) for y,x in points]
proj_points = proj_list(points)
proj_point = proj_list([point])[0]
Is this just because my spread of points is not big enough to introduce distortion? I re-ran a few times and still got the same index out of the projected and un-projected lists being returned.
Q3.
Is it generally faster to project the points (like above) and calculate the hypotenuse distance compared to calculating the haversine or vincenty distance on (un-projected) latitude/longitudes? Also which option would be more accurate? I ran a small test:
from math import *
def haversine(origin,
destination):
"""
Find distance between a pair of lat/lng coordinates
"""
lat1, lon1, lat2, lon2 = map(radians, [origin[0],origin[1],destination[0],destination[1]])
dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat / 2) ** 2 + cos(lat1) * cos(lat2) * sin(dlon / 2) ** 2
c = 2 * asin(sqrt(a))
r = 6371000 # Metres
return (c * r)
def closest_math_unproj(points,point):
""" Haversine on unprojected """
return (min((haversine(point,pt),pt[0],pt[1]) for pt in points))
def closest_math_proj(points,point):
""" Simple angle since projected"""
return (min((hypot(x2-point[1],y2-point[0]),y2,x2) for y2,x2 in points))
Results:
So this seems to say that projecting and then doing distance is faster than not - however, I am not sure which method will bring more accurate results.
Testing this on an online vincenty calculation is seems the projected co-ordinates are the way to go:
Q1.
The reason for the apparent inefficiency of the k-d tree is quite simple: you are measuring both the construction and querying of the k-d tree at once. This is not how you would or should use a k-d tree: you should construct it only once. If you measure only the querying, the time taken reduces to mere tens of milliseconds (vs seconds using the brute-force approach).
Q2.
This will depend on the spatial distribution of the actual data being used and the projection being used. There might be slight differences based on how efficient the implementation of the k-d tree is at balancing the constructed tree. If you are querying only a single point, then the result will be deterministic and unaffected by the distribution of points anyway.
With the sample data that you are using, which has strong central symmetry, and with your map projection (Transverese Mercator), the difference should be negligible.
Q3.
Technically, the answer to your question is trivial: using the Haversine formula for geographic distance measurement is both more accurate and slower. Whether the tradeoff between accuracy and speed is warranted depends heavily on your use case and the spatial distribution of your data (mostly on the spatial extent, obviously).
If the spatial extent of your points is on the small, regional side, then using a suitable projection and the simple Euclidean distance measure might be accurate enough for your use case and faster than using the Haversine formula.

convert latitude and longitude to x and y grid system using python

I have file with latitude and longitude values, that i want to convert the x and y in km
I want to measure the distance from each point.
for instance I make the first points of latitude and longitude(which are 51.58, -124.6 respectfully)
to (0,0) in my x and y system so than basically i want to find out what the other points are and their location from the origin so i want to find what 51.56(lat) -123.64(long) is in (x,y) in km and so on for the rest of the file.
I want to do this all in python, is there some sort code ?
I found sites online , for instance
http://www.whoi.edu/marine/ndsf/cgi-bin/NDSFutility.cgi?form=0&from=LatLon&to=XY
does exactly want i want to do, I just don't know how they do it.
The following gets you pretty close (answer in km). If you need to be better than this, you have to work harder at the math - for example by following some of the links given.
import math
dx = (lon1-lon2)*40000*math.cos((lat1+lat2)*math.pi/360)/360
dy = (lat1-lat2)*40000/360
Variable names should be pretty obvious. This gives you
dx = 66.299 km (your link gives 66.577)
dy = 2.222 km (link gives 2.225)
Once you pick coordinates (for example, lon1, lat1) as your origin, it should be easy to see how to compute all the other XY coordinates.
Note - the factor 40,000 is the circumference of the earth in km (measured across the poles). This gets you close. If you look at the source of the link you provided (you have to dig around a bit to find the javascript which is in a separate file) you find that they use a more complex equation:
function METERS_DEGLON(x)
{
with (Math)
{
var d2r=DEG_TO_RADIANS(x);
return((111415.13 * cos(d2r))- (94.55 * cos(3.0*d2r)) + (0.12 * cos(5.0*d2r)));
}
}
function METERS_DEGLAT(x)
{
with (Math)
{
var d2r=DEG_TO_RADIANS(x);
return(111132.09 - (566.05 * cos(2.0*d2r))+ (1.20 * cos(4.0*d2r)) - (0.002 * cos(6.0*d2r)));
}
}
It looks to me like they are actually taking account of the fact that the earth is not exactly a sphere... but even so when you are making the assumption you can treat a bit of the earth as a plane you are going to have some errors. I'm sure with their formulas the errors are smaller...
UTM projections are in meters. So you could use something like the utm lib at this link:
https://pypi.python.org/pypi/utm
Googling python lat lon to UTM will point to several options.
UTM zones are 6 degrees of longitude wide and start from 0 at the prime meridian. The origin of each UTM zone is on the equator (x-axis) with the y-axis at the western most degree of longitude. This makes the grid positive to the north and east. You could calculate your distance from these results. Values are most accurate in the middle of the UTM zone.
You also should know what datum your original lat lon values are based on and use the same datum in your conversion.
if you were to use a 3D system, these functions will do:
def arc_to_deg(arc):
"""convert spherical arc length [m] to great circle distance [deg]"""
return float(arc)/6371/1000 * 180/math.pi
def deg_to_arc(deg):
"""convert great circle distance [deg] to spherical arc length [m]"""
return float(deg)*6371*1000 * math.pi/180
def latlon_to_xyz(lat,lon):
"""Convert angluar to cartesian coordiantes
latitude is the 90deg - zenith angle in range [-90;90]
lonitude is the azimuthal angle in range [-180;180]
"""
r = 6371 # https://en.wikipedia.org/wiki/Earth_radius
theta = math.pi/2 - math.radians(lat)
phi = math.radians(lon)
x = r * math.sin(theta) * math.cos(phi) # bronstein (3.381a)
y = r * math.sin(theta) * math.sin(phi)
z = r * math.cos(theta)
return [x,y,z]
def xyz_to_latlon (x,y,z):
"""Convert cartesian to angular lat/lon coordiantes"""
r = math.sqrt(x**2 + y**2 + z**2)
theta = math.asin(z/r) # https://stackoverflow.com/a/1185413/4933053
phi = math.atan2(y,x)
lat = math.degrees(theta)
lon = math.degrees(phi)
return [lat,lon]
You can get the distance between GPS points using the Great Circle Distance formula. Latitude and longitude are in an geodectic coordinate system, so you can't just convert to a flat 2D grid and use euclidean distances. You can convert sufficiently close points to an approximate grid by taking an arbitrary point like your (X,Y), setting it to the origin (like you've done) and then using great circle distance together with bearing to plot the points relative to each other on the plane, but it's an approximation.
You can use UTM:
pip install utm
Here is an example:
>>> import utm
>>> utm.from_latlon(51.2, 7.5)
(395201.3103811303, 5673135.241182375, 32, 'U')
The return has the form (EASTING, NORTHING, ZONE_NUMBER, ZONE_LETTER).
Notes
It works with NumPy arrays too:
>>> utm.from_latlon(np.array([51.2, 49.0]), np.array([7.5, 8.4]))
(array([395201.31038113, 456114.59586214]),
array([5673135.24118237, 5427629.20426126]),
32,
'U')
And in reverse:
>>> utm.to_latlon(340000, 5710000, 32, 'U')
(51.51852098408468, 6.693872395145327)

Calculating distance travelled from gps track points using python [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 8 years ago.
Improve this question
I have this very silly question to ask. I have GPS track points for a journey like this:
863.3,2013-10-05T01:21:07Z,0,13.348841,77.686539
863.3,2013-10-05T01:21:08Z,1,13.348841,77.686539
863.3,2013-10-05T01:21:23Z,2,13.348708,77.686248
861.1,2013-10-05T01:21:28Z,3,13.348647,77.686088
867.0,2013-10-05T01:29:03Z,4,13.34732,77.682364
All I want is to find the distance traveled: should I only consider the first track point and the last track point? Or do I need to find the distance traveled between every track point?
Once you parse your gps points, you need to extract the lat/lon points for each. You could use the following formula adapted from here to get the distances between each pair of points and add sum them for your total distance.
import math
def getDistance(lat1,lon1,lat2,lon2):
# This uses the haversine formula, which remains a good numberical computation,
# even at small distances, unlike the Shperical Law of Cosines.
# This method has ~0.3% error built in.
R = 6371 # Radius of Earth in km
dLat = math.radians(float(lat2) - float(lat1))
dLon = math.radians(float(lon2) - float(lon1))
lat1 = math.radians(float(lat1))
lat2 = math.radians(float(lat2))
a = math.sin(dLat/2) * math.sin(dLat/2) + \
math.cos(lat1) * math.cos(lat2) * math.sin(dLon/2) * math.sin(dLon/2)
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
d = R * c * 0.621371 # Converting km to miles with "* 0.621371"
return d
Note that this function returns your distances in miles, but you can keep things metric in (km) by removing the "* 0.621371" from the end.
Of course these are assuming great circle lines. You're probably traveling some sort of network, so this will certainly not be real world accurate.
In order to get an estimate of the distance travelled between the GPS track points you have, you definitely need to consider the distances between all consecutive points. More precisely, if you have N positions, you need to iterate over all positions you have and sum up the distance between each point P_i and P_i+1 (ordered by the time it has been recorded).
If you would only calculate the distance between the first and the last point, the result would not be of any meaning at all. Imagine a set of N points that have been recorded while moving a track that represents a large circle. The first and the last point would be almost the same, hence resulting in a very small distance, even though the total distance you travelled while moving in the circle is significantly larger.
However, be aware that summing up the distance between consecutive points will still only be an estimate of the total distance travelled. Depending on the resolution of your track (i.e., the frequency in wich the positions of your track have been submitted) the accuracy compared to the real distance may vary significantly.

Fast python GIS library that supports Great Circle Distance and polygon

I was looking for a geographical library for python.
I need to be able to do the following:
Get the distance between 2 points (in meters) using Great-circle distance (not liner distance calculation)
Check if a point is inside a polygon
Perform 1 and 2 couple of thousands times per seconds
At start I've looked at this post: Python module for storing and querying geographical coordinates and started to use geopy.
I've encountered 2 problems:
Geopy doesn't support polygons
High CPU usage of geoPy (it takes about 140ms of CPU to calculate distance between a point and relative 5000 points)
I've continued looking and found Best Python GIS library? and https://gis.stackexchange.com/ . It looked promising as geos is using complied C code which should be faster and shapely supports polygons.
The problem is that geos/OGR performs linear distance calculations instead of sphere. This eliminates all other geos based modules (like GEODjango and shapely).
Am I missing something here? I don't think that I'm the first person who is using python to perform GIS calculations and wants to get accurate results.
UPDATE
Moving on now to finishing out the other 576 functions in that library not including the two polygon functions that are finished, the three sphere distance algorithms that are done, and two new ones, an angle_box_2d and angle_contains_ray_2d. Also, I switched to the C version so that externs are not needed, simplifies the work. Put the old C++ version in directory old_c++, so its still there.
Tested performance, it is identical as listed at the bottom of the answer.
UPDATE 2
So just a quick update, I haven't finished the whole library yet (I'm only about 15% of the way through), but I've added these untested functions, in case you need them right away, on github, to add to the old point in polygon and sphere distance algorithms.
angle_box_2d
angle_contains_ray_2d
angle_deg_2d
angle_half_2d # MLM: double *
angle_rad_2d
angle_rad_3d
angle_rad_nd
angle_turn_2d
anglei_deg_2d
anglei_rad_2d
annulus_area_2d
annulus_sector_area_2d
annulus_sector_centroid_2d # MLM: double *
ball_unit_sample_2d # MLM: double *
ball_unit_sample_3d # MLM: double *
ball_unit_sample_nd # MLM; double *
basis_map_3d #double *
box_01_contains_point_2d
box_01_contains_point_nd
box_contains_point_2d
box_contains_point_nd
box_ray_int_2d
box_segment_clip_2d
circle_arc_point_near_2d
circle_area_2d
circle_dia2imp_2d
circle_exp_contains_point_2d
circle_exp2imp_2d
circle_imp_contains_point_2d
circle_imp_line_par_int_2d
circle_imp_point_dist_2d
circle_imp_point_dist_signed_2d
circle_imp_point_near_2d
circle_imp_points_2d # MlM: double *
circle_imp_points_3d # MLM: double *
circle_imp_points_arc_2d
circle_imp_print_2d
circle_imp_print_3d
circle_imp2exp_2d
circle_llr2imp_2d # MLM: double *
circle_lune_area_2d
circle_lune_centroid_2d # MLM; double *
circle_pppr2imp_3d
The ones that I've commented above probably won't work, the others might, but again - polygon & sphere distances definitely do. And you can specify meters, kilometers, miles, nautical miles, it doesn't really matter on the spherical distance ones, the output is in the same units as the input - the algorithms are agnnostic to the units.
I put this together this morning so it currently only provides the point in polygon, point in convex polygon, and three different types of spherical distance algorithms, but at least those ones that you requested are there for you to use now. I don't know if there is a name conflict with any other python library out there, I only get peripherally involved with python these days, so if there's a better name for it I'm open to suggestions.
On github: https://github.com/hoonto/pygeometry
It is just a python bridge to the functions described and implemented here:
http://people.sc.fsu.edu/~jburkardt/cpp_src/geometry/geometry.html
The GEOMETRY library is pretty good actually, so I think it'll be useful to bridge all of those functions for python, which I'll do probably tonight.
Edit: a couple other things
Because the math functions are actually compiled C++, you do of course need to make sure that the shared library is in the path. You can modify the geometry.py to point at wherever you want to put that shared library though.
Only compiled for linux, the .o and .so were compiled on x86_64 fedora.
The spherical distance algorithms expect radians so you need to convert decimal lat/lon degrees for example to radians, as shown in geometry.py.
If you do need this on Windows let me know, it should only take a couple minutes to get it worked out in Visual Studio. But unless someone asks I'll probably just leave it alone for now.
Hope this helps!
Rgds....Hoonto/Matt
(new commit: SHA: 4fa2dbbe849c09252c7bd931edfe8db478de28e6 - fixed some things, like radian conversions and also the return types for the py functions. Also added some basic performance tests to make sure the library performs appropriately.)
Test Results
In each iteration, one call to sphere_distance1 and one call polygon_contains_point_2d so 2 calls to the library total.
~0.062s : 2000 iterations, 4000 calls
~0.603s : 20000 iterations, 40000 calls
~0.905s : 30000 iterations, 60000 calls
~1.198s : 40000 iterations, 80000 calls
If spherical calculation is enough I'd just use numpy for distance and matplotlib for polygon check (as you find similar proposals in stackoverflow).
from math import asin, cos, radians, sin, sqrt
import numpy as np
def great_circle_distance_py(pnt1, pnt2, radius):
""" Returns distance on sphere between points given as (latitude, longitude) in degrees. """
lat1 = radians(pnt1[0])
lat2 = radians(pnt2[0])
dLat = lat2 - lat1
dLon = radians(pnt2[1]) - radians(pnt1[1])
a = sin(dLat / 2.0) ** 2 + cos(lat1) * cos(lat2) * sin(dLon / 2.0) ** 2
return 2 * asin(min(1, sqrt(a))) * radius
def great_circle_distance_numpy(pnt1, l_pnt2, radius):
""" Similar to great_circle_distance_py(), but working on list of pnt2 and returning minimum. """
dLat = np.radians(l_pnt2[:, 0]) - radians(pnt1[0]) # slice latitude from list of (lat, lon) points
dLon = np.radians(l_pnt2[:, 1]) - radians(pnt1[1])
a = np.square(np.sin(dLat / 2.0)) + np.cos(radians(pnt1[0])) * np.cos(np.radians(l_pnt2[:, 0])) * np.square(np.sin(dLon / 2.0))
return np.min(2 * np.arcsin(np.minimum(np.sqrt(a), len(a)))) * radius
def aux_generateLatLon():
import random
while 1:
yield (90.0 - 180.0 * random.random(), 180.0 - 360.0 * random.random())
if __name__ == "__main__":
## 1. Great-circle distance
earth_radius_m = 6371000.785 # sphere of same volume
nPoints = 1000
nRep = 100 # just to measure time
# generate a point and a list of to check against
pnt1 = next(aux_generateLatLon())
l_pnt2 = np.array([next(aux_generateLatLon()) for i in range(nPoints)])
dMin1 = min([great_circle_distance_py(pnt1, pnt2, earth_radius_m) for pnt2 in l_pnt2])
dMin2 = great_circle_distance_numpy(pnt1, l_pnt2, earth_radius_m)
# check performance
import timeit
print "random points: %7i" % nPoints
print "repetitions : %7i" % nRep
print "function 1 : %14.6f s" % (timeit.timeit('min([great_circle_distance_py(pnt1, pnt2, earth_radius_m) for pnt2 in l_pnt2])', 'from __main__ import great_circle_distance_py , pnt1, l_pnt2, earth_radius_m', number=nRep))
print "function 2 : %14.6f s" % (timeit.timeit('great_circle_distance_numpy(pnt1, l_pnt2, earth_radius_m)' , 'from __main__ import great_circle_distance_numpy, pnt1, l_pnt2, earth_radius_m', number=nRep))
# tell distance
assert(abs(dMin1 - dMin2) < 0.0001)
print
print "min. distance: %14.6f m" % dMin1
## 2. Inside polygon?
# Note, not handled:
# - the "pathological case" mentioned on http://paulbourke.net/geometry/polygonmesh/
# - special situations on a sphere: polygons covering "180 degrees longitude edge" or the Poles
from matplotlib.path import Path
x = y = 1.0
l_pnt2 = [(-x, -y), (x, -y), (x, y), (-x, y), (-x, -y)]
path = Path(l_pnt2)
print "isInside ?"
for pnt in [(0.9, -1.9), (0.9, -0.9)]:
print " ", pnt, bool(path.contains_point(pnt))
If you want to do more, the Quantum GIS toolset probably is worth a look: PyQGIS Developer Cookbook (docs.qgis.org).

Categories