Визуализация проведенных радиосвязей с помощью Matplotlib и Basemap
20 марта 2019
Как-то раз мне пришла идея нарисовать карту радиосвязей, проведенных в ходе экспериментов с любительским радио. Вроде бы для решения данной задачи существуют онлайн-сервисы и готовые (закрытые) программы, но мне не хотелось бы завязываться на такие решения. В свое время я где-то то ли слышал, то ли читал, что помимо построения графиков 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))
И, наконец, результат (кликабельно, JPG, 2760x1400, 1.1 Мб):
Можно построить карту поинтереснее, если использовать разные цвета для разных радиолюбительских диапазонов, использованных антенн, и так далее. Также скрипт легко модифицировать для визуализации любой другой информации, например, GPS-координат какого-то подвижного объекта. Больше примеров карт, которые можно построить с помощью Matplotlib и Basemap, вы найдете здесь.
Это все, о чем я хотел сегодня рассказать. Надеюсь, вы нашли данную информацию полезной.
Дополнение: Рисуем диаграммы Вольперта-Смита на Python
Метки: Python, Любительское радио.
Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.