kopia lustrzana https://github.com/ctjacobs/pyqso
Migrate to a world map / grey line that uses Cartopy (#64)
Migrating grey line functionality over to a Cartopy-based implementation to address issue #62. Also renamed GreyLine to WorldMap, and bumped the version to v1.1.0-dev.pull/65/head
rodzic
f283df065b
commit
f222d5cc30
|
@ -1,6 +1,5 @@
|
||||||
sudo: required
|
sudo: required
|
||||||
dist: trusty
|
dist: trusty
|
||||||
group: deprecated-2017Q2
|
|
||||||
|
|
||||||
language: python
|
language: python
|
||||||
|
|
||||||
|
@ -12,7 +11,7 @@ virtualenv:
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- sudo apt-get update -qq
|
- sudo apt-get update -qq
|
||||||
- sudo apt-get install -yq xvfb gir1.2-gtk-3.0 python3-gi-cairo python-mpltoolkits.basemap python3-numpy python3-matplotlib python3-sphinx python-libhamlib2 python3-flake8 python3-pip
|
- sudo apt-get install -yq xvfb python3 python3-pip gir1.2-gtk-3.0 python3-gi-cairo python3-flake8 python3-numpy python3-matplotlib python3-sphinx python-libhamlib2
|
||||||
- "export DISPLAY=:99.0"
|
- "export DISPLAY=:99.0"
|
||||||
- "sh -e /etc/init.d/xvfb start"
|
- "sh -e /etc/init.d/xvfb start"
|
||||||
|
|
||||||
|
|
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -1,5 +1,19 @@
|
||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## [UNRELEASED]
|
||||||
|
### Added
|
||||||
|
- Added support for the SAT_NAME, SAT_MODE, PROP_MODE, and GRIDSQUARE ADIF fields for the purposes of satellite QSO logging.
|
||||||
|
- Pinpointing of callsigns on the world map by looking up the latitude-longitude coordinates based on the value in the COUNTRY field. A new right-click popup menu has been created for this purpose.
|
||||||
|
- Added basic copy/paste functionality for individual records.
|
||||||
|
- Added a requirements.txt file for the purpose of installing dependencies.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Renamed the GreyLine class to WorldMap, since it now does more than just grey line plotting.
|
||||||
|
- Improved the section on dependencies in the README.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Updated the list of supported ADIF fields.
|
||||||
|
|
||||||
## [1.0.0] - 2017-08-02
|
## [1.0.0] - 2017-08-02
|
||||||
### Added
|
### Added
|
||||||
- Pin-pointing of QTH on grey line map.
|
- Pin-pointing of QTH on grey line map.
|
||||||
|
@ -95,6 +109,7 @@
|
||||||
- QSO filtering and sorting.
|
- QSO filtering and sorting.
|
||||||
- Duplicate record removal.
|
- Duplicate record removal.
|
||||||
|
|
||||||
|
[UNRELEASED]: https://github.com/ctjacobs/pyqso/compare/v1.0.0...HEAD
|
||||||
[1.0.0]: https://github.com/ctjacobs/pyqso/compare/v0.3...v1.0.0
|
[1.0.0]: https://github.com/ctjacobs/pyqso/compare/v0.3...v1.0.0
|
||||||
[0.3]: https://github.com/ctjacobs/pyqso/compare/v0.2...v0.3
|
[0.3]: https://github.com/ctjacobs/pyqso/compare/v0.2...v0.3
|
||||||
[0.2]: https://github.com/ctjacobs/pyqso/compare/v0.1...v0.2
|
[0.2]: https://github.com/ctjacobs/pyqso/compare/v0.1...v0.2
|
||||||
|
|
|
@ -30,17 +30,19 @@ As the name suggests, PyQSO is written primarily in the [Python](https://www.pyt
|
||||||
* gir1.2-gtk-3.0
|
* gir1.2-gtk-3.0
|
||||||
* python3-gi-cairo
|
* python3-gi-cairo
|
||||||
|
|
||||||
Several extra packages are necessary to enable the full functionality of PyQSO, such as the grey line tool. Many of these (specified in the `requirements.txt` file) can be readily installed system-wide using the Python package manager by issuing the following command in the terminal:
|
Several extra packages are necessary to enable the full functionality of PyQSO. Many of these (specified in the `requirements.txt` file) can be readily installed system-wide using the Python package manager by issuing the following command in the terminal:
|
||||||
|
|
||||||
sudo pip3 install -U -r requirements.txt
|
sudo pip3 install -U -r requirements.txt
|
||||||
|
|
||||||
but the complete list is given below:
|
but the complete list is given below:
|
||||||
|
|
||||||
* python3-matplotlib (version 1.3.0 or later)
|
* python3-matplotlib (version 1.3.0 or later)
|
||||||
* python3-mpltoolkits.basemap
|
|
||||||
* python3-numpy
|
* python3-numpy
|
||||||
* libxcb-render0-dev
|
* libxcb-render0-dev
|
||||||
* python3-cairocffi
|
* python3-cairocffi
|
||||||
|
* libproj-dev (version 4.9.0 or later)
|
||||||
|
* libgeos-dev (version 3.3.3 or later)
|
||||||
|
* [cartopy](http://scitools.org.uk/cartopy/) (for drawing the world map and grey line)
|
||||||
* [geocoder](https://pypi.python.org/pypi/geocoder) (for QTH lookups)
|
* [geocoder](https://pypi.python.org/pypi/geocoder) (for QTH lookups)
|
||||||
* python3-sphinx (for building the documentation)
|
* python3-sphinx (for building the documentation)
|
||||||
* python3-hamlib (for Hamlib support)
|
* python3-hamlib (for Hamlib support)
|
||||||
|
|
|
@ -51,16 +51,16 @@ master_doc = 'index'
|
||||||
|
|
||||||
# General information about the project.
|
# General information about the project.
|
||||||
project = u'PyQSO'
|
project = u'PyQSO'
|
||||||
copyright = u'2015-2017, Christian Thomas Jacobs'
|
copyright = u'2015-2018, Christian Thomas Jacobs'
|
||||||
|
|
||||||
# The version info for the project you're documenting, acts as replacement for
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
# |version| and |release|, also used in various other places throughout the
|
# |version| and |release|, also used in various other places throughout the
|
||||||
# built documents.
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '1.0.0'
|
version = '1.1.0-dev'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '1.0.0'
|
release = '1.1.0-dev'
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
|
|
@ -24,7 +24,7 @@ include:
|
||||||
|
|
||||||
- Progress tracker for the `DXCC <http://www.arrl.org/dxcc/>`_ award.
|
- Progress tracker for the `DXCC <http://www.arrl.org/dxcc/>`_ award.
|
||||||
|
|
||||||
- Grey line plotter.
|
- World map with grey line.
|
||||||
|
|
||||||
- Filter QSOs based on callsign (e.g. only display contacts with callsigns beginning with "M6").
|
- Filter QSOs based on callsign (e.g. only display contacts with callsigns beginning with "M6").
|
||||||
|
|
||||||
|
@ -65,5 +65,5 @@ If you have any comments or questions about PyQSO, please send them via email to
|
||||||
Structure of this documentation
|
Structure of this documentation
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
The structure of this documentation is as follows. The section on `Getting Started <getting_started.html>`_ provides information on the PyQSO installation process through to creating a new logbook (or opening an existing one). The `Log Management <log_management.html>`_ section explains how to create a log in the logbook, as well as the basic operations that users can perform with existing logs, such as printing, importing/exporting logs, and sorting. The `Record Management <record_management.html>`_ section deals with the bottom layer of the three-tier model - the creation, deletion, and modification of QSO records in a log. The `Toolbox <toolbox.html>`_ section introduces the PyQSO toolbox which contains three tools that are useful to amateur radio operators: a DX cluster, a grey line plotter, and an awards progress tracker. Finally, the `Preferences <preferences.html>`_ section explains how users can set up Hamlib support and show/hide various fields in a log, along with several other user preferences that can be set via the Preferences dialog window. A `keyboard shortcuts list <shortcuts.html>`_ is also available for reference.
|
The structure of this documentation is as follows. The section on `Getting Started <getting_started.html>`_ provides information on the PyQSO installation process through to creating a new logbook (or opening an existing one). The `Log Management <log_management.html>`_ section explains how to create a log in the logbook, as well as the basic operations that users can perform with existing logs, such as printing, importing/exporting logs, and sorting. The `Record Management <record_management.html>`_ section deals with the bottom layer of the three-tier model - the creation, deletion, and modification of QSO records in a log. The `Toolbox <toolbox.html>`_ section introduces the PyQSO toolbox which contains three tools that are useful to amateur radio operators: a DX cluster, a world map, and an awards progress tracker. Finally, the `Preferences <preferences.html>`_ section explains how users can set up Hamlib support and show/hide various fields in a log, along with several other user preferences that can be set via the Preferences dialog window. A `keyboard shortcuts list <shortcuts.html>`_ is also available for reference.
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ Under the ``General`` tab, the user can choose to:
|
||||||
|
|
||||||
- Keep the ``Add Record`` dialog window open after a new QSO is added, in preparation for the next QSO.
|
- Keep the ``Add Record`` dialog window open after a new QSO is added, in preparation for the next QSO.
|
||||||
|
|
||||||
- Pin-point the user's QTH on the grey line map by specifying the latitude-longitude coordinates (or looking them up based on the QTH's name, e.g. city name).
|
- Pin-point the user's QTH on the world map by specifying the latitude-longitude coordinates (or looking them up based on the QTH's name, e.g. city name).
|
||||||
|
|
||||||
.. _figure:summary:
|
.. _figure:summary:
|
||||||
.. figure:: images/summary.png
|
.. figure:: images/summary.png
|
||||||
|
|
|
@ -31,20 +31,18 @@ adjacent ``Send Command`` button (or pressing the Enter key).
|
||||||
|
|
||||||
The DX cluster frame.
|
The DX cluster frame.
|
||||||
|
|
||||||
Grey line
|
World map
|
||||||
---------
|
---------
|
||||||
|
|
||||||
The grey line tool (see figure:grey_line_) can be used to
|
The world map tool (see figure:world_map_) can be used to plot the QTH of your station and stations that you have contacted. It also features a grey line to check which parts of the world are in darkness. The position of the grey line is automatically updated every 30 minutes.
|
||||||
check which parts of the world are in darkness. The position of the grey
|
|
||||||
line is automatically updated every 30 minutes.
|
|
||||||
|
|
||||||
The user's QTH can be pin-pointed on the map by specifying the QTH's location (e.g. city name) and latitude-longitude coordinates in the preferences. If the `geocoder <https://pypi.python.org/pypi/geocoder>`_ library is installed then these coordinates can be filled in for you by clicking the lookup button after entering the QTH's name, otherwise the coordinates will have to be entered manually.
|
The user's QTH can be pin-pointed on the map by specifying the QTH's location (e.g. city name) and latitude-longitude coordinates in the preferences. If the `geocoder <https://pypi.python.org/pypi/geocoder>`_ library is installed then these coordinates can be filled in for you by clicking the lookup button after entering the QTH's name, otherwise the coordinates will have to be entered manually.
|
||||||
|
|
||||||
.. _figure:grey_line:
|
.. _figure:world_map:
|
||||||
.. figure:: images/grey_line.png
|
.. figure:: images/world_map.png
|
||||||
:align: center
|
:align: center
|
||||||
|
|
||||||
The grey line tool with the user's QTH (e.g. Southampton) pin-pointed on the map.
|
The world map tool with the user's QTH (e.g. Southampton) pin-pointed.
|
||||||
|
|
||||||
Awards
|
Awards
|
||||||
------
|
------
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
# Copyright (C) 2012-2017 Christian Thomas Jacobs.
|
# Copyright (C) 2012-2018 Christian Thomas Jacobs.
|
||||||
|
|
||||||
# This file is part of PyQSO.
|
# This file is part of PyQSO.
|
||||||
|
|
||||||
|
@ -1053,7 +1053,7 @@ class Logbook:
|
||||||
return
|
return
|
||||||
|
|
||||||
def pinpoint_callback(self, widget=None, path=None):
|
def pinpoint_callback(self, widget=None, path=None):
|
||||||
""" A callback function used to pinpoint the callsign on the grey line map. """
|
""" A callback function used to pinpoint the callsign on the world map. """
|
||||||
|
|
||||||
try:
|
try:
|
||||||
log_index = self.get_log_index()
|
log_index = self.get_log_index()
|
||||||
|
@ -1065,7 +1065,7 @@ class Logbook:
|
||||||
logging.error(e)
|
logging.error(e)
|
||||||
return
|
return
|
||||||
|
|
||||||
self.application.toolbox.grey_line.pinpoint(r)
|
self.application.toolbox.world_map.pinpoint(r)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ class Popup:
|
||||||
# Collect Gtk menu items and connect signals.
|
# Collect Gtk menu items and connect signals.
|
||||||
self.items = {}
|
self.items = {}
|
||||||
|
|
||||||
# Plot selected QSO on the grey line map.
|
# Plot selected QSO on the world map.
|
||||||
self.items["PINPOINT"] = self.builder.get_object("mitem_pinpoint")
|
self.items["PINPOINT"] = self.builder.get_object("mitem_pinpoint")
|
||||||
self.items["PINPOINT"].connect("activate", self.application.logbook.pinpoint_callback)
|
self.items["PINPOINT"].connect("activate", self.application.logbook.pinpoint_callback)
|
||||||
|
|
||||||
|
|
|
@ -792,7 +792,7 @@
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkBox" id="greyline">
|
<object class="GtkBox" id="worldmap">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="orientation">vertical</property>
|
<property name="orientation">vertical</property>
|
||||||
|
@ -806,10 +806,10 @@
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child type="tab">
|
<child type="tab">
|
||||||
<object class="GtkLabel" id="greyline_label">
|
<object class="GtkLabel" id="worldmap_label">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="label" translatable="yes">Grey Line</property>
|
<property name="label" translatable="yes">World Map</property>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
|
@ -908,8 +908,8 @@
|
||||||
<property name="type_hint">dialog</property>
|
<property name="type_hint">dialog</property>
|
||||||
<property name="transient_for">pyqso</property>
|
<property name="transient_for">pyqso</property>
|
||||||
<property name="program_name">PyQSO</property>
|
<property name="program_name">PyQSO</property>
|
||||||
<property name="version">1.0.0</property>
|
<property name="version">1.1.0-dev</property>
|
||||||
<property name="copyright" translatable="yes">Copyright (C) 2012-2017 Christian Thomas Jacobs</property>
|
<property name="copyright" translatable="yes">Copyright (C) 2012-2018 Christian Thomas Jacobs</property>
|
||||||
<property name="comments" translatable="yes">A contact logging tool for amateur radio operators.</property>
|
<property name="comments" translatable="yes">A contact logging tool for amateur radio operators.</property>
|
||||||
<property name="website">http://christianjacobs.uk/pyqso</property>
|
<property name="website">http://christianjacobs.uk/pyqso</property>
|
||||||
<property name="license" translatable="yes">This program is free software: you can redistribute it and/or modify
|
<property name="license" translatable="yes">This program is free software: you can redistribute it and/or modify
|
||||||
|
@ -1460,7 +1460,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.</pro
|
||||||
<property name="spacing">2</property>
|
<property name="spacing">2</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkCheckButton" id="general_show_qth_checkbutton">
|
<object class="GtkCheckButton" id="general_show_qth_checkbutton">
|
||||||
<property name="label" translatable="yes">Pin-point QTH on grey line map</property>
|
<property name="label" translatable="yes">Pin-point QTH on world map</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="receives_default">False</property>
|
<property name="receives_default">False</property>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
# Copyright (C) 2013-2017 Christian Thomas Jacobs.
|
# Copyright (C) 2013-2018 Christian Thomas Jacobs.
|
||||||
|
|
||||||
# This file is part of PyQSO.
|
# This file is part of PyQSO.
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
# along with PyQSO. If not, see <http://www.gnu.org/licenses/>.
|
# along with PyQSO. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from pyqso.dx_cluster import DXCluster
|
from pyqso.dx_cluster import DXCluster
|
||||||
from pyqso.grey_line import GreyLine
|
from pyqso.world_map import WorldMap
|
||||||
from pyqso.awards import Awards
|
from pyqso.awards import Awards
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ class Toolbox:
|
||||||
self.tools = self.builder.get_object("tools")
|
self.tools = self.builder.get_object("tools")
|
||||||
|
|
||||||
self.dx_cluster = DXCluster(self.application)
|
self.dx_cluster = DXCluster(self.application)
|
||||||
self.grey_line = GreyLine(self.application)
|
self.world_map = WorldMap(self.application)
|
||||||
self.awards = Awards(self.application)
|
self.awards = Awards(self.application)
|
||||||
|
|
||||||
self.tools.connect_after("switch-page", self.on_switch_page)
|
self.tools.connect_after("switch-page", self.on_switch_page)
|
||||||
|
@ -52,7 +52,7 @@ class Toolbox:
|
||||||
return
|
return
|
||||||
|
|
||||||
def on_switch_page(self, widget, label, new_page):
|
def on_switch_page(self, widget, label, new_page):
|
||||||
""" Re-draw the Grey Line if the user switches to the grey line tab. """
|
""" Re-draw the WorldMap if the user switches to the World Map tab. """
|
||||||
if(widget.get_tab_label(label).get_text() == "Grey Line"):
|
if(widget.get_tab_label(label).get_text() == "World Map"):
|
||||||
self.grey_line.draw()
|
self.world_map.draw()
|
||||||
return
|
return
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
# Copyright (C) 2013-2017 Christian Thomas Jacobs.
|
# Copyright (C) 2013-2018 Christian Thomas Jacobs.
|
||||||
|
|
||||||
# This file is part of PyQSO.
|
# This file is part of PyQSO.
|
||||||
|
|
||||||
|
@ -19,8 +19,8 @@
|
||||||
|
|
||||||
from gi.repository import GObject
|
from gi.repository import GObject
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime
|
|
||||||
from os.path import expanduser
|
from os.path import expanduser
|
||||||
|
from datetime import datetime
|
||||||
try:
|
try:
|
||||||
import configparser
|
import configparser
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -30,13 +30,13 @@ try:
|
||||||
logging.info("Using version %s of numpy." % (numpy.__version__))
|
logging.info("Using version %s of numpy." % (numpy.__version__))
|
||||||
import matplotlib
|
import matplotlib
|
||||||
logging.info("Using version %s of matplotlib." % (matplotlib.__version__))
|
logging.info("Using version %s of matplotlib." % (matplotlib.__version__))
|
||||||
import mpl_toolkits.basemap
|
import cartopy
|
||||||
logging.info("Using version %s of mpl_toolkits.basemap." % (mpl_toolkits.basemap.__version__))
|
logging.info("Using version %s of cartopy." % (cartopy.__version__))
|
||||||
from matplotlib.backends.backend_gtk3cairo import FigureCanvasGTK3Cairo as FigureCanvas
|
from matplotlib.backends.backend_gtk3cairo import FigureCanvasGTK3Cairo as FigureCanvas
|
||||||
have_necessary_modules = True
|
have_necessary_modules = True
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
logging.warning(e)
|
logging.warning(e)
|
||||||
logging.warning("Could not import a non-standard Python module needed by the GreyLine class, or the version of the non-standard module is too old. Check that all the PyQSO dependencies are satisfied.")
|
logging.warning("Could not import a non-standard Python module needed by the WorldMap class, or the version of the non-standard module is too old. Check that all the PyQSO dependencies are satisfied.")
|
||||||
have_necessary_modules = False
|
have_necessary_modules = False
|
||||||
try:
|
try:
|
||||||
import geocoder
|
import geocoder
|
||||||
|
@ -64,16 +64,16 @@ class Point:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
class GreyLine:
|
class WorldMap:
|
||||||
|
|
||||||
""" A tool for visualising the grey line. """
|
""" A tool for visualising the world map. """
|
||||||
|
|
||||||
def __init__(self, application):
|
def __init__(self, application):
|
||||||
""" Set up the drawing canvas and the timer which will re-plot the grey line every 30 minutes.
|
""" Set up the drawing canvas and the timer which will re-plot the world map every 30 minutes.
|
||||||
|
|
||||||
:arg application: The PyQSO application containing the main Gtk window, etc.
|
:arg application: The PyQSO application containing the main Gtk window, etc.
|
||||||
"""
|
"""
|
||||||
logging.debug("Setting up the grey line...")
|
logging.debug("Setting up the world map...")
|
||||||
|
|
||||||
self.application = application
|
self.application = application
|
||||||
self.builder = self.application.builder
|
self.builder = self.application.builder
|
||||||
|
@ -82,10 +82,10 @@ class GreyLine:
|
||||||
if(have_necessary_modules):
|
if(have_necessary_modules):
|
||||||
self.fig = matplotlib.figure.Figure()
|
self.fig = matplotlib.figure.Figure()
|
||||||
self.canvas = FigureCanvas(self.fig) # For embedding in the Gtk application
|
self.canvas = FigureCanvas(self.fig) # For embedding in the Gtk application
|
||||||
self.builder.get_object("greyline").pack_start(self.canvas, True, True, 0)
|
self.builder.get_object("worldmap").pack_start(self.canvas, True, True, 0)
|
||||||
self.refresh_event = GObject.timeout_add(1800000, self.draw) # Re-draw the grey line automatically after 30 minutes (if the grey line tool is visible).
|
self.refresh_event = GObject.timeout_add(1800000, self.draw) # Re-draw the world map automatically after 30 minutes (if the world map tool is visible).
|
||||||
|
|
||||||
# Plot the QTH coordinates, if available.
|
# Add the QTH coordinates for plotting, if available.
|
||||||
config = configparser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
have_config = (config.read(expanduser('~/.config/pyqso/preferences.ini')) != [])
|
have_config = (config.read(expanduser('~/.config/pyqso/preferences.ini')) != [])
|
||||||
(section, option) = ("general", "show_qth")
|
(section, option) = ("general", "show_qth")
|
||||||
|
@ -97,11 +97,11 @@ class GreyLine:
|
||||||
qth_longitude = float(config.get("general", "qth_longitude"))
|
qth_longitude = float(config.get("general", "qth_longitude"))
|
||||||
self.add_point(qth_name, qth_latitude, qth_longitude, "ro")
|
self.add_point(qth_name, qth_latitude, qth_longitude, "ro")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logging.warning("Unable to get the QTH name, latitude and/or longitude. The QTH will not be pinpointed on the grey line map. Check preferences?")
|
logging.warning("Unable to get the QTH name, latitude and/or longitude. The QTH will not be pinpointed on the world map. Check preferences?")
|
||||||
|
|
||||||
self.builder.get_object("greyline").show_all()
|
self.builder.get_object("worldmap").show_all()
|
||||||
|
|
||||||
logging.debug("Grey line ready!")
|
logging.debug("World map ready!")
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ class GreyLine:
|
||||||
return
|
return
|
||||||
|
|
||||||
def pinpoint(self, r):
|
def pinpoint(self, r):
|
||||||
""" Pinpoint the location of a QSO on the grey line map based on the COUNTRY field.
|
""" Pinpoint the location of a QSO on the world map based on the COUNTRY field.
|
||||||
|
|
||||||
:arg r: The QSO record containing the location to pinpoint.
|
:arg r: The QSO record containing the location to pinpoint.
|
||||||
"""
|
"""
|
||||||
|
@ -145,7 +145,7 @@ class GreyLine:
|
||||||
def draw(self):
|
def draw(self):
|
||||||
""" Draw the world map and the grey line on top of it.
|
""" Draw the world map and the grey line on top of it.
|
||||||
|
|
||||||
:returns: Always returns True to satisfy the GObject timer, unless the necessary GreyLine dependencies are not satisfied (in which case, the method returns False so as to not re-draw the canvas).
|
:returns: Always returns True to satisfy the GObject timer, unless the necessary WorldMap dependencies are not satisfied (in which case, the method returns False so as to not re-draw the canvas).
|
||||||
:rtype: bool
|
:rtype: bool
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -153,32 +153,64 @@ class GreyLine:
|
||||||
toolbox = self.builder.get_object("toolbox")
|
toolbox = self.builder.get_object("toolbox")
|
||||||
tools = self.builder.get_object("tools")
|
tools = self.builder.get_object("tools")
|
||||||
if(tools.get_current_page() != 1 or not toolbox.get_visible()):
|
if(tools.get_current_page() != 1 or not toolbox.get_visible()):
|
||||||
# Don't re-draw if the grey line is not visible.
|
# Don't re-draw if the world map is not visible.
|
||||||
return True # We need to return True in case this is method was called by a timer event.
|
return True # We need to return True in case this is method was called by a timer event.
|
||||||
else:
|
else:
|
||||||
logging.debug("Drawing the grey line...")
|
# Set up the world map.
|
||||||
# Re-draw the grey line
|
logging.debug("Drawing the world map...")
|
||||||
self.fig.clf()
|
self.fig.clf()
|
||||||
sub = self.fig.add_subplot(111)
|
ax = self.fig.add_subplot(111, projection=cartopy.crs.PlateCarree())
|
||||||
|
ax.set_extent([-180, 180, -90, 90])
|
||||||
|
ax.set_aspect("auto")
|
||||||
|
|
||||||
# Draw the map of the world. This is based on the example from:
|
gl = ax.gridlines(draw_labels=True)
|
||||||
# http://matplotlib.org/basemap/users/examples.html
|
gl.xlabels_top = False
|
||||||
m = mpl_toolkits.basemap.Basemap(projection="mill", lon_0=0, ax=sub, resolution="c", fix_aspect=False)
|
gl.ylabels_right = False
|
||||||
m.drawcountries(linewidth=0.4)
|
gl.xformatter = cartopy.mpl.gridliner.LONGITUDE_FORMATTER
|
||||||
m.drawcoastlines(linewidth=0.4)
|
gl.yformatter = cartopy.mpl.gridliner.LATITUDE_FORMATTER
|
||||||
m.drawparallels(numpy.arange(-90, 90, 30), labels=[1, 0, 0, 0])
|
ax.add_feature(cartopy.feature.LAND, facecolor="green")
|
||||||
m.drawmeridians(numpy.arange(m.lonmin, m.lonmax+30, 60), labels=[0, 0, 0, 1])
|
ax.add_feature(cartopy.feature.OCEAN, color="skyblue")
|
||||||
m.drawmapboundary(fill_color="skyblue")
|
ax.add_feature(cartopy.feature.COASTLINE)
|
||||||
m.fillcontinents(color="green", lake_color="skyblue")
|
ax.add_feature(cartopy.feature.BORDERS, alpha=0.4)
|
||||||
m.nightshade(datetime.utcnow()) # Add in the grey line using UTC time. Note that this requires NetCDF.
|
|
||||||
logging.debug("Grey line drawn.")
|
# Draw the grey line. This is based on the code from the Cartopy Aurora Forecast example (http://scitools.org.uk/cartopy/docs/latest/gallery/aurora_forecast.html) and used under the Open Government Licence (http://scitools.org.uk/cartopy/docs/v0.15/copyright.html).
|
||||||
|
logging.debug("Drawing the grey line...")
|
||||||
|
dt = datetime.utcnow()
|
||||||
|
axial_tilt = 23.5
|
||||||
|
reference_solstice = datetime(2016, 6, 21, 22, 22)
|
||||||
|
days_per_year = 365.2425
|
||||||
|
seconds_per_day = 86400.0
|
||||||
|
|
||||||
|
days_since_reference = (dt - reference_solstice).total_seconds()/seconds_per_day
|
||||||
|
latitude = axial_tilt*numpy.cos(2*numpy.pi*days_since_reference/days_per_year)
|
||||||
|
seconds_since_midnight = (dt - datetime(dt.year, dt.month, dt.day)).seconds
|
||||||
|
longitude = -(seconds_since_midnight/seconds_per_day - 0.5)*360
|
||||||
|
|
||||||
|
pole_longitude = longitude
|
||||||
|
if latitude > 0:
|
||||||
|
pole_latitude = -90 + latitude
|
||||||
|
central_rotated_longitude = 180
|
||||||
|
else:
|
||||||
|
pole_latitude = 90 + latitude
|
||||||
|
central_rotated_longitude = 0
|
||||||
|
|
||||||
|
rotated_pole = cartopy.crs.RotatedPole(pole_latitude=pole_latitude, pole_longitude=pole_longitude, central_rotated_longitude=central_rotated_longitude)
|
||||||
|
|
||||||
|
x = numpy.empty(360)
|
||||||
|
y = numpy.empty(360)
|
||||||
|
x[:180] = -90
|
||||||
|
y[:180] = numpy.arange(-90, 90.)
|
||||||
|
x[180:] = 90
|
||||||
|
y[180:] = numpy.arange(90, -90., -1)
|
||||||
|
|
||||||
|
ax.fill(x, y, transform=rotated_pole, color="black", alpha=0.5)
|
||||||
|
|
||||||
# Plot points on the map.
|
# Plot points on the map.
|
||||||
if(self.points):
|
if(self.points):
|
||||||
|
logging.debug("Plotting QTHs on the map...")
|
||||||
for p in self.points:
|
for p in self.points:
|
||||||
x, y = m(p.longitude, p.latitude)
|
ax.plot(p.longitude, p.latitude, p.style, transform=cartopy.crs.PlateCarree())
|
||||||
m.plot(x, y, p.style)
|
ax.text(p.longitude+0.02*p.longitude, p.latitude+0.02*p.latitude, p.name, color="white", size="small", weight="bold")
|
||||||
sub.text(x+0.01*x, y+0.01*y, p.name, color="white", size="small", weight="bold")
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
|
@ -1,6 +1,6 @@
|
||||||
numpy
|
numpy
|
||||||
matplotlib>=1.3.0
|
matplotlib>=1.3.0
|
||||||
basemap
|
cartopy>=0.16.0
|
||||||
cairocffi
|
cairocffi
|
||||||
sphinx
|
sphinx
|
||||||
geocoder
|
geocoder
|
||||||
|
|
4
setup.py
4
setup.py
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
# Copyright (C) 2013-2017 Christian Thomas Jacobs.
|
# Copyright (C) 2013-2018 Christian Thomas Jacobs.
|
||||||
|
|
||||||
# This file is part of PyQSO.
|
# This file is part of PyQSO.
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
|
||||||
setup(name="PyQSO",
|
setup(name="PyQSO",
|
||||||
version="1.0.0",
|
version="1.1.0-dev",
|
||||||
description="A contact logging tool for amateur radio operators.",
|
description="A contact logging tool for amateur radio operators.",
|
||||||
author="Christian Thomas Jacobs",
|
author="Christian Thomas Jacobs",
|
||||||
author_email="christian@christianjacobs.uk",
|
author_email="christian@christianjacobs.uk",
|
||||||
|
|
Ładowanie…
Reference in New Issue