Как-то раз мне пришла идея нарисовать карту радиосвязей, проведенных в ходе экспериментов с любительским радио . Вроде бы для решения данной задачи существуют онлайн-сервисы и готовые (закрытые) программы, но мне не хотелось бы завязываться на такие решения. В свое время я где-то то ли слышал, то ли читал, что помимо построения графиков Matplotlib может рисовать еще и карты. Поэтому было решено попробовать написать соответствующий скрипт на языке Python.
Установка зависимостей осуществляется так:
brew install geos
# в Debian, если верить документации:
# apt-get install libgeos-3.3.3 libgeos-c1 libgeos-dev
mkvirtualenv qso-map
pip install matplotlib pillow pyhamtools
pip install git +https: // github.com / matplotlib / basemap.git
Библиотека pyhamtools за авторством Tobias Wellnitz, DH1TW будет использована для преобразования QTH locator в координаты GPS, а также для вычисления расстояния между двумя QTH. Точных QTH для ранее проведенных радиосвязей у меня не было, только позывные корреспондентов. К счастью, большинство радиолюбителей имеют свою страничку на qrzcq.com, откуда можно получить их QTH locator.
Конечно же, собирать эти данные вручную в мои планы не входило:
# vim: set ai et ts=4 sw=4:
import re
import os
import sys
import time
import argparse
import requests
HEADERS = { }
HEADERS [ ‘user-agent’ ] = u ‘Mozilla/5.0 (compatible; MSIE 9.0; ‘ +
u ‘Windows NT 6.0; Trident/5.0; Trident/5.0)’
def call_sign_to_qth ( call ) :
url = ‘https://www.qrzcq.com/call/’ +call. upper ( )
res = requests . get ( url , headers = HEADERS )
body = res. text
m = re . search ( «»»(?is)<b>Locator:</b></td><td align=»left»>»»» +
«»»(?:<font[^>]*>)?([A-Z0-9]{6})»»» , body )
if m is None :
return «»
return m. group ( 1 ) . strip ( )
parser = argparse . ArgumentParser ( description = ‘Convert ‘ +
‘call signs to QTH using qrzcq.com’ )
parser . add_argument (
‘-i’ , ‘—infile’ , metavar = ‘FILE’ , type = str ,
required = True , help = ‘file containing list of call signs’ )
args = parser . parse_args ( )
first = True
with open ( args. infile ) as f:
for line in f:
if not first:
print ( «Waiting 120 seconds…» , file = sys . stderr )
time . sleep ( 120 ) # otherwise qrzcq.com blocks by IP
first = False
call = line. strip ( )
print ( «Resolving {}…» . format ( call ) , file = sys . stderr )
qth = call_sign_to_qth ( call )
if qth == «» :
print ( «{} — not found :(» . format ( call ) , file = sys . stderr )
continue
print ( «{} — loc: {}» . format ( call , qth ) , file = sys . stderr )
print ( «{} {}» . format ( call , qth ) )
Непосредственно же построение карты осуществляется следующим скриптом:
# vim: set ai et ts=4 sw=4:
import matplotlib as mpl
# for MacOS, see https://stackoverflow.com/a/21789908/1565238
mpl. use ( ‘TkAgg’ )
from mpl_toolkits. basemap import Basemap
import numpy as np
import matplotlib . pyplot as plt
import pyhamtools. locator as htl
import argparse
import os
import sys
parser = argparse . ArgumentParser ( description = ‘Render a QSO map’ )
parser . add_argument (
‘-s’ , ‘—shack’ , metavar = ‘QTH’ , type = str ,
required = True , help = ‘your shack QTH’ )
parser . add_argument (
‘-i’ , ‘—infile’ , metavar = ‘FILE’ , type = str ,
required = True , help = ‘file containing list of QTHs’ )
parser . add_argument (
‘-o’ , ‘—outfile’ , metavar = ‘FILE’ , type = str ,
required = True , help = ‘where to save the resulting image’ )
args = parser . parse_args ( )
dpi = 80
fig = plt. figure ( dpi = dpi , figsize = ( 8 * 1024 / dpi , 4 * 1024 / dpi ) )
ax = fig. add_axes ( [ 0.1 , 0.1 , 0.8 , 0.8 ] )
m = Basemap ( projection = ‘cyl’ , resolution = None ,
llcrnrlat = — 90 , urcrnrlat = 90 ,
llcrnrlon = — 180 , urcrnrlon = 180 )
( shack_lat , shack_lon ) = htl. locator_to_latlong ( args. shack )
max_distance = 0
max_qth = args. shack
with open ( args. infile ) as f:
for line in f:
qth = line. strip ( )
distance = htl. calculate_distance ( args. shack , qth )
if distance > max_distance:
max_distance = distance
max_qth = qth
( lat , lon ) = htl. locator_to_latlong ( line. strip ( ) )
m. drawgreatcircle ( shack_lon , shack_lat , lon , lat ,
linewidth = 2 , color = ‘r’ )
# ax.set_title(‘Some title’)
m. bluemarble ( )
fig. savefig ( args. outfile )
print ( «Max distance: {} km, qth: {}» . format ( max_distance , max_qth ) )
И, наконец, результат (кликабельно, JPEG, 2760 x 1400, 1.1 Мб):
Можно построить карту поинтереснее, если использовать разные цвета для разных радиолюбительских диапазонов, использованных антенн, и так далее. Также скрипт легко модифицировать для визуализации любой другой информации, например, GPS-координат какого-то подвижного объекта. Больше примеров карт, которые можно построить с помощью Matplotlib и Basemap, вы найдете здесь .
Это все, о чем я хотел сегодня рассказать. Надеюсь, вы нашли данную информацию полезной.
Дополнение: Рисуем диаграммы Вольперта-Смита на Python