diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 000000000..178914ecf --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,25 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the version of Python and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.11" + +# Build documentation in the docs/ directory with Sphinx +# sphinx: +# configuration: docs/conf.py +mkdocs: + configuration: mkdocs.yml + fail_on_warning: false + +# We recommend specifying your dependencies to enable reproducible builds: +# https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html +# python: +# install: +# - requirements: docs/requirements.txt \ No newline at end of file diff --git a/.zenodo.json b/.zenodo.json index 2917f6a4a..db9ba48cc 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -1,5 +1,5 @@ { - "creators":[ + "creators": [ { "name": "SuperDARN Data Visualization Working Group" }, @@ -8,67 +8,72 @@ "name": "Martin, C.J.", "orcid": "0000-0002-8278-9783" }, - { - "affiliation": "Virginia Tech", - "name": "Shi, X.", - "orcid": "0000-0001-8425-8241" - }, { "affiliation": "University of Saskatchewan", - "name": "Schmidt, M.T.", - "orcid": "0000-0002-3265-977X" + "name": "Rohel, R.A.", + "orcid": "0000-0003-2208-1553" }, { - "affiliation": "Lancaster University", - "name": "Day, E. K.", - "orcid": "0000-0002-0169-6201" + "affiliation": "Virginia Tech", + "name": "Kunduri, B.S.R.", + "orcid": "0000-0002-7406-7641" }, { - "affiliation": "The University Centre in Svalbard", - "name": "Bland, E.C.", - "orcid": "0000-0002-0252-0400" + "affiliation": "Virginia Tech", + "name": "Pitzer, P." }, { "affiliation": "University of Alabama", "name": "Khanal, K.", - "orcid": "0000-0003-3927-7501" + "orcid": "0000-0003-3927-7501" }, { - "affiliation": "University of Saskatchewan", - "name": "Billett, D.D.", - "orcid": "0000-0002-8905-8609" + "affiliation": "Virginia Tech", + "name": "Shi, X.", + "orcid": "0000-0001-8425-8241" + }, + { + "affiliation": "University of Scranton", + "name": "Frissell, N.", + "orcid": "0000-0002-8398-4222" + }, + { + "affiliation": "SANSA", + "name": "Hiyadutuje, A.", + "orcid": "0000-0002-3391-8737" }, { "affiliation": "Virginia Tech", - "name": "Kunduri, B.S.R.", - "orcid": "0000-0002-7406-7641" + "name": "Chakraborty, S.", + "orcid": "0000-0001-6792-0037" }, - { "affiliation": "University of Scranton", - "name": "Tholley, F." + { + "affiliation": "Dartmouth College", + "name": "Thomas, E. G.", + "orcid": "0000-0001-8036-8793" }, { - "affiliation": "University of Scranton", - "name": "Frissell, N.", - "orcid": "0000-0002-8398-4222" + "affiliation": "University of Newcastle", + "name": "Waters, C. L.", + "orcid": "0000-0003-2121-6962" }, { - "affiliation": "Virginia Tech", - "name": "Coyle, S.", - "orcid": "0000-0003-1730-2753" + "affiliation": "University of Saskatchewan", + "name": "Billett, D.D.", + "orcid": "0000-0002-8905-8609" }, { "affiliation": "University of Saskatchewan", - "name": "Rohel, R.A.", - "orcid": "0000-0003-2208-1553" + "name": "Galeshuck, D." }, { "affiliation": "University of Saskatchewan", - "name": "Kolkman, T.J.", - "orcid": "0000-0001-9759-9045" + "name": "Detwiller, M." }, { "affiliation": "University of Saskatchewan", - "name": "Krieger, K.J.", - "orcid": "0000-0002-3678-4201" - }] -} + "name": "Schmidt, M.T.", + "orcid": "0000-0002-3265-977X" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md index b9e3c51db..c2c9d5e80 100644 --- a/README.md +++ b/README.md @@ -9,23 +9,24 @@ Python data visualization library for the Super Dual Auroral Radar Network (Supe ## Changelog -## Version 3.1.1 - Patch Release! - -This patch release includes: -- **Bug fix** `hdw` repository installation issues resolved -- Inclusion of ICE and ICW in `hdw` repository and superdarn_radars module - -Most recent minor release (3.1.0) changes listed below: -- Full Cartopy coastline plotting options for all spatial plots - - **NEW** `coastline` keyword in method calls -- Full Cartopy integration for plotting in geographic coordinates for grid and fan plots -- Completed polar coordinate convection maps including reference vector and many customization options -- Improved ACF plotting -- New `HALF_SLANT` range estimation for RTP -- **Bug fix** Multiple fan plots now available on one axis -- **Bug fix** `lowlat` keyword now available for geographic coordinate plots -- **Bug fix** Colorbars now extend/don't extend as required -along with many other minor improvements and bug fixes! +## Version 4.0 - Major Release! + +This major release includes: +- **NEW** IQ level data plotting +- **NEW** Latitude and longitude y-axis in RTP +- **NEW** Ball and stick plots +- **NEW** Map file variable time series plotting +- **NEW** Terminator plotting +- Coastlines available in magnetic coordinate spatial plots without Cartopy +- More flexibility in fan plots - single beams/ range gate range options +- TDiff correction for elevation data available +- Boxcar filtering available for data before plotting +- Corrections to geolocation algorithms +- Standardized plot return values across all plots +- **Bug fix** Radar position labels no longer overlap +- **Bug fix** Warning use refactored +- **Bug fix** Multiple bug fixes for data handling and plotting in grid plots +- **Bug fix** Multiple bug fixes for the aesthetics of convection maps ## Documentation @@ -61,7 +62,9 @@ plt.show() [summary plot](docs/imgs/summary_clyb2.png) -For more information and tutorials on pyDARN please see the [tutorial section](https://pydarn.readthedocs.io/en/latest/index.html) +For more information and tutorials on pyDARN please see the [tutorial section](https://pydarn.readthedocs.io/en/latest/index.html). + +We also have a [Jupyter notebook](https://zenodo.org/record/7005203) with many examples to support our recent [publication](https://doi.org/10.3389/fspas.2022.1022690). ## Getting involved diff --git a/docs/dev/developing.md b/docs/dev/developing.md new file mode 100644 index 000000000..b8bd42e5a --- /dev/null +++ b/docs/dev/developing.md @@ -0,0 +1,70 @@ + + +# Quick Guide to Developing + +Once you have decided on an issue that you would like to develop, or have decided to develop your own feature, you can follow the rough guidelines below to develop your feature. +Each developer has different preferences on how they develop, text editors, OS and style. All are valid and you can use whatever method you wish to achieve the development of a new feature. Below is a quick run-through of how I (Carley) develop a new feature using a basic text editor and command line directly as a branch of the main repository. +It is not required, but probably useful if you have a relatively good knowledge and some experience of writing code in python - however, any style or efficiency issues can be picked up by the testers and fixed then! + +Firstly, if you don't have the repository cloned, find a suitable location where you would like the repo and clone: +``` +git clone https://github.com/SuperDARN/pydarn.git +``` +The default branch is `develop` so your repository will already be showing the development branch. If you have the repository clones already, make sure to pull any new changes to the develop branch: +``` +cd pydarn +git pull origin develop +``` +Now, we want to make a new 'branch' of the repository where only the changes you are making will be present and it won't interfere with anyone else developing. +``` +git checkout -b ehn/new-feature-name +``` +This command will create a new branch with the name 'ehn/new-feature-name' and move to that new branch. + +You can now change any code in the new branch and it will not effect the development branch. You can add a whole new module - make sure you add anything you wish to call using pyDARN to the `__init__.py` file. + +I suggest that you install and run the code frequently during development to check that everything is running as expected. +To do this make a virtual environment, install the branch of pyDARN and run some testing code you have developed. +``` +python3 -m virtualenv (or venv if 3.10+) venv-feature-name +source venv-feature-name/bin/activate +cd pydarn (make sure you are in the pydarn git repository) +pip3 install . +python3 your_testing_code.py +``` + +!!! Note + If repeatedly testing, make sure to uninstall pydarn before reinstalling to pick up the changes. + `pip3 uninstall pydarn` + +If you wish to push finished or partially finished code to the repository on GitHub so others can see and test: +``` +git status +git add . +git commit -m 'commint message here - what did you change, what's new ect.' +git push origin ehn/new-feature-branch +``` + +You can then continue developing, or if you have completed the feature, make a [pull request](dev/PR.md)! + +# Tips to Keep in Mind + + - If making a whole new module, read up on how to structure and have the module accessible to the rest of the code: [library structure](https://docs.python-guide.org/writing/structure/) + - Make a short piece of code that tests your feature - this is helpful for you to test as you develop but also helpful to show testers how they can use your new feature. + - Make sure that the code does not interfere with, change or break another part of the code base - this means you need to test anything peripheral to the code you have added too. + - Write up some documentation! Documentation can be found in the docs directory and is written in markdown. + - [Kwargs](https://realpython.com/python-kwargs-and-args/) - very useful to pass keyword arguments through various methods. + - [Enum](https://realpython.com/python-kwargs-and-args/) is extremely helpful for when a keyword has multiple options to choose from (not just True, False). + - pyDARN has implemented a standard return dictionary, so make sure that if you develop a new plot that you format your plot return the same as all others. diff --git a/docs/imgs/CTP_1.png b/docs/imgs/CTP_1.png new file mode 100644 index 000000000..0e1109a65 Binary files /dev/null and b/docs/imgs/CTP_1.png differ diff --git a/docs/imgs/ball_and_stick.png b/docs/imgs/ball_and_stick.png new file mode 100644 index 000000000..2ad9804ea Binary files /dev/null and b/docs/imgs/ball_and_stick.png differ diff --git a/docs/imgs/ctp_equator.png b/docs/imgs/ctp_equator.png new file mode 100644 index 000000000..38600308c Binary files /dev/null and b/docs/imgs/ctp_equator.png differ diff --git a/docs/imgs/ctp_pole.png b/docs/imgs/ctp_pole.png new file mode 100644 index 000000000..74b06e1d9 Binary files /dev/null and b/docs/imgs/ctp_pole.png differ diff --git a/docs/imgs/filtered.png b/docs/imgs/filtered.png new file mode 100644 index 000000000..5bc61d0ea Binary files /dev/null and b/docs/imgs/filtered.png differ diff --git a/docs/imgs/iq1.png b/docs/imgs/iq1.png new file mode 100644 index 000000000..7b95c970a Binary files /dev/null and b/docs/imgs/iq1.png differ diff --git a/docs/imgs/iq2.png b/docs/imgs/iq2.png new file mode 100644 index 000000000..125ba57dc Binary files /dev/null and b/docs/imgs/iq2.png differ diff --git a/docs/imgs/iq3.png b/docs/imgs/iq3.png new file mode 100644 index 000000000..ea3f58f8d Binary files /dev/null and b/docs/imgs/iq3.png differ diff --git a/docs/imgs/iq4.png b/docs/imgs/iq4.png new file mode 100644 index 000000000..b7bb4d6c4 Binary files /dev/null and b/docs/imgs/iq4.png differ diff --git a/docs/imgs/map_ts.png b/docs/imgs/map_ts.png new file mode 100644 index 000000000..b7eb3d238 Binary files /dev/null and b/docs/imgs/map_ts.png differ diff --git a/docs/imgs/unfiltered.png b/docs/imgs/unfiltered.png new file mode 100644 index 000000000..dbc224637 Binary files /dev/null and b/docs/imgs/unfiltered.png differ diff --git a/docs/index.md b/docs/index.md index d2b23c122..639bf3fd7 100644 --- a/docs/index.md +++ b/docs/index.md @@ -20,6 +20,7 @@ If you have any questions or concerns please submit an **Issue** on the SuperDAR - [Axes Setup](user/axis.md) - [Ranges, Coords and Projs](user/coordinates.md) - [Range-Time plots](user/range_time.md) + - [Coordinate-Time plots](user/coord_time.md) - [Time-Series plots](user/time_series.md) - [Summary plots](user/summary.md) - [FOV plots](user/fov.md) @@ -28,14 +29,16 @@ If you have any questions or concerns please submit an **Issue** on the SuperDAR - [Convection Map Potential plots](user/map.md) - [Power plots](user/power.md) - [ACF plotting](user/acf.md) + - [IQ Plotting](user/iq.md) + - [Filtering data](user/filters.md) - [Logging](user/logging.md) - [pyDARN Team](dev/team.md) - [Communication Guidelines](dev/communication.md) - [Copyrighting and Licensing](dev/copyright_license.md) - Workflow - - [Projects](dev/projects.md) - [Issues](dev/issues.md) - [Branches](dev/branching.md) + - [Developing](dev/developing.md) - [Unit Testing](dev/pytest.md) - [Pull Requests](dev/PR.md) - [Testing](dev/testing.md) diff --git a/docs/user/axis.md b/docs/user/axis.md index fd176d0fb..7cc06460f 100644 --- a/docs/user/axis.md +++ b/docs/user/axis.md @@ -1,32 +1,34 @@ # Axes Setup -For spatial plots (FOV, Fan, Grid), pyDARN allows users to choose between Polar and +For some spatial plots (FOV, Fan, Grid), pyDARN allows users to choose between Polar and Geographic axes using the `projs` keyword and `Projs` module. -Convection maps do not allow for geographic projects due to lack of interest. +Convection maps do not allow for geographic projections due to lack of interest. ## Projs.POLAR -| Option | Action | -| ---------------------------- | ----------------------------------------------------------------- | -| lowlat=(int) | Lower Latitude boundary for the polar plot (degree) (default: 30) | -| hemisphere=(pydarn.Hemisphere) | Hemisphere of the radar (default: Hemisphere.North) | -| coastline=(bool) | Uses Cartopy to add outlines fo the coastlines below data | +| Option | Action | +| ------------------------------ | ----------------------------------------------------------------------------------- | +| lowlat=(int) | Lower Latitude boundary for the polar plot (degree) (default: 30) | +| hemisphere=(pydarn.Hemisphere) | Hemisphere of the radar (default: Hemisphere.North) | +| coastline=(bool) | Uses Cartopy to add outlines to the coastlines below data | +| nightshade=(int) | Uses the value given to calculate and show where on the plot the Earth is in shadow | -This choice will return an `ax` object and a value of None for `ccrs`. +This choice will return an `ax` object and a value of None for the Cartopy `ccrs` (coordinate reference system). ## Projs.GEO **REQUIRES CARTOPY INSTALLATION** -| Option | Action | -| ---------------------------- | ----------------------------------------------------------------- | -| lowlat=(int) | Lower Latitude boundary for the polar plot (degree) (default: 30) | -| hemisphere=(pydarn.Hemisphere) | Hemisphere of the radar (default: Hemisphere.North) | -| coastline=(bool) | Uses Cartopy to add outlines fo the coastlines below data | -| grid_lines=(bool) | Uses Cartopy to plot grid lines | +| Option | Action | +| ------------------------------ | ----------------------------------------------------------------------------------- | +| lowlat=(int) | Lower Latitude boundary for the polar plot (degree) (default: 30) | +| hemisphere=(pydarn.Hemisphere) | Hemisphere of the radar (default: Hemisphere.North) | +| coastline=(bool) | Uses Cartopy to add outlines fo the coastlines below data | +| grid_lines=(bool) | Uses Cartopy to plot grid lines | +| nightshade=(int) | Uses the value given to calculate and show where on the plot the Earth is in shadow | -This choice will return an `ax` object and a Cartopy `ccrs` object. +This choice will return an `ax` object and a Cartopy `ccrs` object (coordinate reference system). ## Custom Axes pyDARN does not currently support use of custom axes to read in and plot on. This means diff --git a/docs/user/citing.md b/docs/user/citing.md index e552762fa..063773717 100644 --- a/docs/user/citing.md +++ b/docs/user/citing.md @@ -13,11 +13,46 @@ and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. --> -If pyDARN contributes to a project that leads to a scientific publication, please acknowledge this fact by citing the software and SuperDARN. +# Publications used within pyDARN -# How to cite SuperDARN +If pyDARN contributes to a project that leads to a scientific publication, please acknowledge this fact by acknowledging the software and citing relevant publications used within the software. +You can print the citations in command line by using the Citations class. -Super Dual Auroral Radar Network (SuperDARN) is a made up of 35+ radars and 20 institutions, to generally cite SuperDARN you can use: +```python +import pydarn + +pydarn.Citations.print_citations() + +``` + +``` +If using pyDARN produced plots in publications please be aware of the following citations that may have been used to produce your plot: + + Ground Scatter Mapped Range: Bristow, W. A. et al, 1994, 10.1029/93JA01470 + AACGMv2 Wrapper: Burrell, A. G. et al, 2023, 10.5281/zenodo.7621545 + Chisham Virtual Height Model: Chisham, G. 2008, 10.5194/angeo-26-823-2008 + pyDARN Software: DVWG, 2023, 10.5281/zenodo.3727269 + pyDARNio Software: DVWG, 2023, 10.5281/zenodo.4009470 + Cartopy: Met Office, 2010-2015, scitools.org.uk/cartopy + AACGMv2 article: Shepherd, S. G., 2014, 10.1002/2014JA020264 + Elevation Angle Calculations: Shepherd, S. G., 2017, 10.1002/2017RS006348 + Ground Scatter Mapped Range: Thomas, E. G. et al, 2022, 10.1029/2022RS007429 + +``` + +These citations refer to methods or codebases previously published that are used in the pyDARN software. +A list of the journal article citations is below, formatted to each journals specification: + +- Bristow, W. A., Greenwald, R. A., and Samson, J. C. (1994), Identification of high-latitude acoustic gravity wave sources using the Goose Bay HF Radar, J. Geophys. Res., 99( A1), 319– 331, doi:10.1029/93JA01470. +- Chisham, G., Yeoman, T. K., and Sofko, G. J.: Mapping ionospheric backscatter measured by the SuperDARN HF radars – Part 1: A new empirical virtual height model, Ann. Geophys., 26, 823–841, https://doi.org/10.5194/angeo-26-823-2008, 2008. +- Shepherd, S. G. (2014), Altitude-adjusted corrected geomagnetic coordinates: Definition and functional approximations, J. Geophys. Res. Space Physics, 119, 7501– 7521, doi:10.1002/2014JA020264. +- Shepherd, S. G. (2017), Elevation angle determination for SuperDARN HF radar layouts, Radio Sci., 52, 938– 950, doi:10.1002/2017RS006348. +- Thomas, E. G., & Shepherd, S. G. (2022). Virtual height characteristics of ionospheric and ground scatter observed by mid-latitude SuperDARN HF radars. Radio Science, 57, e2022RS007429. https://doi.org/10.1029/2022RS007429 + +# How to cite the SuperDARN Community + +Super Dual Auroral Radar Network (SuperDARN) is a made up of 35+ radars and 20 institutions. +To generally cite SuperDARN you can use: - Greenwald, R.A., Baker, K.B., Dudeney, J.R. et al. Space Sci Rev (1995) 71: 761. [doi:10.1007/BF00751350](https://doi.org/10.1007/BF00751350) @@ -29,16 +64,36 @@ For the general achievements of the SuperDARN Network, you can read these papers During your study, if using data from individual radars only, please contact the Principal Investigator (PI) of that radar about potential co-authorship. A list of radars, institutions, and their PI's information can be found [here](http://vt.superdarn.org/tiki-index.php?page=Radar+Overview). -## DOI +## Acknowledgements + +All publications that use SuperDARN Data must contain the following acknowledgement: + +*The authors acknowledge the use of SuperDARN data. SuperDARN is a collection of radars funded by national scientific funding agencies of Australia, Canada, China, France, Italy, Japan, Norway, South Africa, United Kingdom and the United States of America.* -Currently SuperDARN in the process of placing DOI's on their data set. In the meantime, please use any local available services to DOI your data set. -Possible services: +This phrase can be accessed using the Citations class as shown below: - - [FRDR](https://www.frdr.ca/repo/): Canadian resource - - [zenodo](https://help.zenodo.org/features/) + +```python +import pydarn + +pydarn.Citations.print_acknowledgements() + +``` + +``` +Acknowledgement required for SuperDARN data use: + +The authors acknowledge the use of SuperDARN data. SuperDARN is a collection of radars funded by national scientific funding agencies of Australia, Canada, China, France, Italy, Japan, Norway, South Africa, United Kingdom and the United States of America. + +During your study, if using data from individual radars only, please contact the Principal Investigator (PI) of that radar about potential co-authorship or appropriate acknowledgments. + +``` # Citing pyDARN +If pyDARN is used in a publication, we would like to be able to easily track this to show how widely used pyDARN is. +Please either cite using the version DOI's below or acknowledge the use of the software in your acknowledgements section, giving the version or DOI of the software for reproducibility. + ## DOI's - Release 1.0.0 [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.3727270.svg)](https://doi.org/10.5281/zenodo.3727270) @@ -52,11 +107,7 @@ Possible services: - Release 3.1 [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.7468856.svg)](https://doi.org/10.5281/zenodo.7468856) - Release 3.1.1 [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.7767590.svg)](https://doi.org/10.5281/zenodo.7767590) -## Acknowledgements - -pyDARN uses other python libraries and the SuperDARN community's help. - -### Python Library References +## Python Library References #### Matplotlib John D. Hunter. Matplotlib: A 2D Graphics Environment, Computing in Science & Engineering, 9, 90-95 (2007), [DOI:10.5281/zenodo.3264781](https://zenodo.org/record/3264781) @@ -66,7 +117,7 @@ Stéfan van der Walt, S. Chris Colbert and Gaël Varoquaux. The NumPy Array: A S #### pyDARNio -SuperDARN Data Standards Working Group, Krieger, K.J., Kotyk, K., Detwiller, M.H., Billett, D.D., Burrell, A.G., … Schmidt, M.T. (2021, May 25). SuperDARN/pyDARNio: pyDARNio v1.1 (Version v1.1). Zenodo. http://doi.org/10.5281/zenodo.4792463 +SuperDARN Data Visualization Working Group, Rohel et al. Version 1.2.1 [Zenodo Link](https://zenodo.org/records/7615720) #### AACGM diff --git a/docs/user/coord_time.md b/docs/user/coord_time.md new file mode 100644 index 000000000..df375b91a --- /dev/null +++ b/docs/user/coord_time.md @@ -0,0 +1,74 @@ + + +# Coordinate-Time Parameter Plots +--- + +Similar to range-time plots, the coordinate-time plots allow the user to plot data with geographic or magnetic, longitude or latitude. +Coordinate-time plots have all the additional features as the range-time plots, however the plot by default will show magnetic latitude on the y-axis. Where a range estimation can be used to convert the range gate to a distance from the radar which is in turn converted into a location in latitude or longitude. + +Your plot can be made with a combination of the `range_estimate`, `coords` and `latlon` keywords. +For example, if `range_estimate=RangeEstimate.SLANT_RANGE`, `coords=Coords.AACGM` and `latlon='lat'`, this method will produce a plot with magnetic latitude on the y-axis calculated from the slant range value. + +``` +SDarn_read = pydarn.SuperDARNRead('file/name.fitacf') +fitacf_data = SDarn_read.read_fitacf() +pydarn.RTP.plot_coord_time(fitacf_data, beam_num=0, + range_estimation=pydarn.RangeEstimation.SLANT_RANGE, + latlon='lat', coords=pydarn.Coords.AACGM) +plt.title('Magnetic Latitude of Data from the Saskatoon Radar') +plt.ylabel('Magnetic Latitude (Degrees)') +plt.show() +``` + +![](../imgs/CTP_1.png) + +!!! Warning + This plotting method does not evaluate if the data is appropriate to plot in the given circumstances. Some radars point north and some point longitudinally, therefore data shown in a plot may not be useful given the orientation. + Some radars also have a field of view that may increase but then decrease in latitude, we have tried to solve this using the keyword `plot_equatorward`. + +## Plot Equatorward? + +As mentioned, some radar FOV go up then down in latitude. So that we do not overplot and potentially misrepresent data, the user can choose to plot the 'up' section of data (poleward), or the 'down' section of data (equatorward). +For example, using Clyde River data, you can use the `plot_equatorward` keyword to avoid overplotting and can see the data more clearly. The default for this keyword is `False`, however, the console will print information for you regarding the point at which the data changes direction and how to plot the remaining data. + +``` +a = pydarn.RTP.plot_coord_time(fitacf_data, beam_num=0, + range_estimation=pydarn.RangeEstimation.SLANT_RANGE, + latlon='lat', coords=pydarn.Coords.AACGM, + plot_equatorward=True) +plt.title('Magnetic Latitude of Data from the Clyde River Radar (Equatorward)') +plt.ylabel('Magnetic Latitude (Degrees)') +plt.show() +``` + +![](../imgs/ctp_equator.png) + +``` +a = pydarn.RTP.plot_coord_time(fitacf_data, beam_num=0, + range_estimation=pydarn.RangeEstimation.SLANT_RANGE, + latlon='lat', coords=pydarn.Coords.AACGM, + plot_equatorward=False) +plt.title('Magnetic Latitude of Data from the Clyde River Radar (Poleward)') +plt.ylabel('Magnetic Latitude (Degrees)') +plt.show() +``` + +![](../imgs/ctp_pole.png) + +!!! Note + These same key words can also be used in the summary plot method to plot coordinate-time data in summary format. + +!!! Note + In some circumstances the radar is likely to not be located at the 'bottom' of the plot like in the range-time plots, but can be located at a higher lat or lon. Please be aware of the geometry of the system when interpreting data in this plot style. \ No newline at end of file diff --git a/docs/user/coordinates.md b/docs/user/coordinates.md index 9bc73a187..5eab60178 100644 --- a/docs/user/coordinates.md +++ b/docs/user/coordinates.md @@ -12,7 +12,7 @@ and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. --> -# Ranges, Coords and Projs +# Range Estimations, Coordinate Systems and Projections --- pyDARN uses several different measurement and plotting systems to easily allow the user to customise their plots, this page aims to describe their uses: @@ -28,7 +28,11 @@ pyDARN uses several different measurement and plotting systems to easily allow t **Half Slant**: `RangeEstimation.HALF_SLANT` is slant range divided by two, measured in km. -**Ground Scatter Mapped Range**: `RangeEstimation.GSMR` uses echos from ground scatter to adjust slant range coordinates to be more accurate based on [Dr. Bill Bristow's paper](https://agupubs.onlinelibrary.wiley.com/doi/abs/10.1029/93JA01470). Implemented by Dr. Nathaniel Frissell and Francis Tholley from University of Scranton. Measured in km. +**Ground Scatter Mapped Range** `RangeEstimation.GSMR` uses echos from ground scatter to adjust slant range coordinates, more information on this algorithm can be found in the [GitHub discussion](https://github.com/SuperDARN/pydarn/issues/257). + +**Alternate Ground Scatter Mapped Range**: `RangeEstimation.GSMR_BRISTOW` uses echos from ground scatter to adjust slant range coordinates based on [Dr. Bill Bristow's paper](https://agupubs.onlinelibrary.wiley.com/doi/abs/10.1029/93JA01470). Implemented by Dr. Nathaniel Frissell and Francis Tholley from University of Scranton. Measured in km. + +**Time of Flight**: `RangeEstimation.TIME_OF_FLIGHT` Due to the development of bistatic radar measurements, range estimates of distance cannot be easily used so a time of flight option is alos included. This mode can only be used in range-time plots. Measured in ms. !!! Note Slant range is calculated from the value of `frang`, the distance to the first range gate. In pyDARN, we assume @@ -40,11 +44,11 @@ pyDARN uses several different measurement and plotting systems to easily allow t hardware files. We will amend or reconsider this approach as and when a solution to the differing values is found. In some plots, the user can change the `frang` value to fit their needs. -## Coords +## Coords: Coordinate System -Used to determine the position of data in spatial plots: fan, grid and convection map plots -Range time plots now allow for `Coords` use. The y-axis can be converted to latitude, longitude or MLT using a the `coords` keyword. -E.G. using `coords=Coords.Geographic` and `lat_or_lon='lon'` in the method call will convert the chosen range estimate (see above) into Geographic Longitudes. +This function is used to determine the position of data in spatial plots: fan, grid and convection map plots. +Range time plots now allow for `Coords` use. The y-axis can be converted to latitude or longitude using a the `coords` keyword. +E.G. using `coords=Coords.GEOGRAPHIC` and `latlon='lon'` in the method call, will convert the chosen range estimate (see above) into geographic longitudes. **Geographic**: `Coords.GEOGRAPHIC` is the standard geographical coordinate system for latitude and longitude (degrees) @@ -54,9 +58,9 @@ E.G. using `coords=Coords.Geographic` and `lat_or_lon='lon'` in the method call `RangeEstimation` methods can be used with a `Coords` calculation. For example, using `Coords.GEOGRAPHIC` and `RangeEstimation.GSMR` together, will give a plot of ionospheric echoes at a distance from the radar calculated in ground scatter mapped range, in geographic coordinates. -## Projs +## Projs: Projections -Spatial plots have two options for projections. +Spatial plots have two options for projections. See also [Axes Setup](axis.md) tutorial. **Polar**: `Projs.POLAR` sets up the axis of the spatial plot in polar coordinates common in studies that show data over the poles. @@ -69,6 +73,58 @@ Spatial plots have two options for projections. !!! Note Some combinations of Projs/Coords/RangeEstimates are not designed to work. - For example, you cannot plot a fan plot using range gates, spatial plots require a value in kilometers. + For example, you cannot plot a fan plot using range gates; spatial plots require a value in kilometers. At the moment, AACGM Coordinates do not plot on Geographic projections as it has not been developed yet. - Convection maps only support polar projections due to lack of interest in requiring geographic projections. \ No newline at end of file + Convection maps only support polar projections due to lack of interest in requiring geographic projections. + +# Including a Terminator + +Spatial plots have the option to include a terminator called `nightshade` at a given height in the ionosphere. This functions uses the *Cartopy* `nightshade` function. +Nightshade is only available using the geographic projection and can be implemented by adding `nightshade=250` to the spacial plot call where 250 is the desired height in the +ionosphere to be in the Earth's shadow. If you would like to plot your own terminator on any plot, the `terminator` function will return the anti-sub-solar position and the +great circle distance to the terminator in geographic coordinates: +```python +antisolarpsn, arc_length, angle_of_terminator = pydarn.terminator(date, nightshade) +``` +The `antisolarpsn` is given in degrees lon, lat. The `arc_length` is in kilometers and the `angle_of_terminator` is the angle from the subsolar point to the terminator (i.e. is 90 degrees at ground level). +The terminator position can be calculated using `(lat, lon) = new_coordinate(lat, lon, arc_length, bearing, R=Re)` for any bearing from the antisolar position. This can be converted to magnetic coordinates using the +AACGMv2 library. Unfortunately, Matplotlib is unable to plot the terminator using `fill` consistently, hence we leave this option up to the user. +An example of this is shown below: +```python +import pydarn +import aacgmv2 +import datetime as dt +import matplotlib.pyplot as plt +import numpy as np + +# North Winter +pydarn.Fan.plot_fov(66, dt.datetime(2023, 12, 21, 0, 0), + lowlat= 5, boundary=True, line_color='red', coastline=True) + +# Test to plot terminator if ever required - plot line not fill! +# Get antisolar point in geographic coords and radius of terminator +# at given height +date = dt.datetime(2023, 12, 21, 0, 0) +antisolarpsn, arc, ang = pydarn.terminator(date, 250) +# Convert position to magnetic coordinates +mlat, lon_mag, _ = aacgmv2.convert_latlon(antisolarpsn[1], + antisolarpsn[0], + 250, date, method_code='G2A') +# Shift to MLT +shifted_mlts = lon_mag - (aacgmv2.convert_mlt(lon_mag, date) * 15) +shifted_lons = lon_mag - shifted_mlts +mlon = np.radians(shifted_lons) +# Get positions at a distance from new position to plot terminator +lats = [] +lons = [] +for b in range(-180,180,1): + (lat, lon) = pydarn.GeneralUtils.new_coordinate(mlat, shifted_lons, arc, b, R=pydarn.Re) + nlon =np.radians(lon) + lats.append(lat) + lons.append(nlon) +lats2 = np.zeros(len(lats)) +plt.plot(np.squeeze(lons), np.squeeze(lats), color='b', zorder=2.0, + linewidth=3.0, linestyle='dashed') + +plt.show() +``` \ No newline at end of file diff --git a/docs/user/fan.md b/docs/user/fan.md index ab0149a26..95c6e7add 100644 --- a/docs/user/fan.md +++ b/docs/user/fan.md @@ -42,7 +42,7 @@ fitacf_data = SDarn_read.read_fitacf() ``` With the FITACF data loaded as a list of dictionaries (`fitacf_data` variable in above example), you may now call the `plot_fan` method. Make sure you tell it which scan (numbered from first recorded scan in file, counting from 1 or give it a `datetime` object for the scan at that time) you want using `scan_index`: ```python -fanplot = pydarn.Fan.plot_fan(fitacf_data, scan_index=27, +fan_rtn = pydarn.Fan.plot_fan(fitacf_data, scan_index=27, colorbar_label='Velocity [m/s]') plt.show() ``` @@ -64,7 +64,7 @@ plt.show() Default plots also do not show groundscatter as grey. Set it to true to colour groundscatter: ```python -fanplot = pydarn.Fan.plot_fan(fitacf_data, +fan_rtn = pydarn.Fan.plot_fan(fitacf_data, scan_index=27, groundscatter=True) plt.show() @@ -72,17 +72,17 @@ plt.show() ``` ![](../imgs/fan_2.png) -You might have noticed that the variable `fanplot` in the examples above actually holds some information. This contains the AACGM latitude and longitude of the fan just plotted, as well as the data, ground scatter information, and datetime object. If you instead change `fanplot` to 5 separate variables, it will return the latitude, longitude, data, groundscatter and datetime info into seperate variables: +You might have noticed that the variable `fan_rtn` in the examples above actually holds some information. This return value is a dictionary containing data in the plot, ax and ccrs values along with color map and color bar information: ```python -ax, lats, lons, data, grndsct = pydarn.Fan.plot_fan(fitacf_data, - scan_index=27) - -lats.shape +fan_rtn = pydarn.Fan.plot_fan(fitacf_data, scan_index=27) +print(fan_rtn.keys()) +``` +``` +>>> dict_keys(['ax', 'ccrs', 'cm', 'cb', 'fig', 'data']) ``` -Which returns `>>>(76, 17)`, i.e. ranges x beams array of the latitude, and so on for the other variables. The groundscatter array is 0's and 1's, 1 being a range gate flagged as groundscatter. -### Additional parameters +### Parameters Available for Plotting In addition to line-of-sight velocity, you can choose one of three other data products to plot by setting `parameter=String name`: @@ -93,7 +93,23 @@ In addition to line-of-sight velocity, you can choose one of three other data pr | Elevation angle (degrees) | 'elv' | | Power (dB) | 'p_l' | -### Additional options +### Ball and Stick Plots + +Data on fan plots can also be displayed as a 'ball and stick' plot, where each data point is represented by a ball with a stick showing direction towards or away from the radar, coloured by the magnitude of the parameter plotted. +Ball and stick plots can be plotted usng the `ball_and_stick` with `len_factor` key words, as follows: + +``` +pydarn.Fan.plot_fan(fitacf_data, + scan_index=1, lowlat=60, zmin=-1000, zmax=1000, + boundary=True, radar_label=True, + groundscatter=True, ball_and_stick=True, len_factor=300, + coastline=True, parameter="v") +plt.show() +``` + +![](../imgs/ball_and_stick.png) + +### Additional Options Here is a list of all the current options than can be used with `plot_fan` @@ -117,6 +133,7 @@ Here is a list of all the current options than can be used with `plot_fan` | projs=(Projs) | Projections to plot the data on top of | | colorbar_label=(string) | Label that appears next to the color bar, requires colorbar to be True | | coastline=(bool) | Plots outlines of coastlines below data (Uses Cartopy) | +| beam=(int) | Only plots data/outline of specified beam (default: None) | | kwargs ** | Axis Polar settings. See [polar axis](axis.md) | @@ -138,13 +155,13 @@ pyk_file = 'data/20150308.1401.00.pyk.fitacf' pyk_data = pydarn.SuperDARNRead().read_dmap(pyk_file) cly_data = pydarn.SuperDARNRead().read_dmap(cly_file) -ax, _, _, _, _ = pydarn.Fan.plot_fan(cly_data, scan_index=datetime(2015, 3, 8, 14, 4), +fan_rtn = pydarn.Fan.plot_fan(cly_data, scan_index=datetime(2015, 3, 8, 14, 4), colorbar=False, fov_color='grey', line_color='blue', radar_label=True) pydarn.Fan.plot_fan(pyk_data, scan_index=datetime(2015, 3, 8, 14, 4), colorbar_label='Velocity [m/s]', fov_color='grey', - line_color='red', radar_label=True, ax=ax) + line_color='red', radar_label=True, ax=fan_rtn['ax']) plt.show() ``` @@ -154,12 +171,12 @@ plt.show() Using *cartopy* to plot underlaid coastline map using the `coastline` keyword, this example also shows the use of plotting in geographic coordinates: ```python -ax, _, _, _, _ = pydarn.Fan.plot_fan(data, scan_index=5, radar_label=True, - groundscatter=True, - coords=pydarn.Coords.GEOGRAPHIC, - projs=pydarn.Projs.GEO, - colorbar_label="Velocity m/s", - coastline=True) +pydarn.Fan.plot_fan(data, scan_index=5, radar_label=True, + groundscatter=True, + coords=pydarn.Coords.GEOGRAPHIC, + projs=pydarn.Projs.GEO, + colorbar_label="Velocity m/s", + coastline=True) plt.show() ``` diff --git a/docs/user/filters.md b/docs/user/filters.md new file mode 100644 index 000000000..01fb2e443 --- /dev/null +++ b/docs/user/filters.md @@ -0,0 +1,88 @@ + + +# Filtering Data +--- + + + +Currently pyDARN has one filtering option. + +## Boxcar Filtering + +!!! Note + Filtering data can be computationally expensive and time consuming. Please + allow around 5 minutes of processing time to filter a 2 hour FITACF file. + Parallel processing options for the boxcar filter may be developled in the + near future. + + +The boxcar filter filters data in time and 'space' (beams and gates) and is +available by evoking the `Boxcar` instance after reading a file. + +```python +import pydarn + +fitacf_file = "datafilename.fitacf" +darn_read = pydarn.SuperDARNRead(fitacf_file) +fitacf_data = darn_read.read_fitacf() + +# Evoke filter on data +bx = pydarn.Boxcar( + thresh=0.7, + w=None +) +filtered_data = bx.run_filter(fitacf_data) +``` + +The variable `filtered_data` can be treated in the same way as the original data +in `fitacf_data`. The data can be used to in any FITACF plotting methods. For example, +the code below produces comparisons between summary plots and fan plots for the same +time frame. + +```python +import bz2 +import matplotlib.pyplot as plt +import pydarn + +with bz2.open('fitacffilename.fitacf.bz2') as fp: + fitacf_stream = fp.read() +fitacf_data = pydarn.SuperDARNRead(fitacf_stream, True).read_fitacf() + +# Before filtering: +pydarn.RTP.plot_summary(fitacf_data, beam_num=7, + range_estimation=pydarn.RangeEstimation.RANGE_GATE) +plt.show() + +pydarn.Fan.plot_fan(fitacf_data, scan_index=10, coastline=True) +plt.show() + +# Evoke filter on data +bx = pydarn.Boxcar( + thresh=0.7, + w=None +) +filtered_data = bx.run_filter(fitacf_data) + +# After filtering +pydarn.RTP.plot_summary(filtered_data, beam_num=7, + range_estimation=pydarn.RangeEstimation.RANGE_GATE) +plt.show() + +pydarn.Fan.plot_fan(filtered_data, scan_index=10, coastline=True) +plt.show() +``` + +![](../imgs/unfiltered.png) +![](../imgs/filtered.png) \ No newline at end of file diff --git a/docs/user/fov.md b/docs/user/fov.md index c17435d80..c994e38b5 100644 --- a/docs/user/fov.md +++ b/docs/user/fov.md @@ -59,6 +59,7 @@ Here is a list of all the current options than can be used with `plot_fov` | radar_location=(bool) | Places a dot in the plot representing the radar location (default: True) | | radar_label=(bool) | Places the radar 3-letter abbreviation next to the radar location | | coastline=(bool) | Plots outlines of coastlines below FOV (Uses Cartopy) | +| beam=(int) | Only plots outline/fill of specified beam (default: None) | | kwargs ** | Axis Polar settings. See [polar axis](axis.md) | To plot based on hemisphere or selection of radars, here is an example plotting North hemisphere radars with selected SuperDARN Canada radars colored as green, note that the axes object (ax) needs to be updated inside to loop to plot multiple FOV: @@ -68,18 +69,20 @@ import pydarn from datetime import datetime import matplotlib.pyplot as plt -ax = None +fov_rtn={} +fov_rtn['ax'] = None for stid in pydarn.SuperDARNRadars.radars.keys(): if pydarn.SuperDARNRadars.radars[stid].hemisphere == pydarn.Hemisphere.North: if stid != 2: if stid in [66, 65, 6, 65, 5]: - _ , _, ax, _ = pydarn.Fan.plot_fov(stid, datetime(2021, 2, 5, 12, 5), + fov_rtn = pydarn.Fan.plot_fov(stid, datetime(2021, 2, 5, 12, 5), radar_label=True, fov_color='green', - line_color='green', alpha=0.8, ax=ax) + line_color='green', alpha=0.8, ax=fov_rtn['ax']) - _ , _, ax, _ = pydarn.Fan.plot_fov(stid, datetime(2021, 2, 5, 12, 5), + fov_rtn = pydarn.Fan.plot_fov(stid, datetime(2021, 2, 5, 12, 5), radar_label=True, fov_color='blue', - line_color='blue', alpha=0.2, lowlat=10, ax=ax) + line_color='blue', alpha=0.2, lowlat=10, + ax=fov_rtn['ax']) plt.show() ``` @@ -93,13 +96,14 @@ import pydarn from datetime import datetime import matplotlib.pyplot as plt -ax = None +fov_rtn={} +fov_rtn['ax'] = None for stid in pydarn.SuperDARNRadars.radars.keys(): if pydarn.SuperDARNRadars.radars[stid].hemisphere == pydarn.Hemisphere.South: if stid != 2: - _, _, ax, _ = pydarn.Fan.plot_fov(stid, datetime(2021, 2, 5, 12, 5), + fov_rtn = pydarn.Fan.plot_fov(stid, datetime(2021, 2, 5, 12, 5), radar_label=True, fov_color='red', - line_color='red', alpha=0.2, ax=ax) + line_color='red', alpha=0.2, ax=fov_rtn['ax']) plt.show() ``` @@ -113,12 +117,9 @@ import pydarn from datetime import datetime import matplotlib.pyplot as plt -_ , _, ax, ccrs = pydarn.Fan.plot_fov(stid=65, - date=datetime(2022, 1, 8, 14, 5), - fov_color='red', - coords=pydarn.Coords.GEOGRAPHIC, - projs=pydarn.Projs.GEO, - coastline=True) +pydarn.Fan.plot_fov(stid=65, date=datetime(2022, 1, 8, 14, 5), + fov_color='red', coords=pydarn.Coords.GEOGRAPHIC, + projs=pydarn.Projs.GEO, coastline=True) plt.show() ``` @@ -134,30 +135,34 @@ import pydarn from datetime import datetime import matplotlib.pyplot as plt -_, _, ax, ccrs=pydarn.Fan.plot_fov(66, datetime(2021, 6, 21, 6, 0), - lowlat= 50, boundary=True, radar_label=True, - line_color='red', grid = True, - coords=pydarn.Coords.GEOGRAPHIC, - projs=pydarn.Projs.GEO, coastline=True) +fov_rtn = pydarn.Fan.plot_fov(66, datetime(2021, 6, 21, 6, 0), + lowlat= 50, boundary=True, radar_label=True, + line_color='red', grid = True, + coords=pydarn.Coords.GEOGRAPHIC, + projs=pydarn.Projs.GEO, coastline=True) pydarn.Fan.plot_fov(5, datetime(2021, 2, 5, 12, 5), radar_label=True, - ax=ax, ccrs=ccrs, boundary=True, line_color='blue', - grid = True, coords=pydarn.Coords.GEOGRAPHIC, + ax=fov_rtn['ax'], ccrs=fov_rtn['ccrs'], boundary=True, + line_color='blue', grid = True, + coords=pydarn.Coords.GEOGRAPHIC, projs=pydarn.Projs.GEO) pydarn.Fan.plot_fov(64, datetime(2021, 2, 5, 12, 5), radar_label=True, - ax=ax, ccrs=ccrs, boundary=True, line_color='green', + ax=fov_rtn['ax'], ccrs=fov_rtn['ccrs'], + boundary=True, line_color='green', grid = True, coords=pydarn.Coords.GEOGRAPHIC, projs=pydarn.Projs.GEO) pydarn.Fan.plot_fov(65, datetime(2021, 2, 5, 12, 5), radar_label=True, - ax=ax, ccrs=ccrs, boundary=True, line_color='orange', + ax=fov_rtn['ax'], ccrs=fov_rtn['ccrs'], + boundary=True, line_color='orange', grid = True, coords=pydarn.Coords.GEOGRAPHIC, projs=pydarn.Projs.GEO) pydarn.Fan.plot_fov(6, datetime(2021, 2, 5, 12, 5), radar_label=True, - ax=ax, ccrs=ccrs, boundary=True, grid = True, + ax=fov_rtn['ax'], ccrs=fov_rtn['ccrs'], + boundary=True, grid = True, coords=pydarn.Coords.GEOGRAPHIC, projs=pydarn.Projs.GEO) plt.show() ``` -![](../imgs/fov_8.png_) +![](../imgs/fov_8.png) !!! Warning You cannot plot AACGM coordinates on a geographic plot as its not correctly transformed. @@ -189,6 +194,6 @@ plt.show() ![](../imgs/fov_4.png) !!! Note - The radar labels will appear at the same longitude, but at -5 degrees of latitude to the position of the radar station. This may cause some to overlap. Users can plot their own labels using `plt.text(*lon psn in radians*, *lat psn in degrees*, *text string*)` + The radar label positions have been manually set so that no labels overlap. Users can plot their own labels using `plt.text(*lon psn in radians*, *lat psn in degrees*, *text string*)` if the current position used is not suitable. diff --git a/docs/user/grid.md b/docs/user/grid.md index 72ea82fcf..7dd9915f1 100644 --- a/docs/user/grid.md +++ b/docs/user/grid.md @@ -27,9 +27,6 @@ Gridded [parameters](https://radar-software-toolkit-rst.readthedocs.io/en/latest and a time or record number projected onto a polar format plot in [AACGMv2](http://superdarn.thayer.dartmouth.edu/aacgm.html) coordinates. - -Currently, grid plots in pyDARN get geomagnetic positions of the gridded data in [`mlon` and `mlat`](https://pypi.org/project/aacgmv2/) from the GRID file, which uses AACGMv2 coordinates. In the future, pyDARN will also generate the geographic position of the data points, which will bring support for non-standard gridded vector layouts. - ### Basic usage pyDARN and pyplot need to be imported and the desired GRID file needs to be [read in](https://pydarn.readthedocs.io/en/latest/user/SDarnRead/): @@ -49,19 +46,20 @@ With the grid data loaded as a list of dictionaries (`grid_data` variable in abo import datetime as dt stime = dt.datetime(year, month, day, hour, minute) -gridplot = pydarn.Grid.plot_grid(grid_data, start_time=stime) +grid_rtn = pydarn.Grid.plot_grid(grid_data, start_time=stime) plt.show() ``` In this example, the record at `stime` was plotted with the defaulted parameter, line-of-sight velocity, being gridded: ![](../imgs/grid_1.png) -You might have noticed that the variable `gridplot` in the examples above actually holds some information. This contains the AACGM latitude and longitude of the gridded vectors plotted, as well as the data. If you instead change `gridplot` to 3 separate variables, it will return the latitude, longitude, and data info into separate variables: +You might have noticed that the variable `gridplot` in the examples above actually holds some information. This dictionary contains the AACGM latitude and longitude of the gridded vectors plotted, as well as the data: ```python -lats,lons,data=pydarn.Grid.plot_grid(grid_data, start_time=stime) +grid_rtn = pydarn.Grid.plot_grid(grid_data, start_time=stime) +print(grid_rtn.keys()) ``` -### Additional parameters +### Additional Parameters In addition to the gridded line-of-sight velocity, you can choose one of two other data products to plot by setting `parameter=String name`: @@ -71,7 +69,7 @@ In addition to the gridded line-of-sight velocity, you can choose one of two oth | Spectral width (m/s) | `wdt` | | Power (dB) | `pwr` | -### Additional options +### Additional Options Here is a list of all the current options than can be used with `plot_grid` diff --git a/docs/user/hardware.md b/docs/user/hardware.md index b379d4542..55168fdfc 100644 --- a/docs/user/hardware.md +++ b/docs/user/hardware.md @@ -37,7 +37,7 @@ import pydarn from datetime import datetime # Read Goose Bay radars hardware file for 2003 03 20 -hdw_data = pydarn.read_hdw_file('gbr', datetime(2003 3, 20)) +hdw_data = pydarn.read_hdw_file('gbr', datetime(2003, 3, 20)) print(hdw_data.gates) ``` @@ -46,7 +46,7 @@ Expected output: 75 ``` -Other information a user can access from the `_HdwInfo` object is: +Other information a user can access from the `_HdwInfo` object: | Field name | Description | | :---: | :--- | @@ -73,9 +73,9 @@ Other information a user can access from the `_HdwInfo` object is: Prior to version 3.0, pyDARN was built to use the old format of hardware files. However, versions 2.2.1 or lower of pyDARN will try to pull hardware files from the `master` branch of the hardware repository and this may cause some errors in use. Version 3.0 uses the new format of hardware files, and pulls hardware files from the `main` hardware branch. Updating to pyDARN version 3.0 or higher will fix any hardware errors. -# Accessing Radar and Hardware Information +# Accessing Radar Information -Another way to access the hardware information, the radar's full name, the institution's name and the hemisphere that the radar is located in is by using the `SuperDARNRadars` class with the station id number (`stid` field in most files). +Another way to access the hardware information, the radar's full name, the institution's name,the hemisphere that the radar is located in, and other information not tracked by hardware files is by using the `SuperDARNRadars` class with the station id number (`stid` field in most files). This class contains a dictionary of all currently accepted SuperDARN radars (including decommissioned): ``` python import pydarn @@ -93,9 +93,9 @@ _Radar(name='Prince George', institution='University of Saskatchewan', hemispher !!! Warning The hardware information obtained via this class contains most recent updates to the hardware file as it does not take a specific date as an input. To get specific hardware information, please use `read_hdw_file`. -# Obtaining coordinates for radar fields-of-view +# Obtaining coordinates for a radar's field of view -The `radar_fov` function in pyDARN is an easy way to grab the coordinates of a specific radars field-of-view. All you need is the station id (key: `stid`) of the radar of interest. +The `coords` function in pyDARN is an easy way to grab the coordinates of a specific radars field-of-view. All you need is the station id (key: `stid`) of the radar of interest. Example code: ```python @@ -105,7 +105,7 @@ import pydarn geo_lats, geo_lons=pydarn.Coords.GEOGRAPHIC(66) ``` -You also have the option to set the `coords` keyword to `aacgm`. In this case, [Altitude adjusted corrected geomagnetic](http://superdarn.thayer.dartmouth.edu/aacgm.html) latitude and longitude are returned instead of geographic. Because AACGM requires a date to convert coordinates accurately, a python datetime object is also required to be passed in to `radar_fov` under this circumstance: +You also have the option to set the `coords` keyword to `aacgm`. In this case, [Altitude adjusted corrected geomagnetic](http://superdarn.thayer.dartmouth.edu/aacgm.html) latitude and longitude are returned instead of geographic. Because AACGM requires a date to convert coordinates accurately, a python datetime object is also required to be passed in to `coords` under this circumstance: ```python import pydarn import datetime as dt diff --git a/docs/user/install.md b/docs/user/install.md index d177c4d60..19cf3ac69 100644 --- a/docs/user/install.md +++ b/docs/user/install.md @@ -17,18 +17,30 @@ the additional permissions listed below. --- [![License: LGPL v3](https://img.shields.io/badge/License-LGPLv3-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0) -[![Python 3.6](https://img.shields.io/badge/python-3.6-blue.svg)](https://www.python.org/downloads/release/python-360/) +[![Python 3.7](https://img.shields.io/badge/python-3.7-blue.svg)](https://www.python.org/downloads/release/python-370/) ![GitHub release (latest by date)](https://img.shields.io/github/v/release/superdarn/pydarn) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.3727269.svg)](https://doi.org/10.5281/zenodo.3727269) +For most users, pyDARN can be installed simply by: -!!! Important - It is recommended to install pyDARN via `pip`; however, please cite via the [DOI for the release](https://doi.org/10.5281/zenodo.3727269) +``` +pip3 install pydarn +``` + +If already installed, pyDARN can be upgraded by: + +``` +pip3 install --upgrade pydarn +``` +Installing in virtual environments is recommended, see below for details. ## Prerequisites -pyDARN requires **python 3.6** or later and **matplotlib 3.3.4** or later. +pyDARN requires **python 3.7** or later and **matplotlib 3.3.4** or later. + +!!! Note + Python 3.6 is commonly the default version included on many operating systems, you may need to install a newer version and specify that version when running python programs and installing libraries. Depending on your operating system or distribution, the following package installers, development environments or data parsers are required: @@ -41,12 +53,10 @@ You can check your python version using `$ python --version` or `$ python3 --version` -!!! Note - If you have already installed `pydarn` you can use `pip3 install --upgrade pydarn` ## Dependencies -pyDARN's setup will download the following dependencies: +On installation, pyDARN will download the following dependencies: - [Git](https://git-scm.com/) (For developers) - [pip3](https://help.dreamhost.com/hc/en-us/articles/115000699011-Using-pip3-to-install-Python3-modules) @@ -57,39 +67,35 @@ pyDARN's setup will download the following dependencies: - [AACGMv2](https://pypi.org/project/aacgmv2/) !!! Note - If you wish to plot coastlines or geographic projections you will need to install cartopy>=0.19 separately + If you wish to plot coastlines or geographic projections you will need to install cartopy>=0.19 separately, see below. ### Cartopy [Cartopy](https://scitools.org.uk/cartopy/docs/latest/) is a Python package designed for geospatial data processing in order to produce maps and other geospatial data analyses. This library is used when invoking a projection system needing overlapped coastline maps in Fan, Grid and Map plots. -For installing cartopy please follow the packages [installation](https://scitools.org.uk/cartopy/docs/latest/installing.html) instructions. For ubuntu here is good installation [link](https://techoverflow.net/2021/07/11/how-to-install-cartopy-on-ubuntu/) - -!!! Warning - For cartopy to work with pyDARN please make sure it version `>=0.19`. Otherwise pydarn will throw an exception if you try to use it. - +For installing cartopy please follow the [installation](https://scitools.org.uk/cartopy/docs/latest/installing.html) instructions. For ubuntu here is good installation [walkthrough](https://techoverflow.net/2021/07/11/how-to-install-cartopy-on-ubuntu/). !!! Note - cartopy can be a challenging package to install so please provide any information on troubleshooting or solutions to common issues on the [pyDARN github](https://github.com/SuperDARN/pydarn) page. - + pyDARN requires cartopy version 0.19 or higher. + cartopy can be a challenging package to install, please provide any information on troubleshooting or solutions in an issue on the [pyDARN github](https://github.com/SuperDARN/pydarn) page. ## Virtual Environments -It is recommended to install pyDARN in one of the suggested virtual environments if you have multiple python/pip 3 version on your computer, or do not want to affect the main system's python libraries. +It is recommended to install pyDARN in one of the suggested virtual environments if you have multiple python versions on your computer, or do not want to affect the main system's python libraries. -The following virtual environments have been tested by pyDARN developers:" +The following virtual environments have been tested by pyDARN developers: ### pip Virtual Environment Instructions can be found here [virtual environment](https://packaging.python.org/guides/installing-using-pip-and-virtual-environments/) Option 1: + 1. `$ python3 -m pip install --user virtualenv` (Install virtual environment package) -2. `$ python3 -m virtualenv ` (Make your virtual environment) -3. `$ source /bin/activate` (Activate the virtual environment) -4. `$ pip install pydarn` (Install pyDARN) +2. `$ python3 -m virtualenv ` (Make your virtual environment) +* `$ source /bin/activate` (Activate the virtual environment) +* `$ pip3 install pydarn` (Install pyDARN) !!! Note - If you have multiple versions of python 3 on your machine, you can access a specific version by: `python`. - For example, if you want to install python 3.6 virtual environment: `python3.6 -m pip install --user virtualenv`. + In newer python version, `virtualenv` is now `venv`. ### Anaconda Virtual Environment Instructions can be found here [conda environment](https://uoa-eresearch.github.io/eresearch-cookbook/recipe/2014/11/20/conda/) and installing [anaconda](https://docs.anaconda.com/anaconda/install/) @@ -108,44 +114,37 @@ To set the project interpreter to the anaconda environment: * Select "Conda Environment" on the left side menu. * Click "Existing Environment" and give the interpreter field the path to your environment's python.exe and apply. -## Local Install -**pip3 install** - -`pip3 install --user pydarn` - -## System Install -`sudo pip3 install pydarn` -## Installing for Development +## Installing for Development or Testing pyDARN's default github branch is `develop` for quicker and easer development. -It is encouraged to use [SSH keys in GitHub](https://docs.github.com/en/github/authenticating-to-github/connecting-to-github-with-ssh) +`git clone https://github.com/SuperDARN/pydarn.git` -`git clone git@github.com:SuperDARN/pydarn.git` +To install a specific branch to develop or test: +`cd pydarn` +`git checkout branch_name` +`pip3 install .` -To install: +You can alternatively install a specific branch using the following installation, this is most useful for testing new branches: -`$ pip3 install . --user` - -!!! Note - If `pip --version` is pointing to python 3.6+ then you can use `pip install . --user` instead. - -!!! Note - Sometimes `python setup.py install` is needed to grab all hardware files (known issue). +`pip3 install git+https://github.com/superdarn/pydarn@branch_name` Please read pyDARN [Workflow documentation](../dev/team.md) to further understand how to develop in pyDARN. ## Troubleshooting -### Pip3 installation with Ubuntu 20.4/python 3.8.4 +Some known issues with solutions are: + +### pip3 installation with Ubuntu 20.4/python 3.8.4 Issue: `pip3 install --user git+https://github.com/superdarn/pydarn@develop` not working Solution: + 1. check git is installed `apt install git` (for ubuntu) -2. Check pip version `pip --version` - with newer distros of Linux/Virtual machines `pip` may point to pyhon3 and you will not need pip3. -3. Alternative virtual environment steps for getting python 3.8 working +2. Check pip version `pip --version` - with newer distros of Linux/Virtual machines `pip` may point to pyhon3 and you will not need pip3. +* Alternative virtual environment steps for getting python 3.8 working ```bash $ sudo apt-get update @@ -157,26 +156,23 @@ $ echo "source $HOME/venvs/py38/bin/activate" >> ~/.bashrc ``` Then open a new terminal and you should see `(pyy38)` in the prompt. -Credit to this solution is Ashton Reimer, more details on the [issue #37](https://github.com/SuperDARN/pydarn/issues/37) +More details on [issue #37](https://github.com/SuperDARN/pydarn/issues/37) ### aacgmv2 won't install -Issue: `unable to execute 'gcc': No such file or directory - error: command 'gcc' failed with exit status 1` - -Solution: - 1. Ensure `gcc` is installed if not install it - 2. Ensure you install `python3-dev` (Ubuntu) or `python3-devel` for RPM OS Linux operating systems. - -Credit to this solution is Marina Schmidt brought up by Remington Rohel from SuperDARN Canada +Issue: `unable to execute 'gcc': No such file or directory error: command 'gcc' failed with exit status 1` +Solution: -> If you find any problems/solutions, please make a [github issue](https://github.com/superdarn/pydarn/issues/new) so the community can help you or add it to the documentation - -### Summary plots get a ValueError + 1. Ensure `gcc` is installed if not install it + 2. Ensure you install `python3-dev` (Ubuntu) or `python3-devel` for RPM OS Linux operating systems. -Issue: `ValueError: Cannot convert 0 to a date. This often happens if non-datetime values are passed to an axis that expects datetime objects.` when using `plot_summary` +### General Plotting Errors Solution: -1. check matplotlib version, if lower than 3.3.4 then upgrade matplotlib equal or higher version. + +1. check matplotlib version, if lower than 3.3.4 then upgrade matplotlib equal or higher version. 2. `pip install -U matplotlib` + +!!! Note +If you find any problems/solutions, please make a [github issue](https://github.com/superdarn/pydarn/issues/new) so the community can help you or add it to the documentation! diff --git a/docs/user/iq.md b/docs/user/iq.md new file mode 100644 index 000000000..082bb65a7 --- /dev/null +++ b/docs/user/iq.md @@ -0,0 +1,81 @@ + + +# IQ Data and Plotting + +## Reading IQ Data + +```python +import pydarn +iq_file = 'path/to/file/iqdata.iqdat' +iq_data = pydarn.SuperDARNRead(iq_file).read_iqdat() +``` + +!!! Note + These methods only work for iqdat formatted files. + You can use pyDARNio to read antennas IQ data, or bfiq data. + bfiq data can be converted to iqdat for plotting. + +## IQ Plotting Options +### IQ Time Series Plots + +These plots show any of the scalar products found in the IQ file. This method directly calls the time series method in the RTP module. + +```python +pydarn.IQ.plot_time_series(iq_data, beam_num=7, parameter='tfreq') +plt.show() +``` + +![](../imgs/iq1.png) + +### IQ Sequence Plots + +The IQ sequence plots will plot the real and imaginary parts of a single sequence of data. There are additional options to view the phase. +You can also choose to view the IQ data from the main array, or the interferometer array using the key work `interferometer`. + +```python +pydarn.IQ.plot_iq_sequence(iq_data, start_time=datetime(2016,1,13,16,15), + beam_num=15, sequence_num=20, + interferometer=False, plot_phase=True) +plt.show() +``` + +![](../imgs/iq2.png) + +### IQ Record Plots + +Record plots will plot a single record in a file, given a beam. +You can also choose to view the IQ data from the main array, or the interferometer array using the key work `interferometer`. + +```python +pydarn.IQ.plot_iq_record(iq_data, start_time=datetime(2016,1,13,16,0), + beam_num=15, interferometer=False) +plt.show() +``` + +![](../imgs/iq3.png) + +### IQ Overview Plots + +Overview plots will plot every sequence found in a file for a given beam. All beams is also an option. +You can also choose to view the IQ data from the main array, or the interferometer array using the key work `interferometer`. + +```python +pydarn.IQ.plot_iq_overview(iq_data, beam_num='all', interferometer=False) +plt.show() +``` + +![](../imgs/iq4.png) + + diff --git a/docs/user/map.md b/docs/user/map.md index 50e686315..566c54c0b 100644 --- a/docs/user/map.md +++ b/docs/user/map.md @@ -12,9 +12,10 @@ and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. --> -# Map plots +# Map Data Plots --- +## Convection Maps Map plots are a way to visualize data from a MAP file of SuperDARN radar data. Please read RST documentation on how to process [MAP files](https://radar-software-toolkit-rst.readthedocs.io/en/latest/user_guide/map_grid/) from GRID files. Map field descriptions can be found [here](https://radar-software-toolkit-rst.readthedocs.io/en/latest/references/general/map/). pyDARN uses a `enum` object to select different common parameters to plot in a MAP file: @@ -29,7 +30,7 @@ Map field descriptions can be found [here](https://radar-software-toolkit-rst.re for a given `start_time` or `record` number projected onto a polar plot in [AACGMv2](http://superdarn.thayer.dartmouth.edu/aacgm.html) coordinates. -Currently, map plots in pyDARN get geomagnetic positions of the mapped data in [`mlon` and `mlat`](https://pypi.org/project/aacgmv2/) from the MAP file, which uses AACGMv2 coordinates. In the future, pyDARN will also generate the geographic position of the data points, which will bring support for non-standard gridded vector layouts. +Currently, map plots in pyDARN get geomagnetic positions of the mapped data in [`mlon` and `mlat`](https://pypi.org/project/aacgmv2/) from the MAP file, which uses AACGMv2 coordinates. ### Fitted Velocities @@ -51,18 +52,19 @@ SDarn_read = pydarn.SuperDARNRead(file) map_data = SDarn_read.read_map() ``` -With the map data loaded as a list of dictionaries (`map_data` variable in above example), you may now call the `plot_mapdata` method. Make sure you tell the method what time, in [`datetime` format], or record number (numbered from first recorded in file, counting from 0): +With the map data loaded as a list of dictionaries (`map_data` variable in above example), you may now call the `plot_mapdata` method. Make sure you tell the method what time, in `datetime` format, or record number (numbered from first recorded in file, counting from 0): ```python -mapplot = pydarn.Maps.plot_mapdata(map_data, record=150) +map_rtn = pydarn.Maps.plot_mapdata(map_data, record=150) plt.show() ``` -In this example, the record at 150 was plotted with the defaulted parameter, `MapParams.FITTED_VELOCITIES` (fitted velocities), being mapped: +In this example, the record at 150 was plotted with the defaulted parameter, `MapParams.FITTED_VELOCITIES` (fitted velocities): ![](../imgs/map_1.png) -You might have noticed that the variable `mapplot` in the examples above actually holds some information. This contains the AACGM latitude and longitude of the mapped vectors plotted. If you instead change `mapplot` to 3 separate variables, it will return the latitude, longitude, and data info into separate variables: +You might have noticed that the variable `map_rtn` in the examples above actually holds some information. This dictionary contains the AACGM latitude and longitude of the mapped vectors plotted: ```python -lats,lons,data=pydarn.Maps.plot_mapdata(map_data, start_time=stime) +map_rtn = pydarn.Maps.plot_mapdata(map_data, start_time=stime) +print(map_rtn.keys()) ``` ### Additional options @@ -123,3 +125,37 @@ pydarn.Maps.plot_mapdata(map_data, record=150, plt.show() ``` ![](../imgs/map_2.png) + +## Map Time-Series Plots +Values within a map file can also be plotted using the `plot_time_series` method. + +``` +import pydarn +import datetime as dt +import matplotlib.pyplot as plt + +file_path = "path/to/map/file.map" +data = pydarn.SuperDARNRead().read_dmap(file_path) +start_time = dt.datetime(2019,4,21,11,0) +end_time = dt.datetime(2019,4,21,13,0) +pydarn.Maps.plot_time_series(data, parameter=pydarn.TimeSeriesParams.IMF_BY, + start_time=start_time, end_time=end_time, color='r') +plt.show() +``` + +![](../imgs/map_ts.png) + +Specific values available to be plotted are: + +| Name | parameter name | +| ----------------------------- | ------------------------------ | +| Number of vectors | `TimeSeriesParams.NUM_VECTORS` | +| IMF By | `TimeSeriesParams.IMF_BY` | +| IMF Bz | `TimeSeriesParams.IMF_BZ` | +| IMF Bx | `TimeSeriesParams.IMF_BX` | +| IMF Vx | `TimeSeriesParams.IMF_VX` | +| IMF Tilt | `TimeSeriesParams.IMF_TILT` | +| KP index | `TimeSeriesParams.KP` | +| Minimum Latitude | `TimeSeriesParams.LATMIN` | +| Error in model fitting | `TimeSeriesParams.ERR` | +| Cross Polar Cap Potential | `TimeSeriesParams.CPP` | \ No newline at end of file diff --git a/docs/user/range_time.md b/docs/user/range_time.md index 6dc4b8e74..c98464271 100644 --- a/docs/user/range_time.md +++ b/docs/user/range_time.md @@ -20,10 +20,10 @@ Range-time parameter plots (also known as range-time intensity (RTI) plots) are ### Basic RTP The general syntax for plot_range_time is: -'plot_range_time(fitacf_data, options)' -where 'fitacf_data' is the read in data, and the options are several python parameters used to control how the plot looks. +`plot_range_time(fitacf_data, options)` +where `fitacf_data` is the data read in using the read functions, and the options are several python parameters used to control how the plot looks. -First, make sure pyDARN and matplotlib are imported, then read in the .fitacf file with the data you wish to plot: +First, make sure pyDARN and matplotlib are imported, then read in the fitacf file with the data you wish to plot: ```python import matplotlib.pyplot as plt @@ -56,6 +56,14 @@ To specify which beam to look at, add the option: As an example, taking a look at some `v` data from the first record of Clyde River radar FITACF file: ```python +import matplotlib.pyplot as plt + +import pydarn + +fitacf_file = "20190831.C0.cly.fitacf" +sdarn_read = pydarn.SuperDARNRead(fitacf_file) +fitacf_data = sdarn_read.read_fitacf() + pydarn.RTP.plot_range_time(fitacf_data, beam_num=fitacf_data[0]['bmnum'], range_estimation=pydarn.RangeEstimation.RANGE_GATE) plt.title("Radar {:d}, Beam {:d}".format(fitacf_data[0]['stid'], fitacf_data[0]['bmnum'])) @@ -131,16 +139,19 @@ Because the default parameter plotted is line-of-sight velocity, there is also a To change the colormap, use the 'cmap' parameter with the string name of a matplotlib color map ([found here](https://matplotlib.org/tutorials/colors/colormaps.html)). For example, plotting the power along the beam above using the colormap 'viridis': ```python -pydarn.RTP.plot_range_time(fitacf_data, beam_num=7, parameter='p_l', zmax=50, zmin=0, date_fmt='%H%M', colorbar_label='Power (dB)', range_estimation=pydarn.RangeEstimation.RANGE_GATE, cmap='viridis') +pydarn.RTP.plot_range_time(fitacf_data, beam_num=7, parameter='p_l', zmax=50, + zmin=0, date_fmt='%H%M', colorbar_label='Power (dB)', + range_estimation=pydarn.RangeEstimation.RANGE_GATE, + cmap='viridis') ``` produces: ![](../imgs/rtp_cly3.png) -Feel free to choose a color map which is palatable for your needs. +Feel free to choose a color map which is palatable for your needs, except jet. !!! Warning - If the data contains `-inf` or `inf` a warning will be presented and the following parameters will be defaults to the scale: + If the data contains `-inf` or `inf` a warning will be presented and the following parameters will be default to the scale: | Parameter | Name | Scale | | --------- | --------------- | ----------- | @@ -175,7 +186,7 @@ UserWarning: Warning: zmin is -inf, set zmin to 0. You canset zmin and zmax in t When using filters on data you may remove all data or some data which causes a `NoDataError` or stripping in the plot -Example of data looking stripping from filtering setting +Example of data showing striping due to removal of some frequencies: ```python filts = {'min_scalar_filter':{'tfreq': 11000}} diff --git a/docs/user/summary.md b/docs/user/summary.md index 9fe8849ad..8068ef5b6 100644 --- a/docs/user/summary.md +++ b/docs/user/summary.md @@ -19,14 +19,14 @@ the additional permissions listed below. Summary plots in SuperDARN are a collection of set parameter plots from a FITACF file. The parameters typically in the plots are: * Time-series plots: - * Sky Noise (`noise.sky`) - * Transmission Frequency and Number of averages (`tfreq` and `nav`) - * Control Program ID (`cp`) -* Range-time plots: - * Signal to Noise (`p_l`) - * Velocity (`v`) - * Spectral Width (`w_l`) - * Elevation (`elv`) + * Sky Noise (`noise.sky`) + * Transmission Frequency and Number of averages (`tfreq` and `nav`) + * Control Program ID (`cp`) + * Range(or Coord)-time plots: + * Signal to Noise (`p_l`) + * Velocity (`v`) + * Spectral Width (`w_l`) + * Elevation (`elv`) !!! Note Elevation (`elv`) is optional to plot and is set to be plotted, however, not all radars have elevation data. @@ -87,5 +87,7 @@ Other common options include: | watermark=(bool) | True adds a 'not for publication' watermark | | cmaps=(dict/str) | Specifies the colour maps used in plotting | | range_estimation=(RangeEstimation) | Range use for the y-axis (See [Ranges, Coords and Projs](coordinates.md)) | + + For more options on how to modify plot_summary, take a look at the method in `rtp.py`. All options available in time-series and range-time plots can be used in summary plots. diff --git a/docs/user/time_series.md b/docs/user/time_series.md index 29873b16b..2f5e2ed79 100644 --- a/docs/user/time_series.md +++ b/docs/user/time_series.md @@ -15,7 +15,7 @@ the additional permissions listed below. # Time Series Plots -`plot_time_series` simply plots out a time series of any scalar beam parameter in the loaded in FITACF or RAWACF file. Currently there is no functionalilty to plot parameters from MAP files. To do that, you would need to manually extract the information from those loaded dictionaries. See [`pydarnio.SDarnRead`](https://pydarnio.readthedocs.io/en/release-1.0/user/SDarnRead/) for more info. +`plot_time_series` simply plots out a time series of any scalar beam parameter in the loaded in FITACF or RAWACF file. See [Map](map.md) tutorial for map file scalar parameter plotting. Basic code to plot a time series from a FITACF file would look like: ```python diff --git a/mkdocs.yml b/mkdocs.yml index 1897921ab..c4b278b6a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -16,7 +16,8 @@ nav: - Radar and Hardware Information: user/hardware.md - Axes Setup: user/axis.md - Ranges, Coords and Projs: user/coordinates.md - - Range-Time plots: user/range_time.md + - Range-Time plots: user/range_time.md + - Coordinate-Time plots: user/coord_time.md - Time-Series plots: user/time_series.md - Summary plots: user/summary.md - FOV plots: user/fov.md @@ -25,14 +26,16 @@ nav: - Convection Map plots: user/map.md - Power plots: user/power.md - ACF plots: user/acf.md + - IQ Plots: user/iq.md + - Filtering Data: user/filters.md - Logging: user/logging.md - pyDARN Team: dev/team.md - Communication: dev/communication.md - Copyright and Licensing: dev/copyright_license.md - Workflow: - - Projects: dev/projects.md - Issues: dev/issues.md - Branches: dev/branching.md + - Developing: dev/developing.md - Unit Testing: dev/pytest.md - Pull Requests: dev/PR.md - Testing: dev/testing.md diff --git a/pydarn/__init__.py b/pydarn/__init__.py index e95d2d571..c8c1dca3b 100644 --- a/pydarn/__init__.py +++ b/pydarn/__init__.py @@ -12,6 +12,7 @@ # # Modifications: # 2022-03-10 MTS - removed radar_fov from the __init__ file +# 2023-06-20 PXP - added TimeSeriesParams to the __init__ file """ Init file to setup the logging configuration and linking pyDARN's module, classes, and functions. @@ -32,30 +33,37 @@ from .exceptions import radar_exceptions from .exceptions.warning_formatting import standard_warning_format from .exceptions.warning_formatting import only_message_warning_format -from .exceptions.warning_formatting import citing_warning from .exceptions.warning_formatting import partial_record_warning from .exceptions.warning_formatting import cartopy_warning from .exceptions.warning_formatting import cartopy_print_warning +from .exceptions.warning_formatting import nightshade_warning # importing utils from .utils.constants import Re from .utils.constants import EARTH_EQUATORIAL_RADIUS from .utils.constants import C +from .utils.geocoastline import coast_outline +from .utils.citations import Citations from .utils.range_estimations import RangeEstimation from .utils.virtual_heights import VHModels from .utils.conversions import dmap2dict from .utils.plotting import MapParams +from .utils.plotting import TimeSeriesParams from .utils.plotting import check_data_type from .utils.plotting import time2datetime from .utils.plotting import find_record +from .utils.general_utils import GeneralUtils from .utils.superdarn_radars import SuperDARNRadars from .utils.superdarn_cpid import SuperDARNCpids from .utils.superdarn_radars import Hemisphere from .utils.superdarn_radars import read_hdw_file from .utils.superdarn_radars import get_hdw_files from .utils.scan import build_scan -from .utils.geo import geocentric_coordinates +from .utils.geo import geocentric_coordinates, calculate_azimuth from .utils.coordinates import Coords +from .utils.terminator import terminator +from .utils.recalculate_elevation import recalculate_elevation +from .utils.filters import Boxcar # import plotting from .plotting.color_maps import PyDARNColormaps @@ -66,5 +74,4 @@ from .plotting.acf import ACF from .plotting.power import Power from .plotting.maps import Maps - -citing_warning() +from .plotting.iq import IQ diff --git a/pydarn/exceptions/warning_formatting.py b/pydarn/exceptions/warning_formatting.py index ccd88a206..e02b6f5dd 100644 --- a/pydarn/exceptions/warning_formatting.py +++ b/pydarn/exceptions/warning_formatting.py @@ -7,18 +7,6 @@ # import warnings -def citing_warning(): - """ - prints a citation warning for pyDARN users to remind them to cite - pyDARN in publications. - """ - print() # create a newline - print("IMPORTANT: Please make sure to cite pyDARN in publications that" - " use plots created by pyDARN using DOI:" - " https://zenodo.org/record/3727269. Citing information" - " for SuperDARN data is found at" - " https://pydarn.readthedocs.io/en/master/user/citing/") - def cartopy_print_warning(): """ This warning prints on installation to inform users they @@ -43,6 +31,19 @@ def cartopy_warning(): "If you do not need to use cartopy for your plotting, ignore " "this message.") +def nightshade_warning(): + """ + This warning prints when a user tries to use something that is not + implemented yet, however the plot will still plot without the + feature + """ + warnings.warn("Nightshade is not implemented for plots in AACGMv2 " + "coordinates. You can plot nightshade in geographic " + "coordinates, or you can call the terminator function " + "to return the antisolarposition and radius to " + "decide how you would like to plot." + "https://pydarn.readthedocs.io/en/main/user/coordinates/") + def partial_record_warning(): """ prints a warning that the data chosen to be plotted is missing some diff --git a/pydarn/io/superdarn_io.py b/pydarn/io/superdarn_io.py index 2ab7c7e6f..7417424e8 100644 --- a/pydarn/io/superdarn_io.py +++ b/pydarn/io/superdarn_io.py @@ -1,5 +1,7 @@ # Copyright (C) 2020 SuperDARN Canada, University of Saskatchewan # Author: Marina Schmidt +# Modifications: +# 20230623 - CJM - Removed checks for read_dmap, will read in any dmap import bz2 import pydarnio @@ -51,15 +53,7 @@ def read_dmap(self, filename: str): try: # Check which file type it is - if 'rawacf' in filename: - data = self.read_rawacf() - elif 'fitacf' in filename: - data = self.read_fitacf() - elif 'iqdat' in filename: - self.read_iqdat() - # if not noticeable then just read the file - else: - data = self.read_records() + data = self.read_records() except Exception as err: # sometimes files might fail due to issues with # the specific reading methods. This is not a pyDARN @@ -67,8 +61,9 @@ def read_dmap(self, filename: str): # then make an issue on pyDARNio print(err) print("..... Will try to read DMap file with read_dmap") - print(" IF THIS FAILS please make an issue on pyDARNio, not " - "pyDARN's issue") + print(" IF THIS FAILS please make an issue on the pyDARNio" + " GitHub repository:" + " https://github.com/SuperDARN/pyDARNio/issues") data = self.read_records return data diff --git a/pydarn/plotting/acf.py b/pydarn/plotting/acf.py index 96c0cfce4..5fa3cb5b9 100644 --- a/pydarn/plotting/acf.py +++ b/pydarn/plotting/acf.py @@ -2,9 +2,13 @@ # Author: Marina Schmidt # This code is based on acf.py in the DaVitpy library # https://github.com/vtsuperdarn/davitpy/blob/master/davitpy +# # Modifications: # 2022-05-03: CJM - Added options to plot power and phase of acf # - change defaults to fit needs +# 2023-06-28: CJM - Refactored return values +# 2023-12-15: RAR - Made helper function for plotting ACF values +# - Refactored plot_acfs() to use helper function for plotting # # Disclaimer: # pyDARN is under the LGPL v3 license found in the root directory LICENSE.md @@ -17,6 +21,8 @@ import copy + +import matplotlib.markers import matplotlib.pyplot as plt import numpy as np import warnings @@ -32,7 +38,7 @@ warnings.formatwarning = standard_warning_format -class ACF(): +class ACF: """ ACF class plots SuperDARN RAWACF data @@ -56,16 +62,17 @@ def __str__(self): " - plot_acfs()\n"\ - @classmethod - def plot_acfs(cls, dmap_data: List[dict], beam_num: int = 0, + @staticmethod + def plot_acfs(dmap_data: List[dict], beam_num: int = 0, gate_num: int = 15, parameter: str = 'acfd', scan_num: int = 0, start_time: datetime = None, + ax: matplotlib.axes.Axes = None, normalized: bool = False, real_color: str = 'red', plot_blank: bool = True, blank_marker: str = 'o', imaginary_color: str = 'blue', legend: bool = True, pwr_and_phs: bool = True, **kwargs): """ - plots the parameter ACF/XCF field from SuperDARN file, + Plots the parameter ACF/XCF field from SuperDARN file, typically RAWACF format for a given beam and gate number Parameters @@ -78,20 +85,20 @@ def plot_acfs(cls, dmap_data: List[dict], beam_num: int = 0, the gate number to plot, default: 15 parameter : str the parameter to plot, default: acfd - scan_number: int + scan_num: int will plot the scan number for the provided beam start_time: datetime object datetime object containing the record to plot for the given beam - ax: matplotlib.axes - axes object for another way of plotting + ax: matplotlib.axes.Axes + axes object for another way of plotting. **WILL BE OVERWRITTEN IF PLOTTING POWER AND PHASE** Default: None normalized: bool normalizes the parameter data with the associated power 0 value for the given gate number default: False real_color: str - line color of the real part of the paramter + line color of the real part of the parameter default: red plot_blank: bool boolean to determine if blanked lags should be plotted @@ -118,13 +125,24 @@ def plot_acfs(cls, dmap_data: List[dict], beam_num: int = 0, Raises ------ - UnkownParameterError + UnknownParameterError IncorrectPlotMethodError OutOfRangeGateError Returns ------- - + dict of standard parameters, including: + ax: list of axes that were plotted on + fig: Figure that contains plot + ccrs: None, + cm: None, + cb: None, + data: dict of parameters plotted. + real: real component of ACF, + imaginary: imaginary component of ACF, + power: Power of ACF, + phase: Phase of ACF, + blanked: Blanked lags of the ACF """ # Determine if a DmapRecord was passed in, instead of a list try: @@ -134,15 +152,14 @@ def plot_acfs(cls, dmap_data: List[dict], beam_num: int = 0, if parameter in d) except StopIteration: raise plot_exceptions.UnknownParameterError(parameter) - cls.dmap_data = dmap_data - check_data_type(cls.dmap_data, parameter, 'array', index_first_match) + check_data_type(dmap_data, parameter, 'array', index_first_match) - # search over the records to find the correct beam, and scan/time + # search over the records to find the correct beam and scan/time # to plot the corresponding ACF/XCF plot scan_count = 0 re = [] im = [] - for record in cls.dmap_data: + for record in dmap_data: if record['bmnum'] == beam_num: time = time2datetime(record) if start_time is not None: @@ -152,7 +169,7 @@ def plot_acfs(cls, dmap_data: List[dict], beam_num: int = 0, raise plot_exceptions.IncorrectDateError(time, start_time) - if cls.__found_scan(scan_num, scan_count, start_time, time): + if ACF.__found_scan(scan_num, scan_count, start_time, time): if gate_num >= record['nrang'] or gate_num < 0: raise plot_exceptions.\ OutOfRangeGateError(parameter, gate_num, @@ -168,40 +185,33 @@ def plot_acfs(cls, dmap_data: List[dict], beam_num: int = 0, im = [x[1] for x in record[parameter][gate_num]] # calculate the blank lags for this record and gate - blanked_lags = cls.__blanked_lags(record, lags, gate_num) - # Need to deep clone so we keep the values - blank_re = copy.deepcopy(re) - blank_im = copy.deepcopy(im) + blanked_lags = ACF.__blanked_lags(record, lags, gate_num) lag_num = 0 lag_idx = 0 - lags_len = len(lags) + + # Create a mask for hiding missing or blanked lags + mask = [0] * len(lags) + # Search for missing lags # Note: had to use while loop do to insert method - while lag_idx < lags_len: + while lag_idx < len(lags): if lag_num in blanked_lags: - # to remove lines going through the points - re[lag_idx] = np.nan - im[lag_idx] = np.nan + mask[lag_idx] = 1 # This lag is blanked, mask it if lags[lag_idx] != lag_num: lags.insert(lag_num, lag_num) - # increase length by one due to insert - lags_len += 1 - # masking the values so it can create - # gaps in the data + mask.insert(lag_num, 1) # this lag is missing, mask it + # Adding in nan's for missing lags (won't be plotted) re.insert(lag_num, np.nan) im.insert(lag_num, np.nan) - # ensures the points line up on the plot - blank_re.insert(lag_num, np.nan) - blank_im.insert(lag_num, np.nan) lag_idx += 1 - if lag_idx < lags_len: + if lag_idx < len(lags): if lag_num != lags[lag_idx]: if lag_num > lags[lag_idx]: lag_num = lags[lag_idx] else: lag_num += 1 - # once we got the data break free!! + # once we find the data break free!! break scan_count += 1 if record['cp'] == 503: @@ -211,8 +221,7 @@ def plot_acfs(cls, dmap_data: List[dict], beam_num: int = 0, "not be correct. Please contact the PI of the " "radar to confirm if the data looks correct.") if re == [] or im == []: - if gate_num > 0 and gate_num < record['nrang']: - time = time2datetime(record) + if 0 < gate_num < record['nrang']: raise plot_exceptions.\ NoDataFoundError(parameter, beam_num, opt_beam_num=record['bmnum']) @@ -220,29 +229,19 @@ def plot_acfs(cls, dmap_data: List[dict], beam_num: int = 0, raise plot_exceptions.OutOfRangeGateError(parameter, gate_num, record['nrang']) - # generates gaps where there are nan's - masked_re = np.ma.array(re) - masked_re = np.ma.masked_where(np.isnan(masked_re), masked_re) - - masked_im = np.ma.array(im) - masked_im = np.ma.masked_where(np.isnan(masked_im), masked_im) - - # Calculate pwr and phs regardless of choice as - # in return statement - pwr = np.sqrt(np.square(masked_re) + np.square(masked_im)) - phs = np.arctan2(masked_im, masked_re) - - masked_pwr = np.ma.array(pwr) - masked_pwr = np.ma.masked_where(np.isnan(masked_pwr), masked_pwr) - masked_phs = np.ma.array(phs) - masked_phs = np.ma.masked_where(np.isnan(masked_phs), masked_phs) - if normalized is True: - masked_re /= record['pwr0'][gate_num] - masked_im /= record['pwr0'][gate_num] + re /= record['pwr0'][gate_num] + im /= record['pwr0'][gate_num] + + # generates gaps where there are missing or blanked lags + masked_re = np.ma.array(re, mask=mask) + masked_im = np.ma.array(im, mask=mask) - blank_re_n = blank_re / record['pwr0'][gate_num] - blank_im_n = blank_im / record['pwr0'][gate_num] + # Calculate pwr and phs regardless of choice as they are returned + pwr = np.sqrt(np.square(re) + np.square(im)) + phs = np.rad2deg(np.arctan2(im, re)) + masked_pwr = np.ma.array(pwr, mask=mask) + masked_phs = np.ma.array(phs, mask=mask) # plot real and imaginary with power if pwr_and_phs is True: @@ -251,96 +250,82 @@ def plot_acfs(cls, dmap_data: List[dict], beam_num: int = 0, ax = fig.add_subplot(gs[0, :]) ax_pwr = fig.add_subplot(gs[1, 0]) ax_phs = fig.add_subplot(gs[1, 1]) + axes = [ax, ax_pwr, ax_phs] + else: + if ax is not None: + ax = ax + else: + ax = plt.gca() + axes = [ax] + + real_dict = ACF.plot_acf_param(lags, masked_re, ax, + plot_blank=plot_blank, + marker='o', + color=real_color, + blank_marker=blank_marker, + **kwargs) + imag_dict = ACF.plot_acf_param(lags, masked_im, ax, + plot_blank=plot_blank, + marker='o', + color=imaginary_color, + blank_marker=blank_marker, + **kwargs) + # Set parameters (axis labels, line labels, etc.) of main plot + ax.set_ylabel(parameter) + ax.set_xlabel('Lag Number') + real_dict['data']['line'].set_label('Real') + imag_dict['data']['line'].set_label('Imag') + if plot_blank: + real_dict['data']['blank_line'].set_label('Real Blanked') + imag_dict['data']['blank_line'].set_label('Imag Blanked') + lim_val = 1.1 * max(np.nanmax(np.abs(re)), np.nanmax(np.abs(im))) + else: + lim_val = 1.1 * max(np.abs(masked_re).max(), + np.abs(masked_im).max()) + ax.set_ylim([-lim_val, lim_val]) + ax.xaxis.set_major_locator(ticker.MaxNLocator(integer=True)) - ax_pwr.scatter(lags, masked_pwr, marker='o', color='tab:orange', - label='Power', **kwargs) + # Plot the power and phase, if specified + if pwr_and_phs is True: + power_dict = ACF.plot_acf_param(lags, masked_pwr, ax_pwr, + plot_blank=plot_blank, + marker='o', + color='tab:orange', + blank_marker=blank_marker, + **kwargs) ax_pwr.set_ylabel('Power') ax_pwr.set_xlabel('Lag Number') ax_pwr.xaxis.set_major_locator(ticker.MaxNLocator(integer=True)) - ax_pwr.set_ylim([0, abs(max(masked_pwr)) - + 0.1*abs(max(masked_pwr))]) + ax_pwr.set_ylim([0, 1.1 * np.nanmax(pwr)]) ax_pwr.set_title('Power') - ax_phs.scatter(lags, np.degrees(masked_phs), marker='o', - color='tab:purple', label='Phase', **kwargs) + phase_dict = ACF.plot_acf_param(lags, masked_phs, ax_phs, + plot_blank=plot_blank, + marker='o', + color='tab:purple', + blank_marker=blank_marker, + **kwargs) ax_phs.set_ylabel('Phase (degrees)') ax_phs.set_xlabel('Lag Number') ax_phs.xaxis.set_major_locator(ticker.MaxNLocator(integer=True)) ax_phs.set_ylim([-180, 180]) ax_phs.set_title('Phase') - else: - ax = plt.gca() - ax.plot(lags, masked_im, marker='o', color=imaginary_color, - label='Imaginary', **kwargs) - ax.plot(lags, masked_re, marker='o', color=real_color, - label='Real', **kwargs) - - # Plot blanked lags - if plot_blank: - print("Blanked lags:", blanked_lags) - for blank in blanked_lags: - # I use scatter here to make points not lines - # also shows up in the legend nicer - if pwr_and_phs is True: - blank_pwr = np.sqrt(np.square(blank_re) - + np.square(blank_im)) - blank_phs = np.arctan2(blank_im, blank_re) - line_pwr = ax_pwr.scatter(blank, - blank_pwr[lags.index(blank)], - edgecolors='tab:orange', - facecolors=(1, 1, 1, 0), - marker='o') - line_phs = ax_phs.scatter(blank, - np.degrees( - blank_phs[lags.index(blank)]), - edgecolor='tab:purple', - marker='o', - facecolor=(1, 1, 1, 0)) - - if normalized is True: - line_im = ax.scatter(blank, blank_im_n[lags.index(blank)], - edgecolors=imaginary_color, - facecolors=(1, 1, 1, 0), - marker=blank_marker) - line_re = ax.scatter(blank, blank_re_n[lags.index(blank)], - edgecolors=real_color, - facecolors=(1, 1, 1, 0), - marker=blank_marker) - else: - line_im = ax.scatter(blank, blank_im[lags.index(blank)], - edgecolors=imaginary_color, - facecolors=(1, 1, 1, 0), - marker=blank_marker) - line_re = ax.scatter(blank, blank_re[lags.index(blank)], - edgecolors=real_color, - facecolors=(1, 1, 1, 0), - marker=blank_marker) - - # generate generic legend - if legend and blanked_lags != []: - line_re.set_label('Real Blanked') - line_im.set_label('Imaginary Blanked') - if pwr_and_phs is True: - line_pwr.set_label('Power Blanked') - line_phs.set_label('Phase Blanked') + # Set labels on the plots + power_dict['data']['line'].set_label('Power') + phase_dict['data']['line'].set_label('Phase') + if plot_blank: + power_dict['data']['blank_line'].set_label('Power Blanked') + phase_dict['data']['blank_line'].set_label('Phase Blanked') # Make legend on right side of figure if legend is True: fig = plt.gcf() fig.legend(loc=5) plt.subplots_adjust(right=0.8) - # Set labels of main plot - ax.set_ylabel(parameter) - ax.set_xlabel('Lag Number') - # Calc and set limit of main plot - lim_val = max(abs(masked_re + masked_im))\ - + 0.1 * max(abs(masked_re + masked_im)) - ax.set_ylim([-lim_val, lim_val]) - ax.xaxis.set_major_locator(ticker.MaxNLocator(integer=True)) # Set title of Plot - radar_name = SuperDARNRadars.radars[cls.dmap_data[0]['stid']].name + radar_name = SuperDARNRadars.radars[dmap_data[0]['stid']].name title = "{date} UT {radar} Beam {beam}, Gate {gate}, Control "\ "Program: {cpid}"\ "".format(radar=radar_name, beam=beam_num, gate=gate_num, @@ -348,31 +333,117 @@ def plot_acfs(cls, dmap_data: List[dict], beam_num: int = 0, cpid=record['cp']) ax.set_title(title) - return masked_re, masked_im, masked_pwr, masked_phs, blanked_lags + return {'ax': axes, + 'ccrs': None, + 'cm': None, + 'cb': None, + 'fig': plt.gcf(), + 'data': {'real': masked_re, + 'imaginary': masked_im, + 'power': masked_pwr, + 'phase': masked_phs, + 'blanked': blanked_lags} + } + + @staticmethod + def plot_acf_param(x, y, ax, + plot_blank: bool = True, + blank_marker: str = 'o', + **kwargs): + """ + plots the parameter ACF/XCF field from SuperDARN file, + typically RAWACF format for a given beam and gate number + + Parameters + ---------- + x: np.array + X coordinates of values to plot + y: np.ma.array + Y coordinates of values to plot + ax: matplotlib.Axes + Axes object for another way of plotting + Default: None + plot_blank: bool + boolean to determine if blanked lags should be plotted + default: False + blank_marker: str + the marker symbol of blanked lags + default: o - circle + kwargs: dict + keyword arguments for setting plot features + + + Notes + ----- + plot blanked lags as hollow circles - @classmethod - def __found_scan(cls, scan_num: int, count_num: int, + Returns + ------- + + """ + line = ax.plot(x, y, **kwargs) + + # Plot blanked lags + if plot_blank: + mask = y.mask + + # Invert the mask so the blanked data is plotted + blank_mask = ~mask + y.mask = blank_mask + + # Use blank_marker as marker + kwargs['marker'] = blank_marker + + # Check if blank_marker is a filled marker like circle or square, and set face white if so + if blank_marker in matplotlib.markers.MarkerStyle.filled_markers: + kwargs['facecolors'] = (1, 1, 1, 0) # Make the marker face white + kwargs['edgecolors'] = kwargs.get('color', None) + # For unfilled markers like 'x', just set the color + else: + kwargs['color'] = kwargs.get('color', None) + + # Plot the blanks as scatter points + blank_scatter = ax.scatter(x, y, **kwargs) + + # Now put the mask back! + y.mask = mask + else: + blank_scatter = None + + return {'ax': ax, + 'ccrs': None, + 'cm': None, + 'cb': None, + 'fig': plt.gcf(), + 'data': {'x': x, + 'y': y, + 'line': line[0], + 'blank_line': blank_scatter} + } + + @staticmethod + def __found_scan(scan_num: int, count_num: int, start_time: datetime, time: datetime): """ - method to help do the complicated if statement - for scan/time check - - Parameter - --------- - scan_num: int - scan number the user passed in - count_num: int - the current scan count - start_time: datetime - a datetime object the user passes in - time: datetime - current time the record is at - - Return: - ------ - Bool - If the scan is found return True - else False + Method to help do the complicated if statement + for scan/time check + + Parameter + --------- + scan_num: int + scan number the user passed in + count_num: int + the current scan count + start_time: datetime + a datetime object the user passes in + time: datetime + current time the record is at + + Return: + ------ + Bool + If the scan is found return True + else False """ if start_time is None: if scan_num == count_num: @@ -382,8 +453,8 @@ def __found_scan(cls, scan_num: int, count_num: int, return False - @classmethod - def __blanked_lags(cls, record: dict, lags: list, gate: int): + @staticmethod + def __blanked_lags(record: dict, lags: list, gate: int): """ Determines the blanked lags in the data record Lags contaminated by transmit pulse overlap diff --git a/pydarn/plotting/color_maps.py b/pydarn/plotting/color_maps.py index 396e38099..f27a89857 100644 --- a/pydarn/plotting/color_maps.py +++ b/pydarn/plotting/color_maps.py @@ -1,30 +1,30 @@ -import matplotlib.colors as mcol +import matplotlib +import packaging + +if packaging.version.parse(matplotlib.__version__) < \ + packaging.version.parse('3.7.0'): + from matplotlib import cm +else: + from matplotlib import colormaps as cm class PyDARNColormaps(): - PYDARN_VELOCITY =\ - mcol.LinearSegmentedColormap.from_list("pydarn_velocity", - ["darkred", "r", - 'pink', "b", "darkblue"]) + PYDARN_INFERNO = cm.get_cmap('inferno') + PYDARN_PLASMA = cm.get_cmap('plasma') + PYDARN_PLASMA_R = cm.get_cmap('plasma_r') + PYDARN_VELOCITY = matplotlib.colors.LinearSegmentedColormap.from_list( + "pydarn_velocity", ["darkred", "r", 'pink', "b", + "darkblue"]) + + PYDARN_VIRIDIS = matplotlib.colors.LinearSegmentedColormap.from_list( + "pydarn_viridis", ["indigo", "midnightblue", + "navy", "mediumblue", + "teal", "mediumseagreen", + "limegreen", "yellowgreen", + "yellow", "gold"]) - PYDARN_VIRIDIS =\ - mcol.LinearSegmentedColormap.from_list("pydarn_viridis", - ["indigo", "midnightblue", - "navy", "mediumblue", - "teal", - "mediumseagreen", - "limegreen", "yellowgreen", - "yellow", "gold"]) + PYDARN = matplotlib.colors.LinearSegmentedColormap.from_list("pydarn", + ["midnightblue", "darkblue", "mediumblue", "rebeccapurple", + "purple", "darkmagenta", "mediumvioletred", "crimson", "red", + "orangered", "darkorange", "orange", "gold"]) - PYDARN =\ - mcol.LinearSegmentedColormap.from_list("pydarn", ["midnightblue", - "darkblue", - "mediumblue", - "rebeccapurple", - "purple", - "darkmagenta", - "mediumvioletred", - "crimson", "red", - "orangered", - "darkorange", - "orange", "gold"]) diff --git a/pydarn/plotting/fan.py b/pydarn/plotting/fan.py index 3db6c7b0a..2771896c6 100644 --- a/pydarn/plotting/fan.py +++ b/pydarn/plotting/fan.py @@ -13,11 +13,18 @@ # 2021-02-02: CJM - Included rsep and frang options in plot_fov # - Re-arranged logic for ranges option # - Indexing fixed for give lower ranges that are non-zero -# 2022-03-10: MTS - switched coords involving range estimations to RangeEstimation +# 2022-03-10: MTS - switched coords involving range estimations to +# RangeEstimation # - Removed GEO_COASTALINE, replaced with GEO on projections # - reduced some parameters inputs to kwargs # 2022-03-22: CJM - Set cmap bad values to transparent -# 2022-03-23: MTS - added the NotImplementedError for AACGM and GEO projection as this has yet to be figured out +# 2022-03-23: MTS - added the NotImplementedError for AACGM and GEO projection +# as this has yet to be figured out +# 2023-02-06: CJM - Added option to plot single beams in a scan or FOV diagram +# 2023-03-01: CJM - Added ball and stick plotting options (merged later in year) +# 2023-08-16: CJM - Corrected for winding order in geo plots +# 2023-06-28: CJM - Refactored return values +# # Disclaimer: # pyDARN is under the LGPL v3 license found in the root directory LICENSE.md # Everyone is permitted to copy and distribute verbatim copies of this license @@ -36,7 +43,7 @@ import matplotlib.pyplot as plt import numpy as np -from matplotlib import ticker, cm, colors +from matplotlib import ticker, cm, colors, axes from typing import List, Union # Third party libraries @@ -44,10 +51,10 @@ from pydarn import (PyDARNColormaps, build_scan, partial_record_warning, time2datetime, plot_exceptions, SuperDARNRadars, - Projs, Coords, Hemisphere, RangeEstimation) + calculate_azimuth, Projs, Coords, Hemisphere) -class Fan(): +class Fan: """ 'Fan', or 'Field-of-view' plots for SuperDARN FITACF data This class inherits from matplotlib to generate the figures @@ -66,7 +73,7 @@ def __str__(self): " - plot_fov()\n" @classmethod - def plot_fan(cls, dmap_data: List[dict], ax=None, ranges: List = [], + def plot_fan(cls, dmap_data: List[dict], ax=None, ranges=None, scan_index: Union[int, dt.datetime] = 1, parameter: str = 'v', cmap: str = None, groundscatter: bool = False, zmin: int = None, @@ -74,7 +81,8 @@ def plot_fan(cls, dmap_data: List[dict], ax=None, ranges: List = [], colorbar_label: str = '', title: bool = True, boundary: bool = True, projs: Projs = Projs.POLAR, coords: Coords = Coords.AACGM_MLT, - channel: int = 'all', **kwargs): + channel: int = 'all', ball_and_stick: bool = False, + len_factor: float = 300, beam: int = None, **kwargs): """ Plots a radar's Field Of View (FOV) fan plot for the given data and scan number @@ -83,11 +91,14 @@ def plot_fan(cls, dmap_data: List[dict], ax=None, ranges: List = [], ----------- dmap_data: List[dict] Named list of dictionaries obtained from SDarn_read - ax: matplotlib.pyplot axis + ax: axes.Axes Pre-defined axis object to pass in, must currently be polar projection Default: Generates a polar projection for the user with MLT/latitude labels + ranges: List[int] + Range bounds to plot, as [lower_bound, upper_bound]. + Default: Plots all ranges out to max given in hardware file. scan_index: int or datetime Scan number starting from the first record in file with associated channel number or datetime given first record @@ -116,11 +127,6 @@ def plot_fan(cls, dmap_data: List[dict], ax=None, ranges: List = [], the label that appears next to the colour bar. Requires colorbar to be true Default: '' - fov_files: bool - boolean if the fov data should be read in by a file - pyDARN supplies. If false then it uses radar position - code. - default: False title: bool if true then will create a title, else user can define it with plt.title @@ -134,10 +140,18 @@ def plot_fan(cls, dmap_data: List[dict], ax=None, ranges: List = [], coords: Enum choice of plotting coordinates default: Coords.AACGM_MLT (Magnetic Lat and MLT) + beam : int or None + integer indicating if the user would like to plot a single beam channel : int or str integer indicating which channel to plot or 'all' to plot all channels Default: 'all' + ball_and_stick : bool + plot the data as a vector instead of filling a box + Default: False + len_factor : float + control the length of the ball and stick plot stick length + Default : 300 kwargs: key = value Additional keyword arguments to be used in projection plotting and plot_fov for possible keywords, see: projections.axis_polar @@ -148,7 +162,7 @@ def plot_fan(cls, dmap_data: List[dict], ax=None, ranges: List = [], n_beams x n_gates numpy array of latitudes return values dependent on given coords enum beam_corners_aacgm_lons - n_beams x n_gates numpy array of longitudes or MLT + n_beams x n_gates numpy array of longitudes or MLT return values dependent on given coords enum scan n_beams x n_gates numpy array of the scan data @@ -161,6 +175,8 @@ def plot_fan(cls, dmap_data: List[dict], ax=None, ranges: List = [], plot_fov """ # Remove all data from dmap_data that is not in chosen channel + if ranges is None: + ranges = [] if channel != 'all': # Get the first channel used in case of no data in given channel opt_channel = dmap_data[0]['channel'] @@ -223,20 +239,18 @@ def plot_fan(cls, dmap_data: List[dict], ax=None, ranges: List = [], rsep = 45 if coords != Coords.GEOGRAPHIC and projs == Projs.GEO: - raise plot_exceptions.NotImplemented("AACGM coordinates are"\ - " not implemented for "\ - " geographic projections right"\ - " now, if you would like to"\ - " see it sooner please help"\ - " out at "\ - "https://github.com"\ + raise plot_exceptions.NotImplemented("AACGM coordinates are" + " not implemented for " + " geographic projections" + " right now, if you would" + " like to see it sooner" + " please help out at " + "https://github.com" "/SuperDARN/pyDARN") beam_corners_lats, beam_corners_lons =\ - coords(stid=dmap_data[0]['stid'], - rsep=rsep, frang=frang, - gates=ranges, date=date, - **kwargs) + coords(stid=dmap_data[0]['stid'], rsep=rsep, frang=frang, + gates=ranges, date=date, **kwargs) fan_shape = beam_corners_lons.shape if ranges[0] < ranges[1] - fan_shape[0]: @@ -255,11 +269,11 @@ def plot_fan(cls, dmap_data: List[dict], ax=None, ranges: List = [], # Colour table and max value selection depending on parameter plotted # Load defaults if none given if cmap is None: - cmap = {'p_l': 'plasma', 'v': PyDARNColormaps.PYDARN_VELOCITY, + cmap = {'p_l': PyDARNColormaps.PYDARN_PLASMA, + 'v': PyDARNColormaps.PYDARN_VELOCITY, 'w_l': PyDARNColormaps.PYDARN_VIRIDIS, - - 'elv': PyDARNColormaps.PYDARN} - cmap = plt.cm.get_cmap(cmap[parameter]) + 'elv': PyDARNColormaps.PYDARN_INFERNO} + cmap = cmap[parameter] # Set background to transparent - avoids carry over # does not interfere with the fov color if chosen @@ -280,7 +294,7 @@ def plot_fan(cls, dmap_data: List[dict], ax=None, ranges: List = [], # get a list of gates where there is data slist = dmap_data[i.astype(int)]['slist'] # get the beam number for the record - beam = dmap_data[i.astype(int)]['bmnum'] + beami = dmap_data[i.astype(int)]['bmnum'] # Exclude ranges larger than the expected maximum. # This is a temporary fix to manage inconsistencies between the @@ -292,20 +306,25 @@ def plot_fan(cls, dmap_data: List[dict], ax=None, ranges: List = [], temp_data = dmap_data[i.astype(int)][parameter][good_data] temp_ground = dmap_data[i.astype(int)]['gflg'][good_data] - scan[slist-ranges[0], beam] = temp_data - grndsct[slist-ranges[0], beam] = temp_ground + scan[slist-ranges[0], beami] = temp_data + grndsct[slist-ranges[0], beami] = temp_ground # if there is no slist field this means partial record except KeyError: partial_record_warning() continue # Begin plotting by iterating over ranges and beams + if beam is not None: + thetas = thetas[0:ranges[1]-ranges[0]+1, beam:beam+2] + rs = rs[0:ranges[1]-ranges[0]+1, beam:beam+2] + scan = scan[0:ranges[1]-ranges[0], beam:beam+1] + grndsct = grndsct[0:ranges[1]-ranges[0], beam:beam+1] + else: + thetas = thetas[0:ranges[1]-ranges[0]+1] + rs = rs[0:ranges[1]-ranges[0]+1] + scan = scan[0:ranges[1]-ranges[0]] + grndsct = grndsct[0:ranges[1]-ranges[0]] - thetas = thetas[0:ranges[1]-ranges[0]+1] - rs = rs[0:ranges[1]-ranges[0]+1] - - scan = scan[0:ranges[1]-ranges[0]] - grndsct = grndsct[0:ranges[1]-ranges[0]] # Set up axes in correct hemisphere stid = dmap_data[0]['stid'] kwargs['hemisphere'] = SuperDARNRadars.radars[stid].hemisphere @@ -317,13 +336,101 @@ def plot_fan(cls, dmap_data: List[dict], ax=None, ranges: List = [], else: transform = ccrs.PlateCarree() - ax.pcolormesh(thetas, rs, - np.ma.masked_array(scan, ~scan.astype(bool)), - norm=norm, cmap=cmap, transform=transform, - zorder=2) + + if not ball_and_stick: + ax.pcolormesh(thetas, rs, + np.ma.masked_array(scan, ~scan.astype(bool)), + norm=norm, cmap=cmap, transform=transform, + zorder=2) + else: + # Get center of each gate instead of edges + fan_shape = thetas.shape + t_center = np.empty([fan_shape[0]-1, fan_shape[1]-1]) + r_center = np.empty([fan_shape[0]-1, fan_shape[1]-1]) + for i in range(0, fan_shape[0]-1): + for j in range(0, fan_shape[1]-1): + t_center = (thetas[i, j] + thetas[i+1, j] + + thetas[i, j+1] + thetas[i+1, j+1]) / 4 + r_center = (rs[i, j] + rs[i+1, j] + + rs[i, j+1] + rs[i+1, j+1]) / 4 + if scan[i, j] != 0.0: + col = cmap((scan[i, j] - zmin) / (zmax-zmin)) + # Plot balls! + ax.scatter(t_center, r_center, color=col, s=1.0, + transform=transform, zorder=3.0) + # Stick only needed for velocity data + if parameter == 'v': + # Get azimuth in correct coord system + if coords != Coords.GEOGRAPHIC: + lat = r_center + lon = np.degrees(t_center) + else: + lat = r_center + lon = t_center + azm = cls.get_gate_azm(lon, lat, stid, + coords, date) + + # Make sure each coordinate is in correct + # units again + if projs != Projs.GEO: + thetas_calc = np.radians(lon) + rs_calc = lat + else: + thetas_calc = np.radians(lon) + rs_calc = lat + + hemisphere = SuperDARNRadars.radars[stid]\ + .hemisphere + + # Find the end point of the stick to plot + # Angle to rotate each vector + alpha = thetas_calc + + # Convert to Cartesian + start_pos_x = (90 - abs(rs_calc)) \ + * np.cos(thetas_calc) + start_pos_y = (90 - abs(rs_calc)) \ + * np.sin(thetas_calc) + + # Results LOS vector in x and y + los_x = -scan[i, j] * np.cos( + np.radians(-azm * hemisphere.value)) + los_y = -scan[i, j] * np.sin( + np.radians(-azm * hemisphere.value)) + + # Rotate vector into same ref frame + vec_x = (los_x * np.cos(alpha)) \ + - (los_y * np.sin(alpha)) + vec_y = (los_x * np.sin(alpha)) \ + + (los_y * np.cos(alpha)) + + # New vector end points + end_pos_x = start_pos_x\ + + (vec_x * hemisphere.value / len_factor) + end_pos_y = start_pos_y\ + + (vec_y * hemisphere.value / len_factor) + # Convert back to polar for plotting + end_rs = 90 - (np.sqrt(end_pos_x**2 + + end_pos_y**2)) + end_thetas = np.arctan2(end_pos_y, end_pos_x) + end_rs = end_rs * hemisphere.value + + # Convert to degrees for geo plots + if projs == Projs.GEO: + end_thetas = np.degrees(end_thetas) + # Plot sticks! + plt.plot([t_center, end_thetas], + [r_center, end_rs], + color=col, zorder=3.0, linewidth=0.5, + transform=transform) + + # Plot ground scatter balls (no sticks) + if groundscatter and grndsct[i, j] != 0.0: + ax.scatter(t_center, r_center, c='grey', s=1.0, + transform=transform, zorder=3.0) # plot the groundscatter as grey fill - if groundscatter: + if groundscatter and not ball_and_stick: ax.pcolormesh(thetas, rs, np.ma.masked_array(grndsct, ~grndsct.astype(bool)), @@ -332,13 +439,13 @@ def plot_fan(cls, dmap_data: List[dict], ax=None, ranges: List = [], if ccrs is None: azm = np.linspace(0, 2 * np.pi, 100) r, th = np.meshgrid(rs, azm) - plt.plot(azm, r, color='k', ls='none') - plt.grid() + ax.plot(azm, r, color='k', ls='none') + ax.grid(True) if boundary: cls.plot_fov(stid=dmap_data[0]['stid'], date=date, ax=ax, ccrs=ccrs, coords=coords, projs=projs, rsep=rsep, - frang=frang, ranges=ranges, **kwargs) + frang=frang, ranges=ranges, beam=beam, **kwargs) # Create color bar if True if colorbar is True: @@ -356,23 +463,35 @@ def plot_fan(cls, dmap_data: List[dict], ax=None, ranges: List = [], if colorbar_label != '': cb.set_label(colorbar_label) + else: + cb = None if title: start_time = time2datetime(dmap_data[plot_beams[0][0]]) end_time = time2datetime(dmap_data[plot_beams[-1][-1]]) title = cls.__add_title__(start_time, end_time) plt.title(title) - return ax, beam_corners_lats, beam_corners_lons, scan, grndsct - + return {'ax': ax, + 'ccrs': ccrs, + 'cm': cmap, + 'cb': cb, + 'fig': plt.gcf(), + 'data': {'beam_corners_lats': beam_corners_lats, + 'beam_corners_lons': beam_corners_lons, + 'scan_data': scan, + 'ground_scatter': grndsct} + } + + @classmethod - def plot_fov(cls, stid: str, date: dt.datetime, - ax=None, ccrs=None, ranges: List = [], boundary: bool = True, + def plot_fov(cls, stid: int, date: dt.datetime, + ax=None, ccrs=None, ranges: List = None, boundary: bool = True, rsep: int = 45, frang: int = 180, - projs: object = Projs.POLAR, + projs: Projs = Projs.POLAR, coords: Coords = Coords.AACGM_MLT, fov_color: str = None, alpha: int = 0.5, radar_location: bool = True, radar_label: bool = False, line_color: str = 'black', - grid: bool = False, + grid: bool = False, beam: int = None, line_alpha: int = 0.5, **kwargs): """ plots only the field of view (FOV) for a given radar station ID (stid) @@ -381,11 +500,9 @@ def plot_fov(cls, stid: str, date: dt.datetime, ----------- stid: int Radar station ID - ax: matplotlib.pyplot axis - Pre-defined axis object to pass in, must currently be - polar projection - Default: Generates a polar projection for the user - with MLT/latitude labels + ax: matplotlib.axes.Axes + Pre-defined axis object to pass in. + ccrs: date: datetime object Sets the datetime used to find the coordinates of the FOV Default: Current time @@ -393,12 +510,20 @@ def plot_fov(cls, stid: str, date: dt.datetime, Set to a two element list of the lower and upper ranges to plot If None, the max will be obtained by SuperDARNRadars Default: None - projs: Pojs object - Sets the projection type for the plot - Default: Projs.POLAR boundary: bool Set to false to not plot the outline of the FOV Default: True + rsep: int + Separation between range gates, in kilometers. + Default: 45 + frang: int + Kilometers to first range. + Default: 180 + projs: Projs object + Sets the projection type for the plot + Default: Projs.POLAR + coords: Coords object + grid: bool Set to false to not plot the grid of gates in the FOV Default: False @@ -416,6 +541,8 @@ def plot_fov(cls, stid: str, date: dt.datetime, line_alpha controls the transparency of the boundary and grid lines of the fov Default: 0.5 + beam : int or None + integer indicating if the user would like to plot a single beam radar_location: bool Add a dot where radar is located if True Default: False @@ -444,9 +571,21 @@ def plot_fov(cls, stid: str, date: dt.datetime, coords(stid=stid, gates=ranges, rsep=rsep, frang=frang, date=date, **kwargs) + # If beam selected then reduce lats and lons array + if beam is not None: + beam_corners_lats = beam_corners_lats[:, beam:beam+2] + beam_corners_lons = beam_corners_lons[:, beam:beam+2] + if projs == Projs.POLAR: beam_corners_lons = np.radians(beam_corners_lons) + # This section corrects winding order for cartopy plots on a sphere + # so that the outline is always anti-clockwise and will fill inside + bmsep = SuperDARNRadars.radars[stid].hardware_info.beam_separation + if projs == Projs.GEO and bmsep < 0: + beam_corners_lons = beam_corners_lons[::-1] + beam_corners_lats = beam_corners_lats[::-1] + # Setup plot # This may screw up references hemisphere = SuperDARNRadars.radars[stid].hemisphere @@ -461,56 +600,56 @@ def plot_fov(cls, stid: str, date: dt.datetime, if boundary: # left boundary line - plt.plot(beam_corners_lons[0:ranges[1]-ranges[0]+1, 0], - beam_corners_lats[0:ranges[1]-ranges[0]+1, 0], - color=line_color, linewidth=0.5, - alpha=line_alpha, transform=transform, zorder=3) + ax.plot(beam_corners_lons[0:ranges[1]-ranges[0]+1, 0], + beam_corners_lats[0:ranges[1]-ranges[0]+1, 0], + color=line_color, linewidth=0.5, + alpha=line_alpha, transform=transform, zorder=3) # top radar arc - plt.plot(beam_corners_lons[ranges[1]-ranges[0], - 0:beam_corners_lons.shape[1]], - beam_corners_lats[ranges[1]-ranges[0], - 0:beam_corners_lons.shape[1]], - color=line_color, linewidth=0.5, - alpha=line_alpha, transform=transform, zorder=3) + ax.plot(beam_corners_lons[ranges[1]-ranges[0], + 0:beam_corners_lons.shape[1]], + beam_corners_lats[ranges[1]-ranges[0], + 0:beam_corners_lons.shape[1]], + color=line_color, linewidth=0.5, + alpha=line_alpha, transform=transform, zorder=3) # right boundary line - plt.plot(beam_corners_lons[0:ranges[1]-ranges[0]+1, - beam_corners_lons.shape[1] - 1], - beam_corners_lats[0:ranges[1]-ranges[0]+1, - beam_corners_lons.shape[1] - 1], - color=line_color, linewidth=0.5, - alpha=line_alpha, transform=transform, zorder=3) + ax.plot(beam_corners_lons[0:ranges[1]-ranges[0]+1, + beam_corners_lons.shape[1] - 1], + beam_corners_lats[0:ranges[1]-ranges[0]+1, + beam_corners_lons.shape[1] - 1], + color=line_color, linewidth=0.5, + alpha=line_alpha, transform=transform, zorder=3) # bottom arc - plt.plot(beam_corners_lons[0, 0:beam_corners_lons.shape[1]], - beam_corners_lats[0, 0:beam_corners_lons.shape[1]], - color=line_color, linewidth=0.5, alpha=line_alpha, - transform=transform, zorder=3) + ax.plot(beam_corners_lons[0, 0:beam_corners_lons.shape[1]], + beam_corners_lats[0, 0:beam_corners_lons.shape[1]], + color=line_color, linewidth=0.5, alpha=line_alpha, + transform=transform, zorder=3) fan_shape = beam_corners_lons.shape if grid: # This plots lines along the beams for bm in range(fan_shape[1]): - plt.plot(beam_corners_lons[0:ranges[1] + 1, bm - 1], - beam_corners_lats[0:ranges[1] + 1, bm - 1], - color=line_color, linewidth=0.2, - alpha=line_alpha, transform=transform, - zorder=3) + ax.plot(beam_corners_lons[0:ranges[1] + 1, bm - 1], + beam_corners_lats[0:ranges[1] + 1, bm - 1], + color=line_color, linewidth=0.2, + alpha=line_alpha, transform=transform, + zorder=3) # This plots arcs along the gates for g in range(ranges[1] - ranges[0] + 1): - plt.plot(beam_corners_lons[g - 1, - 0:beam_corners_lons.shape[1]], - beam_corners_lats[g - 1, - 0:beam_corners_lons.shape[1]], - color=line_color, linewidth=0.2, - alpha=line_alpha, transform=transform, - zorder=3) + ax.plot(beam_corners_lons[g - 1, + 0:beam_corners_lons.shape[1]], + beam_corners_lats[g - 1, + 0:beam_corners_lons.shape[1]], + color=line_color, linewidth=0.2, + alpha=line_alpha, transform=transform, + zorder=3) if radar_location: - cls.plot_radar_position(stid, date=date, line_color=line_color, + cls.plot_radar_position(stid, ax, date=date, line_color=line_color, transform=transform, projs=projs, coords=coords, ccrs=ccrs, **kwargs) if radar_label: - cls.plot_radar_label(stid, date=date, line_color=line_color, + cls.plot_radar_label(stid, ax, date=date, line_color=line_color, transform=transform, projs=projs, coords=coords, ccrs=ccrs, **kwargs) @@ -554,10 +693,60 @@ def plot_fov(cls, stid: str, date: dt.datetime, ax.fill(theta, r, color=fov_color, alpha=alpha, zorder=1, transform=transform) - return beam_corners_lats, beam_corners_lons, ax, ccrs + return {'ax': ax, + 'ccrs': ccrs, + 'cm': None, + 'cb': None, + 'fig': plt.gcf(), + 'data': {'beam_corners_lats': beam_corners_lats, + 'beam_corners_lons': beam_corners_lons} + } + + @classmethod + def get_gate_azm(cls, theta: float, r: float, stid: int, coords, date): + """ + gets the azimuth of the gate, requires some changes depending on + coordinates before using calculate_azimuth + + Parameters + ---------- + theta: float + longitude + r: float + latitude + stid: int + station id of radar + coords: Enum + enumeration of coordinate system + date: datetime object + date of data + + Returns + ------- + azm: float + azimuth direction of radar from gate in coordinate system + given + """ + # Get position of radar in geographic from hdw files + radlat = SuperDARNRadars.radars[stid].hardware_info.geographic.lat + radlon = SuperDARNRadars.radars[stid].hardware_info.geographic.lon + # Convert radar position to correct coordinate system + if coords == Coords.AACGM_MLT or coords == Coords.AACGM: + geomag_radar = aacgmv2.get_aacgm_coord(radlat, radlon, 250, date) + radlat = geomag_radar[0] + radlon = geomag_radar[1] + if coords == Coords.AACGM_MLT: + mltshift = geomag_radar[1] -\ + (aacgmv2.convert_mlt(geomag_radar[1], date) * 15) + radlon = geomag_radar[1] - mltshift[0] + # Call calculate azimuth function from geo + azm = calculate_azimuth(r, theta, 300, radlat, radlon, 300) + return azm @classmethod - def plot_radar_position(cls, stid: int, date: dt.datetime, + def plot_radar_position(cls, stid: int, ax: axes.Axes, + date: dt.datetime, + transform: object = None, coords: Coords = Coords.AACGM_MLT, projs: Projs = Projs.POLAR, @@ -569,9 +758,14 @@ def plot_radar_position(cls, stid: int, date: dt.datetime, ----------- stid: int Radar station ID + ax: matplotlib.axes.Axes + Pre-defined axis object to plot on. date: datetime datetime object sets the datetime used to find the coordinates of the FOV + transform: + coords: Coords object + projs: Projs object line_color: str color of the dot default: black @@ -595,11 +789,12 @@ def plot_radar_position(cls, stid: int, date: dt.datetime, if projs == Projs.POLAR: lon = np.radians(lon) # Plot a dot at the radar site - plt.scatter(lon, lat, c=line_color, s=5, transform=transform) + ax.scatter(lon, lat, c=line_color, s=5, transform=transform) return @classmethod - def plot_radar_label(cls, stid: int, date: dt.datetime, + def plot_radar_label(cls, stid: int, ax: axes.Axes, + date: dt.datetime, coords: Coords = Coords.AACGM_MLT, projs: Projs = Projs.POLAR, line_color: str = 'black', transform: object = None, @@ -611,44 +806,44 @@ def plot_radar_label(cls, stid: int, date: dt.datetime, ----------- stid: int Radar station ID + ax: matplotlib.axes.Axes + Pre-defined axis object to plot on. + coords: Coords object + projs: Projs object date: datetime datetime object sets the datetime used to find the coordinates of the FOV line_color: str color of the text default: black + transform: Returns ------- No variables returned """ + if coords == Coords.AACGM_MLT or coords == Coords.AACGM: + lat, lon = SuperDARNRadars.radars[stid].mag_label + else: + lat, lon = SuperDARNRadars.radars[stid].geo_label + # Label text label_str = ' ' + SuperDARNRadars.radars[stid]\ .hardware_info.abbrev.upper() - # Get location of radar - lat = SuperDARNRadars.radars[stid].hardware_info.geographic.lat - lon = SuperDARNRadars.radars[stid].hardware_info.geographic.lon # Convert to geomag coords - if coords == Coords.AACGM_MLT or coords == Coords.AACGM: - geomag_radar = aacgmv2.get_aacgm_coord(lat, lon, 250, date) - lat = geomag_radar[0] - lon = geomag_radar[1] - if coords == Coords.AACGM_MLT: - mltshift = geomag_radar[1] -\ - (aacgmv2.convert_mlt(geomag_radar[1], date) * 15) - lon = geomag_radar[1] - mltshift + if coords == Coords.AACGM_MLT: + mltshift = lon -\ + (aacgmv2.convert_mlt(lon, date) * 15) + lon = lon - mltshift if projs == Projs.POLAR: lon = np.radians(lon) theta_text = lon - # Shift in latitude (dependent on hemisphere) - if SuperDARNRadars.radars[stid].hemisphere == Hemisphere.North: - r_text = lat - 5 - else: - r_text = lat + 5 - plt.text(theta_text, r_text, label_str, ha='center', - transform=transform, c=line_color) + r_text = lat + + ax.text(theta_text, r_text, label_str, ha='center', + transform=transform, c=line_color) return @classmethod diff --git a/pydarn/plotting/grid.py b/pydarn/plotting/grid.py index 634b5fb27..24fbadd5b 100644 --- a/pydarn/plotting/grid.py +++ b/pydarn/plotting/grid.py @@ -3,6 +3,8 @@ # # Modifications: # 20220308 MTS added partial record exception +# 20230628 CJM refactored return values +# 20230713 CJM corrected geographic quivers # # Disclaimer: # pyDARN is under the LGPL v3 license found in the root directory LICENSE.md @@ -30,7 +32,7 @@ import aacgmv2 from pydarn import (PyDARNColormaps, Fan, plot_exceptions, Hemisphere, - standard_warning_format, Projs, Coords) + standard_warning_format, Projs, Coords, GeneralUtils) warnings.formatwarning = standard_warning_format @@ -168,6 +170,13 @@ def plot_grid(cls, dmap_data: List[dict], record: int = 0, with warnings.catch_warnings(): warnings.simplefilter("ignore") + # Check for partial records + if all(dmap_data[record]['nvec'] == 0): + raise plot_exceptions.PartialRecordsError('~all vectors~') + + data_lons = dmap_data[record]['vector.mlon'] + data_lats = dmap_data[record]['vector.mlat'] + # Hemisphere is not found in grid files so take from latitudes hemisphere = Hemisphere(np.sign( dmap_data[record]['vector.mlat'][0])) @@ -178,14 +187,11 @@ def plot_grid(cls, dmap_data: List[dict], record: int = 0, transform = ccrs.PlateCarree() for stid in dmap_data[record]['stid']: - _, coord_lons, ax, ccrs =\ - Fan.plot_fov(stid, date, ax=ax, ccrs=ccrs, - coords=coords, projs=projs, **kwargs) - try: - data_lons = dmap_data[record]['vector.mlon'] - data_lats = dmap_data[record]['vector.mlat'] - except KeyError: - raise plot_exceptions.PartialRecordsError('vector.mlon') + fan_rtn = Fan.plot_fov(stid, date, ax=ax, ccrs=ccrs, + coords=coords, projs=projs, **kwargs) + coord_lons = fan_rtn['data']['beam_corners_lons'] + ax = fan_rtn['ax'] + ccrs = fan_rtn['ccrs'] if coords != Coords.GEOGRAPHIC and projs == Projs.GEO: raise plot_exceptions.NotImplemented( @@ -213,30 +219,30 @@ def plot_grid(cls, dmap_data: List[dict], record: int = 0, shifted_mlts = coord_lons[0, 0] - \ (aacgmv2.convert_mlt(coord_lons[0, 0], date) * 15) shifted_lons = data_lons - shifted_mlts - rs_calc = data_lats if projs != Projs.GEO: # Convert to radians for polar plots thetas_calc = np.radians(shifted_lons) thetas = np.radians(shifted_lons) rs = data_lats + rs_calc = data_lats else: # Convert to geographic coordinates glats, glons, _ = aacgmv2.convert_latlon_arr( data_lats, data_lons, 300, date, method_code="A2G") - thetas_calc = np.radians(data_lons) + thetas_calc = np.radians(glons) thetas = glons rs = glats + rs_calc = glats # Colour table and max value selection depending on # parameter plotted Load defaults if none given if cmap is None: - cmap = {'vector.pwr.median': 'plasma', - 'vector.vel.median': 'plasma_r', - 'vector.wdt.median': - PyDARNColormaps.PYDARN_VIRIDIS} - cmap = plt.cm.get_cmap(cmap[parameter]) + cmap = {'vector.pwr.median': PyDARNColormaps.PYDARN_PLASMA, + 'vector.vel.median': PyDARNColormaps.PYDARN_PLASMA_R, + 'vector.wdt.median': PyDARNColormaps.PYDARN_VIRIDIS} + cmap = cmap[parameter] # Setting zmin and zmax defaultzminmax = {'vector.pwr.median': [0, 50], @@ -265,9 +271,46 @@ def plot_grid(cls, dmap_data: List[dict], record: int = 0, # If the parameter is velocity then plot the LOS vectors if parameter == "vector.vel.median": - # Get the azimuths from the data + # Get the mag azimuths from the data azm_v = dmap_data[record]['vector.kvect'] + # Azimuth direction needs to be converted to geographic + if projs == Projs.GEO: + # Pole coords in geo for this date + gpole_lat = 90 * hemisphere.value + gpole_lon = 0 + mpole_lat, mpole_lon, _ = \ + aacgmv2.convert_latlon(gpole_lat, gpole_lon, 300, + date, method_code='A2G') + + # Flatten array to work on + a_m_flat = [] + b_m_flat = [] + thetas_flat = thetas.flatten() + rs_flat = rs.flatten() + for i in range(len(rs_flat)): + a_m_flat.append( + GeneralUtils.great_circle(thetas_flat[i], + rs_flat[i], + gpole_lon, + gpole_lat)) + b_m_flat.append( + GeneralUtils.great_circle(thetas_flat[i], + rs_flat[i], + mpole_lon, + mpole_lat)) + a_m = np.reshape(a_m_flat, rs.shape) + b_m = np.reshape(b_m_flat, rs.shape) + c_m_flat = np.ones(len(rs_flat)) * \ + GeneralUtils.great_circle(gpole_lon, gpole_lat, + mpole_lon, mpole_lat) + c_m = np.reshape(c_m_flat, rs.shape) + declination = np.arccos((np.cos(c_m) - np.cos(a_m) + * np.cos(b_m)) / + (np.sin(a_m) * np.sin(b_m))) + + azm_v = azm_v + np.degrees(declination) * hemisphere.value + # Number of data points num_pts = range(len(data)) @@ -312,35 +355,29 @@ def plot_grid(cls, dmap_data: List[dict], record: int = 0, [rs[i], end_rs[i]], c=cmap(norm(data[i])), linewidth=0.5, transform=transform) else: - # If proj is geographic, convert the end points into - # geographic positions to plot - end_g_rs, end_g_thetas, _ = \ - aacgmv2.convert_latlon_arr(end_rs, - np.degrees(end_thetas), - 300, date, - method_code="A2G") + # If proj is geographic + end_thetas = np.degrees(end_thetas) for i in num_pts: # If the vector does not cross the meridian - if np.sign(thetas[i]) == np.sign(end_g_thetas[i]): - plt.plot([thetas[i], end_g_thetas[i]], - [rs[i], end_g_rs[i]], - c=cmap(norm(data[i])), - linewidth=0.5, transform=transform) + if np.sign(thetas[i]) == np.sign(end_thetas[i]): + plt.plot([thetas[i], end_thetas[i]], + [rs[i], end_rs[i]], + c=cmap(norm(data[i])), + linewidth=0.5, transform=transform) # If the vector crosses the meridian then amend so that # the start and end are in the same sign else: - if abs(end_g_thetas[i]) > 90: - if end_g_thetas[i] < 0: - end_g_thetas[i] = end_g_thetas[i] + 360 + if abs(end_thetas[i]) > 90: + if end_thetas[i] < 0: + end_thetas[i] = end_thetas[i] + 360 else: thetas[i] = thetas[i] + 360 # Vector plots correctly over the 0 meridian so # Nothing is done to correct that section - plt.plot([thetas[i], end_g_thetas[i]], - [rs[i], end_g_rs[i]], - c=cmap(norm(data[i])), - linewidth=0.5, transform=transform) - + plt.plot([thetas[i], end_thetas[i]], + [rs[i], end_rs[i]], + c=cmap(norm(data[i])), + linewidth=0.5, transform=transform) # TODO: Add a velocity reference vector if colorbar is True: @@ -358,6 +395,8 @@ def plot_grid(cls, dmap_data: List[dict], record: int = 0, if colorbar_label != '': cb.set_label(colorbar_label) + else: + cb = None if title == '': title = "{year}-{month}-{day} {start_hour}:{start_minute} -"\ @@ -372,6 +411,19 @@ def plot_grid(cls, dmap_data: List[dict], record: int = 0, end_minute=str(dmap_data[record]['end.minute']). zfill(2)) plt.title(title) - if parameter == 'vector.vel.median': - return thetas, end_thetas, rs, end_rs, data, azm_v - return thetas, rs, data + if parameter != 'vector.vel.median': + end_thetas = None + end_rs = None + azm_v = None + return {'ax': ax, + 'ccrs': ccrs, + 'cm': cmap, + 'cb': cb, + 'fig': plt.gcf(), + 'data': {'data_position_theta': thetas, + 'end_stick_position_theta': end_thetas, + 'data_position_r': rs, + 'end_stick_position_r': end_rs, + 'raw_data': data, + 'raw_azimuths': azm_v} + } diff --git a/pydarn/plotting/iq.py b/pydarn/plotting/iq.py new file mode 100644 index 000000000..495212092 --- /dev/null +++ b/pydarn/plotting/iq.py @@ -0,0 +1,449 @@ +# Copyright (C) 2023 SuperDARN Canada, University of Saskwatchewan +# Author: Carley Martin +# +# Modifications: +# +# Disclaimer: +# pyDARN is under the LGPL v3 license found in the root directory LICENSE.md +# Everyone is permitted to copy and distribute verbatim copies of this license +# document, but changing it is not allowed. +# +# This version of the GNU Lesser General Public License incorporates the terms +# and conditions of version 3 of the GNU General Public License, +# supplemented by the additional permissions listed below. +# + +""" +IQ plots +""" +import matplotlib.pyplot as plt +import numpy as np +import warnings + +from datetime import datetime +from typing import List + +from pydarn import (time2datetime, standard_warning_format, find_record, RTP) + +warnings.formatwarning = standard_warning_format + + +class IQ: + """ + Time-series and specialised plots for IQ data + + Class pattern design: Builder + This class inherits matplotlib.pyplot to inherit plotting features as well + build off their builder design pattern. + + Notes + ----- + This class inherits from matplotlib to generate the figures + + Methods + ------- + plot_time_series + plot_iq_sequence + plot_iq_record + plot_iq_overview + """ + + def __str__(self): + return "This class is static class that provides"\ + " the following methods: \n"\ + " - plot_time_series()\n"\ + " - plot_iq_sequence()\n"\ + " - plot_iq_record()\n"\ + " - plot_iq_overview()\n" + + @staticmethod + def plot_time_series(dmap_data: List[dict], **kwargs): + """ + Plots scalar variables from IQ dat files + + SEE ALSO: RTP.plot_time_series() for more information and + inputs + + Parameters + ---------- + dmap_data: List[dict] + + Returns + ------- + time_series_data: Lines, x, y + standard return values from RTP.plot_time_series + """ + time_series_info = RTP.plot_time_series(dmap_data, **kwargs) + return time_series_info + + @staticmethod + def plot_iq_sequence(dmap_data: List[dict], + start_time: datetime = None, + channel: int = 0, ax=None, beam_num: int = 0, + sequence_num: int = 0, interferometer: bool = False, + plot_phase: bool = False): + """ + Plots a single sequence from a record of IQ data + + Parameters + ----------- + dmap_data: List[dict] + beam_num : int + The beam number of data to plot + Default: 0 + channel : int or str + The frequency channel 0, 1, 2 ... + Default : 0 + ax: matplotlib.axes + axes object for another way of plotting + Default: None + start_time: datetime + Specified time of interest as a datetime object + sequence_num: int + Sequence in the record to be plotted + Default: 0 + interferometer: bool + Data from main array (False) or interferometer array (True) + Default False + plot_phase: bool + Option to plot the phase of the data (True) + Default False + """ + # Finds start of minute scan records, then scans the records to + # find the next record with the correct beam + if start_time is not None: + record_num = find_record(dmap_data, start_time) + else: + record_num = 0 + # Get the next record with the correct beam + while (dmap_data[record_num]['bmnum'] != beam_num + and (dmap_data[record_num]['channel'] != channel + and channel != 'all')): + record_num += 1 + if record_num >= len(dmap_data): + raise Exception("No matching data found for beam {} " + "near time {}" + .format(beam_num, + start_time.strftime('%Y-%m-%d' + + ' %H:%M:%S'))) + dmap_record = dmap_data[record_num] + + # Details from chosen record + date = time2datetime(dmap_record) + smpnum = dmap_record['smpnum'] + chnnum = dmap_record['chnnum'] + seqnum = dmap_record['seqnum'] + + # Warning to too hihc sequence numberes + if sequence_num >= seqnum: + raise ValueError("Sequence numbers available for this record " + "range from 0 to {}.".format(seqnum-1)) + + if interferometer and chnnum < 2: + raise ValueError("No interferometer data for record chosen.") + + # Calculate starting data position + # For layout of data and how to access see: + # https://radar-software-toolkit-rst.readthedocs.io + # /en/latest/references/general/iqdat/ + if interferometer: + smp = sequence_num * chnnum * 2 * smpnum + 2 * smpnum + else: + smp = sequence_num * chnnum * 2 * smpnum + iq_real = [] + iq_imag = [] + smp_initial = smp + while smp < smp_initial + 2*smpnum: + iq_real.append(dmap_record['data'][smp]) + smp = smp + 1 + iq_imag.append(dmap_record['data'][smp]) + smp = smp + 1 + + # Calculate magnitude and phase + mag = [np.sqrt(i**2 + j**2) for i, j in zip(iq_real, iq_imag)] + mag_neg = [-np.sqrt(i**2 + j**2) for i, j in zip(iq_real, iq_imag)] + + # Plotting phase if chosen + if plot_phase: + phase = np.arctan2(iq_imag, iq_real) + fig = plt.gcf() + fig.tight_layout() + gs = fig.add_gridspec(3, 1) + ax = fig.add_subplot(gs[0:2, :]) + ax2 = fig.add_subplot(gs[2, :]) + ax2.plot(phase, 'mediumseagreen') + ax2.grid() + ax2.set_ylabel('Phase') + ax2.set_xlabel('Sample Number') + elif ax is None: + ax = plt.gca() + + # Plot lines + real_line, = ax.plot(iq_real, 'r') + imag_line, = ax.plot(iq_imag, 'b') + mag_line, = ax.plot(mag, 'grey', linestyle='--', linewidth=0.5) + ax.plot(mag_neg, 'grey', linestyle='--', linewidth=0.5) + + # Plot legend and labels + real_line.set_label('Real') + imag_line.set_label('Imaginary') + mag_line.set_label('Magnitude') + ax.legend() + + # Plot title and axis labels + if interferometer: + array_type = 'Interferometer Array' + else: + array_type = 'Main Array' + ax.set_title('IQ Data for ' + array_type + '\n Beam=' + + str(beam_num) + ' ' + + ' Sequence=' + str(sequence_num) + '\n ' + + date.strftime('%Y-%m-%d %H:%M:%S')) + ax.set_ylabel('Raw Data') + ax.set_xlabel('Sample Number') + ax.grid() + + return {'ax': ax, + 'ccrs': None, + 'cm': None, + 'cb': None, + 'fig': plt.gcf(), + 'data': {'iq_real': iq_real, + 'iq_imag': iq_imag, + 'magnitude': mag} + } + + @staticmethod + def plot_iq_record(dmap_data: List[dict], + start_time: datetime = None, + channel: int = 0, ax=None, beam_num: int = 0, + interferometer: bool = False, + cmap=plt.colormaps['viridis']): + """ + Plots all sequences from a record of IQ data + + Parameters + ----------- + dmap_data: List[dict] + beam_num : int + The beam number of data to plot + Default: 0 + channel : int or str + The frequency channel 0, 1, 2 ... + Default : 0 + ax: matplotlib.axes + axes object for another way of plotting + Default: None + start_time: datetime + Specified time of interest as a datetime object + interferometer: bool + Data from main array (False) or interferometer array (True) + Default False + cmap: matplotlib.cm object + Default: viridis + """ + # Finds start of minute scan records, then scans the records to + # find the next record with the correct beam + if start_time is not None: + record_num = find_record(dmap_data, start_time) + else: + record_num = 0 + # Get the next record with the correct beam + while (dmap_data[record_num]['bmnum'] != beam_num + and (dmap_data[record_num]['channel'] != channel + and channel != 'all')): + record_num += 1 + if record_num >= len(dmap_data): + raise Exception("No matching data found for beam {} " + "near time {}" + .format(beam_num, + start_time.strftime('%Y-%m-%d' + + ' %H:%M:%S'))) + dmap_record = dmap_data[record_num] + + # Details from chosen record + date = time2datetime(dmap_record) + smpnum = dmap_record['smpnum'] + chnnum = dmap_record['chnnum'] + seqnum = dmap_record['seqnum'] + + if interferometer and chnnum < 2: + raise ValueError("No interferometer data for record chosen.") + + # Calculate starting data position + # For layout of data and how to access see: + # https://radar-software-toolkit-rst.readthedocs.io + # /en/latest/references/general/iqdat/ + iq_real_arr = np.empty([smpnum, seqnum]) + iq_imag_arr = np.empty([smpnum, seqnum]) + for seq in range(0, seqnum): + if interferometer: + smp = seq * chnnum * 2 * smpnum + 2 * smpnum + else: + smp = seq * chnnum * 2 * smpnum + iq_real_arr[:, seq] = dmap_record['data'][smp: smp + smpnum] + iq_imag_arr[:, seq] =\ + dmap_record['data'][smp + smpnum: smp + 2*smpnum] + + # Calculate magnitude + mag = np.sqrt(iq_real_arr**2 + iq_imag_arr**2) + # Plot + if ax is None: + ax = plt.gca() + pcol = ax.pcolormesh(mag, vmin=0, vmax=600, cmap=cmap) + cb = ax.figure.colorbar(pcol, extend='max') + cb.set_label('Power (AU)') + + # Plot title and axis labels + if interferometer: + array_type = 'Interferometer Array' + else: + array_type = 'Main Array' + ax.set_title('IQ Data for ' + array_type + '\n Beam=' + + str(beam_num) + ' ' + + date.strftime('%Y-%m-%d %H:%M:%S')) + ax.set_ylabel('Sample Number') + ax.set_xlabel('Sequence Number') + ax.grid() + + return {'ax': ax, + 'ccrs': None, + 'cm': cmap, + 'cb': cb, + 'fig': plt.gcf(), + 'data': {'iq_real': iq_real_arr, + 'iq_imag': iq_imag_arr, + 'magnitude': mag} + } + + @staticmethod + def __determine_start_end_time(dmap_data, start_time: datetime, + end_time: datetime) -> tuple: + """ + Sets the start and end time based on import of dmap_data + + Parameter + --------- + dmap_data: List[dict] + start_time: datetime + Start time is used to check if it was set or not + end_time: datetime + End time is used to check if it was set or not + + Returns + ------- + start_time: datetime + end_time: datetime + """ + if not start_time: + start_time = time2datetime(dmap_data[0]) + if not end_time: + end_time = time2datetime(dmap_data[-1]) + return start_time, end_time + + @staticmethod + def plot_iq_overview(dmap_data: List[dict], + start_time: datetime = None, + end_time: datetime = None, + channel: int = 0, ax=None, beam_num: int = 'all', + interferometer: bool = False, + cmap: object = plt.colormaps['viridis']): + """ + Plots all sequences from a record of IQ data + + Parameters + ----------- + dmap_data: List[dict] + beam_num : int + The beam number of data to plot + Default: 0 + channel : int or str + The frequency channel 0, 1, 2 ... + Default : 0 + ax: matplotlib.axes + axes object for another way of plotting + Default: None + start_time: datetime + Specified start time of interest as a datetime object + end_time: datetime + Specified end time of interest as a datetime object + interferometer: bool + Data from main array (False) or interferometer array (True) + Default False + cmap: matplotlib.cm object + Default: viridis + """ + start_time, end_time = IQ.__determine_start_end_time(dmap_data, + start_time, + end_time) + + # Assuming the samples and sequences will stay constant + # over the file + smpnum = dmap_data[0]['smpnum'] + chnnum = dmap_data[0]['chnnum'] + seqnum = dmap_data[0]['seqnum'] + + # Empty lists to append data to + # TODO: did not work using arrays + iq_real_arr = [] + iq_imag_arr = [] + for dmap_record in dmap_data: + if (dmap_record['bmnum'] == beam_num or beam_num == 'all') and\ + (dmap_record['channel'] == channel or channel == 'all'): + rec_time = time2datetime(dmap_record) + if start_time <= rec_time <= end_time: + if interferometer and chnnum < 2: + raise ValueError("No interferometer data for " + "record chosen.") + + # Calculate starting data position + # For layout of data and how to access see: + # https://radar-software-toolkit-rst.readthedocs.io + # /en/latest/references/general/iqdat/ + for seq in range(0, seqnum): + if interferometer: + smp = seq * chnnum * 2 * smpnum + 2 * smpnum + else: + smp = seq * chnnum * 2 * smpnum + iq_real = dmap_record['data'][smp: smp + smpnum] + iq_imag =\ + dmap_record['data'][smp + smpnum: smp + 2*smpnum] + if len(iq_real) == smpnum: + iq_real_arr.append(iq_real) + iq_imag_arr.append(iq_imag) + + # Convert to arrays, dtype important for mag calc + iq_real_arr = np.array(iq_real_arr, dtype='float64') + iq_imag_arr = np.array(iq_imag_arr, dtype='float64') + # Calculate magnitude + mag = np.sqrt(np.add(np.square(iq_real_arr), np.square(iq_imag_arr))) + + # Plot + if ax is None: + ax = plt.gca() + pcol = ax.pcolormesh(mag.T, vmin=0, vmax=1000, cmap=cmap) + cb = ax.figure.colorbar(pcol, extend='max') + cb.set_label('Power (AU)') + + # Plot title and axis labels + if interferometer: + array_type = 'Interferometer Array' + else: + array_type = 'Main Array' + ax.set_title('IQ Data for ' + array_type + ' Beam=' + + str(beam_num) + '\n' + + start_time.strftime('%Y-%m-%d %H:%M:%S') + ' - ' + + end_time.strftime('%Y-%m-%d %H:%M:%S')) + ax.set_ylabel('Sample Number') + ax.set_xlabel('Sequence Number') + ax.grid() + + return {'ax': ax, + 'ccrs': None, + 'cm': cmap, + 'cb': cb, + 'fig': plt.gcf(), + 'data': {'iq_real': iq_real_arr, + 'iq_imag': iq_imag_arr, + 'magnitude': mag} + } diff --git a/pydarn/plotting/maps.py b/pydarn/plotting/maps.py index 265b5366d..5c1c9a5eb 100644 --- a/pydarn/plotting/maps.py +++ b/pydarn/plotting/maps.py @@ -11,6 +11,7 @@ # vector # 2022-08-15: CJM - Removed plot_FOV call for default uses # 2022-12-13: CJM - Limited reference vectors to only velocity use +# 2023-06-28: CJM - Refactored return values # # Disclaimer: # pyDARN is under the LGPL v3 license found in the root directory LICENSE.md @@ -37,13 +38,14 @@ from scipy import special from typing import List + # Third party libraries import aacgmv2 from pydarn import (PyDARNColormaps, plot_exceptions, standard_warning_format, Re, Hemisphere, - time2datetime, find_record, Fan, Projs, MapParams) - + time2datetime, find_record, Fan, Projs, + MapParams, TimeSeriesParams) warnings.formatwarning = standard_warning_format @@ -62,7 +64,6 @@ def __str__(self): " the following methods: \n"\ " - plot_maps()\n" - @classmethod def plot_mapdata(cls, dmap_data: List[dict], ax=None, parameter: Enum = MapParams.FITTED_VELOCITY, @@ -164,12 +165,12 @@ def plot_mapdata(cls, dmap_data: List[dict], ax=None, date = time2datetime(dmap_data[record]) if cmap is None: - cmap = {MapParams.FITTED_VELOCITY: 'plasma_r', - MapParams.MODEL_VELOCITY: 'plasma_r', - MapParams.RAW_VELOCITY: 'plasma_r', - MapParams.POWER: 'plasma', + cmap = {MapParams.FITTED_VELOCITY: PyDARNColormaps.PYDARN_PLASMA_R, + MapParams.MODEL_VELOCITY: PyDARNColormaps.PYDARN_PLASMA_R, + MapParams.RAW_VELOCITY: PyDARNColormaps.PYDARN_PLASMA_R, + MapParams.POWER: PyDARNColormaps.PYDARN_PLASMA, MapParams.SPECTRAL_WIDTH: PyDARNColormaps.PYDARN_VIRIDIS} - cmap = plt.cm.get_cmap(cmap[parameter]) + cmap = cmap[parameter] # Setting zmin and zmax defaultzminmax = {MapParams.FITTED_VELOCITY: [0, 1000], MapParams.MODEL_VELOCITY: [0, 1000], @@ -200,10 +201,11 @@ def plot_mapdata(cls, dmap_data: List[dict], ax=None, # Else just call the axis maker: proj if boundary or radar_location: for stid in dmap_data[record]['stid']: - _, _, ax, _ =\ - Fan.plot_fov(stid, date, ax=ax, boundary=boundary, - radar_location=radar_location, - **kwargs) + fan_rtn = Fan.plot_fov(stid, date, ax=ax, + boundary=boundary, + radar_location=radar_location, + **kwargs) + ax = fan_rtn['ax'] else: ax, _ = projs(date, ax=ax, hemisphere=hemisphere, **kwargs) @@ -305,32 +307,105 @@ def plot_mapdata(cls, dmap_data: List[dict], ax=None, # vector to be plotted later if required) if color_vectors is True: for i in range(len(v_mag) - 1): - plt.plot([mlons[i], end_mlons[i]], - [mlats[i], end_mlats[i]], c=cmap(norm(v_mag[i])), - linewidth=0.5, zorder=5.0) + if parameter == MapParams.FITTED_VELOCITY: + # Shift HMB lons to MLT + shifted_mlts = \ + dmap_data[record]['boundary.mlon'][0] - \ + (aacgmv2.convert_mlt( + dmap_data[record]['boundary.mlon'][0], + date) * 15) + hmblons = (dmap_data[record]['boundary.mlon'] - + shifted_mlts) % 360 + # Find where the closest HMB value is, set equivalent + # latitude as the lat limit for plotting + rounded_mlon = np.degrees(mlons[i]) % 360 + ind = (np.abs(hmblons - rounded_mlon)).argmin() + lat_limit = dmap_data[record]['boundary.mlat'][ind] + if abs(mlats[i]) >= abs(lat_limit): + plt.plot([mlons[i], end_mlons[i]], + [mlats[i], end_mlats[i]], + c=cmap(norm(v_mag[i])), + linewidth=0.5, zorder=5.0) + else: + plt.plot([mlons[i], end_mlons[i]], + [mlats[i], end_mlats[i]], + c=cmap(norm(v_mag[i])), + linewidth=0.5, zorder=5.0) else: for i in range(len(v_mag) - 1): - plt.plot([mlons[i], end_mlons[i]], - [mlats[i], end_mlats[i]], c='#292929', - linewidth=0.5, zorder=5.0) + if parameter == MapParams.FITTED_VELOCITY: + # Shift HMB lons to MLT + shifted_mlts = \ + dmap_data[record]['boundary.mlon'][0] - \ + (aacgmv2.convert_mlt( + dmap_data[record]['boundary.mlon'][0], + date) * 15) + hmblons = (dmap_data[record]['boundary.mlon'] - + shifted_mlts) % 360 + # Find where the closest HMB value is, set equivalent + # latitude as the lat limit for plotting + rounded_mlon = np.degrees(mlons[i]) % 360 + ind = (np.abs(hmblons - rounded_mlon)).argmin() + lat_limit = dmap_data[record]['boundary.mlat'][ind] + if abs(mlats[i]) >= abs(lat_limit): + plt.plot([mlons[i], end_mlons[i]], + [mlats[i], end_mlats[i]], c='#292929', + linewidth=0.5, zorder=5.0) + else: + plt.plot([mlons[i], end_mlons[i]], + [mlats[i], end_mlats[i]], c='#292929', + linewidth=0.5, zorder=5.0) # Plot the sock start dots and reference vector if known if color_vectors is True: - if parameter in [MapParams.FITTED_VELOCITY, - MapParams.MODEL_VELOCITY, + if parameter in [MapParams.MODEL_VELOCITY, MapParams.RAW_VELOCITY]: if reference_vector > 0: - plt.scatter(mlons[:], mlats[:], c=v_mag[:], s=2.0, + plt.scatter(mlons[:-1], mlats[:-1], c=v_mag[:-1], s=2.0, + vmin=zmin, vmax=zmax, cmap=cmap, zorder=5.0, + clip_on=True) + plt.scatter(mlons[-1], mlats[-1], c=v_mag[-1], s=2.0, vmin=zmin, vmax=zmax, cmap=cmap, zorder=5.0, clip_on=False) plt.plot([mlons[-1], end_mlons[-1]], - [mlats[-1], end_mlats[-1]], c=cmap(norm(v_mag[-1])), + [mlats[-1], end_mlats[-1]], + c=cmap(norm(v_mag[-1])), linewidth=0.5, zorder=5.0, clip_on=False) plt.figtext(0.675, 0.15, str(reference_vector) + ' m/s', fontsize=8) else: plt.scatter(mlons[:-1], mlats[:-1], c=v_mag[:-1], s=2.0, vmin=zmin, vmax=zmax, cmap=cmap, zorder=5.0) + elif parameter is MapParams.FITTED_VELOCITY: + # Shift HMB lons to MLT + shifted_mlts = dmap_data[record]['boundary.mlon'][0] - \ + (aacgmv2.convert_mlt( + dmap_data[record]['boundary.mlon'][0], date) * 15) + hmblons = (dmap_data[record]['boundary.mlon'] - + shifted_mlts) % 360 + # Find where the closest HMB value is, set equivalent + # latitude as the lat limit for plotting + for m, mlon in enumerate(mlons[:-1]): + rounded_mlon = np.degrees(mlon) % 360 + ind = (np.abs(hmblons - rounded_mlon)).argmin() + lat_limit = dmap_data[record]['boundary.mlat'][ind] + if abs(mlats[m]) >= abs(lat_limit): + plt.scatter(mlon, mlats[m], color=cmap(norm(v_mag[m])), + s=2.0, zorder=5.0, clip_on=True) + else: + plt.scatter(mlon, mlats[m], c='#DDDDDD', s=2.0, + zorder=5.0, clip_on=True) + if reference_vector > 0: + plt.scatter(mlons[-1], mlats[-1], + color=cmap(norm(v_mag[-1])), + s=2.0, zorder=5.0, clip_on=False) + plt.plot([mlons[-1], end_mlons[-1]], + [mlats[-1], end_mlats[-1]], + c=cmap(norm(v_mag[-1])), + linewidth=0.5, zorder=5.0, clip_on=False) + plt.figtext(0.675, 0.15, str(reference_vector) + ' m/s', + fontsize=8) + # No vector socks on spectral width else: plt.scatter(mlons[:], mlats[:], c=v_mag[:], s=2.0, vmin=zmin, vmax=zmax, cmap=cmap, zorder=5.0) @@ -338,11 +413,12 @@ def plot_mapdata(cls, dmap_data: List[dict], ax=None, else: # no color so make sure colorbar is turned off colorbar = False - if parameter in [MapParams.FITTED_VELOCITY, - MapParams.MODEL_VELOCITY, + if parameter in [MapParams.MODEL_VELOCITY, MapParams.RAW_VELOCITY]: if reference_vector > 0: - plt.scatter(mlons[:], mlats[:], c='#292929', s=2.0, + plt.scatter(mlons[:-1], mlats[:-1], c='#292929', s=2.0, + zorder=5.0, clip_on=True) + plt.scatter(mlons[-1], mlats[-1], c='#292929', s=2.0, zorder=5.0, clip_on=False) plt.plot([mlons[-1], end_mlons[-1]], [mlats[-1], end_mlats[-1]], c='#292929', @@ -352,9 +428,37 @@ def plot_mapdata(cls, dmap_data: List[dict], ax=None, else: plt.scatter(mlons[:-1], mlats[:-1], c='#292929', s=2.0, zorder=5.0) + elif parameter is MapParams.FITTED_VELOCITY: + # Shift HMB lons to MLT + shifted_mlts = dmap_data[record]['boundary.mlon'][0] - \ + (aacgmv2.convert_mlt( + dmap_data[record]['boundary.mlon'][0], date) * 15) + hmblons = (dmap_data[record]['boundary.mlon'] - + shifted_mlts) % 360 + # Find where the closest HMB value is, set equivalent + # latitude as the lat limit for plotting + for m, mlon in enumerate(mlons[:-1]): + rounded_mlon = np.degrees(mlon) % 360 + ind = (np.abs(hmblons - rounded_mlon)).argmin() + lat_limit = dmap_data[record]['boundary.mlat'][ind] + if abs(mlats[m]) >= abs(lat_limit): + plt.scatter(mlon, mlats[m], c='#292929', s=2.0, + zorder=5.0, clip_on=True) + else: + plt.scatter(mlon, mlats[m], c='#DDDDDD', s=2.0, + zorder=5.0, clip_on=True) + if reference_vector > 0: + plt.scatter(mlons[-1], mlats[-1], c='#292929', s=2.0, + zorder=5.0, clip_on=False) + plt.plot([mlons[-1], end_mlons[-1]], + [mlats[-1], end_mlats[-1]], c='#292929', + linewidth=0.5, zorder=5.0, clip_on=False) + plt.figtext(0.675, 0.15, str(reference_vector) + ' m/s', + fontsize=8) + # No vector socks on spectral width else: plt.scatter(mlons[:], mlats[:], c='#292929', s=2.0, - zorder=5.0) + zorder=5.0) if colorbar is True: mappable = cm.ScalarMappable(norm=norm, cmap=cmap) @@ -380,6 +484,8 @@ def plot_mapdata(cls, dmap_data: List[dict], ax=None, cb.set_label('Spectral Width (m s$^{-1}$)') elif parameter is MapParams.POWER: cb.set_label('Power') + else: + cb = None # Plot potential contours fit_coefficient = dmap_data[record]['N+2'] @@ -388,16 +494,25 @@ def plot_mapdata(cls, dmap_data: List[dict], ax=None, lon_shift = dmap_data[record]['lon.shft'] lat_min = dmap_data[record]['latmin'] - cls.plot_potential_contours(fit_coefficient, lat_min, date, ax, - lat_shift=lat_shift, lon_shift=lon_shift, - fit_order=fit_order, hemisphere=hemisphere, - **kwargs) + _, _, pot_arr, cs, cb_contour = \ + cls.plot_potential_contours(fit_coefficient, + lat_min, date, ax, + lat_shift=lat_shift, + lon_shift=lon_shift, + fit_order=fit_order, + hemisphere=hemisphere, + **kwargs) if hmb is True: # Plot the HMB mlats_hmb = dmap_data[record]['boundary.mlat'] mlons_hmb = dmap_data[record]['boundary.mlon'] - cls.plot_heppner_maynard_boundary(mlats_hmb, mlons_hmb, date) + hmb_lon, hmb_lat = cls.plot_heppner_maynard_boundary(mlats_hmb, + mlons_hmb, + date) + else: + hmb_lon = None + hmb_lat = None if title == '': title = "{year}-{month}-{day} {start_hour}:{start_minute} -"\ @@ -419,17 +534,33 @@ def plot_mapdata(cls, dmap_data: List[dict], ax=None, pol_cap_pot = dmap_data[record]['pot.drop'] cls.add_map_info(fit_order, pol_cap_pot, num_points, model) + bx = dmap_data[record]['IMF.Bx'] + by = dmap_data[record]['IMF.By'] + bz = dmap_data[record]['IMF.Bz'] + delay = dmap_data[record]['IMF.delay'] + bt = np.sqrt(bx**2 + by**2 + bz**2) if imf_dial is True: # Plot the IMF dial - bx = dmap_data[record]['IMF.Bx'] - by = dmap_data[record]['IMF.By'] - bz = dmap_data[record]['IMF.Bz'] - delay = dmap_data[record]['IMF.delay'] - bt = np.sqrt(bx**2 + by**2 + bz**2) cls.plot_imf_dial(ax, by, bz, bt, delay) - return mlats, mlons, v_mag - + return {'ax': ax, + 'ccrs': None, + 'cm': cmap, + 'cb': [cb, cb_contour], + 'fig': plt.gcf(), + 'data': {'cpcp': pol_cap_pot, + 'fit_model': model, + 'fit_order': fit_order, + 'num_vectors': num_points, + 'mlats': mlats, + 'mlons': mlons, + 'v_mag': v_mag, + 'azm_v': azm_v, + 'potential_array': pot_arr, + 'hmb': [hmb_lat, hmb_lon], + 'imf': [bx, by, bz, bt, delay], + 'contours': cs} + } @classmethod def index_legendre(cls, l: int, m: int): @@ -450,7 +581,6 @@ def index_legendre(cls, l: int, m: int): return (m == 0 and l**2) or ((l != 0) and (m != 0) and l**2 + 2 * m - 1) or 0 - @classmethod def calculated_fitted_velocities(cls, mlats: list, mlons: list, fit_coefficient: list, @@ -653,7 +783,6 @@ def calculated_fitted_velocities(cls, mlats: list, mlons: list, return velocity, azm_v - @classmethod def add_map_info(cls, fit_order: float, pol_cap_pot: float, num_points: float, model: str): @@ -680,7 +809,6 @@ def add_map_info(cls, fit_order: float, pol_cap_pot: float, + 'Model: ' + model + '\n' plt.figtext(0.1, 0.1, text_string) - @classmethod def plot_heppner_maynard_boundary(cls, mlats: list, mlons: list, date: object, line_color: str = 'black', @@ -712,7 +840,7 @@ def plot_heppner_maynard_boundary(cls, mlats: list, mlons: list, mlon = np.radians(shifted_lons) plt.plot(mlon, mlats, c=line_color, zorder=4.0, **kwargs) - + return mlon, mlats @classmethod def plot_imf_dial(cls, ax: object, by: float = 0, bz: float = 0, @@ -769,7 +897,6 @@ def plot_imf_dial(cls, ax: object, by: float = 0, bz: float = 0, ax_imf.annotate('Delay = -' + str(delay) + ' min', xy=(-16, -17), fontsize=7) - @classmethod def calculate_potentials(cls, fit_coefficient: list, lat_min: list, lat_shift: int = 0, lon_shift: int = 0, @@ -878,20 +1005,23 @@ def calculate_potentials(cls, fit_coefficient: list, lat_min: list, return mlat_center, mlon_center, pot_arr - @classmethod def plot_potential_contours(cls, fit_coefficient: list, lat_min: list, date: object, ax: object, lat_shift: int = 0, lon_shift: int = 0, fit_order: int = 6, hemisphere: Enum = Hemisphere.North, contour_levels: list = [], + contour_spacing: int = None, contour_color: str = 'dimgrey', contour_linewidths: float = 0.8, contour_fill: bool = False, contour_colorbar: bool = True, contour_fill_cmap: str = 'RdBu', contour_colorbar_label: str = 'Potential (kV)', - pot_minmax_color: str = 'k', **kwargs): + pot_minmax_color: str = 'k', + pot_zmin: int = -50, + pot_zmax: int = 50, + **kwargs): # TODO: No evaluation of coordinate system made! May need if in # plotting to plot in radians/geo ect. ''' @@ -927,6 +1057,11 @@ def plot_potential_contours(cls, fit_coefficient: list, lat_min: list, lower than the minimum and maximum values given are colored in as min and max color values if contour_fill=True + contour_spacing: int + If levels are not set explicitly, then use this value to + set the spacing between the contour levels. + Default is None which defaults to the max value/20 + which works out to be 5 with other default values contour_color: str Colour of the contour lines plotted Default: dimgrey @@ -959,6 +1094,12 @@ def plot_potential_contours(cls, fit_coefficient: list, lat_min: list, Colour of the cross and plus symbols for minimum and maximum potentials Default: 'k' - black + pot_zmin: float + Minumum value of color map used for potential contours. + If None, defaults to -abs(pot_arr).max() + pot_zmax: float + Maximum value of color map used for potential contours. + If None, defaults to abs(pot_arr).max() **kwargs including lowlat and hemisphere for calculating potentials @@ -977,38 +1118,50 @@ def plot_potential_contours(cls, fit_coefficient: list, lat_min: list, # Contained in function as too long to go into the function call if contour_levels == []: - contour_levels = [-100, -95, -90, -85, -80, -75, -70, -65, -60, - -55, -50, -45, -40, -35, -30, -25, -20, -15, - -10, -5, -1, 1, 5, 10, 15, 20, 25, 30, 35, 40, - 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100] + if contour_spacing is None: + # If not set this sets the maximum number of contours to be 40 + contour_spacing = int(np.floor(np.max([abs(pot_zmin), + abs(pot_zmax)]) / 10)) + + # Making the levels required, but skipping 0 as default to avoid a + # contour at 0 position (looks weird) + contour_levels = [*range(pot_zmin, 0, contour_spacing), + *range(contour_spacing, + pot_zmax + contour_spacing, + contour_spacing)] + else: + pot_zmax = np.max(contour_levels) + pot_zmin = np.min(contour_levels) if contour_fill: # Filled contours - plt.contourf(np.radians(mlon), mlat, pot_arr, 2, - vmax=abs(pot_arr).max(), - vmin=-abs(pot_arr).max(), - locator=ticker.FixedLocator(contour_levels), - cmap=contour_fill_cmap, alpha=0.5, - extend='both', zorder=3.0) + norm = colors.Normalize + norm = norm(pot_zmin, pot_zmax) + cs = plt.contourf(np.radians(mlon), mlat, pot_arr, 2, + norm=norm, vmax=pot_zmax, vmin=pot_zmin, + levels=np.array(contour_levels), + cmap=contour_fill_cmap, alpha=0.5, + extend='both', zorder=3.0) if contour_colorbar is True: - norm = colors.Normalize - norm = norm(-abs(pot_arr).max(), abs(pot_arr).max()) mappable = cm.ScalarMappable(norm=norm, cmap=contour_fill_cmap) locator = ticker.MaxNLocator(symmetric=True, min_n_ticks=3, integer=True, nbins='auto') - ticks = locator.tick_values(vmin=-abs(pot_arr).max(), - vmax=abs(pot_arr).max()) - cb = plt.colorbar(mappable, ax=ax, extend='both', ticks=ticks) + ticks = locator.tick_values(vmin=pot_zmin, + vmax=pot_zmax) + cb_contour = plt.colorbar(mappable, ax=ax, extend='both', + ticks=ticks) if contour_colorbar_label != '': - cb.set_label(contour_colorbar_label) + cb_contour.set_label(contour_colorbar_label) + else: + cb_contour = None else: # Contour lines only cs = plt.contour(np.radians(mlon), mlat, pot_arr, 2, - vmax=abs(pot_arr).max(), - vmin=-abs(pot_arr).max(), - locator=ticker.FixedLocator(contour_levels), + vmax=pot_zmax, vmin=pot_zmin, + levels=np.array(contour_levels), colors=contour_color, alpha=0.8, linewidths=contour_linewidths, zorder=3.0) + cb_contour = None # TODO: Add in contour labels # if contour_label: # plt.clabel(cs, cs.levels, inline=True, fmt='%d', fontsize=5) @@ -1025,3 +1178,120 @@ def plot_potential_contours(cls, fit_coefficient: list, lat_min: list, color=pot_minmax_color, zorder=5.0) plt.scatter(np.radians(min_mlon), min_mlat, marker='_', s=70, color=pot_minmax_color, zorder=5.0) + return mlat, mlon_u, pot_arr, cs, cb_contour + + @classmethod + def find_map_record(cls, dmap_data: List[dict], start_time: dt.datetime): + """ + looks through the data from a given map file and + returns the record number nearest the + passed datetime object + + Parameters + ----------- + dmap_data: List[dict] + the data to look through + start_time: datetime + the time to find the nearest record number to + + Returns + ------- + Returns the closet record to the passed time + """ + # recursively identify the index of the list + # where the time is closest to the passed time + def find_nearest_time(dmap_data: List[dict], start_time: dt.datetime, + start_index: int, end_index: int): + # base case + if start_index == end_index: + return start_index + # recursive case + else: + # find the middle index + mid_index = int((start_index + end_index)/2) + # if the time at the middle index is + # greater than the passed time + if time2datetime(dmap_data[mid_index]) > start_time: + # search the lower half of the list + return find_nearest_time(dmap_data, start_time, + start_index, mid_index) + # if the time at the middle index + # is less than the passed time + elif time2datetime(dmap_data[mid_index]) < start_time: + # search the upper half of the list + return find_nearest_time(dmap_data, start_time, + mid_index + 1, end_index) + # if the time at the middle index is equal to the passed time + else: + # return the middle index + return mid_index + + return find_nearest_time(dmap_data, + start_time, 0, len(dmap_data) - 1) + + @classmethod + def plot_time_series(cls, dmap_data: List[dict], + parameter: Enum = TimeSeriesParams.NUM_VECTORS, + start_record: int = 0, end_record: int = 1, + start_time: dt.datetime = None, + end_time: dt.datetime = None, ax=None, **kwargs): + ''' + Plot time series of various map parameters + + Params + ---------- + dmap_data: List[dict] + List of dictionaries containing the data to be plotted + start_record: int + time index that we will plot from + end_record: int + time index that we will plot to (-1 will plot the entire period) + start_time: dt.datetime + Start time of the data + end_time: dt.datetime + End time of the data + ax: + matplotlib axis + kwargs: + keyword arguments to be passed to the plotting function + ''' + # if no time objects are passed & no start/end record is passed + # then plot all availaible data + record_absent = start_time is None and end_time is None + if start_record == 0 and end_record == 1 and record_absent: + + start_record = 0 + end_record = len(dmap_data)-1 + # determine the start and end record + if start_time is not None and end_time is not None: + start_record = cls.find_map_record(dmap_data, start_time) + end_record = cls.find_map_record(dmap_data, end_time) + else: + start_time = time2datetime(dmap_data[start_record]) + end_time = time2datetime(dmap_data[end_record]) + # based on the parameter, plot the data + if parameter == TimeSeriesParams.NUM_VECTORS: + datalist = [] + timelist = [] + for records in range(start_record, end_record): + # append the dimension of numv for each record + # we can just uexse any of the keys with dimensionality numv + datalist.append(len(dmap_data[records]['vector.mlat'])) + # now get the associated time data point per record + timelist.append(time2datetime(dmap_data[records])) + plt.plot(timelist, datalist, **kwargs) + plt.ylabel('Number of Vectors') + plt.xlabel('Time (UTC)') + plt.title("Number of Vectors for " + str(start_time) + + " to " + str(end_time)) + elif parameter is not None: + datalist = [] + timelist = [] + for records in range(start_record, end_record): + datalist.append(dmap_data[records][parameter.value]) + timelist.append(time2datetime(dmap_data[records])) + plt.plot(timelist, datalist, **kwargs) + plt.ylabel(parameter.value) + plt.xlabel('Time (UTC)') + plt.title(parameter.value + ' for ' + str(start_time) + + " to " + str(end_time)) diff --git a/pydarn/plotting/power.py b/pydarn/plotting/power.py index 0e2d0cab4..c7329da00 100644 --- a/pydarn/plotting/power.py +++ b/pydarn/plotting/power.py @@ -1,5 +1,19 @@ # Copyright (C) 2020 SuperDARN Canada, University of Saskatchewan # Author: Cooper Ross Robertson, Summer Student 2020, Marina Schmidt +# +# Modifications: +# 2023-06-28 Carley Martin refactored return values +# +# Disclaimer: +# pyDARN is under the LGPL v3 license found in the root directory LICENSE.md +# Everyone is permitted to copy and distribute verbatim copies of this license +# document, but changing it is not allowed. +# +# This version of the GNU Lesser General Public License incorporates the terms +# and conditions of version 3 of the GNU General Public License, +# supplemented by the additional permissions listed below. +# + import copy import matplotlib.pyplot as plt import numpy as np @@ -83,6 +97,8 @@ def plot_pwr0_statistic(cls, records: List[dict], beam_num: int = 0, beam_num) cls.__plot_pwr0(records_of_interest, beam_num, statistical_method) + data = {'method': statistical_method, + 'values': records_of_interest} else: # plot all frequencies lower than max_frequency if min_frequency is None: @@ -91,6 +107,8 @@ def plot_pwr0_statistic(cls, records: List[dict], beam_num: int = 0, beam_num, '<=', max_frequency) cls.__plot_pwr0(records_of_interest, beam_num, statistical_method) + data = {'method': statistical_method, + 'values': records_of_interest} elif max_frequency is None: # plot all frequencies higher than min_frequency @@ -99,6 +117,8 @@ def plot_pwr0_statistic(cls, records: List[dict], beam_num: int = 0, beam_num, '>=', min_frequency) cls.__plot_pwr0(records_of_interest, beam_num, statistical_method) + data = {'method': statistical_method, + 'values': records_of_interest} else: # plot all frequencies between min and max frequency @@ -113,6 +133,8 @@ def plot_pwr0_statistic(cls, records: List[dict], beam_num: int = 0, cls.__plot_pwr0(records_of_interest, beam_num, statistical_method) + data = {'method': statistical_method, + 'values': records_of_interest} else: if min_frequency is None and max_frequency is None: # Plot high and low frequencies @@ -131,6 +153,9 @@ def plot_pwr0_statistic(cls, records: List[dict], beam_num: int = 0, plt.subplot(2, 1, 2) cls.__plot_pwr0(high_frequency_records, beam_num, statistical_method, False) + data = {'method': statistical_method, + 'high_freq_values': high_frequency_records, + 'low_freq_values': low_frequency_records} else: # plot all frequencies lower than @@ -155,6 +180,9 @@ def plot_pwr0_statistic(cls, records: List[dict], beam_num: int = 0, plt.subplot(2, 1, 2) cls.__plot_pwr0(high_frequency_records, beam_num, statistical_method, False) + data = {'method': statistical_method, + 'high_freq_values': high_frequency_records, + 'low_freq_values': low_frequency_records} elif max_frequency is None: # plot all frequencies between min_frequency and @@ -178,6 +206,9 @@ def plot_pwr0_statistic(cls, records: List[dict], beam_num: int = 0, plt.subplot(2, 1, 2) cls.__plot_pwr0(high_frequency_records, beam_num, statistical_method, False) + data = {'method': statistical_method, + 'high_freq_values': high_frequency_records, + 'low_freq_values': low_frequency_records} # if min=max=split frequency this is the same as # split and compare = False @@ -207,12 +238,23 @@ def plot_pwr0_statistic(cls, records: List[dict], beam_num: int = 0, plt.subplot(2, 1, 2) cls.__plot_pwr0(high_frequency_records, beam_num, statistical_method, False) + data = {'method': statistical_method, + 'high_freq_values': high_frequency_records, + 'low_freq_values': low_frequency_records} else: records_of_interest = cls.\ __apply_stat2pwr0(records, statistical_method, beam_num, '==', split_frequency) cls.__plot_pwr0(records_of_interest, beam_num, statistical_method) + data = {'method': statistical_method, + 'values': records_of_interest} + return {'ax': plt.gca(), + 'ccrs': None, + 'cm': None, + 'cb': None, + 'fig': plt.gcf(), + 'data': data} @staticmethod def __plot_pwr0(records: list, beam_num: int, statistical_method: object, diff --git a/pydarn/plotting/projections.py b/pydarn/plotting/projections.py index d81abf65f..5f6b77b9f 100644 --- a/pydarn/plotting/projections.py +++ b/pydarn/plotting/projections.py @@ -3,9 +3,12 @@ # # Modifications: # 2022-03-11 MTS added enums for projection function calls -# 2022-03-22 MTS removed coastline call and added grid lines to cartopy plotting +# 2022-03-22 MTS removed coastline call and added grid lines to cartopy +# plotting # 2022-05-20 CJM added options to plot coastlines # 2022-06-13 Elliott Day don't create new ax if ax passed in to Projs +# 2023-02-22 CJM added options for nightshade +# 2023-08-11 RR added crude check for unmodified axes, handle both hemispheres # # Disclaimer: # pyDARN is under the LGPL v3 license found in the root directory LICENSE.md @@ -21,15 +24,18 @@ import aacgmv2 import enum import matplotlib.pyplot as plt +from matplotlib import axes import numpy as np from packaging import version -from pydarn import Hemisphere, plot_exceptions +from pydarn import (Hemisphere, plot_exceptions, Re, + nightshade_warning, coast_outline) + try: import cartopy - # from cartopy.mpl import geoaxes import cartopy.crs as ccrs import cartopy.feature as cfeature + from cartopy.feature.nightshade import Nightshade cartopyInstalled = True if version.parse(cartopy.__version__) < version.parse("0.19"): cartopyVersion = False @@ -39,10 +45,37 @@ cartopyInstalled = False -def convert_geo_coastline_to_mag(geom, date, alt: float = 0.0): +def convert_coastline_list_to_mag(geom, date, alt: float = 0.0): + ''' + Takes a list of coastlines and converts + the coordinates into AACGM_MLT + Parameters + ---------- + geom: list + A list/collection of lat lon positions + date: datetime object + Date of required plot + alt: float + Altitude in km + Default 0 (sea level) for coastlines ''' + [mlat, lon_mag, _] = \ + aacgmv2.convert_latlon_arr(geom['lat'], geom['lon'], alt, date, + method_code='G2A') + # Clean Nans (effects plotting) + mlat = mlat[np.logical_not(np.isnan(mlat))] + lon_mag = lon_mag[np.logical_not(np.isnan(lon_mag))] + # Shift to MLT + shifted_mlts = lon_mag[0] - (aacgmv2.convert_mlt(lon_mag[0], date) * 15) + shifted_lons = lon_mag - shifted_mlts + mlon = np.radians(shifted_lons) + return [mlat, mlon] + + +def convert_geo_coastline_to_mag(geom, date, alt: float = 0.0): + """ Takes the geometry object of coastlines and converts - the coordinates into AACGM_MLT for convection maps only + the coordinates into AACGM_MLT Only required usage is for cartopys NaturalEarthFeature at 110m resolution only Parameters @@ -54,9 +87,9 @@ def convert_geo_coastline_to_mag(geom, date, alt: float = 0.0): alt: float Altitude in km Default 0 (sea level) for coastlines - ''' + """ # Iterate over the coordinates and convert to MLT - def convert_to_mag(coords, date, alt): + def convert_to_mag(date, alt): for glon, glat in geom.coords: [mlat, lon_mag, _] = \ aacgmv2.convert_latlon_arr(glat, glon, alt, @@ -66,23 +99,28 @@ def convert_to_mag(coords, date, alt): (aacgmv2.convert_mlt(lon_mag[0], date) * 15) shifted_lons = lon_mag - shifted_mlts mlon = np.radians(shifted_lons) - yield (mlon.item(), mlat.item()) + yield mlon.item(), mlat.item() + # Return geometry object - return type(geom)(list(convert_to_mag(geom.coords, date, alt))) + return type(geom)(list(convert_to_mag(date, alt))) -def axis_polar(date, ax: object = None, lowlat: int = 30, +def axis_polar(date, ax: axes.Axes = None, lowlat: int = 30, hemisphere: Hemisphere = Hemisphere.North, - grid_lines: bool = True, coastline: bool = False, - **kwargs): + coastline: bool = False, + nightshade: int = 0, **kwargs): """ - Plots a radar's Field Of View (FOV) fan plot for the given data and - scan number + Sets up the polar plot matplotlib axis object, for use in + various other functions. Magnetic latitude - magnetic local + time projection. Parameters ----------- - ax: matplotlib.pyplot axis + date: datetime object + Date of required plot. Only required if using coastlines + (for AACGM conversion) + ax: matplotlib.axes.Axes Pre-defined axis object to pass in, must be polar projection Default: Generates a polar projection for the user @@ -90,13 +128,17 @@ def axis_polar(date, ax: object = None, lowlat: int = 30, lowlat: int Lower AACGM latitude boundary for the polar plot Default: 30 - hemiphere: enum + hemisphere: enum Hemisphere of polar projection. Can be Hemisphere.North or - Hemisphere.South for northern and southern hemispheres, + Hemisphere. South for northern and southern hemispheres, respectively Default: Hemisphere.North - grid_lines: bool - required for axis_geological + coastline: bool + Set to true to overlay coastlines with cartopy. Requires + date. + nightshade: int + Altitude above surface for calculating regions shadowed from Sun. + Not supported for this projection. """ if ax is None: @@ -119,38 +161,58 @@ def axis_polar(date, ax: object = None, lowlat: int = 30, # Tick labels will depend on coordinate system ax.set_xticklabels(['00', '', '06', '', '12', '', '18', '']) ax.set_theta_zero_location("S") + else: + if ax.get_ylim() == (0.0, 1.0): + # Set upper and lower latitude limits (pole and lowlat) + if hemisphere == Hemisphere.North: + ax.set_ylim(90, lowlat) + ax.set_yticks(np.arange(lowlat, 90, 10)) + else: + # If hemisphere is South, lowlat must be negative + ax.set_ylim(-90, -abs(lowlat)) + ax.set_yticks(np.arange(-abs(lowlat), -90, -10)) + + if coastline: + if not cartopyInstalled or not cartopyVersion: + # Cartopy not installed, call on the set outlines + for g, geom in enumerate(coast_outline): + [mlat, mlon] = convert_coastline_list_to_mag(geom, date) + plt.plot(mlon, mlat, color='k', linewidth=0.5, zorder=2) + else: + # Read in the geometry object of the coastlines + cc = cfeature.NaturalEarthFeature('physical', 'coastline', '110m', + color='k', zorder=2.0) + # Convert geometry object coordinates to MLT + geom_mag = [] + for geom in cc.geometries(): + geom_mag.append(convert_geo_coastline_to_mag(geom, date)) + cc_mag = cfeature.ShapelyFeature(geom_mag, ccrs.PlateCarree(), + color='k', zorder=2.0) + # Plot each geometry object + for geom in cc_mag.geometries(): + plt.plot(*geom.coords.xy, color='k', linewidth=0.5, zorder=2.0) + + if nightshade: + nightshade_warning() - if coastline is True: - if cartopyInstalled is False: - raise plot_exceptions.CartopyMissingError() - if cartopyVersion is False: - raise plot_exceptions.CartopyVersionError(cartopy.__version__) - # Read in the geometry object of the coastlines - cc = cfeature.NaturalEarthFeature('physical', 'coastline', '110m', - color='k', zorder=2.0) - # Convert geometry object coordinates to MLT - geom_mag = [] - for geom in cc.geometries(): - geom_mag.append(convert_geo_coastline_to_mag(geom, date)) - cc_mag = cfeature.ShapelyFeature(geom_mag, ccrs.PlateCarree(), - color='k', zorder=2.0) - # Plot each geometry object - for geom in cc_mag.geometries(): - plt.plot(*geom.coords.xy, color='k', linewidth=0.5, zorder=2.0) return ax, None -def axis_geological(date, ax: object = None, +def axis_geological(date, ax: axes.Axes = None, hemisphere: Hemisphere = Hemisphere.North, lowlat: int = 30, grid_lines: bool = True, - coastline: bool = False, **kwargs): + coastline: bool = False, nightshade: int = 0, + **kwargs): """ - Plots a radar's Field Of View (FOV) fan plot for the given data and - scan number + + Sets up the cartopy orthographic plot axis object, for use in + various other functions. Geographic projection. Parameters ----------- - ax: matplotlib.pyplot axis + date: datetime object + Date of required plot + ax: matplotlib.axes.Axes Pre-defined axis object to pass in, must be geological projection Default: Generates a geographical projection for the user @@ -158,7 +220,7 @@ def axis_geological(date, ax: object = None, lowlat: int Lower geographic latitude boundary for the geographic plot Default: 30 - hemiphere: enum + hemisphere: enum Hemisphere of geographic projection. Can be Hemisphere.North or Hemisphere.South for northern and southern hemispheres, respectively @@ -166,6 +228,10 @@ def axis_geological(date, ax: object = None, grid_lines: bool add latitude/longtidue lines with labels to the plot Default: True + coastline: bool + Set to true to overlay coastlines with cartopy + nightshade: int + Altitude above surface for calculating regions shadowed from Sun. """ if cartopyInstalled is False: raise plot_exceptions.CartopyMissingError() @@ -178,25 +244,31 @@ def axis_geological(date, ax: object = None, if hemisphere == Hemisphere.North: pole_lat = 90 noon = -deg_from_midnight - ylocations = -5 else: pole_lat = -90 noon = 360 - deg_from_midnight - ylocations = 5 lowlat = -abs(lowlat) + # handle none types or wrongly built axes proj = ccrs.Orthographic(noon, pole_lat) if ax is None: ax = plt.subplot(111, projection=proj, aspect='auto') - if grid_lines: - ax.gridlines(draw_labels=True) - extent = abs(proj.transform_point(noon, lowlat, ccrs.PlateCarree())[1]) - ax.set_extent(extents=(-extent, extent, -extent, extent), crs=proj) + if grid_lines: + ax.gridlines(draw_labels=True) - if coastline is True: + extent = abs(proj.transform_point(noon, lowlat, ccrs.PlateCarree())[1]) + ax.set_extent(extents=(-extent, extent, -extent, extent), crs=proj) + + if coastline: ax.coastlines() + + if nightshade: + refraction_value = -np.degrees(np.arccos(Re / (Re + nightshade))) + ns = Nightshade(date, refraction=refraction_value, alpha=0.1) + ax.add_feature(ns) + return ax, ccrs diff --git a/pydarn/plotting/rtp.py b/pydarn/plotting/rtp.py index cb6bdff7d..7de06c109 100644 --- a/pydarn/plotting/rtp.py +++ b/pydarn/plotting/rtp.py @@ -9,6 +9,8 @@ # 2021-07-06 Carley Martin added keyword to aid in rounding start times # 2022-03-04 Marina Schmidt added RangeEstimations in # 2022-08-04 Carley Martin added elifs for HALF_SLANT options +# 2023-06-12 Carley Martin added coordinate plotting method +# 2023-06-28 Carley Martin refactored return values # # Disclaimer: # pyDARN is under the LGPL v3 license found in the root directory LICENSE.md @@ -30,10 +32,10 @@ import warnings from datetime import datetime, timedelta -from matplotlib import dates, colors, cm, ticker +from matplotlib import dates, colors, colormaps, ticker from typing import List -from pydarn import (RangeEstimation, check_data_type, +from pydarn import (RangeEstimation, check_data_type, Coords, time2datetime, rtp_exceptions, plot_exceptions, SuperDARNCpids, SuperDARNRadars, standard_warning_format, PyDARNColormaps) @@ -58,6 +60,7 @@ class RTP(): plot_range_time plot_time_series plot_summary + plot_coord_time """ def __str__(self): @@ -65,7 +68,8 @@ def __str__(self): " the following methods: \n"\ " - plot_range_time()\n"\ " - plot_time_series()\n"\ - " - plot_summary()\n" + " - plot_summary()\n"\ + " - plot_coord_time()\n" @classmethod def plot_range_time(cls, dmap_data: List[dict], parameter: str = 'v', @@ -154,12 +158,12 @@ def plot_range_time(cls, dmap_data: List[dict], parameter: str = 'v', colorbar_label: str the label that appears next to the color bar Default: '' - cmap: str or matplotlib.cm + cmap: matplotlib.colormaps or str matplotlib colour map https://matplotlib.org/tutorials/colors/colormaps.html Default: PyDARNColormaps.PYDARN_VELOCITY note: to reverse the color just add _r to the string name - plot_filter: dict + filter_settings: dict dictionary of the following keys for filtering data out: max_array_filter : dict dictionary that contains the key parameter names and the values @@ -201,7 +205,7 @@ def plot_range_time(cls, dmap_data: List[dict], parameter: str = 'v', matplotlib object from pcolormesh cb: matplotlib.colorbar matplotlib color bar - cmap: matplotlib.cm + cmap: matplotlib.colormaps matplotlib color map object time_axis: list list representing the x-axis datetime objects @@ -288,8 +292,23 @@ def plot_range_time(cls, dmap_data: List[dict], parameter: str = 'v', break if x != []: # 60.0 seconds in a minute - delta_diff_time = (rec_time - x[-1]) + delta_diff_time = abs(rec_time - x[-1]) diff_time = delta_diff_time.seconds/60.0 + # Abs added above as some files have data out of order + # abs stops the code from hanging and plotting over a day + # of white space, but user needs to be warned that the + # output may be incorrect + if (rec_time - x[-1]) < timedelta(0): + # warnings are turned off for summary plots so + # for now print to console + # May be repeated, but will show what records are out + # of time order by doing so to help user + warnings.warn("Please be aware that the data for" + " timestamp {} contains a record that is not" + " in time order. As such the plot of the" + " data may not be correct, you can solve" + " this by sorting the data stream by date" + " before plotting.".format(rec_time)) # separation roughly 2 minutes if diff_time > 2.0: @@ -395,14 +414,12 @@ def plot_range_time(cls, dmap_data: List[dict], parameter: str = 'v', " options".format(zmax)) norm = norm(zmin, zmax) if isinstance(cmap, str): - cmap = cm.get_cmap(cmap) + cmap = colormaps.get_cmap(cmap) else: - # need to do this as matplotlib 3.5 will - # not all direct mutations of the object - cmaps = {'p_l': copy.copy(cm.get_cmap('plasma')), + cmaps = {'p_l': PyDARNColormaps.PYDARN_PLASMA, 'v': PyDARNColormaps.PYDARN_VELOCITY, 'w_l': PyDARNColormaps.PYDARN_VIRIDIS, - 'elv': PyDARNColormaps.PYDARN} + 'elv': PyDARNColormaps.PYDARN_INFERNO} cmap = cmaps[parameter] # set the background color, this needs to happen to avoid @@ -433,11 +450,14 @@ def plot_range_time(cls, dmap_data: List[dict], parameter: str = 'v', ax.set_ylim(ymin, ymax) - if range_estimation != RangeEstimation.RANGE_GATE: + if (range_estimation != RangeEstimation.RANGE_GATE and + range_estimation != RangeEstimation.TIME_OF_FLIGHT): ax.yaxis.set_ticks(np.arange(np.ceil(ymin/100.0)*100, ymax+1, yspacing)) - else: + elif range_estimation == RangeEstimation.RANGE_GATE: ax.yaxis.set_ticks(np.arange(ymin, ymax+1, (ymax)/5)) + else: + ax.yaxis.set_ticks(np.arange(0, np.ceil(ymax)+1, 5)) # SuperDARN file typically are in 2hr or 24 hr files # to make the minute ticks sensible, the time length is detected @@ -518,7 +538,17 @@ def plot_range_time(cls, dmap_data: List[dict], parameter: str = 'v', cb = colorbar if colorbar_label != '': cb.set_label(colorbar_label) - return im, cb, cmap, x, y, z_data + return {'ax': ax, + 'ccrs': None, + 'cm': cmap, + 'cb': cb, + 'fig': plt.gcf(), + 'data': {'plot_data': im, + 'x': x, + 'y': y, + 'z': z_data} + } + @classmethod def plot_time_series(cls, dmap_data: List[dict], @@ -738,8 +768,8 @@ def plot_time_series(cls, dmap_data: List[dict], my = np.ma.array(y) my = np.ma.masked_where(np.isnan(my), my) - lines = ax.plot_date(x, my, fmt='k', tz=None, xdate=True, - ydate=False, color=color, linestyle=linestyle, + lines = ax.plot_date(x, my, fmt=color, tz=None, xdate=True, + ydate=False, linestyle=linestyle, linewidth=linewidth) if round_start: @@ -807,18 +837,28 @@ def plot_time_series(cls, dmap_data: List[dict], ax.margins(x=0) ax.tick_params(axis='y', which='minor') - return lines, x, y + return {'ax': ax, + 'ccrs': None, + 'cm': None, + 'cb': None, + 'fig': plt.gcf(), + 'data': {'lines': lines, + 'x': x, + 'y': y} + } @classmethod def plot_summary(cls, dmap_data: List[dict], beam_num: int = 0, figsize: tuple = (11, 8.5), - watermark: bool = True, boundary: dict = {}, + watermark: bool = False, boundary: dict = {}, cmaps: dict = {}, lines: dict = {}, plot_elv: bool = True, title=None, background: str = 'w', groundscatter: bool = True, channel: int = 'all', line_color: dict = {}, range_estimation: object = - RangeEstimation.SLANT_RANGE, **kwargs): + RangeEstimation.SLANT_RANGE, + latlon: str = None, coords: object = Coords.AACGM, + **kwargs): """ Plots the summary of several SuperDARN parameters using time-series and range-time plots. Please see Notes for further description @@ -850,6 +890,11 @@ def plot_summary(cls, dmap_data: List[dict], channel number that will be plotted in the summary plot. Default: 'all' + line_color: Dict + dictionary of time series parameters and the line color you + require for each + e.g.: {'nave': 'b', 'tfreq': 'r'} + Default {} (set in code later) range_estimation: RangeEstimation object set the y-axis to a desired range gate estimation calculation @@ -864,10 +909,10 @@ def plot_summary(cls, dmap_data: List[dict], dictionary of matplotlib color maps for the summary range time parameter plots. https://matplotlib.org/tutorials/colors/colormaps.html - Default: {'p_l': 'plasma', + Default: {'p_l': PyDARNColormaps.PYDARN_PLASMA, 'v': PyDARNColormaps.PYDARN_VELOCITY, 'w_l': PyDARNColormaps.PYDARN_VIRIDIS, - 'elv': PyDARNColormaps.PYDARN} + 'elv': PyDARNColormaps.PYDARN_INFERNO} note: to reverse the color just add _r to the string name lines: dict or str dictionary of time-series line colors. @@ -891,6 +936,12 @@ def plot_summary(cls, dmap_data: List[dict], Default: auto-generated by the files details {radar name} {Radar system (if applicable)} Fitacf {version} {start hour/date} - {end hour/date} Beam {number} + coords: Coords + set default coordinate system for the coordinate time plot + default: Coords.AACGM + latlon: str + set which coordinate you want to plot with + default: None kwargs: reflection_height for ground_scatter_mapped method background @@ -927,12 +978,6 @@ def plot_summary(cls, dmap_data: List[dict], - elv : elevation (optional) (range-time) """ - message = "WARNING: matplotlib Default dpi may cause distortion"\ - " in range gates and time period. The figure size can"\ - " be adjusted with the option figsize and dpi can be"\ - " adjusted when saving the file." - warnings.warn(message) - # Default boundary ranges for the various parameter boundary_ranges = {'noise.search': (1e0, 1e5), 'noise.sky': (1e0, 1e5), @@ -952,7 +997,7 @@ def plot_summary(cls, dmap_data: List[dict], color = {'noise.search': 'k', 'noise.sky': 'k', 'tfreq': 'k', - 'nave': 'k'} + 'nave': 'b'} if isinstance(line_color, dict): color.update(line_color) @@ -963,10 +1008,10 @@ def plot_summary(cls, dmap_data: List[dict], line.update(lines) else: line.update({k: lines for k, v in line.items()}) - cmap = {'p_l': 'plasma', + cmap = {'p_l': PyDARNColormaps.PYDARN_PLASMA, 'v': PyDARNColormaps.PYDARN_VELOCITY, 'w_l': PyDARNColormaps.PYDARN_VIRIDIS, - 'elv': PyDARNColormaps.PYDARN} + 'elv': PyDARNColormaps.PYDARN_INFERNO} if isinstance(cmaps, dict): cmap.update(cmaps) else: @@ -1025,13 +1070,10 @@ def plot_summary(cls, dmap_data: List[dict], # plot time-series parameters that share a plot if i < 2: - # with warning catch, catches all the warnings - # that would be produced by time-series this would be - # the citing warning. with warnings.catch_warnings(): - # ignore the warnings because summary plots - # has its own warning message - warnings.simplefilter("ignore") + # Only show the first warning of each type so we don't + # get four of each warnings in summary plots + warnings.simplefilter("once") cls.plot_time_series(dmap_data, beam_num=beam_num, parameter=axes_parameters[i][0], scale=scale, channel=channel, @@ -1063,13 +1105,8 @@ def plot_summary(cls, dmap_data: List[dict], if i == 1: # plot the shared parameter second_ax = axes[i].twinx() - - # with warning catch, catches all the warnings - # that would be produced by time-series this would be - # the citing warning. - # warnings are not caught with try/except with warnings.catch_warnings(): - warnings.simplefilter("ignore") + warnings.simplefilter("once") cls.plot_time_series(dmap_data, beam_num=beam_num, parameter=axes_parameters[ i][1], @@ -1082,7 +1119,8 @@ def plot_summary(cls, dmap_data: List[dict], **kwargs) second_ax.set_xticklabels([]) second_ax.set_ylabel(labels[i][1], rotation=0, - labelpad=25) + labelpad=25, color=color[ + axes_parameters[i][1]]) second_ax.\ axhline(y=boundary_ranges[axes_parameters[i][1]][0] + 0.8, xmin=1.07, xmax=1.13, @@ -1093,6 +1131,14 @@ def plot_summary(cls, dmap_data: List[dict], set_ylim(boundary_ranges[axes_parameters[i][1]][0], boundary_ranges[axes_parameters[i][1]][1]) second_ax.yaxis.set_label_coords(1.1, 0.7) + # Set color of second axis + second_ax.spines["right"].set_edgecolor(color=color[ + axes_parameters[i][1]]) + second_ax.tick_params(axis='y', color=color[ + axes_parameters[i][1]]) + [lab.set_color(color=color[axes_parameters[i][1]]) + for lab in second_ax.yaxis.get_ticklabels()] + if scale == 'log': second_ax.yaxis.\ set_major_locator(ticker. @@ -1107,11 +1153,8 @@ def plot_summary(cls, dmap_data: List[dict], axes[i].set_facecolor(background) # plot cp id elif i == 2: - # with warning catch, catches all the warnings - # that would be produced by time-series this would be - # the citing warning. with warnings.catch_warnings(): - warnings.simplefilter("ignore") + warnings.simplefilter("once") cls.plot_time_series(dmap_data, beam_num=beam_num, channel=channel, parameter=axes_parameters[i], @@ -1122,7 +1165,7 @@ def plot_summary(cls, dmap_data: List[dict], # plot range-time else: # Current standard is to only have groundscatter - # on the velocity plot. + # on the velocity plot. if groundscatter and axes_parameters[i] == 'v': grndflg = True else: @@ -1131,9 +1174,10 @@ def plot_summary(cls, dmap_data: List[dict], # that would be produced by time-series this would be # the citing warning. with warnings.catch_warnings(): - warnings.simplefilter("ignore") - _, cbar, _, x, _, _ =\ - cls.plot_range_time(dmap_data, beam_num=beam_num, + warnings.simplefilter("once") + if latlon is None: + rt_rtn =\ + cls.plot_range_time(dmap_data, beam_num=beam_num, colorbar_label=labels[i], channel=channel, parameter=axes_parameters[i], @@ -1147,6 +1191,25 @@ def plot_summary(cls, dmap_data: List[dict], background=background, range_estimation=range_estimation, **kwargs) + else: + rt_rtn =\ + cls.plot_coord_time(dmap_data, beam_num=beam_num, + colorbar_label=labels[i], + channel=channel, + parameter=axes_parameters[i], + ax=axes[i], groundscatter=grndflg, + cmap=cmap[axes_parameters[i]], + zmin=boundary_ranges[ + axes_parameters[i]][0], + zmax=boundary_ranges[ + axes_parameters[i]][1], + yspacing=5, + background=background, + range_estimation=range_estimation, + coords=coords, latlon=latlon, + **kwargs) + cbar = rt_rtn['cb'] + x = rt_rtn['data']['x'] # Overwriting velocity ticks to get a better pleasing # look on the colorbar # Preference by Marina Schmidt @@ -1164,14 +1227,26 @@ def plot_summary(cls, dmap_data: List[dict], if ticks[-1] > boundary_ranges[axes_parameters[i]][1]: ticks[-1] = boundary_ranges[axes_parameters[i]][1] cbar.set_ticks(ticks) - if range_estimation == RangeEstimation.SLANT_RANGE: + if latlon == 'lat' and coords == Coords.AACGM: + axes[i].set_ylabel('Mag Latitude ($^\circ$)') + elif latlon == 'lon' and coords == Coords.AACGM: + axes[i].set_ylabel('Mag Longitude ($^\circ$)') + elif latlon == 'lat' and coords == Coords.GEOGRAPHIC: + axes[i].set_ylabel('Geo Latitude ($^\circ$)') + elif latlon == 'lon' and coords == Coords.GEOGRAPHIC: + axes[i].set_ylabel('Geo Longitude ($^\circ$)') + elif range_estimation == RangeEstimation.SLANT_RANGE: axes[i].set_ylabel('Slant Range (km)') elif range_estimation == RangeEstimation.GSMR: axes[i].set_ylabel('Ground Scatter\nMapped Range\n(km)') + elif range_estimation == RangeEstimation.GSMR_BRISTOW: + axes[i].set_ylabel('Ground Scatter\nMapped Range\n(km)') elif range_estimation == RangeEstimation.HALF_SLANT: axes[i].set_ylabel('Slant Range/2\n(km)') - else: + elif range_estimation == RangeEstimation.RANGE_GATE: axes[i].set_ylabel('Range Gates') + else: + axes[i].set_ylabel('Time of Flight\n(ms)') if i < num_plots-1: axes[i].set_xticklabels([]) # last plot needs the label on the x-axis @@ -1189,7 +1264,14 @@ def plot_summary(cls, dmap_data: List[dict], color='gray', ha='right', va='top', rotation=-38, alpha=0.3) - return fig, axes + return {'ax': axes, + 'ccrs': None, + 'cm': cmap, + 'cb': None, + 'fig': fig, + 'data': 'Individual range-time plots will return full data.' + } + @classmethod def __generate_title(cls, start_time: datetime, end_time: datetime, @@ -1283,6 +1365,545 @@ def __filter_data_check(cls, dmap_record: dict, return pass_flg + + + @classmethod + def plot_coord_time(cls, dmap_data: List[dict], parameter: str = 'v', + beam_num: int = 0, channel: int = 'all', ax=None, + background: str = 'w', groundscatter: bool = False, + zmin: int = None, zmax: int = None, + coords: object = Coords.AACGM, latlon: str = 'lat', + start_time: datetime = None, end_time: datetime = None, + colorbar: plt.colorbar = None, ymin: int = None, + ymax: int = None, yspacing: int = 2, + range_estimation: RangeEstimation = + RangeEstimation.SLANT_RANGE, + colorbar_label: str = '', + norm=colors.Normalize, cmap: str = None, + filter_settings: dict = {}, + date_fmt: str = '%y/%m/%d\n %H:%M', + round_start: bool = True, + plot_equatorward: bool = False, **kwargs): + """ + Plots a range-time parameter plot of the given + field name in the dmap_data using coordinates in latitude and + longitude for the y-axis + + Future Work + ----------- + Support for other data input, like "time" + dictionary key containing the datetime. However, + further discussion is needed if this will be the keys + name or maybe another input. + + Parameters + ----------- + dmap_data: List[dict] + parameter: str + key name indicating which parameter to plot. + Default: v (Velocity) + beam_num : int + The beam number of data to plot + Default: 0 + channel : int or str + The channel 0, 1, 2, 'all' + Default : 'all' + ax: matplotlib.axes + axes object for another way of plotting + Default: None + groundscatter : boolean or str + Flag to indicate if groundscatter should be plotted. If string + groundscatter will be represented by that color else grey. + Default : False + background : str + color of the background in the plot + default: white + zmin: int + Minimum normalized value + Default: minimum parameter value in the data set + zmax: int + Maximum normalized value + Default: maximum parameter value in the data set + coords: Coords + set default coordinate system for the coordinate time plot + default: Coords.AACGM + latlon: str + set which coordinate in the system you want to plot with + default: latitude 'lat' + ymax: int + Sets the maximum y value + Default: None, uses 'nrang' from data + ymin: int + sets the minimum y value + Default: None, uses 0 range gate or minimum slant-range value + yspacing: int + sets the spacing between ticks + Default: 2 + range_estimation: RangeEstimation + set the y-axis to a desired range estimation calculation + Default: RangeEstimation.SLANT_RANGE + norm: matplotlib.colors.Normalization object + This object use dependency injection to use any normalization + method with the zmin and zmax. + Default: colors.Normalization() + start_time: datetime + Start time of the plot x-axis as a datetime object + Default: rounded to nearest hour-30 minutes from the first + record containing the chosen parameters data + end_time: datetime + End time of the plot x-axis as a datetime object + Default: last record of the chosen parameters data + date_fmt : str + format of x-axis date ticks, follow datetime format + Default: '%y/%m/%d\n %H:%M' (Year/Month/Day Hour:Minute) + colorbar: matplotlib.pyplot.colorbar + Setting a predefined colorbar for the range-time plot + If None, then a colorbar will be created for the plot + Default: None + colorbar_label: str + the label that appears next to the color bar + Default: '' + cmap: str or matplotlib.cm + matplotlib colour map + https://matplotlib.org/tutorials/colors/colormaps.html + Default: PyDARNColormaps.PYDARN_VELOCITY + note: to reverse the color just add _r to the string name + filter_settings: dict + dictionary of the following keys for filtering data out: + max_array_filter : dict + dictionary that contains the key parameter names and the values + to compare against. Will filter out any data points + that is above this value. + min_array_filter : dict + dictionary that contains the key parameter names and the value + to compare against. Will filter out any data points that is + below this value. + max_scalar_filter : dict + dictionary that contains the key parameter names and the values + to compare against. Will filter out data sections that is + above this value. + min_scalar_filter : dict + dictionary that contains the key parameter names and the value + to compare against. Will filter out data sections + that is below this value. + equal_scalar_filter : dict + dictionary that contains the key parameter names and the value + to compare against. Will filter out data sections + that is does not equal the value. + round_start: bool=True + option to round the start time to give tick at start of xaxis + Set True to round, set False to plot from start of data. + Default: True + plot_equatorward: bool = False + option if the radar plots data in latitude that changes + direction to plot the equator-ward or pole-ward data + No option to overplot. + Default: False (plot poleward data only) + kwargs: + used for other methods in pyDARN + - reflection_height + Raises + ------ + UnknownParameterError + IncorrectPlotMethodError + NoDataFoundError + IndexError + + Returns + ------- + im: matplotlib.pyplot.pcolormesh + matplotlib object from pcolormesh + cb: matplotlib.colorbar + matplotlib color bar + cmap: matplotlib.cm + matplotlib color map object + time_axis: list + list representing the x-axis datetime objects + y_axis: list + list representing the y-axis range gates + z_data: 2D numpy array + 2D array of the parameters values at the given time and range gate + + See Also + --------- + colors: https://matplotlib.org/2.0.2/api/colors_api.html + color maps: PyDARNColormaps or + https://matplotlib.org/tutorials/colors/colormaps.html + normalize: + https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.colors.Normalize.html + colorbar: + https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.colorbar.html + pcolormesh: + https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.pcolormesh.html + + """ + # Settings + plot_filter = {'min_array_filter': dict(), + 'max_array_filter': dict(), + 'min_scalar_filter': dict(), + 'max_scalar_filter': dict(), + 'equal_scalar_filter': dict()} + + plot_filter.update(filter_settings) + + # If an axes object is not passed in then store + # the equivalent object in matplotlib. This allows + # for variant matplotlib plotting styles. + if not ax: + ax = plt.gca() + + # Determine if a DmapRecord was passed in, instead of a list + try: + # because of partial records we need to find the first + # record that has that parameter + index_first_match = next(i for i, d in enumerate(dmap_data) + if parameter in d) + except StopIteration: + raise plot_exceptions.UnknownParameterError(parameter) + cls.dmap_data = dmap_data + check_data_type(cls.dmap_data, parameter, 'array', index_first_match) + start_time, end_time = cls.__determine_start_end_time(start_time, + end_time) + + # y-axis coordinates, i.e., range gates, + # TODO: implement variant other coordinate systems for the y-axis + # y shape needs to be +1 longer as requirement of how pcolormesh + # draws the pixels on the grid + + # because nrang can change based on mode we need to look + # for the largest value + y_max = max(record['nrang'] for record in cls.dmap_data) + y = np.arange(0, y_max+1, 1) + + # z: parameter data mapped into the color mesh + z = np.zeros((1, y_max)) * np.nan + + # x: time date data + x = [] + + # We cannot simply use numpy's built in min and max function + # because of the groundscatter value :( + + # These flags indicate if zmin and zmax should change + set_zmin = True + set_zmax = True + if zmin is None: + zmin = cls.dmap_data[index_first_match][parameter][0] + set_zmin = False + if zmax is None: + zmax = cls.dmap_data[index_first_match][parameter][0] + set_zmax = False + + for dmap_record in cls.dmap_data: + # get time difference to test if there is some gap data + rec_time = time2datetime(dmap_record) + diff_time = 0.0 + if rec_time > end_time: + break + if x != []: + # 60.0 seconds in a minute + delta_diff_time = abs(rec_time - x[-1]) + diff_time = delta_diff_time.seconds/60.0 + # Abs added above as some files have data out of order + # abs stops the code from hanging and plotting over a day + # of white space, but user needs to be warned that the + # output may be incorrect + if (rec_time - x[-1]) < timedelta(0): + # warnings are turned off for summary plots so + # for now print to console + # May be repeated, but will show what records are out + # of time order by doing so to help user + print("Please be aware that the data for timestamp {}" + " contains a record that is not" + " in time order. As such the plot of the" + " data may not be correct, you can solve" + " this by sorting the data stream by date" + " before plotting.".format(rec_time)) + + + # separation roughly 2 minutes + if diff_time > 2.0: + # if there is gap data (no data recorded past 2 minutes) + # then fill it in with white space + for _ in range(0, int(np.floor(diff_time/2.0))): + x.append(x[-1] + timedelta(0, 120)) + i = len(x) - 1 # offset since we start at 0 not 1 + if i > 0: + z = np.insert(z, len(z), np.zeros(1, y_max) * np.nan, + axis=0) + # Get data for the provided beam number + if (beam_num == 'all' or dmap_record['bmnum'] == beam_num) and\ + (channel == 'all' or + dmap_record['channel'] == channel): + if start_time <= rec_time: + # construct the x-axis array + # Numpy datetime is used because it properly formats on the + # x-axis + x.append(rec_time) + # I do this to avoid having an extra loop to just count how + # many records contain the beam number + i = len(x) - 1 # offset since we start at 0 not 1 + + # insert a new column into the z_data + if i > 0: + z = np.insert(z, len(z), np.zeros(1, y_max) * np.nan, + axis=0) + try: + if len(dmap_record[parameter]) == dmap_record['nrang']: + good_gates = range(len(dmap_record[parameter])) + else: + good_gates = dmap_record['slist'] + + # get the range gates that have "good" data in it + for j in range(len(good_gates)): + # if it is groundscatter store a very + # low number in that cell + if groundscatter and\ + dmap_record['gflg'][j] == 1: + # chosen value from davitpy to make the + # groundscatter a different color + # from the color map + z[i][good_gates[j]] = -1000000 + # otherwise store parameter value + # TODO: refactor and clean up this code + elif cls.__filter_data_check(dmap_record, + plot_filter, j): + z[i][good_gates[j]] = \ + dmap_record[parameter][j] + # calculate min and max value + if not set_zmin and\ + z[i][good_gates[j]] < zmin: + zmin = z[i][good_gates[j]] + if not set_zmax and \ + z[i][good_gates[j]] > zmax: + zmax = z[i][good_gates[j]] + # a KeyError may be thrown because slist is not created + # due to bad quality data. + except KeyError: + continue + x.append(end_time) + # Check if there is any data to plot + if np.all(np.isnan(z)): + raise plot_exceptions.\ + NoDataFoundError(parameter, beam_num, + start_time=start_time, + end_time=end_time, + opt_beam_num=cls.dmap_data[0]['bmnum']) + + frang = int(cls.dmap_data[0]['frang']) + rsep = int(cls.dmap_data[0]['rsep']) + + # MLT is not applicable for plotting + if coords == Coords.AACGM_MLT: + raise Exception("Error: MLT cannot be used in coord-time plots. " + "Please choose Coords from AACGM or GEOGRAPHIC.") + # Get position of the range gates in lat lon + lats,lons = coords(stid=dmap_data[0]['stid'], rsep=rsep, frang=frang, + date=start_time, center=False, + gates=[0, dmap_data[0]['nrang']], + range_estimation=range_estimation, **kwargs) + + if latlon == 'lat': + y = lats[:, beam_num] + # If the FOV is over the pole, only plot up to the pole to avoid + # overplotting data unless the user specifies downward + if y[0] > 0: + diff_y = [j-i for i, j in zip(y[:-1], y[1:])] + else: + # If southern hemisphere, just switch diff_y values to get + # correct position + diff_y = [-(j-i) for i, j in zip(y[:-1], y[1:])] + + if any(x < 0 for x in diff_y) and not plot_equatorward: + yind = np.min([i for i in range(len(diff_y)) if diff_y[i] < 0]) - 1 + warnings.warn('Warning: This radar has a field of view that over' + 'plots data in latitude. Only the partial ' + 'field of view to range gate ' + '{} is plotted. To see the other section of data ' + 'use the keyword plot_equatorward=True.' + .format(yind,)) + y = y[:yind] + y = np.append(y, y[-1]) + z = z[:, :yind] + if any(x < 0 for x in diff_y) and plot_equatorward: + yind = np.min([i for i in range(len(diff_y)) if diff_y[i] < 0]) -1 + warnings.warn('Warning: This radar has a field of view that over' + 'plots data in latitude. Only the partial ' + 'field of view from range gate ' + '{} is plotted. To see the other section of data ' + 'use the keyword plot_equatorward=False.' + .format(yind)) + y = y[yind-1:] + z = z[:, yind-1:] + elif latlon == 'lon': + y = lons[:, beam_num] + else: + raise Exception('Error: latlon values can be "lat" or "lon" only.') + + time_axis, y_axis = np.meshgrid(x, y) + z_data = np.ma.masked_where(np.isnan(z.T), z.T) + Default = {'noise.sky': (1e0, 1e5), + 'tfreq': (8, 22), + 'nave': (0, 60), + 'p_l': (0, 45), + 'v': (-200, 200), + 'w_l': (0, 250), + 'elv': (0, 45)} + + if np.isinf(zmin) and zmin < 0: + zmin = Default[parameter][0] + warnings.warn("Warning: zmin is -inf, set zmin to {}. You can" + "set zmin and zmax in the function" + " options".format(zmin)) + if np.isinf(zmax) and zmax > 0: + zmax = Default[parameter][1] + warnings.warn("Warning: zmax is inf, set zmax to {}. You can" + "set zmin and zmax in the functions" + " options".format(zmax)) + norm = norm(zmin, zmax) + if isinstance(cmap, str): + cmap = colormaps.get_cmap(cmap) + else: + # need to do this as matplotlib 3.5 will + # not all direct mutations of the object + cmaps = {'p_l': copy.copy(colormaps.get_cmap('plasma')), + 'v': PyDARNColormaps.PYDARN_VELOCITY, + 'w_l': PyDARNColormaps.PYDARN_VIRIDIS, + 'elv': PyDARNColormaps.PYDARN} + cmap = cmaps[parameter] + + # set the background color, this needs to happen to avoid + # the overlapping problem that occurs + cmap.set_bad(color=background, alpha=1.) + # plot! + im = ax.pcolormesh(time_axis, y_axis, z_data, lw=0.01, + cmap=cmap, norm=norm, **kwargs) + + if isinstance(groundscatter, str): + ground_scatter = np.ma.masked_where(z_data != -1000000, z_data) + gs_color = colors.ListedColormap([groundscatter]) + ax.pcolormesh(time_axis, y_axis, ground_scatter, lw=0.01, + cmap=gs_color, norm=norm, **kwargs) + + elif groundscatter: + ground_scatter = np.ma.masked_where(z_data != -1000000, z_data) + gs_color = colors.ListedColormap(['grey']) + ax.pcolormesh(time_axis, y_axis, ground_scatter, lw=0.01, + cmap=gs_color, norm=norm, **kwargs) + + # setup some standard axis information + if ymax is None: + ymax = np.max(y) + + if ymin is None: + ymin = np.min(y) + + ax.set_ylim(ymin, ymax) + if yspacing != 2: + ax.yaxis.set_ticks(np.arange(np.floor(ymin), np.ceil(ymax), + yspacing)) + elif ymax-ymin < 100: + ax.yaxis.set_ticks(np.arange(np.floor(ymin), np.ceil(ymax), + yspacing)) + else: + ax.yaxis.set_ticks(np.arange(np.floor(ymin/10)*10, + np.ceil(ymax/10)*10, + yspacing*5)) + + # SuperDARN file typically are in 2hr or 24 hr files + # to make the minute ticks sensible, the time length is detected + # then a interval is picked. 30 minute ticks for 24 hr plots + # and 5 minute ticks for 2 hour plots. + data_time_length = end_time - start_time + # 3 hours * 60 minutes * 60 seconds + if data_time_length.total_seconds() > 3*60*60: + tick_interval = 30 + else: + tick_interval = 1 + # byminute keyword makes sure that the ticks are situated at + # the minute or half hour marks, rather than at a set interval + ax.xaxis.set_minor_locator( + dates.MinuteLocator(byminute=range(0, 60, tick_interval))) + + # Upon request of Daniel Billet and others, I am rounding + # the time down so the plotting x-axis will show the origin + # time label + # Updated to give option to round down and make sure + # rounding to same frequency as plot axis ticks if less than 1 hour + if round_start: + major_locator, _ = plt.xticks() + dt = dates.num2date(major_locator[1]) -\ + dates.num2date(major_locator[0]) + tick_sep = dt.seconds//60 + if tick_sep > 0: + rounded_down_start_time = x[0] -\ + timedelta(minutes=x[0].minute % tick_sep, + seconds=x[0].second, + microseconds=x[0].microsecond) + else: + rounded_down_start_time = x[0] -\ + timedelta(minutes=x[0].minute % 15, + seconds=x[0].second, + microseconds=x[0].microsecond) + else: + rounded_down_start_time = x[0] + + ax.set_xlim([rounded_down_start_time, x[-1]]) + ax.xaxis.set_major_formatter(dates.DateFormatter(date_fmt)) + # Make sure the axis flips with pole at the top for southern data + if y[0] < 0 and latlon == 'lat': + ax.invert_yaxis() + + if range_estimation != RangeEstimation.RANGE_GATE: + ax.yaxis.set_minor_locator(ticker.AutoMinorLocator(2)) + else: + ax.yaxis.set_minor_locator(ticker.MultipleLocator(5)) + # so the plots gets to the ends + ax.margins(0) + + # Create color bar if None supplied + if not colorbar: + with warnings.catch_warnings(): + warnings.filterwarnings('error') + try: + if isinstance(norm, colors.LogNorm): + if zmin == 0: + cb = ax.figure.colorbar(im, ax=ax, extend='max') + else: + cb = ax.figure.colorbar(im, ax=ax, extend='both') + else: + locator = ticker.MaxNLocator(symmetric=True, + min_n_ticks=3, + integer=True, + nbins='auto') + ticks = locator.tick_values(vmin=zmin, vmax=zmax) + if zmin == 0: + cb = ax.figure.colorbar(im, ax=ax, extend='max', + ticks=ticks) + else: + cb = ax.figure.colorbar(im, ax=ax, extend='both', + ticks=ticks) + + except (ZeroDivisionError, Warning): + raise rtp_exceptions.RTPZeroError(parameter, beam_num, + zmin, zmax, + norm) from None + else: + cb = colorbar + if colorbar_label != '': + cb.set_label(colorbar_label) + return {'ax': ax, + 'ccrs': None, + 'cm': cmap, + 'cb': cb, + 'fig': plt.gcf(), + 'data': {'plot_data': im, + 'x': x, + 'y': y, + 'z': z_data} + } + + # TODO: if used in other plotting methods then this should moved to # utils @classmethod diff --git a/pydarn/utils/citations.py b/pydarn/utils/citations.py new file mode 100644 index 000000000..c58f99c8a --- /dev/null +++ b/pydarn/utils/citations.py @@ -0,0 +1,79 @@ +# (C) Copyright SuperDARN Canada, University of Saskatchewan +# Author: Carley Martin +# +# Disclaimer: +# pyDARN is under the LGPL v3 license found in the root directory LICENSE.md +# Everyone is permitted to copy and distribute verbatim copies of this license +# document, but changing it is not allowed. +# +# This version of the GNU Lesser General Public License incorporates the terms +# and conditions of version 3 of the GNU General Public License, +# supplemented by the additional permissions listed below. +# +# Modifications: +# + + +class Citations(): + ''' + A class to contain the different citations for pyDARN use + + Parameters + ---------- + citations with format authorYYYY = str + ''' + # Groundscatter equation + bristow1994 = 'Bristow, W. A. et al, 1994, 10.1029/93JA01470 \n' + # AACGMv3 Wrapper: + burrell2023 = 'Burrell, A. G. et al, 2023, 10.5281/zenodo.7621545 \n' + # Cartopy: + cartopy2015 = 'Met Office, 2010-2015, scitools.org.uk/cartopy \n' + # Chisham model/ Standard model: + chisham2008 = 'Chisham, G. 2008, 10.5194/angeo-26-823-2008 \n' + #pydarn citation: + pydarn2023 = 'DVWG, 2023, 10.5281/zenodo.3727269 \n' + #pydarnio citation: + pydarnio2023 = 'DVWG, 2023, 10.5281/zenodo.4009470 \n' + # AACGMv2 Paper: + shepherd2014 = 'Shepherd, S. G., 2014, 10.1002/2014JA020264 \n' + # elevation angle claculations: + shepherd2017 = 'Shepherd, S. G., 2017, 10.1002/2017RS006348 \n' + # GSMR Options: + thomas2022 = 'Thomas, E. G. et al, 2022, 10.1029/2022RS007429 \n' + + + @classmethod + def print_citations(self): + print("\nIf using pyDARN produced plots in publications please be " + "aware of the following citations that may have been used to" + " produce your plot and should be included in your publication:" + "\n\n", + "Ground Scatter Mapped Range: ", self.bristow1994, + "AACGMv2 Wrapper: ", self.burrell2023, + "Chisham Virtual Height Model:", self.chisham2008, + "pyDARN Software: ", self.pydarn2023, + "pyDARNio Software: ", self.pydarnio2023, + "Cartopy: ", self.cartopy2015, + "AACGMv2 article: ", self.shepherd2014, + "Elevation Angle Calculations:", self.shepherd2017, + "Ground Scatter Mapped Range: ", self.thomas2022, + "\nFurther information can be found at" + " https://pydarn.readthedocs.io/en/main/user/citing/\n") + + + @classmethod + def print_acknowledgements(self): + print("\nAcknowledgement required for SuperDARN data use:\n\n" + "\x1B[3m" + "The authors acknowledge the use of SuperDARN data. " + "SuperDARN is a collection of radars funded by " + "national scientific funding agencies of Australia, " + "Canada, China, France, Italy, Japan, Norway, South " + "Africa, United Kingdom and the United States of " + "America." + "\x1B[0m \n\n" + "During your study, if using data from individual " + "radars only, please contact the Principal Investigator " + "(PI) of that radar about potential co-authorship or " + "appropriate acknowledgments." + "\n") diff --git a/pydarn/utils/const.py b/pydarn/utils/const.py deleted file mode 100644 index b4117cc0f..000000000 --- a/pydarn/utils/const.py +++ /dev/null @@ -1,18 +0,0 @@ -# (C) Copyright SuperDARN Canada, University of Saskatchewan -# Author: Marina Schmidt -# -# Disclaimer: -# pyDARN is under the LGPL v3 license found in the root directory LICENSE.md -# Everyone is permitted to copy and distribute verbatim copies of this license -# document, but changing it is not allowed. -# -# This version of the GNU Lesser General Public License incorporates the terms -# and conditions of version 3 of the GNU General Public License, -# supplemented by the additional permissions listed below. -# -# Modifications: -# - -#TODO: what should this be? Should we have both as one is equatorial? -EARTH_RADIUS = 6378.137 - diff --git a/pydarn/utils/coordinates.py b/pydarn/utils/coordinates.py index 363b3b5ec..e2a83b381 100644 --- a/pydarn/utils/coordinates.py +++ b/pydarn/utils/coordinates.py @@ -13,6 +13,7 @@ # Modifications: # 2022-03-10 MTS added 4 new methods to generate coordinates for the various # enums +# 2023-08-26 CJM corrected calculations to use bmoff and removed abs() # """ @@ -102,13 +103,13 @@ def convert2MLT(lons: float, date: object, **kwargs): return beam_corners_mlts -# RPosGeo line 335 def gate2geographic_location(stid: int, beam: int, height: float = None, - elv_angle: float = 0.0, center: bool = True, + elv_angle: float = 0.0, center: bool = False, range_estimation: RangeEstimation = RangeEstimation.SLANT_RANGE, **kwargs): """ determines the geographic cell position for a given range gate and beam + Notes: From RPosGeo line 335 parameters ---------- @@ -116,16 +117,6 @@ def gate2geographic_location(stid: int, beam: int, height: float = None, station id of the radar to use beam: int beam number (indexing at 0) - range_gate: int - range gate number (indexing at 0) - rsep: int - range seperation, determined by the mode the - radar is using, in [km] - default: 45 - normalscan mode - frang: int - frequency range from the radar to the front edge of the range gate - Please note: this definition may be changed, currently defined in - RST code to keep consistency height: float transmutation height [km] default: none @@ -135,8 +126,9 @@ def gate2geographic_location(stid: int, beam: int, height: float = None, default: 0 center: bool obtain geographic location of the centre of the range gates - False obtains the front edge of the range gates. - default: True + False obtains the near-left corner of the range gates. + See also: gate2slant in range_estimation module + default: False (return corner values) returns ------- @@ -153,34 +145,40 @@ def gate2geographic_location(stid: int, beam: int, height: float = None, # too much converting back and forth. boresight = np.radians(SuperDARNRadars. radars[stid].hardware_info.boresight.physical) + bmoff = np.radians(SuperDARNRadars. + radars[stid].hardware_info.boresight.electronic) radar_lat = np.radians(SuperDARNRadars. radars[stid].hardware_info.geographic.lat) radar_lon = np.radians(SuperDARNRadars. radars[stid].hardware_info.geographic.lon) - # Some beam seperations are negative which changes how the coordinates wrap - # we absolute to make it easier of fov-color for cartopy plotting - beam_sep = np.radians(abs(SuperDARNRadars. - radars[stid].hardware_info.beam_separation)) + # Note that some beam separations are negative + beam_sep = np.radians(SuperDARNRadars. + radars[stid].hardware_info.beam_separation) rxrise = SuperDARNRadars.radars[stid].hardware_info.rx_rise_time - # TODO: fix after slant range change - if center is True: - # beam edge in [rad] - beam_edge = -beam_sep * 0.5 - # range_edge in [km] - else: + # If the user wants the edge corner of the range gate: + # Radar outwards direction center value is corrected in + # range_estimation module + if center: beam_edge = 0 + else: + beam_edge = -beam_sep * 0.5 # psi [rad] in the angle from the boresight - psi = beam_sep * (beam - offset) + beam_edge + psi = beam_sep * (beam - offset) + beam_edge + bmoff # Calculate the slant range [km] - if range_estimation != RangeEstimation.RANGE_GATE: - target_range = range_estimation(rxrise=rxrise, **kwargs) + if range_estimation == RangeEstimation.RANGE_GATE: + raise radar_exceptions.RangeEstimationError("Range gates cannot be " + "used in to estimate " + "distance. Try SLANT_RANGE" + " instead.") + elif range_estimation == RangeEstimation.TIME_OF_FLIGHT: + raise radar_exceptions.RangeEstimationError("Time of flight cannot be " + "used in to estimate " + "distance. Try SLANT_RANGE" + " instead.") else: - raise radar_exceptions.RangeEstimationError("Range Gates cannot be" - "used in estimating the" - " km for geographic" - " coordinates systems") + target_range = range_estimation(rxrise=rxrise, **kwargs) # If no height is specified then use elevation angle (default 0) # to calculate the transmutation height diff --git a/pydarn/utils/filters.py b/pydarn/utils/filters.py new file mode 100644 index 000000000..072f402ca --- /dev/null +++ b/pydarn/utils/filters.py @@ -0,0 +1,512 @@ +# Copyright (C) 2023 SuperDARN Canada, University of Saskatchewan +# Author: Shibaji Chakraborty +# +# Modifications: +# 20230202 - CJM: Integrate code into pyDARN +# +# Disclaimer: +# pyDARN is under the LGPL v3 license found in the root directory LICENSE.md +# Everyone is permitted to copy and distribute verbatim copies of this license +# document, but changing it is not allowed. +# +# This version of the GNU Lesser General Public License incorporates the terms +# and conditions of version 3 of the GNU General Public License, +# supplemented by the additional permissions listed below. + + +"""filters.py: Module is dedicated to filters used on FITACF SuperDARN data.""" + +import copy +import datetime as dt +import numpy as np +import warnings + +from pydarn import standard_warning_format + +warnings.formatwarning = standard_warning_format + +class Gate(object): + """Class object to hold each range cell value + + Methods + ------- + NA + """ + def __init__(self, bm, i, params=["v", "w_l", "gflg", "p_l", "v_e", "elv"], + gflg_type=-1): + """ + Initialize the parameters which will be stored in Gate + Parameters + ---------- + bm : beam object + A collection of data from the filtering process + i : int + Index to store in collection + params : + Parameters to store in collection + Returns + ------- + NA + """ + for p in params: + if len(getattr(bm, p)) > i: + setattr(self, p, getattr(bm, p)[i]) + else: + setattr(self, p, np.nan) + if gflg_type >= 0 and len(getattr(bm, "gsflg")[gflg_type]) > 0: + setattr(self, "gflg", getattr(bm, "gsflg")[gflg_type][i]) + return + + +class Beam(object): + """Class to hold one radar beam + + Methods + ------- + set + copy + """ + def __init__(self): + """ Initialize the instance """ + return + + def set(self, time, d, + s_params=["bmnum", "noise.sky", "tfreq", "scan", "nrang"], + v_params=["v", "w_l", "gflg", "p_l", "slist", "v_e", "elv"], k=None): + """ + Parameters + ---------- + time : datetime object + Time of data in beam + d : Dict + Containing data for other parameters in beam + s_params : list + Other scalar params + v_params : list + Other vector params + """ + for p in s_params: + if p in d.keys(): + if p == "scan" and d[p] != 0: + setattr(self, p, 1) + else: + setattr(self, p, d[p]) if k is None else setattr(self, p, + d[p][k]) + else: + setattr(self, p, None) + for p in v_params: + if p in d.keys(): + setattr(self, p, d[p]) + else: + setattr(self, p, []) + self.time = time + return + + def copy(self, bm): + """Copy all parameters""" + for p in bm.__dict__.keys(): + setattr(self, p, getattr(bm, p)) + return + + +class Scan(object): + """Class to hold one radar scans + + Methods + ------- + update_time + """ + def __init__(self): + """ Initialize the instance """ + self.beams = [] + return + + def update_time(self): + """ + Update stime and etime of the scan. + """ + if len(self.beams) > 0: + self.stime = min([b.time for b in self.beams]) + self.etime = max([b.time for b in self.beams]) + self.scan_time = 60 * np.rint((self.etime - self.stime) + .total_seconds() / 60) + return + + +class FetchData(object): + """Class to fetch data from fitacf files + + Methods + ------- + parse_data + """ + def __init__(self, beam_sounds): + """ + Initialize the variables in a fitacf file + """ + self.beam_sounds = beam_sounds + self.s_params = [ + "bmnum", + "noise.sky", + "tfreq", + "scan", + "nrang", + "intt.sc", + "intt.us", + "mppul", + "rsep", + "cp", + "frang", + "smsep", + "lagfr", + "channel", + "mplgs", + "nave", + "noise.search", + "mplgexs", + "xcf", + "noise.mean", + "ifmode", + "bmazm", + "rxrise", + "mpinc", + ] + self.v_params = ["v", "w_l", "gflg", "p_l", "slist", "v_e", "elv"] + self.scans, self.beams = [], [] + return + + def parse_data(self, by="scan"): + """ + Parse data by data type + + Parameters + ---------- + by: str + "scan" - no other options for now + + Returns + ------- + NA + """ + for d in self.beam_sounds: + time = dt.datetime( + d["time.yr"], + d["time.mo"], + d["time.dy"], + d["time.hr"], + d["time.mt"], + d["time.sc"], + d["time.us"] + ) + bm = Beam() + bm.set(time, d, self.s_params, self.v_params) + self.beams.append(bm) + if by == "scan": + sc = Scan() + sc.beams.append(self.beams[0]) + for _ix, d in enumerate(self.beams[1:]): + if d.scan == 1: + sc.update_time() + self.scans.append(sc) + del sc + sc = Scan() + sc.beams.append(d) + else: + sc.beams.append(d) + self.scans.append(sc) + return + + +class Boxcar(object): + """Class to filter data - Boxcar median filter. + + Methods + ------- + format_data_for_pydarn + run_filter + __discard_repeating_beams__ + __do_filter__ + """ + def __init__(self, thresh=0.7, w=None, gflg_type=-1): + """ + Initialize variables + + Parameters + ---------- + thresh: float + Threshold of the weight matrix + w: list(list) + Weight matrix + pbnd: float + Lower and upper bounds of IS / GS probability + pth: float + Probability of the threshold + + Returns + ------- + NA + """ + self.thresh = thresh + if w is None: + w = np.array( + [ + [[1, 2, 1], [2, 3, 2], [1, 2, 1]], + [[2, 3, 2], [3, 5, 3], [2, 3, 2]], + [[1, 2, 1], [2, 3, 2], [1, 2, 1]], + ] + ) + self.w = w + self.gflg_type = gflg_type + return + + def format_data_for_pydarn(self, original_data): + """ + Place filtered data into original data structure for pyDARN + only changing the data fields that were filtered + + Parameters + ---------- + original_data: List[Dict] + List of SuperDARN fitacf data + + Returns + ------- + NA + """ + # Deep copy original fitacf data + self.copied_data = copy.deepcopy(original_data) + # For each record in the fitacf data, find matching time in + # filtered data, replace with the new filtered data + for r, record in enumerate(original_data): + # Track to see if match is found or not + match_found = False + record_time = dt.datetime(record["time.yr"], record["time.mo"], + record["time.dy"], record["time.hr"], + record["time.mt"], record["time.sc"], + record["time.us"]) + for frec in self.filtered_data["beam_sounds"]: + if record_time == frec['time']: + match_found = True + if not bool(frec['slist']): + # If new data is empty remove it from dictionary + self.copied_data[r].pop('slist', None) + self.copied_data[r].pop('v', None) + self.copied_data[r].pop('w_l', None) + self.copied_data[r].pop('p_l', None) + self.copied_data[r].pop('elv', None) + self.copied_data[r].pop('gflg', None) + else: + # Replace the data with new filtered data if there is + # new data to replace it + self.copied_data[r]['slist'] = np.array(frec['slist']) + self.copied_data[r]['v'] = np.array(frec['v']) + self.copied_data[r]['w_l'] = np.array(frec['w_l']) + self.copied_data[r]['p_l'] = np.array(frec['p_l']) + self.copied_data[r]['elv'] = np.array(frec['elv']) + self.copied_data[r]['gflg'] = np.array(frec['gflg']) + # If no match is found for the record, then + # empty the fields, new data needs to be empty + if not match_found: + self.copied_data[r].pop('slist', None) + self.copied_data[r].pop('v', None) + self.copied_data[r].pop('w_l', None) + self.copied_data[r].pop('elv', None) + self.copied_data[r].pop('gflg', None) + return + + def run_filter(self, beam_sounds, cpus=1): + """ + Set data and convert to scan objects + + Parameters + ---------- + beam_sounds: List[Dict] + List of SuperDARN fitacf data + cpus: int + Number of cpus available/rdesired + to run in parallel (UNUSED) + + Returns + ------- + copied_data: List[Dict] + List of dictionaries that contain + the new filtered data + """ + warnings.warn('The boxcar filter may take 5-10 minutes to filter a ' + + 'two hour FITACF file. For more information on this ' + + 'filter see the documentation at ' + + 'https://pydarn.readthedocs.io/en/main/') + warnings.warn('The boxcar filter may not be applicable to all data, '+ + 'for example, the boxcar filter should not be applied '+ + 'to twofsound data.') + fd = FetchData(beam_sounds) + fd.parse_data() + self.scan_stacks = [fd.scans[i - 1: i + 2] + for i in range(1, len(fd.scans) - 1)] + self.filtered_data = {"scans": [], "beams": [], "beam_sounds": []} + if cpus > 1: + # TODO: Parallel processing options + # ray.init(num_cpus=cpus) + # futures = [ + # self.bx.doFilter.remote(scan_stack, comb=comb, + # gflg_type=gflg_type) + # for scan_stack in scan_stacks + # ] + # self.filtered_data["scans"] = ray.get(futures) + pass + else: + from collections import OrderedDict + scans = [ + self.__do_filter__(scan_stack) + for scan_stack in self.scan_stacks + ] + beams = [] + for s in scans: + beams.extend(s.beams) + self.filtered_data["scans"] = scans + self.filtered_data["beams"] = beams + self.filtered_data["beam_sounds"] = [ + OrderedDict([(k, getattr(b, k)) for k in b.__dict__.keys()]) + for b in beams + ] + # Format the data for pyDARN plotting and return the new + # filtered version of the fitacf data + self.format_data_for_pydarn(beam_sounds) + return self.copied_data + + def __discard_repeating_beams__(self, scan, ch=True): + """ + Discard all more than one repeating beams + + Parameters + ---------- + scan: Object + Object containing a single SuperDARN scan + + Returns + ------- + oscan: Object + Object containing a single SuperDARN scan + without repeating beams + """ + oscan = Scan() + if ch: + scan.beams = sorted(scan.beams, key=lambda bm: (bm.bmnum)) + else: + scan.beams = sorted(scan.beams, key=lambda bm: (bm.bmnum, bm.time)) + bmnums = [] + for bm in scan.beams: + if bm.bmnum not in bmnums: + if hasattr(bm, "slist") and len(getattr(bm, "slist")) > 0: + oscan.beams.append(bm) + bmnums.append(bm.bmnum) + if len(oscan.beams) > 0: + oscan.update_time() + oscan.beams = sorted(oscan.beams, key=lambda bm: bm.bmnum) + return oscan + + def __do_filter__(self, scans, params_to_run_filter=["v", "w_l", + "p_l", "elv"]): + """ + Median filter based on the weight given by matrix (3X3X3) weight, + and threshold based on thresh + + Parameters + ---------- + scans: Object + Object containing SuperDARN data in scans + params_to_run_filter: list + List of parameters to run boxcar filter + + Returns + ------- + oscan: Object + Object containing SuperDARN scans + """ + scans = [self.__discard_repeating_beams__(s) for s in scans] + if len(scans) == 3: + w = self.w + oscan = Scan() + + for b in scans[1].beams: + bmnum = b.bmnum + beam = Beam() + beam.copy(b) + + for key in beam.__dict__.keys(): + if type(getattr(beam, key)) == np.ndarray: + setattr(beam, key, []) + + for r in range(0, b.nrang): + box = [[[None for j in range(3)] + for k in range(3)] for n in range(3)] + + # Iterate through time + for j in range(0, 3): + # Iterate through beam + for k in range(-1, 2): + # Iterate through gate + for n in range(-1, 2): + # Get the scan we are working on + s = scans[j] + if s is None: + continue + # Get the beam we are working on + if s is None: + continue + # Get the beam we are working on + tbm = None + for bm in s.beams: + if bm.bmnum == bmnum + k: + tbm = bm + if tbm is None: + continue + # Check if target gate number is in the beam + if r + n in tbm.slist: + ind = np.array(tbm.slist).tolist()\ + .index(r + n) + box[j][k + 1][n + 1] = Gate( + tbm, ind, gflg_type=self.gflg_type + ) + else: + box[j][k + 1][n + 1] = 0 + pts = 0.0 + tot = 0.0 + v, w_l, p_l, elv, gfx = \ + list(), list(), list(), list(), list() + + # Iterate through time + for j in range(0, 3): + # Iterate through beam + for k in range(0, 3): + # Iterate through gate + for n in range(0, 3): + bx = box[j][k][n] + if bx is None: + continue + wt = w[j][k][n] + tot += wt + if bx != 0: + pts += wt + for m in range(0, wt): + v.append(bx.v) + w_l.append(bx.w_l) + p_l.append(bx.p_l) + elv.append(bx.elv) + gfx = bx.gflg + # Check if we meet the threshold + if pts / tot >= self.thresh: + beam.slist.append(r) + beam.v.append(np.median(v)) + beam.w_l.append(np.median(w_l)) + beam.p_l.append(np.median(p_l)) + beam.elv.append(np.median(elv)) + beam.gflg.append(gfx) + oscan.beams.append(beam) + + if len(oscan.beams) > 0: + oscan.update_time() + sorted(oscan.beams, key=lambda bm: bm.bmnum) + else: + oscan = Scan() + return oscan diff --git a/pydarn/utils/general_utils.py b/pydarn/utils/general_utils.py new file mode 100644 index 000000000..19e6fb2d7 --- /dev/null +++ b/pydarn/utils/general_utils.py @@ -0,0 +1,97 @@ +# Copyright (C) 2023 SuperDARN Canada, University of Saskatchewan +# Author(s): Carley Martin +# +# Modifications: +# +# Disclaimer: +# pyDARN is under the LGPL v3 license found in the root directory LICENSE.md +# Everyone is permitted to copy and distribute verbatim copies of this license +# document, but changing it is not allowed. +# +# This version of the GNU Lesser General Public License incorporates the terms +# and conditions of version 3 of the GNU General Public License, +# supplemented by the additional permissions listed below. +# +""" +This module contains general calculations used across pyDARN library and may be +useful for the user +""" +import numpy as np + +from pydarn import Re + + +class GeneralUtils(): + """ + General Utility Functions + + Methods + ------- + great_circle + new_coordinate + """ + def __str__(self): + return "This class is static class that provides"\ + " the following methods: \n"\ + " - great_circle()\n" + + @classmethod + def great_circle(cls, lon1, lat1, lon2, lat2): + ''' + Calculates the great circle distance between two points on a sphere + + Parameters + ----------- + lon1: float in degrees + longitude of first point + lat1: float in degrees + latitude of first point + lon2: float in degrees + longitude of second point + lat1: float in degrees + latitude of second point + + Returns + ------- + distance: float + assuming radius of sphere is 1 (1 Re) + ''' + lon1 = np.radians(lon1) + lat1 = np.radians(lat1) + lon2 = np.radians(lon2) + lat2 = np.radians(lat2) + return (np.arccos(np.sin(lat1) * np.sin(lat2) + + np.cos(lat1) * np.cos(lat2) + * np.cos(lon1 - lon2))) + + @classmethod + def new_coordinate(cls, lat, lon, d, bearing, R=Re): + """ + new coordinate will calculate the new coordinate from a given + position, distance and bearing + + Parameters + ---------- + lat: float + initial latitude, in degrees + lon: float + initial longitude, in degrees + d: target distance from initial + bearing: (true) heading in degrees + R: optional radius of sphere, defaults to mean radius of earth + + Returns + ------- + lat: float + new latitude, in degrees + lon: float + new longitude, in degrees + """ + lat1 = np.radians(lat) + lon1 = np.radians(lon) + a = np.radians(bearing) + lat2 = np.arcsin(np.sin(lat1) * np.cos(d/R) + np.cos(lat1) + * np.sin(d/R) * np.cos(a)) + lon2 = lon1 + np.arctan2(np.sin(a) * np.sin(d/R) * np.cos(lat1), + np.cos(d/R) - np.sin(lat1) * np.sin(lat2)) + return (np.degrees(lat2), np.degrees(lon2)) diff --git a/pydarn/utils/geo.py b/pydarn/utils/geo.py index f310a23a5..e74c1e7a7 100644 --- a/pydarn/utils/geo.py +++ b/pydarn/utils/geo.py @@ -18,6 +18,8 @@ # Modifications: # 2022-03-10 MTS added kwargs to the functions just to avoid errors when # extra keys are passed in from other functions +# 2023-01-03 CJM added functions to calculate azimuth from XS and SC existing +# codebase, can be expanded and added to when required # Disclaimer: # pyDARN is under the LGPL v3 license found in the root directory LICENSE.md # Everyone is permitted to copy and distribute verbatim copies of this license @@ -35,7 +37,6 @@ from pydarn import VHModels, EARTH_EQUATORIAL_RADIUS -# fldpnth line 90 def geocentric_coordinates(target_range: float, psi: float, boresight: float, virtual_height_model: VHModels = VHModels.STANDARD, @@ -268,6 +269,7 @@ def geocentric2flattening(delta: float, azimuth: float, elv: float, **kwargs): def geodetic2geocentric(lat: float, lon: float, **kwargs): """ convert geodetic coordinates to geocentric + radian version parameters ---------- @@ -311,6 +313,7 @@ def geodetic2geocentric(lat: float, lon: float, **kwargs): def geocentric2geodetic(lat: float, lon: float, **kwargs): """ convert geocentric coordinates to geodetic + radian version parameters ---------- @@ -337,3 +340,356 @@ def geocentric2geodetic(lat: float, lon: float, **kwargs): rho = EARTH_EQUATORIAL_RADIUS / np.sqrt(1+e2*np.sin(lat)**2) return rho + + +def geod2geoc(lat, lon, inverse=False): + """Converts position from geodetic to geocentric or vice-versa. + Based on the IAU 1964 oblate spheroid model of the Earth. + Parameters + ---------- + lat : float + latitude [degree] + lon : float + longitude [degree] + inverse : Optional[bool] + inverse conversion (geocentric to geodetic). Default is false. + Returns + ------- + lat_out : float + latitude [degree] (geocentric/detic if inverse=False/True) + lon_out : float + longitude [degree] (geocentric/detic if inverse=False/True) + rade : float + Earth radius [km] (geocentric/detic if inverse=False/True) + """ + a = 6378.16 + f = 1.0 / 298.25 + b = a * (1.0 - f) + e2 = (a**2 / b**2) - 1.0 + + if not inverse: + # geodetic into geocentric + lat_out = np.degrees(np.arctan(b**2 / a**2 * np.tan(np.radians(lat)))) + lon_out = lon + else: + # geocentric into geodetic + lat_out = np.degrees(np.arctan(a**2 / b**2 * np.tan(np.radians(lat)))) + lon_out = lon + + rade = a / np.sqrt(1.0 + e2 * np.sin(np.radians(lat_out)) ** 2) + + return lat_out, lon_out, rade + + +def globalspherical2globalcartesian(xin, yin, zin, inverse=False): + """Converts a position from global spherical (geocentric) to global + cartesian (and vice-versa). + + Parameters + ---------- + xin : float + latitude [degree] or global cartesian X [km] + yin : float + longitude [degree] or global cartesian Y [km] + zin : float + distance from center of the Earth [km] or global cartesian Z [km] + inverse : Optional[bool] + inverse conversion + + Returns + ------- + xout : float + global cartesian X [km] (inverse=False) or latitude [degree] + yout : float + global cartesian Y [km] (inverse=False) or longitude [degree] + zout : float + global cartesian Z [km] (inverse=False) or distance from the center of + the Earth [km] + + Notes + ------- + The global cartesian coordinate system is defined as: + - origin: center of the Earth + - x-axis in the equatorial plane and through the prime meridian. + - z-axis in the direction of the rotational axis and through the North + pole + The meaning of the input (x,y,z) depends on the direction of the conversion + (to global cartesian or to global spherical). + """ + + if not inverse: + # Global spherical to global cartesian + xout = zin * np.cos(np.radians(xin)) * np.cos(np.radians(yin)) + yout = zin * np.cos(np.radians(xin)) * np.sin(np.radians(yin)) + zout = zin * np.sin(np.radians(xin)) + else: + # Calculate latitude (xout), longitude (yout) and distance from center + # of the Earth (zout) + zout = np.sqrt(xin**2 + yin**2 + zin**2) + xout = np.degrees(np.arcsin(zin / zout)) + yout = np.degrees(np.arctan2(yin, xin)) + + return xout, yout, zout + + +def globalcartesian2localcartesian(X, Y, Z, lat, lon, rho, inverse=False): + """Converts a position from global cartesian to local cartesian + (or vice-versa). + + Parameters + ---------- + X : float + global cartesian X [km] or local cartesian X [km] + Y : flaot + global cartesian Y [km] or local cartesian Y [km] + Z : float + global cartesian Z [km] or local cartesian Z [km] + lat : float + geocentric latitude [degree] of local cartesian system origin + lon : float + geocentric longitude [degree] of local cartesian system origin + rho : float + distance from center of the Earth [km] of local cartesian system origin + inverse : Optional[bool] + inverse conversion + + Returns + ------- + X : float + local cartesian X [km] or global cartesian X [km] + Y : float + local cartesian Y [km] or global cartesian Y [km] + Z : float + local cartesian Z [km] or global cartesian Z [km] + + Notes + ------- + The global cartesian coordinate system is defined as: + - origin: center of the Earth + - Z axis in the direction of the rotational axis and through the North + pole + - X axis in the equatorial plane and through the prime meridian. + The local cartesian coordinate system is defined as: + - origin: local position + - X: East + - Y: North + - Z: up + The meaning of the input (X,Y,Z) depends on the direction of the conversion + (to global cartesian or to global spherical). + """ + # First get global cartesian coordinates of local origin + (goX, goY, goZ) = globalspherical2globalcartesian(lat, lon, rho) + + if not inverse: + # Translate global position to local origin + tx = X - goX + ty = Y - goY + tz = Z - goZ + # Then, rotate about global-Z to get local-X pointing eastward + rot = -np.radians(lon + 90.0) + sx = tx * np.cos(rot) - ty * np.sin(rot) + sy = tx * np.sin(rot) + ty * np.cos(rot) + sz = tz + # Finally, rotate about X axis to align Z with upward direction + rot = -np.radians(90.0 - lat) + xOut = sx + yOut = sy * np.cos(rot) - sz * np.sin(rot) + zOut = sy * np.sin(rot) + sz * np.cos(rot) + else: + # First rotate about X axis to align Z with Earth rotational axis + # direction + rot = np.radians(90.0 - lat) + sx = X + sy = Y * np.cos(rot) - Z * np.sin(rot) + sz = Y * np.sin(rot) + Z * np.cos(rot) + # Rotate about global-Z to get global-X pointing to the prime meridian + rot = np.radians(lon + 90.0) + xOut = sx * np.cos(rot) - sy * np.sin(rot) + yOut = sx * np.sin(rot) + sy * np.cos(rot) + zOut = sz + # Finally, translate local position to global origin + xOut = xOut + goX + yOut = yOut + goY + zOut = zOut + goZ + + return xOut, yOut, zOut + + +def localspherical2localcartesian(X, Y, Z, inverse=False): + """Convert a position from local spherical to local cartesian, + or vice-versa + + Parameters + ---------- + X : float + azimuth [degree, N] or local cartesian X [km] + Y : float + elevation [degree] or local cartesian Y [km] + Z : float + distance origin [km] or local cartesian Z [km] + inverse : Optional[bool] + inverse conversion + + Returns + ------- + X : float + local cartesian X [km] or azimuth [degree, N] + Y : float + local cartesian Y [km] or elevation [degree] + Z : float + local cartesian Z [km] or distance from origin [km] + + Notes + ------ + The local spherical coordinate system is defined as: + - origin: local position + - azimuth (with respect to North) + - Elevation (with respect to horizon) + - Altitude + The local cartesian coordinate system is defined as: + - origin: local position + - X: East + - Y: North + - Z: up + The meaning of the input (X,Y,Z) depends on the direction of the conversion + (to global cartesian or to global spherical). + """ + if not inverse: + # local spherical into local cartesian + r = Z + el = Y + az = X + xOut = r * np.cos(np.radians(el)) * np.sin(np.radians(az)) + yOut = r * np.cos(np.radians(el)) * np.cos(np.radians(az)) + zOut = r * np.sin(np.radians(el)) + else: + # local cartesian into local spherical + r = np.sqrt(X**2 + Y**2 + Z**2) + el = np.degrees(np.arcsin(Z / r)) + az = np.degrees(np.arctan2(X, Y)) + xOut = az + yOut = el + zOut = r + + return xOut, yOut, zOut + + +def geodetic2geocAzEl(lat, lon, az, el, inverse=False): + """Converts pointing azimuth and elevation measured with respect to the + local horizon to azimuth and elevation with respect to the horizon defined + by the plane perpendicular to the Earth-centered radial vector drawn + through a user defined point. + + Parameters + ---------- + lat : float + latitude [degree] + lon : float + longitude [degree] + az : float + azimuth [degree, N] + el : float + elevation [degree] + inverse : Optional[bool] + inverse conversion + + Returns + ------- + lat : float + latitude [degree] + lon : float + longitude [degree] + Re : float + Earth radius [km] + az : float + azimuth [degree, N] + el : float + elevation [degree] + """ + taz = np.radians(az) + tel = np.radians(el) + + # In this transformation x is east, y is north and z is up + if not inverse: + # Calculate deviation from vertical (in radians) + (geocLat, geocLon, Re) = geod2geoc(lat, lon) + devH = np.radians(lat - geocLat) + # Calculate cartesian coordinated in local system + kxGD = np.cos(tel) * np.sin(taz) + kyGD = np.cos(tel) * np.cos(taz) + kzGD = np.sin(tel) + # Now rotate system about the x axis to align local vertical vector + # with Earth radial vector + kxGC = kxGD + kyGC = kyGD * np.cos(devH) + kzGD * np.sin(devH) + kzGC = -kyGD * np.sin(devH) + kzGD * np.cos(devH) + # Finally calculate the new azimuth and elevation in the geocentric + # frame + azOut = np.degrees(np.arctan2(kxGC, kyGC)) + elOut = np.degrees(np.arctan(kzGC / np.sqrt(kxGC**2 + kyGC**2))) + latOut = geocLat + lonOut = geocLon + else: + # Calculate deviation from vertical (in radians) + (geodLat, geodLon, Re) = geod2geoc(lat, lon, inverse=True) + devH = np.radians(geodLat - lat) + # Calculate cartesian coordinated in geocentric system + kxGC = np.cos(tel) * np.sin(taz) + kyGC = np.cos(tel) * np.cos(taz) + kzGC = np.sin(tel) + # Now rotate system about the x axis to align local vertical vector + # with Earth radial vector + kxGD = kxGC + kyGD = kyGC * np.cos(-devH) + kzGC * np.sin(-devH) + kzGD = -kyGC * np.sin(-devH) + kzGC * np.cos(-devH) + # Finally calculate the new azimuth and elevation in the geocentric + # frame + azOut = np.degrees(np.arctan2(kxGD, kyGD)) + elOut = np.degrees(np.arctan(kzGD / np.sqrt(kxGD**2 + kyGD**2))) + latOut = geodLat + lonOut = geodLon + + return latOut, lonOut, Re, azOut, elOut + + +def calculate_azimuth(slat, slon, salt, elat, elon, ealt): + """ + calculates the azimuth between two given points + Only one method used and only azimuth returned, this can be expanded + using XS and SC existing codebase + + Parameters + ---------- + slat : float + origin latitude [degree] + slon : float + origin longitude [degree] + salt : float + origin altitude [km] + elat : float + distant latitude [degree] + elon : float + distant longitude [degree] + ealt : float + distant altitude [km] + + Returns + ------- + azm : float + azimuth between origin location and distant location [degrees] + in reference to North + """ + # Convert point of origin from geodetic to geocentric + gclat, gclon, srho = geod2geoc(slat, slon) + # Convert distant point from geodetic to geocentric + gcelat, gcelon, erho = geod2geoc(elat, elon) + # Convert distant point from geocentric to global cartesian + (pX, pY, pZ) = globalspherical2globalcartesian(gcelat, gcelon, erho + ealt) + # Convert pointing direction from global cartesian to local cartesian + (dX, dY, dZ) = globalcartesian2localcartesian(pX, pY, pZ, gclat, + gclon, srho + salt) + # Convert pointing direction from local cartesian to local spherical + (gaz, gel, rho) = localspherical2localcartesian(dX, dY, dZ, inverse=True) + # Convert pointing azimuth and elevation to geodetic + (_, _, _, azm, _) = geodetic2geocAzEl(gclat, gclon, gaz, gel, inverse=True) + return azm diff --git a/pydarn/utils/geocoastline.py b/pydarn/utils/geocoastline.py new file mode 100644 index 000000000..9b616f697 --- /dev/null +++ b/pydarn/utils/geocoastline.py @@ -0,0 +1,11081 @@ +# Copyright (C) 2023 SuperDARN Canada, University of Saskatchewan +# Author: Carley Martin +# +# Modifications: +# +# Disclaimer: +# pyDARN is under the LGPL v3 license found in the root directory LICENSE.md +# Everyone is permitted to copy and distribute verbatim copies of this license +# document, but changing it is not allowed. +# +# This version of the GNU Lesser General Public License incorporates the terms +# and conditions of version 3 of the GNU General Public License, +# supplemented by the additional permissions listed below. + +''' coast_outline +This coast outline was created by converting a Cartopy Natural Feature object +of the Earths coastlines in geographic coordinates into a list of shapes to be +read in to a plotting function +''' +coast_outline =\ + [ + { + "lon": [ + -163.7128956777287, + -163.1058009511638, + -161.24511349184644, + -160.24620805564453, + -159.48240454815448, + -159.20818356019765, + -161.12760128481472, + -162.43984676821842, + -163.027407803377, + -163.06660437727038, + -163.7128956777287 + ], + "lat": [ + -78.59566741324154, + -78.22333871857859, + -78.38017669058443, + -78.69364592886694, + -79.04633757925897, + -79.4970077452764, + -79.63420867301133, + -79.28146534618699, + -78.92877369579496, + -78.8699659158468, + -78.59566741324154 + ] + }, + { + "lon": [ + -6.197884894220991, + -6.032985398777611, + -6.788856573910849, + -8.56161658368356, + -9.977085740590269, + -9.166282517930782, + -9.688524542672454, + -8.327987433292009, + -7.572167934591064, + -6.733847011736145, + -5.661948614921968, + -6.197884894220991 + ], + "lat": [ + 53.867565009163364, + 53.1531900091605, + 52.260117906292336, + 51.669301255899356, + 51.82045482035308, + 52.86462881124268, + 53.8813626165853, + 54.66451894796863, + 55.13162221945487, + 55.17286001242378, + 54.55460317648381, + 53.867565009163364 + ] + }, + { + "lon": [ + 141.00021040259185, + 142.73524661679147, + 144.58397098203324, + 145.27312788307768, + 145.8297864117257, + 145.981921828393, + 147.64807335834757, + 147.89110761941623, + 146.97090538959486, + 147.19187381407494, + 148.08463585834932, + 148.73410525939357, + 149.30683515848443, + 149.26663089416132, + 150.03872846903425, + 149.7387984560122, + 150.80162763895913, + 150.6905749859639, + 150.02839318257583, + 149.78231001200197, + 148.92313764871727, + 147.913018426708, + 147.13544315001218, + 146.56788089415056, + 146.04848107318492, + 144.74416792213805, + 143.89708784400966, + 143.28637576718432, + 143.41391320208066, + 142.62843143124417, + 142.06825890520025, + 141.03385176001382, + 140.14341515519254, + 139.1277665549281, + 138.881476678625, + 137.61447391169287, + 138.03909915583517, + 138.66862145401478, + 138.4079138531023, + 137.92783979711078, + 135.98925011611345, + 135.16459760959975, + 133.66288048719787, + 133.36770470594672, + 132.98395551974727, + 132.75694095268904, + 132.75378869031925, + 131.98980431531618, + 133.0668445171434, + 133.78003095920354, + 133.69621178602614, + 132.23237348849426, + 131.83622195854474, + 130.94283979708285, + 130.5195581401801, + 131.8675378765136, + 132.3801164084167, + 133.98554813042836, + 134.14336795464772, + 134.42262739475302, + 135.45760298069467, + 136.29331424371884, + 137.44073774632756, + 138.3297274110447, + 139.18492068904288, + 139.92668419816044, + 141.00021040259185 + ], + "lat": [ + -2.60015105551566, + -3.28915292726321, + -3.861417738463416, + -4.373737888205049, + -4.876497897972683, + -5.465609226100043, + -6.0836593563108465, + -6.614014580922343, + -6.721656589386313, + -7.388024183790023, + -8.044108168167647, + -9.104663588093764, + -9.07143564213009, + -9.514406019736029, + -9.684318129111709, + -9.872937106977048, + -10.293686618697478, + -10.582712904505925, + -10.652476088099952, + -10.393267103723923, + -10.280922539921384, + -10.13044076908745, + -9.492443536011983, + -8.942554619994155, + -8.067414239131281, + -7.630128269077446, + -7.915330498896296, + -8.24549122480908, + -8.983068942910982, + -9.326820570516524, + -9.159595635620022, + -9.117892754760483, + -8.29716765710095, + -8.096042982620979, + -8.380935153846075, + -8.41168263105974, + -7.597882175327321, + -7.320224704623087, + -6.232849216337485, + -5.393365573756, + -4.54654387778907, + -4.462931410340822, + -3.538853448097541, + -4.024818617370315, + -4.112978610860253, + -3.7462826473171233, + -3.3117872046070502, + -2.820551039240499, + -2.460417982598436, + -2.4798483211401816, + -2.214541517753702, + -2.2125261368943185, + -1.6171619604596472, + -1.4325220678807826, + -0.9377202286860893, + -0.6954611141017892, + -0.36953785563694913, + -0.7802104630604559, + -1.151867364103623, + -2.769184665542376, + -3.3677011043468568, + -2.307042331556154, + -1.7035132788193648, + -1.7026347794704006, + -2.0512956681436734, + -2.4089999324680207, + -2.60015105551566 + ] + }, + { + "lon": [ + 114.20401655482837, + 114.59996137904872, + 115.45071048386981, + 116.22074100145102, + 116.72510298061971, + 117.12962609260047, + 117.64339318244627, + 117.68907514859231, + 118.34769127815224, + 119.18190392463997, + 119.11069380094176, + 118.43972700406408, + 118.6183207540648, + 117.88203494677018, + 117.3132324565335, + 118.0483297058854, + 117.87562706916597, + 118.99674726773816, + 117.8118583517178, + 117.47833865770603, + 117.52164350796664, + 116.56004845587947, + 116.5337968282752, + 116.14808393764866, + 116.00085778204911, + 114.86480309454456, + 114.46865156459506, + 113.75567182826407, + 113.25699425664752, + 112.06812625534067, + 111.70329064336005, + 111.04824018762824, + 110.223846063276, + 110.07093550012434, + 109.571947869914, + 109.0918738139225, + 108.9526575053282, + 109.06913618371408, + 109.66326012577375, + 110.3961352885371, + 111.16885298059748, + 111.37008100794205, + 111.7969283386729, + 112.99561486211522, + 113.71293541875868, + 114.20401655482837 + ], + "lat": [ + 4.5258739282368055, + 4.900011298029966, + 5.447729803891534, + 6.1431912296755655, + 6.924771429873999, + 6.92805288332454, + 6.422166449403249, + 5.987490139180154, + 5.708695786965492, + 5.407835598162207, + 5.016128241389808, + 4.966518866389606, + 4.478202419447555, + 4.137551377779516, + 3.234428208830593, + 2.2876901310273325, + 1.8276406925489255, + 0.9022191430660627, + 0.7842418481437078, + 0.10247467691702639, + -0.8037232397532676, + -1.4876091447039175, + -2.483517347832901, + -4.012726332214022, + -3.6570374487490582, + -4.106984144714396, + -3.495703627133828, + -3.4391696102065197, + -3.118775729996905, + -3.4783920223160507, + -2.9944422339026535, + -3.0494259578612106, + -2.9340324845534553, + -1.5928740372824635, + -1.3149065079844746, + -0.45950652425709393, + 0.41537547444431766, + 1.3419339054376138, + 2.0064928247111027, + 1.663774725751395, + 1.8506367049188128, + 2.6973033715888595, + 2.885896511238059, + 3.102394924324855, + 3.8935094262811556, + 4.5258739282368055 + ] + }, + { + "lon": [ + -93.61275590694046, + -94.15690873897391, + -95.60868058956564, + -96.82093217648455, + -96.28858740922982, + -94.85081987178917, + -93.97774654821797, + -93.61275590694046 + ], + "lat": [ + 74.97999726022438, + 74.59234650338688, + 74.66686391875176, + 74.92762319609658, + 75.37782827422338, + 75.64721751576089, + 75.29648956979595, + 74.97999726022438 + ] + }, + { + "lon": [ + -93.84000301794399, + -94.29560828324529, + -96.16965410031007, + -96.43630449093614, + -94.42257727738641, + -93.7206562975659, + -93.84000301794399 + ], + "lat": [ + 77.51999726023455, + 77.49134267852868, + 77.55511139597685, + 77.83462921824362, + 77.820004787905, + 77.63433136668031, + 77.51999726023455 + ] + }, + { + "lon": [ + -96.75439876990876, + -95.5592779202946, + -95.83029496944934, + -97.30984290239799, + -98.12428931353404, + -98.55286780474668, + -98.63198442258553, + -97.33723141151266, + -96.75439876990876 + ], + "lat": [ + 78.76581268992702, + 78.41831452098033, + 78.05694122996324, + 77.85059723582181, + 78.08285696075761, + 78.45810537384507, + 78.87193024363837, + 78.83198436147676, + 78.76581268992702 + ] + }, + { + "lon": [ + -88.15035030796028, + -89.7647220527584, + -92.42244096552946, + -92.76828548864282, + -92.88990597204175, + -93.89382402217599, + -95.9624574450358, + -97.1213789538295, + -96.74512285031237, + -94.68408586299944, + -93.57392106807313, + -91.6050231595366, + -90.7418458727493, + -90.96966142450802, + -89.82223792189926, + -89.18708289259985, + -87.83827633334965, + -86.37919226758864, + -84.78962521029058, + -82.75344458691006, + -81.12853084992436, + -80.05751095245915, + -79.83393286814837, + -80.45777075877587, + -81.94884253612557, + -83.22889360221143, + -86.09745235873332, + -88.15035030796028 + ], + "lat": [ + 74.39230703398503, + 74.51555532500116, + 74.83775788034099, + 75.38681997344214, + 75.88265534128267, + 76.31924367950056, + 76.4413809272224, + 76.7510777859476, + 77.16138865834507, + 77.09787832305837, + 76.77629588490605, + 76.7785179714946, + 76.44959747995681, + 76.07401317005947, + 75.84777374948565, + 75.61016551380762, + 75.56618886992725, + 75.4824213731821, + 75.69920400664653, + 75.78431509063124, + 75.71398346628199, + 75.33684886341591, + 74.92312734648716, + 74.65730377877777, + 74.44245901152432, + 74.56402781849094, + 74.41003205026117, + 74.39230703398503 + ] + }, + { + "lon": [ + -111.26444332563088, + -109.85445187054711, + -110.18693803591302, + -112.0511911690585, + -113.53427893761912, + -112.7245867582539, + -111.26444332563088 + ], + "lat": [ + 78.15298187937769, + 77.99632477488488, + 77.69701487905034, + 77.4092288276169, + 77.73220652944111, + 78.05105011668196, + 78.15298187937769 + ] + }, + { + "lon": [ + -110.96366065147602, + -109.6631457182026, + -110.88131425661892, + -112.54209143761516, + -112.52589087609164, + -111.5000103422334, + -110.96366065147602 + ], + "lat": [ + 78.8044408230652, + 78.60197256134565, + 78.40694570587611, + 78.4079017198735, + 78.55055451121522, + 78.8499935981305, + 78.8044408230652 + ] + }, + { + "lon": [ + -66.28243445500821, + -65.7713028632093, + -65.59100379094295, + -65.84716386581377, + -66.59993445500949, + -67.18416236028527, + -67.24242753769435, + -67.10067908391774, + -66.28243445500821 + ], + "lat": [ + 18.514761664295364, + 18.426679185453878, + 18.228034979723915, + 17.97590566657186, + 17.981822618069273, + 17.946553453030077, + 18.374485988839083, + 18.52060110114435, + 18.514761664295364 + ] + }, + { + "lon": [ + -77.56960079619921, + -76.89661861846213, + -76.36535905628554, + -76.19965857614164, + -76.9025614081757, + -77.20634131540348, + -77.76602291534061, + -78.33771928578561, + -78.21772661000388, + -77.79736467152563, + -77.56960079619921 + ], + "lat": [ + 18.490525417550487, + 18.400866807524082, + 18.160700588447597, + 17.886867173732966, + 17.868237819891746, + 17.70111623785982, + 17.86159739834224, + 18.225967922432233, + 18.454532782459196, + 18.524218451404778, + 18.490525417550487 + ] + }, + { + "lon": [ + -82.26815121125706, + -81.40445716014683, + -80.6187686835812, + -79.67952368846025, + -79.28148596873208, + -78.34743445505649, + -77.99329586456028, + -77.14642249216105, + -76.52382483590856, + -76.19462012399319, + -75.59822241891267, + -75.67106035022806, + -74.9338960435845, + -74.17802486845126, + -74.29664811877726, + -74.96159461129294, + -75.63468014189459, + -76.323656175426, + -77.75548092315307, + -77.08510840524674, + -77.49265458851661, + -78.13729224314159, + -78.48282670766119, + -78.71986650258401, + -79.28499996612794, + -80.21747534861865, + -80.51753455272141, + -81.82094336620318, + -82.16999182811864, + -81.79500179719267, + -82.77589799674085, + -83.49445878775936, + -83.90880042187563, + -84.05215084505326, + -84.54703019889638, + -84.97491105827311, + -84.44706214062776, + -84.23035702181178, + -83.7782399156902, + -83.26754757356575, + -82.51043616405751, + -82.26815121125706 + ], + "lat": [ + 23.188610744717707, + 23.117271429938782, + 23.10600596769915, + 22.76530324959883, + 22.399201565027056, + 22.512166246017088, + 22.277193508385935, + 21.657851467367834, + 21.206819566324373, + 21.220565497314013, + 21.016624457274133, + 20.735091254148003, + 20.693905137611385, + 20.284653632075887, + 20.05037852628068, + 19.92343537035569, + 19.873774318923196, + 19.95289093676206, + 19.855480861891877, + 20.413353786698792, + 20.673105373613893, + 20.739948838783434, + 21.02861338956585, + 21.598113511638434, + 21.5591753199065, + 21.827324327069036, + 22.03707896574176, + 22.19205658618507, + 22.387109279870753, + 22.636964830001958, + 22.688150336187064, + 22.16851797127613, + 22.154565334557333, + 21.910575059491254, + 21.801227728761646, + 21.89602814380109, + 22.204949856041907, + 22.565754706303764, + 22.788118394455694, + 22.983041897060644, + 23.078746649665188, + 23.188610744717707 + ] + }, + { + "lon": [ + -55.600218268442056, + -56.13403581401709, + -56.795881720595276, + -56.14310502788433, + -55.471492275603, + -55.82240108908096, + -54.935142584845636, + -54.473775397343786, + -53.47654944519137, + -53.786013759971254, + -53.08613399922626, + -52.958648240762216, + -52.64809872090421, + -53.069158291218386, + -53.521456264853, + -54.17893551290251, + -53.9618686590605, + -54.24048214376214, + -55.40077307801157, + -55.99748084168583, + -55.29121904155279, + -56.250798712780586, + -57.32522925477708, + -59.26601518414682, + -59.419494188053676, + -58.79658647320744, + -59.23162451845657, + -58.3918049790652, + -57.35868974468606, + -56.738650071832026, + -55.87097693543532, + -55.40697424988659, + -55.600218268442056 + ], + "lat": [ + 51.31707469339794, + 50.68700979267928, + 49.81230866149089, + 50.15011749938286, + 49.93581533466846, + 49.58712860777905, + 49.3130109726868, + 49.556691189159125, + 49.24913890237404, + 48.516780503933624, + 48.68780365660358, + 48.15716421161447, + 47.53554840757552, + 46.65549876564492, + 46.61829173439477, + 46.80706574155698, + 47.62520701760193, + 47.752279364607645, + 46.884993801453135, + 46.919720363953275, + 47.38956248635099, + 47.632545070987376, + 47.57280711525797, + 47.60334788674247, + 47.899453843774886, + 48.25152537697942, + 48.52318838153781, + 49.12558055276418, + 50.71827403421587, + 51.28743825947855, + 51.63209422464921, + 51.5882726100657, + 51.31707469339794 + ] + }, + { + "lon": [ + -83.88262630891977, + -82.78757687043883, + -81.6420137193926, + -81.55344031444432, + -80.81736121287886, + -80.10345130076664, + -80.99101986359572, + -82.54717810741704, + -83.10879757356511, + -84.10041663281388, + -85.52340471061905, + -85.8667687649824, + -87.22198320183678, + -86.35275977247133, + -86.2248864407651, + -85.88384782585486, + -85.1613079495499, + -84.97576371940592, + -84.4640120104195, + -83.88262630891977 + ], + "lat": [ + 65.10961782496354, + 64.76669302027467, + 64.45513580998697, + 63.97960928003714, + 64.057485663501, + 63.72598135034862, + 63.41124603947496, + 63.65172231714521, + 64.10187571883971, + 63.569711819098, + 63.052379055424055, + 63.63725291610349, + 63.54123810490519, + 64.0358332383707, + 64.82291697860823, + 65.7387783881171, + 65.6572846543928, + 65.21751821558898, + 65.37177236598022, + 65.10961782496354 + ] + }, + { + "lon": [ + -78.77063859731078, + -77.8246239895596, + -75.60584469267573, + -74.228616095665, + -74.09914079455771, + -72.24222571479768, + -71.20001542833518, + -68.7860542466849, + -67.91497046575694, + -66.9690333726542, + -68.8051228502006, + -66.4498660956339, + -64.86231441919524, + -63.424934454996794, + -61.851981370680605, + -62.16317684594226, + -63.918444383384184, + -65.14886023625368, + -66.72121904159852, + -68.015016038674, + -68.1412874009792, + -67.08964616562342, + -65.73208045109976, + -65.32016760930125, + -64.66940629744968, + -65.01380388045888, + -66.27504472519048, + -68.7831862046927, + -67.36968075221309, + -66.32829728866726, + -66.16556820338015, + -68.87736650254465, + -71.02343705919385, + -72.23537858751902, + -71.88627844917127, + -73.37830624051838, + -74.83441891142263, + -74.81850257027673, + -77.70997982452008, + -78.5559488593542, + -77.89728105336198, + -76.01827429879717, + -73.95979529488268, + -74.29388342964964, + -73.94491248238262, + -72.65116716173942, + -72.92605994331605, + -73.31161780464572, + -74.84330725777684, + -76.86910091826672, + -76.22864905465738, + -77.28736996123715, + -78.1686339993266, + -78.95724219431673, + -79.49245500356366, + -81.30547095409176, + -84.94470618359851, + -87.06000342481789, + -88.68171322300148, + -89.51341956252303, + -88.46772111688082, + -89.88815121128755, + -90.20516028518205, + -89.436576707705, + -88.40824154331287, + -85.82615108920098, + -86.56217851433412, + -85.77437130404454, + -84.85011247428822, + -82.31559017610101, + -80.60008765330768, + -80.74894161652443, + -78.77063859731078 + ], + "lat": [ + 72.35219900175032, + 72.74961660429098, + 72.2436784939374, + 71.76714427355789, + 71.33084015571758, + 71.55692454699452, + 70.92001251899718, + 70.52502370877427, + 70.12194753689765, + 69.18608734809182, + 68.72019847276444, + 68.06716339789203, + 67.84753856065159, + 66.92847321234059, + 66.86212067327783, + 66.16025136988962, + 64.9986685248329, + 65.42603261988667, + 66.38804108343219, + 66.26272573512439, + 65.68978913030439, + 65.10845510523696, + 64.64840566675856, + 64.38273712834605, + 63.392926744227495, + 62.67418508569598, + 62.94509878198612, + 63.74567007105183, + 62.88396556258484, + 62.28007477482201, + 61.93089712182582, + 62.330149237712824, + 62.91070811629588, + 63.39783600529522, + 63.67998932560887, + 64.19396312118384, + 64.67910146753995, + 64.38909332951793, + 64.22954234481678, + 64.57290639918013, + 65.30919220647475, + 65.32696889918314, + 65.45476471624094, + 65.81177134872938, + 66.31057811142666, + 67.28457550726391, + 67.72692576768235, + 68.06943716091287, + 68.55462718370127, + 68.89473562283025, + 69.14776927354741, + 69.76954010688321, + 69.82648753526887, + 70.16688019477543, + 69.87180776638884, + 69.74318512641436, + 69.96663401964442, + 70.26000112576538, + 70.4107412787608, + 70.76208934191324, + 71.21818553332132, + 71.22255219184997, + 72.23507436796079, + 73.12946421985238, + 73.53788890247121, + 73.80381582304518, + 73.15744700793844, + 72.53412588163387, + 73.34027822538708, + 73.7509508328106, + 72.71654368762417, + 72.06190664335072, + 72.35219900175032 + ] + }, + { + "lon": [ + -94.50365759965237, + -92.42001217321173, + -90.50979285354263, + -92.00396521682987, + -93.19629553910026, + -94.26904659704726, + -95.40985551632266, + -96.03374508338244, + -96.01826799191102, + -95.49579342322404, + -94.50365759965237 + ], + "lat": [ + 74.13490672473922, + 74.1000251329422, + 73.85673248971206, + 72.96624420845852, + 72.77199249947334, + 72.02459625923599, + 72.06188080513458, + 72.94027680123183, + 73.43742991809582, + 73.86241689726417, + 74.13490672473922 + ] + }, + { + "lon": [ + -100.43835995156411, + -101.54, + -100.35642696816535, + -99.16386410194966, + -97.38, + -97.12, + -98.05359595415875, + -96.54, + -96.72000000000001, + -98.35964962440737, + -99.3228466458956, + -100.01481991249995, + -102.48000000000002, + -102.48000000000002, + -100.43835995156411 + ], + "lat": [ + 72.70589834257204, + 73.36, + 73.84386505807139, + 73.63338694934659, + 73.76, + 73.47, + 72.99053213163567, + 72.56, + 71.66, + 71.2728591986861, + 71.35639415148593, + 71.73825714790671, + 72.48292128497508, + 72.83000000000001, + 72.70589834257204 + ] + }, + { + "lon": [ + -107.81943396689313, + -106.92891984742343, + -105.88099931519267, + -105.70498938680655, + -106.31347937704336, + -109.6999910144267, + -112.22306698286127, + -113.74380103234652, + -113.87133846724286, + -111.79420427127101, + -116.31219723190107, + -117.71040646042228, + -116.34601945683609, + -115.40486243372035, + -112.59056393110492, + -110.81421240928793, + -109.06710974814813, + -110.49725501182571, + -109.58110938193923, + -108.54858999999999, + -108.21141, + -107.81943396689313 + ], + "lat": [ + 75.84552582468096, + 76.0128282742259, + 75.9693942328846, + 75.47952749297376, + 75.00526703561509, + 74.85000519479418, + 74.41695669218826, + 74.39427073841215, + 74.72029734974156, + 75.16249258086312, + 75.04343008086265, + 75.22223053659253, + 76.19901845977351, + 76.47887217885015, + 76.14134756133579, + 75.54918732370321, + 75.47322296823417, + 76.42980540638904, + 76.79417593047903, + 76.67832000000001, + 76.20168000000001, + 75.84552582468096 + ] + }, + { + "lon": [ + -122.85492448615902, + -121.15753455288399, + -119.1039389718211, + -117.570130784966, + -116.19858659550738, + -116.33581336145845, + -117.10605058476882, + -118.04041215703819, + -119.89931677944145, + -121.49999426968223, + -122.85492448615902 + ], + "lat": [ + 76.11654287383568, + 76.86453339304443, + 77.51221995717462, + 77.4983189968881, + 77.6452867703262, + 76.87696157501061, + 76.53003184681911, + 76.48117178008714, + 76.05323924427815, + 75.90001862253276, + 76.11654287383568 + ] + }, + { + "lon": [ + -121.53787309455218, + -120.1097690499501, + -117.55563554570813, + -116.58442867721466, + -115.5107991199187, + -116.76793168828308, + -119.22000000000001, + -120.46, + -120.46, + -123.09219682502714, + -123.62, + -125.92894873747339, + -125.5, + -124.80729000000002, + -123.94000000000001, + -124.91774431038601, + -121.53787309455218 + ], + "lat": [ + 74.44894440377693, + 74.24136017526048, + 74.18575633411443, + 73.8960582546862, + 73.47520539010118, + 73.22292104765224, + 72.52000000000001, + 71.82000000000001, + 71.3836017930876, + 70.90164154731742, + 71.34, + 71.8686884630114, + 72.29226081179497, + 73.02256, + 73.68, + 74.29272654895861, + 74.44894440377693 + ] + }, + { + "lon": [ + -166.46779212142462, + -165.67442969466364, + -165.57916419173358, + -166.19277014876727, + -166.84833736882197, + -167.45527706609008, + -166.46779212142462 + ], + "lat": [ + 60.384169826897754, + 60.29360687930625, + 59.90998688418753, + 59.75444082298899, + 59.941406155020985, + 60.21306915957936, + 60.384169826897754 + ] + }, + { + "lon": [ + -153.22872941792113, + -152.56479061583514, + -152.1411472239064, + -153.00631405333692, + -154.0050902984581, + -154.51640275777004, + -154.67099280497118, + -153.7627795074415, + -153.22872941792113 + ], + "lat": [ + 57.96902008730477, + 57.901427313866996, + 57.591058661522, + 57.11584219016593, + 56.734676825581076, + 56.99274892844669, + 57.46119578717253, + 57.81657461204373, + 57.96902008730477 + ] + }, + { + "lon": [ + -132.71000769746146, + -131.74998877655918, + -132.04947953990674, + -131.1790417143824, + -131.5778287423788, + -132.18042761933432, + -132.54999162486968, + -133.0546119861998, + -133.239665290237, + -133.18000484915603, + -132.71000769746146 + ], + "lat": [ + 54.04000926372134, + 54.12000438090915, + 52.98462148702441, + 52.18043284769826, + 52.18237071390922, + 52.63970713969229, + 53.10001496033216, + 53.41146881775528, + 53.85108022726224, + 54.1699754909354, + 54.04000926372134 + ] + }, + { + "lon": [ + -125.41500078011457, + -124.92076738167509, + -123.92250790087682, + -123.51000078010694, + -124.01288998095531, + -125.65501196989416, + -125.95499365934849, + -126.8500036284276, + -127.02999264210017, + -128.05933549692202, + -128.44458329965792, + -128.35841284881124, + -127.30858028858567, + -126.69500016976812, + -125.75500586637895, + -125.41500078011457 + ], + "lat": [ + 49.950000515332576, + 49.47527497008329, + 49.062483628935794, + 48.51001089130338, + 48.37084625914137, + 48.8250045843385, + 49.17999583596752, + 49.530000311880386, + 49.814995835970066, + 49.994959011426516, + 50.539137681676074, + 50.77064809834367, + 50.55257355407198, + 50.40090322529532, + 50.295018215529275, + 49.950000515332576 + ] + }, + { + "lon": [ + -171.73165686753944, + -171.1144335602453, + -170.4911124339407, + -169.6825054596536, + -168.6894394603007, + -168.77194088445466, + -169.5294398672051, + -170.29055620021595, + -170.67138566799093, + -171.55306311753873, + -171.79111060289122, + -171.73165686753944 + ], + "lat": [ + 63.782515367275934, + 63.59219106714495, + 63.694975490973505, + 63.43111562769119, + 63.297506212000556, + 63.18859813094544, + 62.97693146427792, + 63.194437567794424, + 63.3758218451389, + 63.317789211675105, + 63.40584585230046, + 63.782515367275934 + ] + }, + { + "lon": [ + -105.4922891914932, + -103.52928239623795, + -100.8251580472688, + -100.0601918200522, + -99.67093909381364, + -101.30394019245301, + -102.94980872273302, + -105.17613277873151, + -104.21042945027713, + -105.41958045125853, + -105.4922891914932 + ], + "lat": [ + 79.30159393992916, + 79.16534902619163, + 78.80046173777872, + 78.32478017853204, + 77.90754466420744, + 78.01898489044486, + 78.34322866486023, + 78.3803323432458, + 78.67742015249176, + 78.91833567983649, + 79.30159393992916 + ] + }, + { + "lon": [ + 32.946960890440806, + 33.667227003724946, + 34.576473829900465, + 33.900804477684204, + 34.00488081232004, + 32.97982710137845, + 32.49029625827754, + 32.25666710788596, + 32.80247358575275, + 32.946960890440806 + ], + "lat": [ + 35.3867033961337, + 35.37321584730552, + 35.67159556735879, + 35.24578176527376, + 34.97809784600186, + 34.57186941175544, + 34.701654771456475, + 35.10323232679663, + 35.14550364841138, + 35.3867033961337 + ] + }, + { + "lon": [ + 26.290002882601698, + 26.16499759288766, + 24.724982130642303, + 24.735007358506916, + 23.51497846852808, + 23.699980096133004, + 24.246665073348705, + 25.02501549652891, + 25.769207797964185, + 25.745023227651586, + 26.290002882601698 + ], + "lat": [ + 35.29999034274793, + 35.00499542900977, + 34.91998769788964, + 35.08499054619759, + 35.27999156345098, + 35.70500438083549, + 35.368022365860185, + 35.42499563246197, + 35.35401805270908, + 35.1799976669662, + 35.29999034274793 + ] + }, + { + "lon": [ + 49.54351891459575, + 49.808980747279094, + 50.056510857957164, + 50.21743126811407, + 50.47653689962553, + 50.377111443895956, + 50.20027469259318, + 49.86060550313868, + 49.67260664246086, + 49.863344354050156, + 49.77456424337271, + 49.49861209493412, + 49.435618523970305, + 49.041792433473944, + 48.54854088724801, + 47.93074913919867, + 47.54772342305131, + 47.095761346226595, + 46.282477654817086, + 45.40950768411045, + 44.833573846217554, + 44.03972049334976, + 43.76376834491117, + 43.697777540874455, + 43.345654331237625, + 43.254187046081, + 43.43329756040464, + 43.893682895692926, + 43.896370070172104, + 44.37432539243966, + 44.46439741392439, + 44.23242190936617, + 44.042976108584156, + 43.96308434426091, + 44.31246870298628, + 44.4465173683514, + 44.94493655780653, + 45.50273196796499, + 45.87299360533626, + 46.31224327981721, + 46.882182651564285, + 47.70512983581236, + 48.005214878131255, + 47.868995802609874, + 48.29382775248138, + 48.84506025573879, + 48.86350874206698, + 49.194651320193316, + 49.54351891459575 + ], + "lat": [ + -12.469832858940554, + -12.895284925999555, + -13.555761407121985, + -14.758788750876796, + -15.226512139550543, + -15.706069431219127, + -16.000263360256767, + -15.414252618066918, + -15.710151869370186, + -16.451036879138776, + -16.8750420060936, + -17.106035658438273, + -17.953064060134366, + -19.118781019774445, + -20.496888116134127, + -22.391501153251085, + -23.781958916928517, + -24.941629733990453, + -25.178462823184105, + -25.60143442149309, + -25.34610116953894, + -24.988345228782308, + -24.46067717864999, + -23.574116306250602, + -22.776903985283873, + -22.057413018484123, + -21.33647511158019, + -21.16330738697013, + -20.830459486578174, + -20.07236622485639, + -19.435454196859048, + -18.961994724200906, + -18.33138722094317, + -17.409944756746782, + -16.85044402432267, + -16.216219170804507, + -16.1793738745804, + -15.97437346767854, + -15.793454278224687, + -15.780018405828798, + -15.210182386946315, + -14.594302666891764, + -14.091232598530375, + -13.663868503476586, + -13.784067884987486, + -13.089174899958664, + -12.48786793381042, + -12.040505059459676, + -12.469832858940554 + ] + }, + { + "lon": [ + 167.2168013857696, + 167.84487674384502, + 167.51518110582288, + 167.1800077659778, + 167.2168013857696 + ], + "lat": [ + -15.89184620530842, + -16.46633310309717, + -16.59784962327999, + -16.159995212470946, + -15.89184620530842 + ] + }, + { + "lon": [ + 166.79315799384085, + 166.6498592470955, + 166.6291369977464, + 167.10771243720149, + 167.27002811103023, + 167.00120731024793, + 166.79315799384085 + ], + "lat": [ + -15.668810723536687, + -15.392703545801211, + -14.626497084209605, + -14.933920179913954, + -15.740020847234888, + -15.614602146062516, + -15.668810723536687 + ] + }, + { + "lon": [ + 134.21013390516885, + 134.11277550673094, + 134.29033572808584, + 134.49962527886788, + 134.72700158095216, + 134.7246244650667, + 134.21013390516885 + ], + "lat": [ + -6.89523772545472, + -6.142467136259, + -5.783057549669017, + -5.445042006047871, + -5.737582289252167, + -6.214400730009288, + -6.89523772545472 + ] + }, + { + "lon": [ + -48.66061601418252, + -48.1513964503784, + -46.66285681821098, + -45.15475765642109, + -43.92082780615574, + -43.48994971370611, + -43.37243750667439, + -43.33326677099714, + -44.880536668464266, + -46.50617387550203, + -48.38642086444183, + -50.48210689960646, + -52.85198808451179, + -54.16425940613162, + -53.987991095584036, + -51.85313432474216, + -50.99132646341059, + -50.364594692574755, + -49.91413123228649, + -49.30695899107312, + -48.66061601418252 + ], + "lat": [ + -78.04701873159873, + -78.04707040803102, + -77.83147633250933, + -78.04707040803102, + -78.47810352977753, + -79.0855599913685, + -79.51664478954731, + -80.0261227355129, + -80.33964365022769, + -80.59435678499433, + -80.82948455192233, + -81.02544158317313, + -80.96668547965729, + -80.63352752067158, + -80.22202809033138, + -79.94772958772612, + -79.6146233051727, + -79.1834868305616, + -78.81120981233094, + -78.4585698383712, + -78.04701873159873 + ] + }, + { + "lon": [ + -66.29003089055513, + -64.03768775089767, + -61.88324561221718, + -61.13897579613348, + -60.61011918805844, + -59.572094692611586, + -59.86584937197473, + -60.15965572777019, + -62.25539343936711, + -64.48812537296979, + -65.74166642928991, + -65.74166642928991, + -66.29003089055513 + ], + "lat": [ + -80.25577280061798, + -80.29489185986293, + -80.39287037548831, + -79.98137094514813, + -79.6286792947561, + -80.04017872509628, + -80.54965667106185, + -81.00032683707929, + -80.86317758577665, + -80.92193368929253, + -80.5888274067391, + -80.54965667106185, + -80.25577280061798 + ] + }, + { + "lon": [ + -73.9158186510023, + -73.23033077665059, + -72.07471655952358, + -71.78096188016042, + -71.72217993842841, + -71.74179114448319, + -71.1738154771632, + -70.25325151231577, + -69.72444658067303, + -69.48942216660959, + -69.05851823594381, + -68.72554114447112, + -68.45134599473043, + -68.33383378769872, + -68.51012793646244, + -68.78429724798698, + -69.95947099473648, + -71.07588863797011, + -72.38813412137378, + -71.89849992540829, + -73.07362199572549, + -74.19003963895912, + -74.95389482288145, + -75.01262508818117, + -73.9158186510023 + ], + "lat": [ + -71.26934457792578, + -71.15178069446176, + -71.19095143013901, + -70.68147348417342, + -70.30914478951048, + -69.50578297310102, + -69.03547576281268, + -68.87874114367142, + -69.25101816190208, + -69.62334685656502, + -70.07401702258245, + -70.50515349719356, + -70.95582366321098, + -71.40649382922841, + -71.79840789172998, + -72.17068490996063, + -72.30788583769555, + -72.50384286894634, + -72.48420582467543, + -72.09234343860615, + -72.22949268990878, + -72.3666936176437, + -72.07275807076753, + -71.66125864042735, + -71.26934457792578 + ] + }, + { + "lon": [ + -102.33072506387639, + -101.70396745482441, + -100.43091854531409, + -98.98154964882391, + -97.88474321164506, + -96.78793677446619, + -96.20034990109144, + -96.98376461463623, + -98.19808325884682, + -99.43201310911218, + -100.78345516640925, + -101.80186845580137, + -102.33072506387639 + ], + "lat": [ + -71.89416432076682, + -71.71779265735465, + -71.85499358508957, + -71.93333505644407, + -72.07053598417899, + -71.95297210071497, + -72.5212061501964, + -72.44286467884193, + -72.48203541451917, + -72.44286467884193, + -72.50162078235779, + -72.305663751107, + -71.89416432076682 + ] + }, + { + "lon": [ + -122.62173458544193, + -122.40624386278482, + -121.21151058641286, + -119.91885047084779, + -118.72414303269196, + -119.29211870001194, + -120.23221635626571, + -121.62282914924002, + -122.62173458544193 + ], + "lat": [ + -73.65777760202387, + -73.32461964303816, + -73.50099130645033, + -73.65772592559158, + -73.48135426217942, + -73.83409758900375, + -74.0888107237704, + -74.01046925241592, + -73.65777760202387 + ] + }, + { + "lon": [ + -127.28312964568192, + -126.55847103565299, + -125.55956559945108, + -124.03188106982256, + -124.61946794319732, + -125.91217973519467, + -127.28312964568192 + ], + "lat": [ + -73.46176889434079, + -73.24622649525139, + -73.48135426217942, + -73.87326832468099, + -73.83409758900375, + -73.73611907337835, + -73.46176889434079 + ] + }, + { + "lon": [ + 165.77998986232637, + 166.59999148993384, + 167.1200114280869, + 166.7400346214448, + 166.18973229396866, + 165.47437544175222, + 164.82981530177568, + 164.16799523341365, + 164.029605747736, + 164.45996707586272, + 165.02003624904205, + 165.46000939357512, + 165.77998986232637 + ], + "lat": [ + -21.08000497811563, + -21.700018812753527, + -22.15999073658349, + -22.39997608814695, + -22.129708347260454, + -21.679606621998232, + -21.14981983814195, + -20.444746595951628, + -20.105645847252354, + -20.1200118954295, + -20.45999114347773, + -20.80002206795826, + -21.08000497811563 + ] + }, + { + "lon": [ + 152.64001671774253, + 153.0199935243847, + 153.14003787659874, + 152.82729210836828, + 152.63867313050298, + 152.40602583232493, + 151.95323693258354, + 151.38427941305002, + 150.66204959533883, + 150.93996544820448, + 151.47998416565457, + 151.8200150901351, + 152.23998945537113, + 152.64001671774253 + ], + "lat": [ + -3.659983005389691, + -3.9800151505732653, + -4.4999834122940925, + -4.7664270971909914, + -4.176127211120921, + -3.7897425268745835, + -3.4620622697118155, + -3.0354216447101123, + -2.741486097833935, + -2.500002129734007, + -2.779985039891379, + -2.9999716121578857, + -3.24000864015364, + -3.659983005389691 + ] + }, + { + "lon": [ + 151.30139041565388, + 150.75444705627666, + 150.2411967307538, + 149.70996300679332, + 148.89006473205046, + 148.31893680236067, + 148.40182579975686, + 149.29841190002082, + 149.84556196512722, + 149.99625044169028, + 150.13975589416486, + 150.23690758687354, + 150.80746707580812, + 151.08967207255404, + 151.6478808941709, + 151.53786176982146, + 152.1367916200843, + 152.33874311748093, + 152.3186926617517, + 151.98279585185452, + 151.45910688700866, + 151.30139041565388 + ], + "lat": [ + -5.840728448106752, + -6.083711032743138, + -6.317753594593028, + -6.316513360218025, + -6.026040134305404, + -5.747142429226166, + -5.437755629094717, + -5.58374155031926, + -5.505503431829368, + -5.026101169457654, + -5.0013481583898525, + -5.532220147324267, + -5.455842380396874, + -5.113692722192383, + -4.757073662946162, + -4.167807305521933, + -4.14879037843852, + -4.312966403829805, + -4.867661228050771, + -5.478063246282382, + -5.560280450058754, + -5.840728448106752 + ] + }, + { + "lon": [ + 162.1190246930409, + 162.3986458681722, + 161.70003218001835, + 161.31979699121476, + 161.91738325423802, + 162.1190246930409 + ], + "lat": [ + -10.48271900802115, + -10.826367282762106, + -10.820011081590211, + -10.204751478723168, + -10.446648858281423, + -10.48271900802115 + ] + }, + { + "lon": [ + 161.67998172428912, + 161.5293966005906, + 160.78825320866054, + 160.57999718652434, + 160.92002811100485, + 161.28000613835, + 161.67998172428912 + ], + "lat": [ + -9.599982191611367, + -9.784312025596485, + -8.917543226764892, + -8.32000864017396, + -8.32000864017396, + -9.120011488484451, + -9.599982191611367 + ] + }, + { + "lon": [ + 160.85222863183787, + 160.4625883323572, + 159.84944746321412, + 159.64000288313514, + 159.70294477766663, + 160.36295617089843, + 160.68851769433724, + 160.85222863183787 + ], + "lat": [ + -9.872937106977048, + -9.895209649294841, + -9.794027194867354, + -9.639979750205278, + -9.242949720906815, + -9.40030445723557, + -9.610162448772869, + -9.872937106977048 + ] + }, + { + "lon": [ + 159.64000288313514, + 159.87502729719859, + 159.91740197167792, + 159.13367719953936, + 158.5861137229747, + 158.21114953026483, + 158.35997765526542, + 158.8200012555277, + 159.64000288313514 + ], + "lat": [ + -8.020026950719632, + -8.337320244991737, + -8.53828989017483, + -8.114181410355428, + -7.7548235001977375, + -7.421872246941199, + -7.320017998893917, + -7.560003350457379, + -8.020026950719632 + ] + }, + { + "lon": [ + 157.14000044171888, + 157.5384257346892, + 157.33941979393325, + 156.90203047101483, + 156.4913578635913, + 156.542827590154, + 157.14000044171888 + ], + "lat": [ + -7.021638278840641, + -7.347819919466943, + -7.404767347852592, + -7.1768742814454285, + -6.765943291860452, + -6.599338474151452, + -7.021638278840641 + ] + }, + { + "lon": [ + 154.75999067608439, + 155.06291792217934, + 155.5477462099417, + 156.0199654482248, + 155.8800256695784, + 155.59999108298877, + 155.16699425681514, + 154.72919152243838, + 154.51411421123964, + 154.65250369691728, + 154.75999067608439 + ], + "lat": [ + -5.339983819198495, + -5.56679168052753, + -6.200654799019645, + -6.540013929880381, + -6.819996840037753, + -6.9199907365225215, + -6.535931491729322, + -5.900776462429902, + -5.139117526879986, + -5.042379245629597, + -5.339983819198495 + ] + }, + { + "lon": [ + 176.8858236026052, + 176.50801720611926, + 176.01244022044023, + 175.23956749908297, + 175.06789839100935, + 174.65097293527847, + 175.22763024322356, + 174.9001566917899, + 173.82404666574394, + 173.85226199777532, + 174.57480187408035, + 174.74347374908098, + 174.69696496001828, + 174.2920284365792, + 174.31900353423552, + 173.8409965355357, + 173.0541711774596, + 172.63600548735377, + 173.00704227120946, + 173.55129845610747, + 174.3293904971262, + 174.61200890533044, + 175.33661583892712, + 175.3575964704376, + 175.80888675364253, + 175.9584900251275, + 176.76319542877656, + 177.4388131045605, + 178.01035444570866, + 178.51709354076274, + 178.27473107331383, + 177.97046023997927, + 177.20699262929918, + 176.93998050364706, + 177.0329464053401, + 176.8858236026052 + ], + "lat": [ + -40.0659778785822, + -40.60475636165728, + -41.28962411882147, + -41.68830779395328, + -41.42589487077513, + -41.2818209775454, + -40.45923552832336, + -39.90888152441491, + -39.50885426204351, + -39.14660247167748, + -38.797683200842755, + -38.02780771255843, + -37.38112883885792, + -36.71109221776149, + -36.53482390721391, + -36.12198088963413, + -35.23712533950039, + -34.52910654066943, + -34.45066171645037, + -35.00618336358801, + -35.26549570082862, + -36.15634571710823, + -37.20909799575827, + -36.52619394302117, + -36.79894215265767, + -37.55538176854612, + -37.881253350578675, + -37.961248467766495, + -37.579824721020174, + -37.6953732236248, + -38.58281259537314, + -39.166342868812976, + -39.14577564876082, + -39.44973642350161, + -39.879942722331464, + -40.0659778785822 + ] + }, + { + "lon": [ + 169.66781456937315, + 170.52491987536615, + 171.125089960004, + 171.56971398344325, + 171.94870893787186, + 172.0972270042787, + 172.79857954334403, + 173.02037479074076, + 173.2472343285021, + 173.9584053897028, + 174.24758670480816, + 174.24851688058942, + 173.87644656808794, + 173.2227396995957, + 172.71124637277074, + 173.08011274647015, + 172.3085836123525, + 171.45292524646362, + 171.18513797432718, + 170.61669721911653, + 169.8314221540093, + 169.33233117093428, + 168.41135379462855, + 167.76374474514682, + 166.67688602118417, + 166.50914432196467, + 167.046372512071, + 168.30376346259686, + 168.94940880765157, + 169.66781456937315 + ], + "lat": [ + -43.555325616226376, + -43.031688327812816, + -42.51275359473782, + -41.767424411792135, + -41.514416599291124, + -40.956104424809716, + -40.4939620908235, + -40.919052422856446, + -41.33199879330081, + -40.926700534835646, + -41.34915536882171, + -41.77000823340673, + -42.23318409603879, + -42.970038344088614, + -43.372287693048555, + -43.853343601253606, + -43.86569426857136, + -44.242467136411406, + -44.89710418068486, + -45.908928724959736, + -46.35577483498757, + -46.641235446967876, + -46.61994475686363, + -46.29019744240919, + -46.219917494492236, + -45.85270476662619, + -45.110941257508635, + -44.12397307716614, + -43.935819187191434, + -43.555325616226376 + ] + }, + { + "lon": [ + 147.68925947488418, + 148.289067824496, + 148.35986453673587, + 148.01730146707303, + 147.91405195535384, + 147.56456424376393, + 146.87034305235488, + 146.66332726459365, + 146.04837772032033, + 145.4319295595106, + 145.29509036680173, + 144.71807132383066, + 144.7437545106797, + 145.3979781434948, + 146.3641207216237, + 146.90858361225088, + 147.68925947488418 + ], + "lat": [ + -40.808258152022674, + -40.87543751400211, + -42.06239348731415, + -42.40702361426865, + -43.211522312188535, + -42.937688897473905, + -43.6345972633621, + -43.58085377377856, + -43.549744561538844, + -42.693776137056254, + -42.033609714527564, + -41.16255177181576, + -40.70397511165767, + -40.79254851660594, + -41.137643731451085, + -41.00054615658073, + -40.808258152022674 + ] + }, + { + "lon": [ + 126.14871382050114, + 125.08862348846566, + 124.22164798390492, + 124.02894656788851, + 123.65966678273077, + 122.81103641163364, + 122.1830644064228, + 121.29919070850259, + 120.58026818245806, + 119.89369510302822, + 119.29889936734875, + 119.00734093635802, + 118.5057178081008, + 118.02497195848949, + 117.29550744025741, + 116.62510908413495, + 115.56434695847966, + 115.02680870977957, + 115.04861616420676, + 115.54512332566708, + 115.7146737000167, + 115.67937869676135, + 115.80164513556394, + 115.68961063035516, + 115.160909051577, + 114.99704308477948, + 115.04003787644629, + 114.64197431850201, + 114.6164978373821, + 114.17357913620847, + 114.04888390508816, + 113.47749759323692, + 113.33895307826242, + 113.77835778204022, + 113.44096235560656, + 113.93690107631167, + 114.23285200404723, + 114.21616051641698, + 113.7212553243577, + 113.62534386602397, + 113.39352339076264, + 113.5020438985756, + 113.70699262904515, + 113.84341841029567, + 113.73655154831609, + 114.1497563009219, + 114.22530724493262, + 114.6477620789187, + 115.46016727097924, + 115.94737267462702, + 116.71161543179153, + 117.16631635952771, + 117.44154503791424, + 118.229558953933, + 118.83608523974274, + 118.98780724495168, + 119.25249393115067, + 119.80522505094451, + 120.85622033089668, + 121.39985639860717, + 121.65508629769673, + 122.24166548064179, + 122.28662397673571, + 122.3127722514754, + 123.01257449757193, + 123.43378909718304, + 123.85934451710659, + 123.50324222218329, + 123.81707319549184, + 124.25828657439985, + 124.37972619028575, + 124.92615278534004, + 125.16727501841387, + 125.67008670461381, + 125.68579634003055, + 126.12514936737608, + 126.14282270721986, + 126.58258914602374, + 127.06586714081732, + 127.80463341686196, + 128.35968997610894, + 128.98554324759584, + 129.62147342337965, + 129.40960005098293, + 129.8886405783286, + 130.33946577364293, + 130.18350630098604, + 130.61779503796697, + 131.22349450086, + 131.73509118054955, + 132.5752982931831, + 132.55721154188097, + 131.82469811414364, + 132.3572237489114, + 133.01956058159635, + 133.55084598198908, + 134.39306847548204, + 134.67863244032696, + 135.29849124566795, + 135.8826933127276, + 136.2583809754895, + 136.49247521377168, + 136.951620314685, + 136.6851249533558, + 136.3054065288751, + 135.96175825413417, + 136.07761681533253, + 135.78383629775323, + 135.4286641786112, + 135.50018436090318, + 136.2951745952813, + 137.06536014215942, + 137.5804708192448, + 138.30321740127897, + 138.58516401586343, + 139.10854292211548, + 139.2605749859182, + 140.2151420432137, + 140.87541181860695, + 141.07111046769626, + 141.27409549373874, + 141.39822228410384, + 141.70218305884464, + 141.56338016170866, + 141.6355204611881, + 141.5198686057189, + 141.65092003801107, + 141.8426912782462, + 141.68699018775084, + 141.9286291851476, + 142.11848839738798, + 142.1437064963464, + 142.51526004452495, + 142.797310011974, + 142.86676313697427, + 143.11594689348573, + 143.15863162655876, + 143.5221236512998, + 143.5971578309876, + 143.5618111513, + 143.9220992372389, + 144.56371382057483, + 144.89485639870117, + 145.3747237489635, + 145.27199100156724, + 145.4852596376358, + 145.63698164284472, + 145.88885257383532, + 146.16030887266453, + 146.06367394427872, + 146.38747846901964, + 147.4710815777479, + 148.17760176004242, + 148.84841352762322, + 148.71746544819558, + 149.28942020080206, + 149.6783370302307, + 150.07738244038853, + 150.48293908101516, + 150.72726525289113, + 150.89955447815225, + 151.60917524638427, + 152.07353966695905, + 152.8551973818059, + 153.1361621441768, + 153.16194868389044, + 153.0929089703485, + 153.56946902894418, + 153.51210818910022, + 153.339095493787, + 153.06924116435886, + 153.08955000224955, + 152.89157759013938, + 152.45000247620533, + 151.70911746643674, + 151.3439717958624, + 151.0105554547152, + 150.71413943908902, + 150.3282198427333, + 150.0752120302323, + 149.9461243023672, + 149.99728397033613, + 149.42388227762552, + 148.30462243061584, + 147.38173302631526, + 146.92212283751132, + 146.31792199115478, + 145.4896521343806, + 144.87697635312816, + 145.03221235573295, + 144.48568240781407, + 143.60997358619602, + 142.74542687395297, + 142.17832970598192, + 141.60658165910468, + 140.63857872941327, + 139.99215823787426, + 139.8065881695141, + 139.57414757706528, + 139.08280805883413, + 138.12074791885635, + 138.44946170466494, + 138.20756432510672, + 137.71917036351618, + 136.8294055523147, + 137.35237104710848, + 137.50388634658827, + 137.8901160015377, + 137.81032759007905, + 136.9968371929404, + 136.37201745009935, + 135.98904341038428, + 135.20821251845405, + 135.23921837782916, + 134.6134167827746, + 134.08590376193916, + 134.27390262261702, + 132.99077680880976, + 132.28808068250487, + 131.32633060112084, + 129.53579389863972, + 128.24093753470225, + 127.1028674663383, + 126.14871382050114 + ], + "lat": [ + -32.21596607842059, + -32.72875131605285, + -32.95948658623607, + -33.4838473447017, + -33.89017913181271, + -33.914467054989885, + -34.0034021949642, + -33.821036065406176, + -33.93017669040661, + -33.9760653622818, + -34.50936614353394, + -34.46414926527854, + -34.74681934991509, + -35.0647327613747, + -35.02545867283287, + -35.02509693780683, + -34.38642791111157, + -34.19651702243893, + -33.623425388322055, + -33.48725798923297, + -33.25957162855497, + -32.900368747694166, + -32.205062351207005, + -31.612437025683807, + -30.601594333622465, + -30.03072478609414, + -29.461043796508527, + -28.81023080822467, + -28.51639861421308, + -28.11807667410732, + -27.334713636994813, + -26.543134047147902, + -26.116545098578484, + -26.549025160429174, + -25.621278171493167, + -25.91123463308287, + -26.29844614024588, + -25.786281019801123, + -24.99893889740214, + -24.683971042583167, + -24.384712823180937, + -23.806350192970285, + -23.56021534596409, + -23.059987481378755, + -22.47547535572538, + -21.755829359628745, + -22.517488295178673, + -21.829519952076954, + -21.495173435148537, + -21.068687839443704, + -20.701681817306824, + -20.623547051681516, + -20.74689869556221, + -20.37420826587322, + -20.263310642174858, + -20.044202569257315, + -19.952941989829867, + -19.976506442954964, + -19.683707777589206, + -19.239755547769725, + -18.70531788500717, + -18.197648614171804, + -17.798603204013958, + -17.254915459871157, + -16.405199883695886, + -17.268558037996215, + -17.069035332917288, + -16.596506036040402, + -16.111316013252, + -16.327943617419535, + -15.56705982835399, + -15.07510019293536, + -14.680395603090028, + -14.510070082256014, + -14.23065561285385, + -14.347340996968903, + -14.095986830301227, + -13.952791436420448, + -13.817967624570954, + -14.27690601975508, + -14.869169610252243, + -14.875990899314765, + -14.969783623924522, + -14.42066985439107, + -13.618703301653492, + -13.357375583553484, + -13.107520033422276, + -12.536392103732489, + -12.183648776908166, + -12.302452894747184, + -12.114040622611007, + -11.603012383676678, + -11.27378183354515, + -11.128519382372696, + -11.376411228076812, + -11.786515394745116, + -12.042365411022182, + -11.941182956594693, + -12.248606052299046, + -11.962266940969776, + -12.049341729381588, + -11.857208754120398, + -12.351958916882793, + -12.887223402562022, + -13.291229750219884, + -13.324509372615852, + -13.724278252825783, + -14.2239893530882, + -14.715432224183912, + -14.997740573794424, + -15.55026498785913, + -15.87076222093333, + -16.21508228929408, + -16.807604261952704, + -16.806622409739155, + -17.06267913174539, + -17.371600843986208, + -17.710804945550066, + -17.369068698803908, + -16.83204721442676, + -16.38887013109165, + -15.840531508042588, + -15.044921156476901, + -14.561333103089552, + -14.270394789286307, + -13.698078301653808, + -12.944687595270585, + -12.741547539931231, + -12.407614434461145, + -11.877465915578817, + -11.328042087451612, + -11.042736504768186, + -10.668185723516686, + -11.157354831591562, + -11.784706719614903, + -11.905629571177885, + -12.325655612846232, + -12.834358412327433, + -13.400422051652612, + -13.763655694232192, + -14.548310642151996, + -14.171176039285903, + -14.594457696188641, + -14.98497649501833, + -15.428205254785732, + -16.28567229580478, + -16.78491830817657, + -16.906926364817686, + -17.761654554925272, + -18.28007252367734, + -18.958274021075887, + -19.48072275154673, + -19.9559392229028, + -20.391209812097244, + -20.63346892668155, + -21.260510756111135, + -22.342511895438385, + -22.122783705333337, + -22.556142266532994, + -22.402353204032373, + -23.462236830338696, + -24.07625619883074, + -24.45783497487393, + -25.267501316023, + -26.071173191026215, + -26.641319268502457, + -27.260299574494514, + -28.11006682710208, + -28.99507740653271, + -29.45820159273248, + -30.350240166954794, + -30.923641859665423, + -31.640445651986, + -32.550002536755265, + -33.041342054986394, + -33.81602345147387, + -34.31036020277793, + -35.173459974916796, + -35.671879164371916, + -36.42020558039054, + -37.10905242284121, + -37.42526051203518, + -37.77268116633344, + -37.809061374666925, + -38.21921721776752, + -38.606532077795116, + -39.03575652441141, + -38.59376799901902, + -38.41744801203915, + -37.89618783951102, + -38.085323581699285, + -38.8094654274053, + -38.538267510737555, + -38.380034275059835, + -38.30851409276788, + -38.019332777662555, + -37.402936293285094, + -36.64360279718831, + -36.13836231867066, + -35.732754001611745, + -35.61229623793939, + -35.127261244447865, + -34.38472258884593, + -35.076825046531, + -35.26053476332861, + -34.7073385556441, + -34.13026783624075, + -33.64047861097838, + -32.90000701266812, + -33.752771498348615, + -34.094766127256236, + -34.89011809666046, + -34.478670342752565, + -33.94795338311502, + -33.222778008763164, + -32.84807219821479, + -32.61723357516699, + -32.01122405368019, + -31.982646986622782, + -31.49580331800104, + -31.590422865527465, + -31.948488864877852, + -32.28226694105106, + -32.21596607842059 + ] + }, + { + "lon": [ + 81.7879590188914, + 81.63732221876059, + 81.21801964714433, + 80.34835696810441, + 79.87246870312853, + 79.69516686393513, + 80.14780073437964, + 80.83881798698656, + 81.30431928907177, + 81.7879590188914 + ], + "lat": [ + 7.523055324733164, + 6.481775214051922, + 6.197141424988288, + 5.968369859232155, + 6.76346344647493, + 8.200843410673386, + 9.824077663609557, + 9.268426825391188, + 8.56420624433369, + 7.523055324733164 + ] + }, + { + "lon": [ + 129.37099775606094, + 130.47134402885177, + 130.83483605359282, + 129.99054650280817, + 129.15524865124235, + 128.59068362845363, + 127.89889122936235, + 128.13587934785284, + 129.37099775606094 + ], + "lat": [ + -2.8021542293445947, + -3.093764336767634, + -3.8584721818227763, + -3.446300957862796, + -3.3626368139822485, + -3.428679294451264, + -3.393435967628207, + -2.843650404474971, + -2.8021542293445947 + ] + }, + { + "lon": [ + 126.87492272349886, + 126.18380211802736, + 125.98903364471926, + 127.00065148326497, + 127.24921512258891, + 126.87492272349886 + ], + "lat": [ + -3.790931084817302, + -3.607376397316564, + -3.177221774919012, + -3.129317722184446, + -3.45906503663889, + -3.790931084817302 + ] + }, + { + "lon": [ + 127.93237755748748, + 128.00415612194087, + 128.5945593608755, + 128.6882487326207, + 128.63595218314134, + 128.1201697124361, + 127.96803429576886, + 128.3799988139997, + 128.1000159038423, + 127.69647464407507, + 127.39949018769369, + 127.60051150930906, + 127.93237755748748 + ], + "lat": [ + 2.1745962589565693, + 1.6285313989283452, + 1.5408106551128782, + 1.1323859724940633, + 0.2584858260061935, + 0.3564126651992865, + -0.25207732503751856, + -0.7800037573313005, + -0.8999964331130315, + -0.26659840251153355, + 1.011721503092545, + 1.810690822757195, + 2.1745962589565693 + ] + }, + { + "lon": [ + 122.9275667664518, + 124.07752241424288, + 125.0659892111218, + 125.2405005229715, + 124.4370353536974, + 123.6855049988767, + 122.72308312387287, + 121.05672488818911, + 120.18308312386272, + 120.04086958219548, + 120.93590538949073, + 121.4758207540762, + 123.34056481332846, + 123.25839928598441, + 122.82266360889932, + 122.38852990121529, + 121.50827355355551, + 122.4545723816843, + 122.2718961935325, + 123.17096276254655, + 123.1623327983538, + 122.62851525277875, + 122.23639448454801, + 122.71956912647701, + 121.73823367725436, + 121.48946333220127, + 121.61917117725386, + 120.89818159391766, + 120.97238895068878, + 120.30545291552986, + 120.39004723519167, + 120.43071658740537, + 119.79654341031949, + 119.36690555224489, + 119.65360639860017, + 119.49883548388601, + 119.07834435432704, + 118.76776899625287, + 119.18097374885869, + 119.3233939962551, + 119.82599897672587, + 120.0357019389663, + 120.88577925016762, + 121.66681684782696, + 122.9275667664518 + ], + "lat": [ + 0.8751923689774088, + 0.9171019555661245, + 1.6432591821315297, + 1.4198361271176054, + 0.4278811710589565, + 0.235593166500891, + 0.4311367862933366, + 0.3812173526993945, + 0.2372468123342344, + -0.5196578914448367, + -1.408905938323393, + -0.9559620092851304, + -0.6156727026431383, + -1.0762130672283092, + -0.9309506160558526, + -1.516858005381117, + -1.904482924002458, + -3.1860584448409237, + -3.5295000138527115, + -4.683693129091701, + -5.340603936385996, + -5.634591159694466, + -5.2829330379482675, + -4.464171644715826, + -4.851331475446543, + -4.574552504091265, + -4.1884778784386825, + -3.602105401222794, + -2.627642917494939, + -2.9316036922357327, + -4.097579034037274, + -5.528241062037793, + -5.673400160345665, + -5.3798780249278195, + -4.459417412944973, + -3.4944117163265322, + -3.487021986508793, + -2.801999200047718, + -2.1471037736128054, + -1.3531470678804638, + 0.1542544620734816, + 0.5664773624657613, + 1.3092227237968501, + 1.0139435896810909, + 0.8751923689774088 + ] + }, + { + "lon": [ + 120.29501427620689, + 118.96780846565471, + 119.90030968636157, + 120.42575564990534, + 120.77550174365675, + 120.71560875863045, + 120.29501427620689 + ], + "lat": [ + -10.258649997603591, + -9.557969252158074, + -9.361340427287502, + -9.665921319215798, + -9.96967538822743, + -10.239581394087885, + -10.258649997603591 + ] + }, + { + "lon": [ + 121.34166873584651, + 122.00736453663043, + 122.90353722543607, + 122.75698286345632, + 121.2544905945701, + 119.92439090380958, + 119.92092858284605, + 120.71509199430757, + 121.34166873584651 + ], + "lat": [ + -8.536739597206072, + -8.460620212440148, + -8.094234307490765, + -8.649807631060696, + -8.933666273639957, + -8.81041798262384, + -8.444858900591122, + -8.236964613480914, + -8.536739597206072 + ] + }, + { + "lon": [ + 118.26061648974044, + 118.87845991422208, + 119.12650678922307, + 117.97040164598928, + 117.27773074754901, + 116.74014082241665, + 117.0837374207253, + 117.6320243673421, + 117.90001834520776, + 118.26061648974044 + ], + "lat": [ + -8.362383314653293, + -8.280682875199844, + -8.705824883665088, + -8.906639499551304, + -9.040894870645594, + -9.032885023640354, + -8.45715789147659, + -8.449303073768228, + -8.09568124759494, + -8.362383314653293 + ] + }, + { + "lon": [ + 108.48684614464926, + 108.62347863162896, + 110.53922732955328, + 110.75957563684585, + 112.6148112325564, + 112.97876834518806, + 114.47893517462114, + 115.70552697150106, + 114.56451134649649, + 113.46473351446085, + 112.55967247930097, + 111.52206139531245, + 110.58614953007432, + 109.42766727095511, + 108.69365522668133, + 108.27776329959633, + 106.45410200401612, + 106.28062422081231, + 105.36548628135552, + 106.05164594932702, + 107.2650085795402, + 108.07209109907467, + 108.48684614464926 + ], + "lat": [ + -6.42198495852574, + -6.777673841990705, + -6.877357679881726, + -6.465186455921747, + -6.946035658397626, + -7.594213148634594, + -7.7765276017603275, + -8.370806573116873, + -8.751816908404855, + -8.348947442257405, + -8.376180922075221, + -8.302128594600973, + -8.122604668819001, + -7.740664157749762, + -7.641600437046243, + -7.766657403192576, + -7.354899590690934, + -6.924899997590252, + -6.851416110871206, + -5.895918877794472, + -5.954985039904081, + -6.3457622208952245, + -6.42198495852574 + ] + }, + { + "lon": [ + 104.36999148968489, + 104.53949018760221, + 104.88789269411402, + 105.62211144411697, + 106.10859337771265, + 105.85744591677414, + 105.8176550639094, + 104.71038414919144, + 103.86821333213078, + 102.5842606954069, + 102.156173130301, + 101.39911339722507, + 100.90250288290015, + 100.14198082886065, + 99.26373986206028, + 98.97001102091326, + 98.60135135294306, + 97.69959760944985, + 97.17694217324984, + 96.42401655475726, + 95.3808760925135, + 95.29302615761729, + 95.93686282754174, + 97.4848820332771, + 98.36916914265566, + 99.1425586283358, + 99.69399783732241, + 100.64143354696162, + 101.65801232300734, + 102.49827111207323, + 103.07684044801303, + 103.83839603069836, + 103.4376452982749, + 104.01078860882404, + 104.36999148968489 + ], + "lat": [ + -1.0848430314210589, + -1.7823715144967662, + -2.340425306816705, + -2.4288436824680986, + -3.0617766251789647, + -4.305524997579774, + -5.85235564537242, + -5.873284600450632, + -5.037314955264996, + -4.2202588842981825, + -3.6141460099468006, + -2.7997771134591645, + -2.050262139497832, + -0.6503475887109857, + 0.1831415877246343, + 1.042882391764536, + 1.8235065779655741, + 2.45318390544206, + 3.3087905948985963, + 3.868859768077925, + 4.970782172053688, + 5.479820868344788, + 5.439513251157123, + 5.246320909033955, + 4.2683702661263965, + 3.590349636240873, + 3.174328518075143, + 2.099381211755741, + 2.0836974145551608, + 1.3987004663102311, + 0.5613613956688681, + 0.10454173420869493, + -0.7119458960029021, + -1.0592115210042863, + -1.0848430314210589 + ] + }, + { + "lon": [ + 120.83389611214656, + 120.32343631396745, + 121.18012820850211, + 121.5273938335035, + 121.26219038298159, + 120.83389611214656 + ], + "lat": [ + 12.704496161342433, + 13.466413479053825, + 13.429697373910443, + 13.06959015548452, + 12.205560207564403, + 12.704496161342433 + ] + }, + { + "lon": [ + 122.5860889018671, + 122.83708133350875, + 122.9474105164519, + 123.49884972543845, + 123.33777428598472, + 124.0779358257012, + 123.98243777882584, + 123.62307986866814, + 123.30992068897939, + 122.9958313335094, + 122.38005496631942, + 122.5860889018671 + ], + "lat": [ + 9.981044826696134, + 10.26118276615037, + 10.88186839440806, + 10.94062449792392, + 10.267383938025404, + 11.232725531453738, + 10.278778591345755, + 9.950090643753299, + 9.318268744336706, + 9.022188625520414, + 9.713360907424217, + 9.981044826696134 + ] + }, + { + "lon": [ + 126.37681359263745, + 126.47851281138789, + 126.53742394420061, + 126.19677290253259, + 125.83142052622907, + 125.36385216685221, + 125.68316084198369, + 125.39651167206063, + 124.21978763234239, + 123.9387195171069, + 124.24366214406128, + 123.61016076059519, + 123.29607140512519, + 122.82550581267537, + 122.08549930225573, + 121.91992801319256, + 122.31235884001705, + 122.94239790251959, + 123.48768761606347, + 123.84115441293983, + 124.60146976125021, + 124.76461225799562, + 125.47139082245155, + 125.41211795461277, + 126.2227144715431, + 126.30663699758514, + 126.37681359263745 + ], + "lat": [ + 8.414706325713297, + 7.750354112168978, + 7.189406439640692, + 6.274294338400054, + 7.293715318221842, + 6.786485297060949, + 6.049656887227272, + 5.5810033227722755, + 6.161355495626154, + 6.885135606306136, + 7.360610459823661, + 7.83352732994274, + 7.418875637232759, + 7.457374579290204, + 6.899424139834836, + 7.192119452336015, + 8.034962063016465, + 8.316236883981134, + 8.693035590037326, + 8.240324204944372, + 8.514157619659002, + 8.960409450715488, + 8.986996975129657, + 9.760334784377534, + 9.286074327018866, + 8.78248749433456, + 8.414706325713297 + ] + }, + { + "lon": [ + 109.47520958866365, + 108.65520796105616, + 108.62621748254044, + 109.11905561730804, + 110.21159874882281, + 110.78655073450221, + 111.01005130416458, + 110.57064660038677, + 110.33918786015147, + 109.47520958866365 + ], + "lat": [ + 18.197700913968575, + 18.507681993071387, + 19.367887885001906, + 19.821038519769345, + 20.101253973872033, + 20.077534491450052, + 19.69592987719072, + 19.25587921800927, + 18.678395087147592, + 18.197700913968575 + ] + }, + { + "lon": [ + 121.77781782438993, + 121.17563235889274, + 120.74707970589623, + 120.22008344938368, + 120.1061885926124, + 120.69467980355225, + 121.49504438688878, + 121.95124393116146, + 121.77781782438993 + ], + "lat": [ + 24.3942735865194, + 22.790857245367167, + 21.970571397382113, + 22.81486094816674, + 23.556262722258236, + 24.538450832613737, + 25.295458889257386, + 24.997595933527037, + 24.3942735865194 + ] + }, + { + "lon": [ + 141.88460086483497, + 140.95948937394581, + 140.97633589087297, + 140.5997697287621, + 140.77407433488258, + 140.2532792502451, + 138.9755277853962, + 137.21759891169125, + 135.79298302626893, + 135.1209827007454, + 135.0794348491827, + 133.34031619683202, + 132.15677086805124, + 130.98614464734345, + 132.00003624890996, + 131.33279015515734, + 130.686317987186, + 130.2024198752049, + 130.44767622286213, + 129.81469160371893, + 129.40841149304026, + 130.35393517468464, + 130.87845096244718, + 131.8842293641439, + 132.61767296766243, + 134.6083008159777, + 135.67753787652885, + 136.72383060114242, + 137.39061160700447, + 138.8576021669062, + 139.42640465714283, + 140.054790073812, + 139.88337934789985, + 140.30578250545364, + 141.3689734234266, + 141.91426313697048, + 141.88460086483497 + ], + "lat": [ + 39.180864569651476, + 38.17400096287662, + 37.14207428644019, + 36.3439834661245, + 35.842877102190215, + 35.13813975680979, + 34.66760000257614, + 34.60628591566183, + 33.46480520276663, + 33.849071153289, + 34.596544908174806, + 34.375938218720805, + 33.90493337659652, + 33.88576142021624, + 33.149992377244544, + 31.450354519164822, + 31.029579169228246, + 31.418237616495432, + 32.319474595665696, + 32.61030955660436, + 33.29605581311752, + 33.60415070244167, + 34.23274282484002, + 34.74971385348792, + 35.433393052709405, + 35.731617743465804, + 35.52713410088687, + 37.304984239240326, + 36.82739065199884, + 37.82748464614346, + 38.21598806411376, + 39.43880748143637, + 40.56331248632368, + 41.19500519465953, + 41.378559882160275, + 39.991616115878685, + 39.180864569651476 + ] + }, + { + "lon": [ + 144.61342654843963, + 145.32082523008307, + 145.5431372418027, + 144.05966189999987, + 143.18384972551723, + 141.6114909201724, + 141.06728641170668, + 139.955106235921, + 139.81754357315998, + 140.31208703019325, + 141.38054894426, + 141.67195234595386, + 141.96764489152798, + 143.14287031470974, + 143.91016198137947, + 144.61342654843963 + ], + "lat": [ + 43.96090871843361, + 44.38473297787541, + 43.262114162766764, + 42.98835826270056, + 41.9952147486992, + 42.6787905950561, + 41.58459381770797, + 41.56955597591103, + 42.563758856774385, + 43.33327261003269, + 43.38882477474644, + 44.77212535255146, + 45.55148346616134, + 44.51035838477697, + 44.17409983985374, + 43.96090871843361 + ] + }, + { + "lon": [ + 8.709990675500109, + 9.210011834356266, + 9.80997521326492, + 9.669518670295616, + 9.214817742559433, + 8.806935662479674, + 8.428302443077115, + 8.388253208050912, + 8.159998406617689, + 8.709990675500109 + ], + "lat": [ + 40.899984442705225, + 41.209991360024176, + 40.50000885676613, + 39.17737641047178, + 39.24047333430015, + 38.906617743478506, + 39.17184703221655, + 40.37831085871876, + 40.95000722916376, + 40.899984442705225 + ] + }, + { + "lon": [ + 8.746009148807559, + 9.390000848028876, + 9.560016310269134, + 9.229752231491773, + 8.775723097375362, + 8.544212680707773, + 8.746009148807559 + ], + "lat": [ + 42.62812185319392, + 43.00998484961471, + 42.152517808595654, + 41.380006822264455, + 41.58361196549443, + 42.2565424667992, + 42.62812185319392 + ] + }, + { + "lon": [ + 12.370904168353292, + 12.690006137755603, + 12.089991082414684, + 11.043543328504226, + 10.903913608451603, + 12.370904168353292 + ], + "lat": [ + 56.111407375708794, + 55.60999095318074, + 54.80001455343792, + 55.36486379660424, + 55.77995473898872, + 56.111407375708794 + ] + }, + { + "lon": [ + -4.211494513353671, + -3.005004848635309, + -4.073828497728101, + -3.05500179687769, + -1.9592805647769467, + -2.2199881656894433, + -3.1190030582711756, + -2.08500932454308, + -1.1149910139923236, + -0.430484991854172, + 0.18498131674203933, + 0.4699768408317197, + 1.6815307959147103, + 1.559987827164207, + 1.0505615576309424, + 1.4498653499502439, + 0.5503336930455873, + -0.7875174625587248, + -2.489997524414491, + -2.956273972984065, + -3.617448085942442, + -4.542507900399272, + -5.245023159191136, + -5.776566941745344, + -4.30998979330198, + -3.4148506331421515, + -4.984367234710916, + -5.267295701508927, + -4.222346564134966, + -4.770013393564227, + -4.579999152027, + -3.092079637047106, + -2.9450085107444295, + -3.630005458989359, + -4.8441690739030605, + -5.082526617849339, + -4.719112107756729, + -5.047980922862223, + -5.5863976709112535, + -5.644998745130239, + -6.149980841486425, + -5.786824713555276, + -5.009998745127689, + -4.211494513353671 + ], + "lat": [ + 58.55084503847897, + 58.635000108466286, + 57.553024807355186, + 57.69001902936095, + 57.68479970969946, + 56.870017401753486, + 55.97379303651553, + 55.909998480851215, + 54.62498647726534, + 54.4643761257022, + 53.32501414653097, + 52.92999949809191, + 52.73952016866405, + 52.09999848083598, + 51.80676056579574, + 51.28942780212179, + 50.76573883727595, + 50.77498891865619, + 50.50001862243113, + 50.69687999124703, + 50.228355617872744, + 50.34183706318571, + 49.95999990498106, + 50.15967763935686, + 51.21000112568919, + 51.42600861266921, + 51.59346609151103, + 51.9914004583746, + 52.30135569926125, + 52.8400049912556, + 53.495003770555094, + 53.40444082296359, + 53.98499970154664, + 54.615012925833014, + 54.790971177786844, + 55.06160065369939, + 55.50847260194335, + 55.78398550070749, + 55.31114614523683, + 56.27501496034486, + 56.78500967063335, + 57.818848375064576, + 58.63001333275011, + 58.55084503847897 + ] + }, + { + "lon": [ + -14.508695441129234, + -14.739637417041607, + -13.60973222497981, + -14.909833746794902, + -17.794438035543422, + -18.656245896874992, + -19.97275468594276, + -22.762971971110158, + -21.778484259517683, + -23.95504391121911, + -22.184402635170358, + -22.227423265053332, + -24.326184047939336, + -23.65051469572309, + -22.134922451250887, + -20.57628373867955, + -19.05684160000159, + -17.79862382655905, + -16.167818976292125, + -14.508695441129234 + ], + "lat": [ + 66.45589223903143, + 65.8087482774403, + 65.12667104761987, + 64.36408193628868, + 63.678749091233854, + 63.49638296167582, + 63.64363495549153, + 63.960178941495386, + 64.40211579045551, + 64.8911298692335, + 65.0849681667603, + 65.37859365504274, + 65.61118927678847, + 66.26251902939522, + 66.41046865504687, + 65.73211212835143, + 66.27662669541091, + 65.99385325790978, + 66.52681814235201, + 66.45589223903143 + ] + }, + { + "lon": [ + 142.91461551327654, + 143.2608476096321, + 143.23526777564763, + 143.64800744036285, + 144.6541475770856, + 143.1739278505172, + 142.55866824765013, + 143.53349246640403, + 143.50527713437265, + 142.74770063697383, + 142.09203006405454, + 141.906925083585, + 142.01844282447087, + 141.90444461483503, + 142.1358000022057, + 142.17998335181528, + 141.59407596249002, + 141.6825460145737, + 142.60693403541075, + 142.20974897681543, + 142.65478641171302, + 142.91461551327654 + ], + "lat": [ + 53.704577541714784, + 52.74076040303906, + 51.75666026468876, + 50.747600409541505, + 48.97639069273754, + 49.306551418650315, + 47.86157501890495, + 46.83672801369252, + 46.137907619809525, + 46.74076487892651, + 45.966755276058834, + 46.80592886004656, + 47.78013296161296, + 48.85918854429957, + 49.61516307229739, + 50.9523424342819, + 51.9354348822025, + 53.301966457728795, + 53.762145087287934, + 54.225475979216874, + 54.36588084575389, + 53.704577541714784 + ] + }, + { + "lon": [ + 118.50458092659036, + 117.17427453010066, + 117.66447716682137, + 118.38691369026175, + 118.98734215706105, + 119.51149620979751, + 119.68967654833989, + 119.02945844937892, + 118.50458092659036 + ], + "lat": [ + 9.316382554558047, + 8.367499904814679, + 9.066888739452892, + 9.68449961998921, + 10.376292019080523, + 11.3696680770272, + 10.554291490109875, + 10.003653265823829, + 9.316382554558047 + ] + }, + { + "lon": [ + 122.336956821788, + 122.17427941293317, + 122.5156539246533, + 122.25231082569393, + 121.66278608610821, + 121.50501793832112, + 121.7288285665772, + 122.25892540902726, + 122.70127566944569, + 123.9502950379403, + 123.85510704965867, + 124.18128869028493, + 124.0774190613783, + 123.29803510955225, + 122.92865197152994, + 122.6713550151487, + 122.03464969288052, + 121.12638471891857, + 120.62863732308324, + 120.67938357959386, + 120.99181928923053, + 120.69333621631267, + 120.56414513558299, + 120.07042850146644, + 119.92092858284605, + 119.88377322802819, + 120.28643598844644, + 120.39004723519167, + 120.71586714079191, + 121.32130822152351, + 121.9376013530364, + 122.24600630095429, + 122.336956821788 + ], + "lat": [ + 18.224882717354106, + 17.810282701076403, + 17.093504746971973, + 16.26244436285407, + 15.931017564350142, + 15.124813544164622, + 14.328376369682275, + 14.21820221603599, + 14.336541245984378, + 13.782130642141027, + 13.237771104378425, + 12.9975273706535, + 12.536676947474575, + 13.02752553959894, + 13.552919826710422, + 13.185836289925092, + 13.784481919810304, + 13.636687323455547, + 13.857655747935596, + 14.271015529838294, + 14.52539276779504, + 14.756670640517312, + 14.396279201713796, + 14.970869452367126, + 15.406346747290739, + 16.363704331929995, + 16.034628811095345, + 17.599081122299523, + 18.505227362537525, + 18.504064642810945, + 18.218552354398355, + 18.478975734933243, + 18.224882717354106 + ] + }, + { + "lon": [ + 122.03837039600555, + 121.88354780485909, + 122.48382124236149, + 123.12021650603594, + 123.10083784392646, + 122.63771365772669, + 122.00261030485957, + 121.96736697803652, + 122.03837039600555 + ], + "lat": [ + 11.415840969279998, + 11.891755072471994, + 11.582213243043682, + 11.583660183147856, + 11.16593374271649, + 10.74130849857417, + 10.441016750526089, + 10.905691229694625, + 11.415840969279998 + ] + }, + { + "lon": [ + 125.50255171112354, + 125.78341312062992, + 125.01188398651226, + 125.03276126515817, + 125.27744917206019, + 124.80181928924577, + 124.76016808481853, + 124.45910119028605, + 124.30252160044171, + 124.89101281138153, + 124.87799035044401, + 124.26676150929569, + 125.22711632700788, + 125.50255171112354 + ], + "lat": [ + 12.162694606978292, + 11.046147772663929, + 11.311454576050409, + 10.975816148314692, + 10.358722032101284, + 10.134678859899864, + 10.837995103392258, + 10.889929917845592, + 11.495370998577187, + 11.415582587118536, + 11.794189968304947, + 12.557760931849671, + 12.53572093347718, + 12.162694606978292 + ] + }, + { + "lon": [ + -77.35336076527386, + -76.83667395700357, + -76.08638383655786, + -75.67460018584006, + -75.66470414905618, + -75.48042599150335, + -74.90689510771199, + -74.27675269234489, + -74.1972226630477, + -73.41476396350029, + -72.62783525255963, + -72.23819495307892, + -71.75409013536864, + -71.3998223537917, + -71.13746110704588, + -71.3315836249503, + -71.36000566271082, + -71.94704993354651, + -71.62086829292019, + -71.63306393094109, + -72.07417395698451, + -71.69564409044654, + -71.26455929226773, + -71.03999935574339, + -71.35008378771079, + -71.40062333849224, + -70.15529883490652, + -70.29384334988103, + -69.94324459499683, + -69.58430009629747, + -68.88299923366445, + -68.23327145045873, + -68.19412655299763, + -67.29624854192633, + -66.227864142508, + -65.65523759628175, + -64.89045223657817, + -64.32947872583374, + -64.31800655786495, + -63.07932247582873, + -61.880946010980196, + -62.73011898461641, + -62.388511928950976, + -61.58876746280194, + -60.83059668643172, + -60.67125240745973, + -60.15009558779618, + -59.758284878159195, + -59.10168412945866, + -58.48296220562806, + -58.45487606467742, + -58.078103196837375, + -57.542218593970645, + -57.14743648947689, + -55.9493184067898, + -55.841779751190415, + -55.033250291551774, + -53.9580446030709, + -53.618452928264844, + -52.88214128275409, + -51.8233428615259, + -51.65779741067889, + -51.29998979348996, + -51.069771287629656, + -50.508875291533656, + -49.97407589374506, + -49.94710079608871, + -50.699251268096916, + -50.38821082213214, + -48.62056677915632, + -48.58449662941659, + -47.824956427590635, + -46.566583624851226, + -44.905703090990414, + -44.417619187993665, + -44.58158850765578, + -43.418791266440195, + -41.47265682632825, + -39.97866533055404, + -38.50038347019657, + -37.2232521225352, + -36.45293738457639, + -35.59779578301047, + -35.23538896334756, + -34.89602983248683, + -34.729993455533034, + -35.12821204277422, + -35.636966518687714, + -37.046518724097, + -37.68361161960736, + -38.42387651218844, + -38.67388709161652, + -38.953275722802545, + -38.88229814304965, + -39.16109249526431, + -39.2673392400564, + -39.58352149103423, + -39.76082333022764, + -40.77474077001034, + -40.94475623225061, + -41.754164191238225, + -41.98828426773656, + -43.07470374202475, + -44.64781185563781, + -45.35213578955992, + -46.47209326840554, + -47.64897233742066, + -48.4954581365777, + -48.64100480812774, + -48.474735887228654, + -48.661520351747626, + -48.8884574041574, + -49.587329474472675, + -50.696874152211485, + -51.576226162306156, + -52.256081305538046, + -52.712099982297694, + -53.373661668498244, + -53.806425950726535, + -54.93586605489773, + -55.67408972840329, + -56.21529700379607, + -57.1396850246331, + -57.81786068381551, + -58.42707414410439, + -58.49544206402655, + -57.22582963726366, + -57.36235877137878, + -56.73748735210545, + -56.78828528504836, + -57.74915686708346, + -59.23185706240189, + -61.23744523786564, + -62.33595699731013, + -62.125763108962936, + -62.330530971919494, + -62.145994432205214, + -62.745802781816984, + -63.77049475773255, + -64.73208980981973, + -65.11803524439158, + -64.97856055363582, + -64.3034079657425, + -63.75594784204239, + -63.458059048095876, + -64.37880388045633, + -65.18180396183975, + -65.32882341171013, + -65.5652689276616, + -66.50996578638934, + -67.29379391139247, + -67.58054643418008, + -66.59706641301729, + -65.64102657740149, + -65.98508826360079, + -67.16617896184769, + -67.81608761256643, + -68.72874508327321, + -69.13853919134777, + -68.81556148952356, + -68.14999487982038, + -68.57154537624133, + -69.46128434922667, + -69.9427795071062, + -70.8451016913546, + -71.00633216010525, + -71.429794684521, + -72.55794287788488, + -73.7027567206629, + -74.94676347522517 + ], + "lat": [ + 8.67050466555807, + 8.638749497914716, + 9.336820583529487, + 9.443248195834599, + 9.774003200718738, + 10.618990383339309, + 11.083044745320322, + 11.102035834187587, + 11.310472723836867, + 11.22701528568548, + 11.731971543825523, + 11.955549628136326, + 12.437303168177309, + 12.376040757695293, + 12.112981879113505, + 11.776284084515808, + 11.539993597861212, + 11.423282375530022, + 10.969459947142795, + 10.446494452349029, + 9.865651353388373, + 9.072263088411248, + 9.137220363802129, + 9.859992784052409, + 10.211935126176215, + 10.968969021036015, + 11.37548167566004, + 11.846822414594214, + 12.162307033736099, + 11.459610907431212, + 11.443384507691563, + 10.885744126829946, + 10.554653225135922, + 10.54586823164631, + 10.648626817258688, + 10.200798855017323, + 10.0772146671913, + 10.38959870039568, + 10.64141795495398, + 10.7017243514386, + 10.715625311725104, + 10.420268662960906, + 9.94820445397464, + 9.873066921422264, + 9.381339829948942, + 8.580174261911878, + 8.602756862823426, + 8.367034816924047, + 7.999201971870492, + 7.347691351750697, + 6.832787380394464, + 6.809093736188643, + 6.321268215353356, + 5.973149929219161, + 5.772877915872002, + 5.95312531170606, + 6.025291449401664, + 5.756548163267765, + 5.6465290389183735, + 5.409850979021584, + 4.565768133966131, + 4.156232408053029, + 4.120007229016437, + 3.650397650564031, + 1.901563828942457, + 1.736483465986069, + 1.0461896834312228, + 0.22298411702168153, + -0.07844451253681939, + -0.2354891902718208, + -1.2378052710050014, + -0.5816179337628, + -0.941027520352776, + -1.551739597178134, + -2.137750339367976, + -2.691308282078524, + -2.383110039889793, + -2.9120183243971165, + -2.873054294449041, + -3.7006523576033956, + -4.820945733258917, + -5.109403578312154, + -5.149504489770649, + -5.464937432480247, + -6.738193047719711, + -7.343220716992967, + -8.996401462442286, + -9.649281508017815, + -11.040721123908803, + -12.171194756725823, + -13.038118584854288, + -13.057652276260619, + -13.793369642800023, + -15.667053724838768, + -17.208406670808472, + -17.867746270420483, + -18.262295830968938, + -19.59911345792741, + -20.904511814052423, + -21.93731698983781, + -22.370675551037458, + -22.970070489190896, + -22.96769337330547, + -23.351959323827842, + -23.796841729428582, + -24.088968601174543, + -24.885199069927722, + -25.877024834905654, + -26.62364592865864, + -27.17591196056189, + -28.18613453543572, + -28.674115085567884, + -29.224469089476337, + -30.98446502047296, + -31.77769825615321, + -32.24536996839467, + -33.19657805759118, + -33.768377780900764, + -34.39681487400223, + -34.952646579733624, + -34.75265878676407, + -34.85983570733742, + -34.430456231424245, + -34.4625472958775, + -33.909454441057576, + -34.43148976007008, + -35.28802662530788, + -35.977390232081476, + -36.41312590916655, + -36.901571547189334, + -38.18387053807989, + -38.72016855240494, + -38.9284245745412, + -38.827707208004334, + -39.42410491308485, + -40.17258635840034, + -40.67689666113672, + -41.0287614886121, + -41.16678923926369, + -40.80267709733515, + -41.06431487402891, + -42.05800099056934, + -42.35901620866951, + -42.043686618824495, + -42.563138116222405, + -42.87355844499969, + -43.495380954767796, + -44.501366062193696, + -45.036785577169795, + -45.03962778094586, + -45.55189625425519, + -46.30177296324257, + -47.033872979521526, + -47.23613453551193, + -48.133289076531135, + -48.697337334996945, + -49.86966887797038, + -50.26416676208654, + -50.732510267947795, + -51.77110320414986, + -52.349982598683425, + -52.299443047901974, + -52.29194996521966, + -52.53792978292897, + -52.89919972108146, + -53.83325123475707, + -53.85645395285612, + -53.53140919374024, + -52.835069268607235, + -52.26275278097475 + ] + }, + { + "lon": [ + -77.88157141794525, + -77.47666073272228, + -77.31881507028675, + -77.53322058786573, + -77.3076012844794, + -77.49627193877703, + -77.12768978545526, + -77.51043128122501, + -77.93154252797149, + -78.42761043975733, + -78.66211808949785, + -78.61783138702371, + -78.99093522817104, + -78.85525875518871, + -79.5427620103998, + -80.09060970734211, + -80.02089820018037, + -80.39932471385376, + -80.58337032746127, + -80.93365902375172, + -80.76480628123804, + -80.96776546906436, + -80.36878394236925, + -79.98655921092242, + -79.77029334178093, + -80.30256059438722, + -81.09966956248937, + -81.41094255239946, + -80.92634680858244, + -81.24999630402642, + -80.53748165558608, + -79.76057817251005, + -79.44592037628485, + -79.03695309112695, + -78.09215287953464, + -77.10619238962184, + -76.25924150257417, + -76.42346920439775, + -76.00920508492995, + -75.23788265654144, + -73.44452958850042, + -71.46204077827113, + -71.37525021023693, + -70.37257239447771, + -70.16441972520605, + -70.09124589708074, + -70.40396582709502, + -70.72495398627599, + -70.90512386746161, + -71.48989437527645, + -71.37008256700773, + -71.66872066922247, + -71.4384504869299, + -71.86173214383263, + -72.55313696968174, + -73.1667170884993, + -73.58806087919109, + -73.50555945503712, + -73.21759253609065, + -73.67709937202999, + -74.0179571194272, + -74.33194312203261, + -73.70133561877488, + -73.38889990913822, + -72.7178039211798, + -73.24035600451522, + -74.35170935738425, + -74.69215369332312, + -75.64439531116545, + -74.1265809801047, + -75.18276974150216, + -75.60801510283198, + -75.47975419788355, + -74.97663245308988, + -75.2600260077785, + -74.94676347522517 + ], + "lat": [ + 7.223771267114785, + 6.691116441266303, + 5.84535411216136, + 5.582811997902497, + 4.6679841170394525, + 4.087606105969428, + 3.8496361352653565, + 3.325016994638247, + 2.6966057397529255, + 2.629555568854215, + 2.2673554549204766, + 1.766404120283056, + 1.6913699405952514, + 1.380923773601822, + 0.982937730305963, + 0.7684288598623965, + 0.3603400740534682, + -0.28370330160014134, + -0.9066626928786832, + -1.057454522306358, + -1.9650477026485331, + -2.246942640800704, + -2.6851587866357884, + -2.220794366061014, + -2.65751189535964, + -3.4048564591647126, + -4.036394138203697, + -4.7367648250554595, + -5.690556735866565, + -6.136834405139183, + -6.541667575713717, + -7.194340915560084, + -7.93083342858386, + -8.386567884965892, + -10.377712497604065, + -12.22271615972082, + -13.535039157772943, + -13.823186944232432, + -14.649286390850321, + -15.265682875227782, + -16.359362888252996, + -17.363487644116383, + -17.77374684008157, + -18.34797535570887, + -19.756468194256165, + -21.39331918710126, + -23.628996677344574, + -25.705924167587256, + -27.640379734001247, + -28.861442152625923, + -30.09568206148503, + -30.920644626592495, + -32.41889942803078, + -33.90909270603153, + -35.50884002049106, + -37.12378020604439, + -37.15628468195598, + -38.282882582351114, + -39.25868865331856, + -39.94221282324317, + -41.79481292090683, + -43.22495818458442, + -43.365776462579774, + -42.117532240569574, + -42.38335580827898, + -44.454960625995604, + -44.10304412208794, + -45.76397633238103, + -46.64764332457207, + -46.93925343199511, + -47.7119194476232, + -48.67377288187184, + -50.37837167745158, + -51.0433956846157, + -51.62935475037325, + -52.26275278097475 + ] + }, + { + "lon": [ + -74.66254309761987, + -73.83809729683531, + -72.43417782254585, + -71.1077213202619, + -70.59178382025983, + -70.26748836941218, + -69.3456583319736, + -68.63412553574679, + -68.2500146145213, + -67.74999345566513, + -66.44999528671462, + -65.05000322127933, + -65.50000159367697, + -66.44999528671462, + -66.95991248235468, + -67.29102922226485, + -68.14862545436465, + -68.63999081081192, + -69.23209937201221, + -69.95807573106458, + -71.00568620470159, + -72.26390397814413, + -73.28521114774458, + -74.66254309761987 + ], + "lat": [ + -52.83749806092496, + -53.04740772889455, + -53.71537729269931, + -54.07432179139866, + -53.61584848410516, + -52.93123910910242, + -52.51829273865806, + -52.6362700335804, + -53.10001433696767, + -53.84999439881963, + -54.45000945416058, + -54.700020033588665, + -55.199989516012536, + -55.25001230247107, + -54.896803887756114, + -55.30122364687231, + -55.61185068137877, + -55.58001799908697, + -55.499041029685614, + -55.19843922304378, + -55.05384856549112, + -54.49512297955138, + -53.957533054419024, + -52.83749806092496 + ] + }, + { + "lon": [ + 44.84695804218114, + 46.79913862487123, + 48.31847741068461, + 48.52280602396667, + 49.097189568890855, + 50.03976769389462, + 51.522932977103665, + 51.13618655783128, + 49.79368452332071, + 48.89441124857755, + 48.75493655782177, + 47.58611901224418, + 46.50282596210963, + 47.07245527526294, + 44.84695804218114 + ], + "lat": [ + 80.58980988231714, + 80.77191762971368, + 80.78400991486998, + 80.51456899690017, + 80.7539859077084, + 80.91888540315178, + 80.69972565380193, + 80.54728017854093, + 80.4154277615482, + 80.33956675894375, + 80.17546824820089, + 80.01018117951533, + 80.2472468126543, + 80.55942414012951, + 80.58980988231714 + ] + }, + { + "lon": [ + 53.50828982932515, + 55.90245893740766, + 55.631932814359686, + 57.86864383324885, + 61.170044386647476, + 64.49836836127017, + 66.21092532742284, + 68.1570597675348, + 68.85221113472508, + 68.1805725442276, + 64.63732628770302, + 61.58350752141476, + 58.47708214705335, + 56.98678551618803, + 55.419335971910925, + 55.62283776227633, + 57.535692579992315, + 56.94497928246388, + 53.67737511578417, + 53.412016635965394, + 51.601894565645665, + 51.455753615124216, + 52.47827518088354, + 52.44416873557088, + 54.42761355979758, + 53.50828982932515 + ], + "lat": [ + 73.7498139513002, + 74.62748647734536, + 75.08141225859718, + 75.60939036732326, + 76.25188345000812, + 76.43905548776927, + 76.80978221303117, + 76.93969676381293, + 76.5448113064546, + 76.23364166940907, + 75.73775462513625, + 75.26088450794684, + 74.30905630156285, + 73.33304352486623, + 72.37126760526603, + 71.54059479439032, + 70.72046397570212, + 70.63274323188666, + 70.76265778266846, + 71.20666168892022, + 71.47475901965045, + 72.01488108996513, + 72.22944163684097, + 72.77473135038481, + 73.6275475124976, + 73.7498139513002 + ] + }, + { + "lon": [ + 27.407505730913446, + 25.92465050629815, + 23.024465773213617, + 20.075188429451828, + 19.897266473070914, + 18.462263624757867, + 17.368015170977458, + 20.45599205901064, + 21.907944777115404, + 22.91925255706738, + 25.447625359811866, + 27.407505730913446 + ], + "lat": [ + 80.05640574820042, + 79.51783397085451, + 79.40003754344518, + 79.56682322866722, + 79.84236196564747, + 79.85988027619443, + 80.31889618602698, + 80.59815562613225, + 80.35767934846204, + 80.65714427359343, + 80.40734039989452, + 80.05640574820042 + ] + }, + { + "lon": [ + 24.72410363129333, + 22.490338169044833, + 20.726001417735688, + 21.416088494561365, + 20.81188764820476, + 22.88426761240578, + 23.281349318136538, + 24.72410363129333 + ], + "lat": [ + 77.85385285105617, + 77.4449372423306, + 77.67704193796955, + 77.93503652618672, + 78.25462942169581, + 78.45495311147526, + 78.0795238308748, + 77.85385285105617 + ] + }, + { + "lon": [ + 15.142827996489387, + 15.522546420970059, + 16.990828891679058, + 18.25183719246536, + 21.543832635186874, + 19.027397088301797, + 18.471720411867295, + 17.594409620848154, + 17.11821129727855, + 15.913168572664349, + 13.762602166405742, + 14.669575229560424, + 13.170596958070035, + 11.22229210780182, + 10.444561801809131, + 13.170751987366913, + 13.718522169660758, + 15.142827996489387 + ], + "lat": [ + 79.6743102078343, + 80.01609813101275, + 80.05087636994519, + 79.70175039338129, + 78.95611115184185, + 78.56259511993922, + 77.82667104767067, + 77.63794871694073, + 76.80942047800512, + 76.77045644805706, + 77.38034170196575, + 77.73566885040468, + 78.02492768015843, + 78.86929474559149, + 79.65239940054254, + 80.01046539989294, + 79.66040924754778, + 79.6743102078343 + ] + }, + { + "lon": [ + -77.88157141794525, + -78.21493608266012, + -78.42916073272607, + -78.18209570993864, + -78.4354652574657, + -78.62212053090394, + -79.12030717641375, + -79.55787736684519, + -79.76057817251005, + -80.16448116730334, + -80.38265906443962, + -80.4806892564973, + -80.00368994822716, + -80.276670701809, + -80.42115800649708, + -80.8864009264208, + -81.05954281281473, + -81.18971574575795, + -81.51951473664468, + -81.72131120474447, + -82.13144120962892, + -82.39093441438257, + -82.60549496125842, + -82.82008134635042, + -82.85095801464482, + -82.96578304719736, + -83.50843726269431, + -83.71147396516908, + -83.59631303580665, + -83.63264156770784, + -83.90988562695374, + -84.30340165885636, + -84.64764421256866, + -84.71335079622777, + -84.97566036654133, + -84.91137488477024, + -85.11092342806532, + -85.33948828809227, + -85.66078650586698, + -85.79744483106285, + -85.79170874707843, + -85.65931372754667, + -85.80051957878422, + -85.94172543002176, + -85.7125404528073, + -86.05848832878526, + -86.52584998243296, + -86.74599158399633, + -87.16751624220116, + -87.66849341505471, + -87.55746660027562, + -87.39238623731923, + -87.31665442579549, + -87.48940873894722, + -87.64125993523689, + -87.79311113152657, + -87.90411210808952, + -88.48330156121682, + -88.84322791212972, + -89.2567427233293, + -89.81239356154767, + -90.09555457229098, + -90.60862403030085, + -91.23241024449605, + -91.68974667027913, + -92.22775000686983, + -93.35946387406186, + -93.87516883011861, + -94.6916564603302, + -95.25022701697306, + -96.05338212765335, + -96.55743404822829, + -97.26359249549674, + -98.01302995480964, + -98.9476757474566, + -99.69739742714711, + -100.82949886758132, + -101.66608862995447, + -101.91852800170025, + -102.47813208698895, + -103.50098954955814, + -103.91752743204681, + -104.99200965047558, + -105.49303849976143, + -105.73139604370769, + -105.39777299683136, + -105.50066077352449, + -105.27075232625793, + -105.26581722697405, + -105.60316097697542, + -105.69341386597317, + -106.02871639689899, + -106.90998043498846, + -107.91544877809143, + -108.40190487347098, + -109.26019873740672, + -109.44408932171734, + -109.29164384645631, + -109.8014576892318, + -110.3917317370857, + -110.64101884646172, + -111.17891883018783, + -111.7596068998516, + -112.22823462609044, + -112.27182369672866, + -112.80959448937405, + -113.16381059451868, + -113.14866939985716, + -113.8718810697819, + -114.20573666060356, + -114.77645117883502, + -114.93669979537212, + -114.77123185917355, + -114.6738992989518, + -114.33097449426293, + -113.58887508833548, + -113.42405310754054, + -113.27196936730557, + -113.14003943566442, + -112.96229834679652, + -112.76158708377488, + -112.4579105294117, + -112.24495195193688, + -111.61648902061926, + -111.28467464887314, + -110.98781938357247, + -110.71000688357137, + -110.65504899782896, + -110.17285620811349, + -109.77184709352855, + -109.40910437705575, + -109.43339230023292, + -109.8542193266018, + -110.03139197471448, + -110.29507097048376, + -110.94950130902805, + -111.67056840701271, + -112.18203589562152, + -112.14898881717087, + -112.30071082237981, + -112.77729671919163, + -113.46467078332196, + -113.59672990604385, + -113.84893673384434, + -114.46574662968014, + -115.0551421781851, + -114.98225257043741, + -114.57036556685503, + -114.19932878299939, + -114.16201839888465, + -114.93184221073669, + -115.51865393762705, + -115.88736528202958, + -116.25835038945293, + -116.72152625208501, + -117.12775468633141, + -117.2959376912739, + -117.944, + -118.41060227589757, + -118.51989482279983, + -119.081, + -119.43884064201674, + -120.36778947638344, + -120.62286434617613, + -120.74432980027817, + -121.71458065477424, + -122.54747555223851, + -122.51199968147014, + -122.953187222162, + -123.72719682502968, + -123.86517289924899, + -124.39806026904279, + -124.17884884326065, + -124.21370459684152, + -124.53284000000001, + -124.14214, + -124.020535, + -123.89893000000001, + -124.079635, + -124.39567, + -124.6872100830078, + -124.56610107421875, + -123.12, + -122.58736975796783, + -122.33999467658664, + -122.50001074917841, + -122.84, + -122.97421000000001, + -124.91025122770371, + -125.62460038949041, + -127.43560095915909, + -127.99275041391394, + -127.85033016651754, + -129.12978695363202, + -129.30522844126293, + -130.51497372121568, + -130.53610938202306, + -131.08581743052787, + -131.96721065969805, + -132.25000993541533, + -133.5391818918007, + -134.07806372774036, + -135.03821183972337, + -136.628063117399, + -137.80000708713024, + -139.86778784885726, + -140.82527462457725, + -142.57444434300874, + -143.95888180232416, + -145.92555762427213, + -147.11437394914668, + -148.22430620012767, + -148.01806555885082, + -148.57082251686083, + -149.72785783587588, + -150.6082433746164, + -151.71639278868332, + -151.85943315326722, + -151.4097190012472, + -150.34694149473253, + -150.62111080625706, + -151.89583919981686, + -152.5783298410956, + -154.01917212625764, + -153.28751135965314, + -154.2324924387585, + -155.30749142151018, + -156.30833472392305, + -156.55609737854644, + -158.11721655986779, + -158.43332129619716, + -159.60332739971747, + -160.28971961163427, + -161.2230476552578, + -162.23776607974102, + -163.06944658104644, + -164.78556922102723, + -164.9422263255201, + -163.8483396067657, + -162.87000139061595, + -161.80417497459607, + -160.56360470278122, + -160.07055986228445, + -158.68444291891953, + -158.46109737855406, + -157.72277035218391, + -157.55027442119365, + -157.041674974577, + -158.1947312083056, + -158.51721798402303, + -159.05860612692885, + -159.71166704001737, + -159.98128882550023, + -160.35527116599653, + -161.35500342511511, + -161.96889360252638, + -162.0549865387247, + -161.87417070213542, + -162.51805904849212, + -163.81834143782024, + -164.66221757714658, + -165.34638770247483, + -165.35083187565192, + -166.12137915755602, + -165.73445187077064, + -164.9191786367179, + -164.5625079010394, + -163.75333248599713, + -163.0672244944579, + -162.26055538638175, + -161.53444983624863, + -160.7725066803211, + -160.95833513084267, + -161.51806840721216, + -160.77777767641487, + -161.39192623598765, + -162.45305009666896, + -162.75778601789415, + -163.54639421288428, + -164.96082984114514, + -166.42528825586453, + -166.84500423893917, + -168.11056006576712, + -166.70527116602193, + -164.4747096425755, + -163.65251176659564, + -163.7886016510363, + -161.67777442121016, + -162.48971452538007, + -163.7197169667912, + -164.43099138085657, + -165.39028683170673, + -166.7644406809961, + -166.2047074046267, + -164.43081051334352, + -163.16861365461455, + -162.93056616926202, + -161.90889726463556, + -160.93479651593373, + -159.0391757883871, + -158.11972286683394, + -156.58082455139808, + -155.06779029032433, + -154.34416520894123, + -153.90000627339256, + -152.2100060699353, + -152.27000240782615, + -150.7399924387445, + -149.72000301816752, + -147.61336157935702, + -145.68999060766964, + -144.9200117665207, + -143.58944698786956, + -142.07251115615776, + -140.98598832900498, + -139.12052079970064, + -137.5463533192256, + -136.50357459200788, + -135.6257470366658, + -134.41463233125734, + -132.92924496145972, + -131.43135189504747, + -129.79470760793157, + -129.1077211170434, + -128.36156511118105, + -128.13816789438326, + -127.44712480356019, + -125.75632361540238, + -124.42482866096998, + -124.28966895231058, + -123.06108761278743, + -122.68348792203072, + -121.47226986375765, + -119.94288001186351, + -117.60268693730987, + -116.2264401925127, + -115.24688758020409, + -113.8979518298732, + -115.30489437545172, + -113.49727861209814, + -110.79801184776443, + -109.94617753786518, + -108.88019609254842, + -107.79238135458836, + -108.81299089235284, + -108.16721635621744, + -106.95000383179851, + -106.15000098348801, + -105.34281511108895, + -104.3379152087412, + -103.22116166869766, + -101.4543444486385, + -99.90195858437448, + -98.44321041542332, + -98.55860388873108, + -97.66948503293327, + -96.11991553422915, + -96.12588416215885, + -95.48943722205215, + -94.68499020056456, + -94.23282141801066, + -95.3040738594212, + -96.47131527381387, + -96.39113928911304, + -95.20880835649112, + -93.88997412797022, + -92.87817542191148, + -91.51965369339042, + -92.40691219762576, + -90.54710323765737, + -90.55149573440218, + -89.21514319533433, + -88.01966061069413, + -88.31749772820834, + -87.35016659213676, + -86.30607011589562, + -85.57663143587968, + -85.52198360873102, + -84.10080420605608, + -82.62257402213088, + -81.28043372264632, + -81.22020484081015, + -81.96437130402929, + -81.25927222362282, + -81.38652543814156, + -83.34457129589678, + -84.73541663281641, + -85.76943620476065, + -86.06760921908479, + -87.0314263577605, + -87.3232431709127, + -88.48296566440692, + -89.91442867710796, + -90.7039928860955, + -90.77003536656451, + -91.93342688675146, + -93.15696977412614, + -94.24152889685183, + -94.62930884477005, + -94.68460262732236, + -93.21502824580605, + -92.7646164619501, + -92.29702226435708, + -90.89767615432544, + -89.0395208401904, + -88.03978858107182, + -87.32419918491009, + -86.07120073112904, + -85.01180803092949, + -83.36053931347496, + -82.27285376659565, + -82.43620296907024, + -82.1250333320247, + -81.40073645702181, + -79.91289445669035, + -79.14301896840601, + -78.60191504587782, + -79.12420874705178, + -79.82956620961971, + -78.22873369008205, + -77.095598721002, + -76.54136898467166, + -76.62319861520584, + -77.3022527737372, + -78.51688147654153, + -77.33674679229202, + -77.77271501332241, + -78.10688066273781, + -77.41066992868555, + -75.69620093453807, + -74.66820166695584, + -73.83988013374939, + -72.9085416327691, + -71.67709225125375, + -71.37369991726817, + -69.59042375352405, + -69.6203185696049, + -69.28788408067129, + -68.37455481634471, + -67.64976701523504, + -66.2017675442006, + -65.24518510604574, + -64.58352006698058, + -63.804756232342065, + -62.50235510928999, + -61.396556972892306, + -61.798651292555384, + -60.46852576357871, + -59.569614223861585, + -57.975086229063535, + -57.333213263566165, + -56.93688086610365, + -56.15811703146511, + -55.756306932179655, + -55.683391486215825, + -56.40916113953904, + -57.12692094585701, + -58.77483069521256, + -60.03310014508739, + -61.72366878929988, + -63.86250464542823, + -65.36331743026496, + -66.39904232447483, + -67.23630388046776, + -68.51113562689214, + -69.95363155788749, + -71.10456905789209, + -70.25521521674287, + -68.6499902004604, + -66.55244381373326, + -65.05625606958665, + -64.17098710799456, + -65.11545142277699, + -64.79854570174707, + -64.47218319360775, + -63.17329606795151, + -61.520709601473534, + -60.51813513857891, + -60.448604498930194, + -59.8028816392271, + -61.03988623721381, + -63.25471228702736, + -64.24656389022142, + -65.3640667385332, + -66.12340023462998, + -66.1617183091744, + -64.42549353703204, + -66.02604183619209, + -67.13742102727727, + -66.96466000000001, + -68.03252, + -69.06, + -70.11617000000001, + -70.64547563341108, + -70.81489681668, + -70.82499955919306, + -70.49499386257716, + -70.08000627305726, + -70.1849869452582, + -69.88497941758774, + -69.96502621120786, + -70.63999793158814, + -71.1203820461734, + -71.85382564969197, + -72.29498735216768, + -72.8764247300997, + -73.71000000000001, + -72.24124386258414, + -71.94500871447097, + -73.34500077990626, + -73.98199032255204, + -73.952325, + -74.25670223661564, + -73.96244, + -74.1783866034773, + -74.90604244657918, + -74.98040483264718, + -75.20002966988764, + -75.52804582386031, + -75.31999650745323, + -75.07183476478983, + -75.05673, + -75.37746070016179, + -75.94024288603643, + -76.03127092151857, + -75.72205000000001, + -76.23287, + -76.35000000000001, + -76.542725, + -76.32933, + -76.98999793161354, + -76.30162, + -76.25874, + -75.9718, + -75.86805091012468, + -75.72749101429079, + -76.36318864612927, + -77.39763500000001, + -78.05496000000001, + -78.55434688995314, + -79.06067000000002, + -79.20357, + -80.301325, + -80.86498, + -81.33629, + -81.49042090526437, + -81.31371, + -80.97998694530139, + -80.535585, + -80.52998857290376, + -80.05653928497766, + -80.088015, + -80.13156, + -80.38103000000001, + -80.68000525584706, + -81.17211992056258, + -81.32999142121425, + -81.70999406607253, + -82.24001339387414, + -82.70515, + -82.85526, + -82.65001420767786, + -82.93, + -83.70959, + -84.1, + -85.10882000000001, + -85.28784, + -85.7731, + -86.3999920315861, + -87.53036231153854, + -88.41782752150303, + -89.18048999999999, + -89.59383117841979, + -89.41373499999999, + -89.43, + -89.21767000000001, + -89.40823000000002, + -89.77928, + -90.15463, + -90.88022500000001, + -91.626785, + -92.49906, + -93.22636999999999, + -93.84842, + -94.69000281449686, + -95.60025733110206, + -96.59404680050707, + -97.14000830767073, + -97.3699942695857, + -97.37999365923417, + -97.32999671099181, + -97.14000830767073, + -97.52807247596655, + -97.70294552284224, + -97.77604183631911, + -97.87236670611115, + -97.6990439522042, + -97.38895952023682, + -97.18933346229332, + -96.52557552772033, + -96.29212724484181, + -95.90088497596004, + -94.83906348344277, + -94.42572953975622, + -93.5486512926824, + -92.7861138577835, + -92.0373481920904, + -91.40790340855925, + -90.77186987991085, + -90.53358985061305, + -90.45147599970126, + -90.27861833368493, + -89.6013211738515, + -88.54386633986289, + -87.6584165107578, + -87.05189022494808, + -86.81198238803304, + -86.84590796583268, + -87.38329118523586, + -87.62105445021076, + -87.43675045444179, + -87.58656043165594, + -87.83719112827153, + -88.09066402866317, + -88.3000310940937, + -88.29633622918482, + -88.10681291375438, + -88.1234785631685, + -88.2853549873228, + -88.19786678745265, + -88.30264075392444, + -88.23951799187991, + -88.35542822951057, + -88.55182451043585, + -88.73243364129594, + -88.93061275913527, + -88.60458614780585, + -88.51836402052686, + -88.18998613152814, + -88.12115312371537, + -87.90181250685251, + -87.61568010125242, + -87.5229209052885, + -87.36776241733216, + -86.90319129102821, + -86.4409456041774, + -86.11923397494434, + -86.00195431185793, + -85.68331743034625, + -85.44400387240259, + -85.18244361035727, + -84.98372188997887, + -84.52697974316715, + -84.36825558138266, + -84.06305457226686, + -83.77397661002611, + -83.41038123242049, + -83.14721900097413, + -83.23323442252394, + -83.2841615465476, + -83.18212643098728, + -83.41249996614445, + -83.51983191601468, + -83.55220720084554, + -83.49851538769427, + -83.47332312695198, + -83.62610449902292, + -83.71961300325506, + -83.65085751009072, + -83.8554703437504, + -83.80893571647155, + -83.65561174186158, + -83.59000851106704, + -83.40231970898296, + -83.01567664257517, + -82.54619625520348 + ], + "lat": [ + 7.223771267114785, + 7.512254950384161, + 8.052041123888927, + 8.319182440621773, + 8.38770538984079, + 8.718124497915028, + 8.996092027213024, + 8.932374986197146, + 8.5845150822244, + 8.333315944853595, + 8.298408514840432, + 8.09030752200107, + 7.547524115423372, + 7.419754136581716, + 7.271571966984765, + 7.220541490096537, + 7.817921047390597, + 7.64790558515034, + 7.706610012233909, + 8.108962714058435, + 8.175392767769637, + 8.29236237226229, + 8.291613063994063, + 8.290863755725823, + 8.073822740099956, + 8.225053819202117, + 8.446926581247283, + 8.656836249216866, + 8.830443223501419, + 9.051385809765321, + 9.29080272057358, + 9.487354030795714, + 9.61553742109571, + 9.908051866083852, + 10.086723130733006, + 9.795991522658923, + 9.55703969974131, + 9.83454214114866, + 9.933347479690724, + 10.134885565629034, + 10.439337266476613, + 10.75433095951172, + 10.824791774941687, + 10.895278428587801, + 11.088444932494824, + 11.403438625529944, + 11.806876532432597, + 12.143961900272487, + 12.458257961471658, + 12.909909979702633, + 13.064551703336065, + 12.914018256069838, + 12.984685777228975, + 13.297534898323974, + 13.341020616097595, + 13.384480495655055, + 13.149016831917137, + 13.163951320849492, + 13.259759426318624, + 13.458532823129303, + 13.520622056527998, + 13.735337632700734, + 13.909771429901951, + 13.927832342987957, + 14.126218166556455, + 14.538828640190928, + 15.615429592343673, + 15.940190131081948, + 16.200975246642884, + 16.128318182840516, + 15.752087917539525, + 15.653515122942778, + 15.917064927631332, + 16.10731171311386, + 16.566043402568823, + 16.70616404872824, + 17.17107107184208, + 17.64902639410961, + 17.91609019619402, + 17.975750637274984, + 18.29229462327885, + 18.74857168219995, + 19.316133938061597, + 19.94676727953548, + 20.434101874263987, + 20.531718654863337, + 20.81689504646604, + 21.0762848983551, + 21.422103583252305, + 21.871145941652546, + 22.269080308516124, + 22.773752346278556, + 23.767800197845034, + 24.548915310152836, + 25.172313951105863, + 25.58060944264395, + 25.824883938087634, + 26.44293406829844, + 26.676175645447817, + 27.16211497650444, + 27.859876003525457, + 27.941240546169013, + 28.467952582303937, + 28.95440867768349, + 29.266844387320145, + 30.021113593052338, + 30.786880804969456, + 31.17096588797881, + 31.567608344035076, + 31.524045111613034, + 31.799532172161012, + 31.393484605427616, + 30.913617255165278, + 30.162681179315925, + 29.750432440707495, + 29.061611436472973, + 28.826173610951205, + 28.75478261973998, + 28.411289374295894, + 28.42519033458241, + 27.780216783147537, + 27.525813706974642, + 27.171752631126875, + 26.662817287700364, + 25.732589830014348, + 25.29463206634072, + 24.82600434010186, + 24.298594672131, + 24.265547593680353, + 23.811182562754055, + 23.36467234953612, + 23.185587673428643, + 22.818271592697997, + 22.82307750090115, + 23.43097321216659, + 24.00096426034597, + 24.484423122652586, + 24.738412787367135, + 25.470125230403927, + 26.0120042994165, + 26.321959540303165, + 26.768185533143495, + 26.639459540304426, + 26.90006378835235, + 27.142090358991343, + 27.722726752222822, + 27.798200181585113, + 27.741485297144777, + 28.115002549750443, + 28.566111965442342, + 29.279479275015515, + 29.556361599235373, + 30.180793768834224, + 30.836464341753512, + 31.635743720011916, + 32.53532705334885, + 33.04622461520375, + 33.62123643120128, + 33.74090922312447, + 34.02778157757573, + 34.078, + 34.34847717828417, + 34.447096665986706, + 34.60855967868267, + 35.15687246351558, + 36.161513983701894, + 37.55176504165017, + 37.783378811182345, + 38.113694566392, + 38.95165375422087, + 39.7669786647059, + 40.313198554031004, + 41.14203685156036, + 41.99963308366016, + 42.76599, + 43.708380000000005, + 44.615895, + 45.52341, + 46.86475, + 47.72017, + 48.18443298339844, + 48.379714965820305, + 48.040000000000006, + 47.095988674500845, + 47.36000356708003, + 48.18000519468748, + 49.0, + 49.00253777777778, + 49.984572048535846, + 50.41656118427976, + 50.830592759802244, + 51.71583588317819, + 52.32962270772491, + 52.75538483337766, + 53.56158885356318, + 54.28756521261556, + 54.802753404349396, + 55.17890615500194, + 55.49777558045893, + 56.36999624289732, + 57.178887437562025, + 58.12306753196684, + 58.187714748763966, + 58.21220937767033, + 58.49999542910376, + 59.53776154238916, + 59.72751740176493, + 60.0844465196049, + 59.999180406323305, + 60.458609727614196, + 60.88465607364455, + 60.672989406977045, + 59.978328965893525, + 59.914172675203176, + 59.70565827090546, + 59.36821116803952, + 59.15582103131994, + 59.74498403587958, + 60.72580272077933, + 61.033587551509726, + 61.28445079207063, + 60.72719798445121, + 60.06165721296418, + 59.35027944603425, + 58.8647276882198, + 58.14637360293046, + 57.7277945013663, + 57.422774359763515, + 56.9799848496706, + 56.46360809999405, + 55.99415355083853, + 55.56668610292015, + 55.64358063417046, + 55.36473460552351, + 55.02418691672007, + 54.68973704692707, + 54.40417308208217, + 54.57222483989534, + 55.039431464246164, + 55.34804311789323, + 55.89498647727042, + 56.00805451112504, + 56.41805532492877, + 57.016675116597824, + 57.216947129944984, + 57.57000051536306, + 58.32832632103016, + 58.918884589261694, + 58.61580231386985, + 58.787781480537205, + 58.424186102931586, + 58.93139028587632, + 58.57254914004156, + 59.071123358793535, + 58.6708377142607, + 58.671664537177364, + 59.266951198963596, + 59.63362132429059, + 59.98972361921389, + 59.798055731843334, + 60.2674844427827, + 60.50749563256231, + 61.07389516869739, + 61.500019029376176, + 62.07499685327171, + 62.6330764838078, + 63.14637848576298, + 63.21944896102367, + 63.05945872664804, + 63.541961574957256, + 63.45581696232672, + 63.76610810002326, + 64.2227985704027, + 64.40278758407528, + 64.7886038275664, + 64.77723501246221, + 64.55944468856809, + 64.33860545516877, + 64.55916046819051, + 64.4469450954687, + 64.6866720648707, + 65.0888955756145, + 65.66999705673662, + 66.08831777613933, + 66.57666006129752, + 66.57666006129752, + 66.07720734319658, + 66.11611969671235, + 66.73556509059505, + 67.11639455837, + 67.61633820257772, + 68.04277212185026, + 68.35887685817967, + 68.88303091091613, + 68.91553538682773, + 69.37111481391288, + 69.8580618353992, + 70.33332998318757, + 70.44768992784948, + 70.89164215766895, + 70.82472117785098, + 71.35776357694165, + 71.14777639432363, + 70.69640859647025, + 70.88998851183563, + 70.82999217394475, + 70.60000621202978, + 70.43001658800564, + 70.53001048449043, + 70.21403493924176, + 70.12000967068671, + 69.98999176704037, + 70.1525141465983, + 69.85196401638875, + 69.71199839952622, + 69.47100535753306, + 68.99000112576032, + 68.89801707628077, + 69.31512339952464, + 69.62742991808058, + 69.505344346791, + 69.94451650662351, + 70.19370026313491, + 69.7792552761541, + 70.01285858832951, + 70.48383759223763, + 70.37720327420335, + 69.48056549750707, + 70.15840525987956, + 69.39969188097028, + 69.56371287706467, + 69.8555296902169, + 69.79778127713074, + 69.37785858832696, + 69.01129181586457, + 68.84148305935348, + 68.90592357042142, + 68.39890025498973, + 67.90262563747471, + 67.68816844346343, + 67.80609406195349, + 67.98104462347762, + 67.38144297959501, + 67.88732941351633, + 68.31164459906488, + 68.65394928656626, + 68.69999298773833, + 68.79998688422309, + 68.5612159288185, + 68.01801911078248, + 68.09775584580883, + 67.64687897406223, + 67.80562897406286, + 67.78165110947943, + 68.40393870713818, + 68.57865672471699, + 68.23940094672083, + 67.29338633896965, + 68.09070201280097, + 68.0638302680092, + 69.06901439073458, + 69.68572093370581, + 70.08977895779596, + 71.19482778592537, + 71.92051992460016, + 71.76016795519847, + 71.318696194129, + 70.1912714708172, + 69.69998362901835, + 69.49767039659567, + 68.4749938015395, + 69.25871857367805, + 68.61508860948275, + 67.87337677679751, + 67.1987409532271, + 67.9214616970451, + 68.78456146918397, + 69.88209137641492, + 69.80540355089379, + 69.65825490994267, + 69.16203196885995, + 68.6656798366965, + 68.13253408474127, + 67.59716624619743, + 67.11078766546633, + 66.41155386012498, + 66.25729970973374, + 66.5583149278339, + 66.05625254990223, + 65.21297068954728, + 64.77563304306115, + 64.09898183863136, + 64.03273265243318, + 63.610174465582546, + 62.96021413843151, + 62.83507965763674, + 62.024689846435564, + 60.898660386795655, + 60.110207221102385, + 58.94880524355869, + 58.78212291120124, + 57.84572011985635, + 57.0870842555955, + 57.28466909446348, + 56.85172394472216, + 56.47161794699929, + 55.99911448833855, + 55.723834133519745, + 55.30261953390868, + 55.244896959038655, + 55.14831370708515, + 54.282268378305645, + 53.27703257914797, + 52.15785024678672, + 51.20839915628814, + 51.533934841510785, + 52.56206330017376, + 54.14145010031027, + 54.66772288677072, + 55.13645396587417, + 55.83741893169727, + 56.53422394472089, + 57.20263275820014, + 58.05208995221395, + 58.80457632103206, + 59.85262604434355, + 60.75789378523259, + 62.31965892195758, + 62.55054922143768, + 62.27839529077252, + 62.18111440698307, + 62.443785712322665, + 62.10507253686558, + 61.52536631941534, + 61.13719879825494, + 61.061415310298905, + 60.22123403588148, + 58.95735769310299, + 58.801062323636216, + 58.21205434837344, + 58.76731761334962, + 59.8707127956457, + 60.3355939805434, + 59.44257355410754, + 58.16709585227951, + 56.96742747662366, + 56.33945547141284, + 55.77548472759547, + 55.20407257752808, + 54.945483710339545, + 54.626485093801804, + 53.78033519145467, + 53.647475084032266, + 53.27036631938232, + 52.146636460979394, + 51.77069041605601, + 51.4197040879296, + 51.064299424842254, + 50.242773342482195, + 50.08045766865341, + 50.2909874538105, + 50.29817047789908, + 50.22897573506026, + 49.511551825552175, + 49.068374742217074, + 47.7448896347899, + 46.82171601011173, + 46.98607290301604, + 48.29999787046922, + 49.13307363544649, + 49.232783311553675, + 48.742503160184526, + 48.070864569687046, + 46.992971706727005, + 46.23849579526565, + 45.73901723894854, + 45.88376292579808, + 47.007932033875505, + 46.28265330665906, + 45.920401516293026, + 45.265247707696645, + 44.670141913423436, + 44.26551544857807, + 43.54524933529393, + 43.618681545580685, + 44.46511566830543, + 45.29204193783998, + 45.25930491798309, + 45.13750356707113, + 44.80970000000001, + 44.3252, + 43.980000000000004, + 43.68405, + 43.09023834896399, + 42.86529083919747, + 42.334987291018265, + 41.80499380143282, + 41.78000824641968, + 42.144998887697184, + 41.92281606705828, + 41.63717458756496, + 41.47498810481691, + 41.4944442815748, + 41.31998464615744, + 41.26998769791504, + 41.2206367050763, + 40.93110235165436, + 41.11948008886496, + 40.930008449866804, + 40.630000922196345, + 40.6280113795531, + 40.750750000000004, + 40.4734988470004, + 40.42763, + 39.70925608983589, + 38.939535630848425, + 39.19639333755519, + 39.24845734308924, + 39.49849376073348, + 38.95999949803601, + 38.78203223017923, + 38.404120000000006, + 38.015509345037444, + 37.21690176039883, + 37.25658926039898, + 37.93705, + 38.319215, + 39.15, + 38.717615, + 38.08326, + 38.239991766913334, + 37.917944999999996, + 36.9664, + 36.89726, + 36.55125763604721, + 35.55075023044425, + 34.80854747165222, + 34.51201, + 33.925470000000004, + 33.861344305958326, + 33.49395, + 33.158390000000004, + 32.509355, + 32.0333, + 31.44049, + 30.729985053016108, + 30.03552, + 29.180002142853652, + 28.47213, + 28.039994208278785, + 26.88, + 26.205765, + 25.816775, + 25.20616, + 25.079994004816427, + 25.20125275318931, + 25.639985663347304, + 25.869997463478445, + 26.72999664967979, + 27.49504, + 27.88624, + 28.54998891856728, + 29.1, + 29.93656, + 30.09, + 29.63615, + 29.686120000000003, + 30.152610000000003, + 30.400005194616355, + 30.274328111282514, + 30.384915676387124, + 30.315980000000003, + 30.159994004836747, + 29.894190000000002, + 29.48864, + 29.29108, + 29.15961, + 29.30714, + 29.117430000000002, + 29.148535000000003, + 29.677, + 29.552300000000002, + 29.78375, + 29.71363, + 29.480009670524126, + 28.738633734648772, + 28.307471421821518, + 27.830007025660766, + 27.38000865326312, + 26.68999909108588, + 26.210002549742825, + 25.869997463478445, + 24.992144069920244, + 24.272343044526735, + 22.932579860927632, + 22.44421173755327, + 21.89868948006412, + 21.41101898852571, + 20.635433254473128, + 19.89093089444411, + 19.32039724372568, + 18.828024196848702, + 18.562717393462222, + 18.14437083584336, + 18.423836981677823, + 18.524838568592287, + 18.704595038319567, + 18.876083278880145, + 19.28412038825678, + 19.8674181177513, + 20.707521877520293, + 20.999855454995412, + 21.26172577563449, + 21.493675441976563, + 21.45884552661184, + 21.54354319913821, + 21.331514797444655, + 20.849864610268256, + 20.255404771398688, + 19.646553046135836, + 19.472403469312226, + 19.0401301131907, + 18.259815985583415, + 18.516647854074023, + 18.4999822046599, + 18.35327281338327, + 18.348673610909287, + 18.07667470954101, + 17.644142971258034, + 17.489475409408456, + 17.131693630435663, + 17.036066392479555, + 16.530774237529627, + 16.265467434143147, + 16.2336605900675, + 15.887273464415076, + 15.70638011317736, + 15.855389105690975, + 15.71999685308627, + 15.688655096901257, + 15.86445831955821, + 15.878798529519202, + 15.797278957578769, + 15.846940009011263, + 15.756712958229656, + 15.78283539475319, + 15.893448798073948, + 16.00540578863429, + 15.953651841693983, + 15.885749009662463, + 15.909158433490672, + 15.995923163308731, + 15.857223619037342, + 15.835157782448718, + 15.648244126849006, + 15.424071763566857, + 15.270902818253745, + 14.99582916916411, + 14.899866034398102, + 14.6766238468972, + 14.31070302983845, + 13.970077826386557, + 13.567699286345883, + 13.127054348193086, + 12.869292303921227, + 12.419087225794428, + 12.320850328007566, + 11.893124497927728, + 11.62903209070012, + 11.373311265503787, + 11.103043524617275, + 10.938764146361422, + 10.785000922076946, + 10.395438137244653, + 9.992982082555557, + 9.566160590040823 + ] + }, + { + "lon": [ + -82.54619625520348, + -82.18712256542341, + -82.20758643261097, + -81.80856686066929, + -81.71415401887204, + -81.43928707551154, + -80.94730160187676, + -80.52190121125008, + -79.91459977895599, + -79.57330278188431, + -79.02119177927793, + -79.05845048696037, + -78.50088762074719, + -78.05592770049802, + -77.72951351592641, + -77.35336076527386 + ], + "lat": [ + 9.566160590040823, + 9.20744863528678, + 8.9955752628901, + 8.950616766796173, + 9.031955471223583, + 8.786234035675719, + 8.858503526235907, + 9.111072089062432, + 9.31276520429762, + 9.611610012241528, + 9.552931423374105, + 9.454565334506526, + 9.420458889193881, + 9.2477304142583, + 8.946844387238869, + 8.67050466555807 + ] + }, + { + "lon": [ + -71.71236141629296, + -71.58730445014663, + -71.38000444200779, + -70.80670610216174, + -70.21436499701613, + -69.95081519232758, + -69.76925004747008, + -69.22212582057988, + -69.25434607611385, + -68.80941199408083, + -68.31794328476897, + -68.68931596543452, + -69.16494584824892, + -69.62398759629764, + -69.95293392605154, + -70.1332329983179, + -70.51713721381422, + -70.66929846869763, + -70.99995012071719, + -71.4002099270339, + -71.65766191271202, + -71.70830481635805, + -72.37247616238935, + -72.84441118029488, + -73.45455481636503, + -73.92243323433566, + -74.45803361682478, + -74.36992529976713, + -73.44954220243272, + -72.69493709989064, + -72.334881557897, + -72.79164954292489, + -72.78410478381028, + -73.41502234566175, + -73.18979061551762, + -72.57967281766362, + -71.71236141629296 + ], + "lat": [ + 19.714455878167357, + 19.8849105900821, + 19.904986884027494, + 19.880285549391985, + 19.62288524014616, + 19.64799998624001, + 19.29326711677244, + 19.313214219637103, + 19.015196234609874, + 18.979100246654, + 18.612197577381693, + 18.205142320218613, + 18.42264842373511, + 18.38071299893025, + 18.42830699307106, + 18.245915025296895, + 18.184290879788833, + 18.426885891183034, + 18.283328762276213, + 17.5985643579766, + 17.7575727401387, + 18.044997056546094, + 18.21496084235406, + 18.145611070218365, + 18.2179063989947, + 18.030992743395004, + 18.342549953682706, + 18.66490753831941, + 18.526052964751145, + 18.445799465401862, + 18.668421535715254, + 19.10162506761803, + 19.48359141690341, + 19.639550889560283, + 19.915683905511912, + 19.871500555902358, + 19.714455878167357 + ] + }, + { + "lon": [ + 14.761249220446189, + 15.520324334381513, + 15.160242954171736, + 15.309897902089006, + 15.099988234119422, + 14.335228712631988, + 13.826732618879959, + 12.431003859108756, + 12.570943637755136, + 13.741156447004613, + 14.761249220446189 + ], + "lat": [ + 38.14387360285046, + 38.231180935207576, + 37.44404551853776, + 37.13421946873183, + 36.6199872909954, + 36.996630967754726, + 37.10453135838016, + 37.61294993748375, + 38.12638113051966, + 38.03496552179533, + 38.14387360285046 + ] + }, + { + "lon": [ + 37.53913536962585, + 38.679995965333546, + 39.955008579270924 + ], + "lat": [ + 44.65722280535048, + 44.279984849619794, + 43.43499766699922 + ] + }, + { + "lon": [ + 132.37117638563024, + 132.92437259331473, + 133.4929683778222, + 133.90410607313635, + 134.63842817600386, + 134.76637902235854, + 134.2034159689709, + 133.79295006727654, + 133.28026818250885, + 133.0148580262578, + 132.36311486219267, + 132.37117638563024 + ], + "lat": [ + 33.46364248304006, + 34.06029857028204, + 33.94462087659667, + 34.36493113864263, + 34.149233710256354, + 33.80633474378362, + 33.20117788342964, + 33.5219851750976, + 33.28957042086489, + 32.70456736910474, + 32.989382025681394, + 33.46364248304006 + ] + }, + { + "lon": [ + -16.256883307347167, + -16.37765112961327, + -16.277838100641517, + -16.536323614965468, + -17.06342322434257, + -17.020428432675743, + -16.973247849993257, + -16.589136928767758, + -16.26192175949562, + -16.32641394699587, + -15.98261064295805, + -15.426003790742271, + -15.089331834360719, + -14.82464514816175, + -14.800925665739769, + -14.439939947964888, + -13.773804897506494, + -13.139941779014379, + -12.618836635783126, + -11.688919236690865, + -10.900956997104387, + -10.399592251008627, + -9.564811163765697, + -9.814718390329206, + -9.43479326011935, + -9.300692918321941, + -8.657476365584985, + -7.654178432638275, + -6.912544114601445, + -6.244342006851383, + -5.929994269219918, + -5.193863491222174, + -4.591006232105173, + -3.640056525070122, + -2.6043057926441127, + -2.1699137027986244, + -1.2086028710890557, + -0.12745439289460592, + 0.5038765804152092, + 1.466918572606545, + 3.1616988460508253, + 4.81575809084913, + 5.3201200700177935, + 6.261819695672613, + 7.330384962603971, + 7.737078484741005, + 8.420964389691676, + 9.509993523810607, + 10.210002475636317, + 10.180650262094531, + 11.02886722173335, + 11.100025668999251, + 10.600004510143094, + 10.593286573945138, + 10.939518670300687, + 10.807847120821009, + 10.149592726287125, + 10.339658644256616, + 10.856836378633687, + 11.108500603895122, + 11.488787469131012, + 12.663341098692996, + 13.083263787496776, + 13.918664991927187, + 15.24561242031791, + 15.713955926179182, + 16.61162723152131, + 18.021101922282156, + 19.08641157397912, + 19.574030389085237, + 20.053380975024652, + 19.820320265388318, + 20.13399620939998, + 20.854520704845555, + 21.54300581227019, + 22.895791456806847, + 23.23680423350092, + 23.609132928163888, + 23.927511427514105, + 24.921145867622243, + 25.16480024587844, + 26.495313348097312, + 27.457631870236554, + 28.450491163860335, + 28.913511997195513, + 29.683439161912133, + 30.095041945116918, + 30.97695193861003, + 31.68796797051391, + 31.960406121556677, + 32.19248497897948, + 32.99393476739414, + 33.77337039565245, + 34.26543338393569, + 34.55637169773891, + 34.48810713068136, + 34.75258711115117, + 34.95541710789678, + 35.098457472480675, + 35.126052687324545, + 35.48220665868013, + 35.9795923194894, + 35.99840254084364, + 35.905023227692226, + 36.149762811026534, + 35.782084995269855, + 36.160821567537, + 35.55093631362831, + 34.714553256984345, + 34.026894972476384, + 32.509158156064075, + 31.699595167779567, + 30.621624790171097, + 30.391096225717064, + 29.69997562024554, + 28.732902866335422, + 27.641186557737317, + 27.048767937943264, + 26.318218214633045, + 26.804700148228733, + 26.17078535330433, + 27.28001997244939, + 28.81997765474722, + 29.240003696415584, + 31.14593387220444, + 32.34797936374571, + 33.51328291192746, + 35.167703891751785, + 36.9131270688421, + 38.34766482926452, + 39.512606642420195, + 40.373432651538224, + 41.55408410011066, + 41.70317060727271, + 41.45347008643839, + 40.87546919125379, + 40.32139448422032, + 39.955008579270924, + 38.679995965333546, + 37.53913536962585, + 36.67546715673177, + 37.403174676265934, + 38.232943149576556, + 37.673700799313906, + 39.14766767757499, + 39.12120934424155, + 38.22353803889942, + 37.42513715998999, + 36.75985477066439, + 35.82368452326483, + 34.96234174982388, + 35.020787794745985, + 35.51000857925317, + 36.52999799983016, + 36.33471276219916, + 35.23999922052812, + 33.882511020652885, + 33.326420932760044, + 33.54692426934946, + 32.4541744321055, + 32.630804477679135, + 33.58816206231839, + 33.29856733575471, + 31.74414025241518, + 31.675307244602408, + 30.7487488136091, + 30.377608676888883, + 29.603289015427436, + 29.62654340995877, + 29.141611769331835, + 28.8378577003202, + 28.558081495891997, + 28.03909508638472, + 27.67389773937805, + 27.99672041190539, + 28.115524529744416, + 28.988442824018733, + 28.806438429486743, + 27.61901736828409, + 27.19237674328238, + 26.35800906749779, + 26.04335127127257, + 26.05694217296534, + 25.44767703624416, + 24.925848422960826, + 23.71481123220076, + 24.407998894963953, + 23.899967889102555, + 23.342999301860743, + 22.81398766448882, + 22.62629886240475, + 22.84974775563481, + 23.350027296652428, + 22.97309939951549, + 23.53001631032501, + 24.02502485524889, + 24.040011020613516, + 23.115002882588982, + 23.409971958110987, + 22.774971958108466, + 23.154225294698506, + 22.490028110451075, + 21.67002648284361, + 21.295010613701493, + 21.12003421396122, + 20.73003217945444, + 20.2177120297128, + 20.150015903410463, + 19.980000441170205, + 19.960001661873235, + 19.406081984136648, + 19.319058872157143, + 19.403549838954348, + 19.54002729663719, + 19.371768833094848, + 19.162479282312745, + 18.882134637129354, + 18.450016310304704, + 17.50997033048324, + 16.930005730871528, + 16.015384555737654, + 15.174453973052012, + 15.376250441151768, + 14.920309279040566, + 14.901602410550908, + 14.258747592840024, + 13.95225467291692, + 13.656975538801165, + 13.67940311041582, + 13.715059848697223, + 13.937630242578308, + 13.141606479554296, + 12.32858117030625, + 12.383874952858548, + 12.261453484759102, + 12.589237094786455, + 13.526905958722494, + 14.029820997787029, + 15.142569614327925, + 15.926191033601896, + 16.169897088290384, + 15.889345737377797, + 16.785001661860548, + 17.51916873543118, + 18.37668745288252, + 18.48024702319543, + 18.293385044028042, + 17.738380161213314, + 16.869595981522338, + 16.448743116937322, + 17.17148969897147, + 17.052840610429314, + 16.635088331781816, + 16.100960727613, + 15.684086948314473, + 15.687962680736348, + 15.89198123542468, + 16.109332309644287, + 15.718813510814613, + 15.413612501698793, + 14.99849572109818, + 14.703268263414714, + 14.060671827865264, + 13.627985060285397, + 12.888081902730365, + 12.106682570044939, + 11.191906365614216, + 10.51194786951774, + 10.200028924203991, + 9.702488234097842, + 8.88894616052687, + 8.428560825238577, + 7.8507666357831445, + 7.435184767291872, + 6.52924523278304, + 4.556962517931424, + 3.1004105973526634, + 2.9859989762584576, + 3.0394840836805486, + 2.0918416683121848, + 0.8105245296351882, + 0.7213310074994013, + 0.10669152181986863, + -0.2787113102129411, + 0.11129072429383768, + -0.467123582349103, + -0.6833894514905976, + -1.4383821272748492, + -2.146452602538119, + -3.415780808923386, + -4.368900926114719, + -4.995219285492212, + -5.3771597965614575, + -5.866432257500904, + -6.236693894872175, + -6.520190802425404, + -7.453725551778092, + -7.855613165711986, + -8.382816127953689, + -8.898856980820328, + -8.746101446965556, + -8.83999752443988, + -9.287463751655224, + -9.526570603869713, + -9.446988898140235, + -9.048305223008427, + -8.977353481471683, + -8.768684047877102, + -8.79085323733031, + -8.99078935386757, + -9.034817674180246, + -8.984433152695674, + -9.392883673530648, + -7.97818966310831, + -6.754491746436756, + -5.411886359061597, + -4.3478427799557835, + -3.51753170410609, + -1.901351284177764, + -1.384225226232985, + -1.1937975732374184, + -2.225724249673845, + -2.9632761295596026, + -4.491554938159482, + -4.5923498193447765, + -3.2958139713578025, + -1.616510789384961, + -1.9334940250633106, + -0.98946895995536, + 1.3387610205226963, + 1.6390010921384996, + 2.5135730322461427, + 3.3149711442285366, + 3.8302885270430806, + 4.705997348661185, + 6.07418257002081, + 6.905139601274129, + 7.100424838905127, + 7.936239454793877, + 8.121706170289428, + 8.80073449060464, + 8.572117954145398, + 8.526229282270208, + 8.120310906617533, + 8.08997684086222, + 8.256581658571207, + 8.543437534223415, + 9.424469028367554, + 9.775558709358535, + 10.580005730846125, + 10.546105991262664, + 10.250000034230226, + 10.369992710011957, + 10.912181837618306, + 10.667803989310016, + 10.369992710011957, + 9.649984978889279, + 9.921906365609118, + 9.939579705452957, + 10.950112338920519, + 10.939466993868393, + 11.95625247564331, + 12.5184403825466, + 13.647467075259442, + 14.119686313542587, + 14.802900424873458, + 16.36347700365573, + 17.622831658608675, + 18.62085859546164, + 18.696254510175464, + 19.660640089606403, + 19.888481479581287, + 21.268448927503467, + 21.055800408622417, + 21.090423618257972, + 21.581866489353672, + 22.52434126149288, + 23.318452996522097, + 24.12072960785343, + 24.312862583114622, + 24.42892785004216, + 24.061198357853186, + 23.426560092876684, + 23.339795363058645, + 24.604214308376186, + 25.86418908051664, + 26.949135776484525, + 27.981114129353244, + 29.117685581180694, + 28.069997592895277, + 26.255172967236973, + 24.496623976344523, + 22.869694858499457, + 22.290763787533592, + 21.322244093519316, + 21.544866163832694, + 21.05921105315369, + 21.536029493910803, + 22.442744174903993, + 24.730511508897536, + 25.398067661243942, + 25.294043003040404, + 23.903378533633802, + 22.18317345550193, + 21.21351687997722, + 21.369631381930958, + 19.77887576669022, + 17.84777916837521, + 17.119554884518124, + 17.83134606290639, + 18.78772179533209, + 17.86922488777634, + 16.829185011470088, + 16.447709588291474, + 15.879785597403783, + 14.666681349352075, + 14.100721062891465, + 12.942910597392057, + 12.625100538797028, + 11.787942335668674, + 11.027368605196868, + 10.356556837616067, + 8.382000359743586, + 7.048748406613271, + 5.665835402050419, + 5.308234490590678, + 4.992078077828978, + 5.912900424837886, + 8.553411085655739, + 10.527709181366758, + 12.358346795306373, + 14.761145867581604, + 16.435927361728943, + 19.18402835457846, + 21.378416375420585, + 23.023742303161526, + 24.546543409938465, + 26.37004967622181, + 28.165547316202943, + 31.293418409965454, + 30.005435011522792, + 31.101078728975097, + 32.13274702325006, + 33.77548912937641, + 36.51397830581968, + 40.29235232927229, + 41.059850701671195, + 41.125944858572495, + 40.01583, + 38.382959832519845, + 33.91868452325721, + 33.18446577325426, + 34.81477, + 34.87857425307874, + 34.94391, + 36.23129, + 37.012730000000005, + 37.14197, + 36.53957903508969, + 37.17604, + 39.593450000000004, + 40.4356, + 39.7626, + 42.09309, + 43.01604000000001, + 43.949750000000016, + 44.53224856952364, + 43.69839765806197, + 44.17478966436946, + 43.45283125181098, + 46.25002485533779, + 46.821340000000006, + 45.555170000000004, + 45.56200483580378, + 46.34915000000001, + 47.89416000000001, + 48.13876000000001, + 53.717430000000014, + 54.47171000000001, + 53.485820000000004, + 54.75301463713508, + 55.44268, + 57.31702, + 58.802, + 59.94142, + 61.07784000000001, + 60.03000000000001, + 60.55003055200956, + 63.504010451109934, + 64.888115, + 68.51216000000001, + 69.18068000000001, + 68.16444000000001, + 68.13522, + 66.93008000000002, + 67.25976, + 66.72492000000001, + 66.69466, + 68.54006, + 69.19636, + 69.94000000000001, + 72.58754, + 72.79603, + 71.84811000000002, + 72.47011000000002, + 72.79188, + 72.56469770700558, + 73.66787000000001, + 73.23870000000001, + 71.28000000000002, + 72.42301, + 72.82077000000001, + 73.92099000000002, + 74.18651000000001, + 75.052, + 74.46926, + 74.93584, + 73.84236000000001, + 73.60187, + 74.3998, + 73.10110000000002, + 74.89082000000002, + 74.65926000000002, + 75.15801, + 75.68351000000001, + 75.28898, + 76.35911, + 75.90313, + 77.57663984569749, + 79.65201704297142, + 81.50001793816108, + 80.61071821485025, + 80.5110860533915, + 82.24999800001305, + 84.655225864606, + 86.822328729198, + 86.00956180211142, + 87.16680382685564, + 88.31567426956859, + 90.25994835811801, + 92.90061404823274, + 93.2342370951091, + 95.86001997272373, + 96.67821292520098, + 98.92257205606934, + 100.75966922404542, + 101.03531131389028, + 101.99080854696703, + 104.35159467978896, + 106.06663211469166, + 104.70500980023309, + 106.97014285688276, + 107.23999718631096, + 108.15373986209585, + 111.07726000000001, + 113.33151000000001, + 114.13417, + 113.88539, + 112.77919396367685, + 110.15125, + 109.39999999999999, + 110.64, + 112.11919, + 113.01954, + 113.52958000000001, + 113.96881, + 115.56782, + 118.77633, + 119.02, + 123.20067671111434, + 123.25777000000001, + 125.38000000000001, + 126.97644000000001, + 128.59126, + 129.05157, + 128.46, + 129.71599, + 131.28855512911548, + 132.2535, + 133.85766, + 135.56193, + 137.49755000000002, + 138.23409, + 139.86983, + 139.14791, + 140.46817000000001, + 149.50000166239147, + 150.3511641786709, + 152.96888553284805, + 157.00688000000002, + 158.99779, + 159.83031, + 159.70866, + 160.94053000000002, + 162.27907, + 164.05248, + 165.94037000000003, + 167.86295235868673, + 169.57763000000003, + 170.81688, + 170.00820000000002, + 170.45345000000003, + 173.64391, + 175.72403000000003, + 178.59998253815886, + 180.00000044181039 + ], + "lat": [ + 19.096715806550307, + 19.593817246981985, + 20.0925206568147, + 20.567866319251493, + 20.999752102130827, + 21.42231028898148, + 21.885744533774997, + 22.158234361250052, + 22.679339504481305, + 23.017768459560788, + 23.72335846607402, + 24.35913361256094, + 24.520260728447003, + 25.10353261972537, + 25.63626496022229, + 26.25441844329768, + 26.61889232025227, + 27.640147813420413, + 28.038185533148567, + 28.148643907172456, + 28.83214223888092, + 29.098585923777815, + 29.933573716749905, + 31.177735500609046, + 32.03809642183644, + 32.564679266890636, + 33.2402452662423, + 33.697064927702456, + 34.11047638603745, + 35.145865383437425, + 35.75998810479405, + 35.755182196590894, + 35.33071198174545, + 35.39985504815198, + 35.1790933294011, + 35.16839630791668, + 35.7148487411871, + 35.888662421200806, + 36.30127289483528, + 36.605647081034405, + 36.78390493422522, + 36.86503693292346, + 36.71651886651662, + 37.11065501560674, + 37.11838064223437, + 36.885707505840216, + 36.94642731378316, + 37.349994411766545, + 37.230001735984814, + 36.724037787415085, + 37.09210317641396, + 36.899996039368915, + 36.410000108377375, + 35.94744436293281, + 35.698984076473494, + 34.83350718844919, + 34.33077301689771, + 33.78574168551532, + 33.76874013929128, + 33.293342800422195, + 33.13699575452314, + 32.79277903902697, + 32.87882029879293, + 32.71195709892248, + 32.2650851506785, + 31.37625051525828, + 31.182179673786152, + 30.76357473400583, + 30.266395778925713, + 30.525811469030913, + 30.985757554644735, + 31.75178314872332, + 32.23818756767058, + 32.70678945569328, + 32.843215236943834, + 32.63857656506802, + 32.19149791109487, + 32.187260443646935, + 32.01667654065146, + 31.89934520113276, + 31.569158637003838, + 31.585669257121097, + 31.32126679129972, + 31.025755113238645, + 30.870054022743233, + 31.18685639090856, + 31.473402207967, + 31.55585195568868, + 31.429606431599638, + 30.933616034462233, + 31.260340277627606, + 31.024075629189156, + 30.967464097613416, + 31.219360866820153, + 31.548823960896996, + 31.60553884533732, + 32.07292633720117, + 32.82737641044638, + 33.080539252244265, + 33.09090037691878, + 33.90545014091944, + 34.61005829521913, + 34.644914048800004, + 35.410009467097325, + 35.82153473565367, + 36.27499542901485, + 36.65060557712833, + 36.565442816711325, + 36.7955321314909, + 36.219960028624016, + 36.107563788389186, + 36.64427521417258, + 36.6778648951623, + 36.26298065850699, + 36.144357408180994, + 36.67683136651647, + 36.65882212986274, + 37.653360907536, + 38.208133246405396, + 38.985760199533516, + 39.463612168936464, + 40.42001373957831, + 40.46001129817221, + 41.21999074967267, + 41.08762156835702, + 41.736264146484615, + 42.01896006933731, + 42.040224921225416, + 41.33535838476427, + 40.94858612727573, + 41.10276276301855, + 41.01367259374735, + 41.53565623632757, + 41.96294281673292, + 42.64512339941794, + 43.013628038091284, + 43.128633938156845, + 43.43499766699922, + 44.279984849619794, + 44.65722280535048, + 45.24468048764449, + 45.40451569272325, + 46.24087291115107, + 46.63658519142609, + 47.044725653667314, + 47.26336863869423, + 47.102189846375886, + 47.022220567404204, + 46.698700263040934, + 46.64596446388707, + 46.27319651954964, + 45.65121898048466, + 45.40999339454619, + 45.46998973243706, + 45.113215643893966, + 44.939996242851606, + 44.36147858334407, + 44.56487702084489, + 45.03477081967489, + 45.32746613217608, + 45.51918569597891, + 45.85156850848024, + 46.080598456397844, + 46.333347886737386, + 46.70624502215554, + 46.583100084004, + 46.03241018328567, + 45.293308010431126, + 45.0353909368624, + 44.820210272799045, + 44.913873806328056, + 43.70746165625813, + 43.293171698574184, + 42.57789236100622, + 42.00735871028779, + 41.62288605403624, + 41.29993419042819, + 41.05496206314856, + 40.99982330989314, + 40.69056570084242, + 40.151993923496505, + 40.61775360774317, + 40.82412344010076, + 40.8525454778613, + 40.947061672523134, + 40.68712921809501, + 40.12499298762401, + 39.96200552017544, + 39.96099782974575, + 40.476005153966554, + 40.25656118423912, + 39.65931081802579, + 39.190011298167136, + 38.9709032252496, + 38.51000112563838, + 38.21999298761638, + 37.65501455336933, + 37.920011298162066, + 37.40999074965741, + 37.30501007745647, + 36.422505804992014, + 36.410000108377375, + 36.84498647719421, + 37.64498932550471, + 38.310323391262585, + 38.7699852564988, + 39.34023468683962, + 39.62499766698399, + 39.69499339452332, + 39.915005805005976, + 40.25077342382242, + 40.727230129553504, + 41.40956574153539, + 41.71998607031267, + 41.8775475123706, + 41.95501048437612, + 42.281502183596174, + 42.47999136002926, + 42.84999461523907, + 43.2099984808004, + 43.50721548112712, + 44.243191229827985, + 44.317915350922036, + 44.73848399512944, + 45.076060289076096, + 45.2337767604309, + 44.80212352149688, + 45.13693512631593, + 45.48414907488502, + 45.500323798192376, + 45.59101593686462, + 45.73669179949542, + 45.381778062514826, + 44.885374253919096, + 44.600482082693986, + 44.09136587175446, + 43.587727362637864, + 42.761007798832466, + 41.95513967545685, + 41.961315009115715, + 41.74029490820339, + 41.541082261718216, + 41.17960561783656, + 40.87714345963222, + 40.35562490494263, + 40.16886627863981, + 39.810774441073264, + 40.277671006830346, + 40.44223460546381, + 39.79540070246644, + 39.42469981542068, + 38.90287120213735, + 38.843572496082416, + 37.9858987493342, + 37.908849188787016, + 38.21459280044188, + 38.75094249119924, + 38.9645470240777, + 39.54407237401492, + 40.048356838535156, + 40.17294871679087, + 40.604550279292596, + 40.7863479680954, + 41.1882872584616, + 41.253089504555604, + 41.70453481705741, + 42.3554253199897, + 42.93146251074721, + 43.9200068222746, + 44.03627879493132, + 44.36633616797951, + 44.23122813575242, + 43.76714793555524, + 43.69384491634922, + 43.128892320318315, + 43.399650987311595, + 43.075200507167054, + 42.47301504166986, + 41.892120266276905, + 41.226088568683096, + 41.01473196060934, + 40.678318386389236, + 40.12393362076202, + 39.30997813573272, + 38.73851430923304, + 38.29236583104115, + 37.642353827457825, + 37.44306366632422, + 36.67414419203729, + 36.65889964451118, + 36.677839056946155, + 36.32470815687964, + 35.946850083961465, + 36.02981659600606, + 36.367677110330334, + 36.94291331638732, + 37.09778758396607, + 36.83826854099627, + 36.97888011326246, + 36.86880931248078, + 37.65134552667661, + 38.266243394517616, + 38.3584858261586, + 38.73742910415491, + 39.39206614842837, + 39.75509308527877, + 40.15930613866581, + 40.76063894303019, + 41.18433401139126, + 41.54345937760364, + 41.880570583659676, + 42.59277517350627, + 43.0266246608127, + 43.74833771420099, + 43.567909450853925, + 43.57423981380968, + 43.40344920508504, + 43.4559007838613, + 43.42280202897834, + 44.022610378590116, + 46.01491771095486, + 47.06436269793822, + 47.57032664650795, + 47.954954332056374, + 48.68416046812699, + 48.90169240985963, + 48.64442129169454, + 49.776341864615745, + 49.34737580016091, + 50.12717316344526, + 50.9466063502975, + 51.14850617126186, + 51.34578095153609, + 51.62054454203196, + 53.09179840759775, + 53.51040334737807, + 53.48216217713056, + 53.69393219666266, + 53.748295803433706, + 53.527792466844296, + 54.02078563090876, + 54.395646470754016, + 54.96274363872503, + 55.5177226833236, + 56.54001170513759, + 56.80996938743033, + 57.11000275331695, + 57.1720661484995, + 57.44794078228966, + 57.73001658795485, + 57.21573273378612, + 56.89001618105044, + 56.60998159446079, + 56.458621324277885, + 56.08138336854721, + 56.19000722922473, + 55.469999498102055, + 54.98310415304803, + 54.596641954153256, + 54.363607082733054, + 54.00869334575247, + 54.19648550070113, + 54.47037059184805, + 54.07551097270586, + 53.75702912049104, + 54.05070628520575, + 54.513158677785725, + 54.85153595643291, + 54.68260569927078, + 54.43871877706929, + 54.42608388937393, + 54.86616038677151, + 55.190481675835315, + 56.031076361711065, + 56.78387278912294, + 57.411870632549935, + 57.75337433535076, + 57.00623647727487, + 57.02569265403277, + 57.79342357037697, + 58.38341339785329, + 58.25737457949341, + 58.612753404364625, + 59.187240302153384, + 59.46585378685502, + 59.61109039981133, + 59.445803331125774, + 59.475388088612874, + 60.02806753197446, + 60.50351654727584, + 60.4239606797625, + 60.05731639265166, + 59.846373196036225, + 60.39192129174154, + 60.720169989659524, + 61.70532949487179, + 62.60739329695874, + 63.18973501245587, + 63.81781037053129, + 64.90234365504084, + 65.11142650009374, + 65.53434642197045, + 66.00692739527962, + 65.72374054632017, + 65.02600535751527, + 64.41358795842429, + 63.60955434839504, + 62.74940013289681, + 61.34116567651097, + 60.63658336042741, + 60.081914374422595, + 58.9537661810587, + 58.71982697207339, + 57.041118069071885, + 56.10430186626866, + 56.200885118222175, + 55.40778107362265, + 55.36173737245058, + 56.30708018658197, + 57.44181712506307, + 58.85614940045936, + 59.469807033925356, + 58.313288479233215, + 58.078884182357285, + 58.5881554225937, + 59.663231919993834, + 61.97099803328432, + 62.614472968182724, + 63.45400828719648, + 64.4860383164975, + 65.87972585719318, + 67.81064158799516, + 68.56320547146173, + 69.81744415961778, + 70.2551693793461, + 70.2020718451662, + 71.03049673123722, + 70.98626170519539, + 71.18547435168055, + 70.4537877468599, + 70.18625885688489, + 69.55808014594488, + 69.90596588813376, + 69.30140330675114, + 69.06343333604705, + 67.93239126247484, + 67.45712311468647, + 66.79158234319944, + 66.26618, + 65.99953766546189, + 66.75959463161077, + 66.63252228460506, + 65.90015000000001, + 65.43621287704816, + 64.41437, + 64.10945000000001, + 63.849830000000004, + 64.33471, + 64.76446, + 65.14322, + 64.52079, + 64.76446, + 65.49682, + 66.47623, + 66.41857999999999, + 66.06908, + 66.75633901637637, + 67.35242666286312, + 67.96161428493588, + 68.57080190700863, + 68.24999461534067, + 67.68997, + 67.56652, + 67.01004446071333, + 66.66767, + 66.88455, + 67.52238, + 68.85737999999999, + 68.80815000000001, + 68.20130999999999, + 68.08684648168837, + 68.43866, + 68.46628, + 68.88082, + 68.27844, + 68.94069, + 69.52000000000001, + 69.85000031196167, + 69.54738312446047, + 69.234835, + 68.09233, + 68.61563000000001, + 69.14436, + 69.35649, + 69.45461, + 69.92873, + 70.70889, + 71.02897, + 71.9345, + 72.84336, + 73.04, + 72.77629, + 72.22006, + 71.40898, + 71.09019, + 70.39114000000001, + 69.02085195583855, + 68.4079, + 67.74040000000001, + 66.32000000000001, + 66.17267000000001, + 66.53267000000001, + 66.78946, + 67.28429, + 67.76047, + 68.32899, + 68.98918, + 69.07146, + 69.62763, + 70.63175000000001, + 71.44717, + 72.12119, + 72.83227000000001, + 72.85497, + 72.30056, + 71.33556, + 71.15287000000001, + 71.87401000000001, + 72.26716543241405, + 72.32010793729707, + 71.74998769803697, + 72.58285675728509, + 73.64821808541437, + 73.85001455351413, + 73.805908718553, + 73.93688263619676, + 74.4596672634775, + 75.11644887969108, + 75.14394074167033, + 75.63998281524003, + 75.77333384876921, + 76.04719310169999, + 76.14000397409622, + 75.91546987578802, + 76.44688446726148, + 76.43027049427967, + 76.8618720567814, + 77.28753082956955, + 77.69791921661546, + 77.37388214792925, + 77.12738556589703, + 76.97419078236776, + 76.47998322214444, + 76.72335338002303, + 76.71000000000001, + 76.22224, + 75.84764000000001, + 75.32779000000001, + 75.03185456002926, + 74.47673, + 74.18, + 74.04, + 73.78774, + 73.97693000000001, + 73.33505000000001, + 73.59488, + 73.75285000000001, + 73.58772, + 73.12, + 72.97120514595854, + 73.73503000000001, + 73.56, + 73.56549, + 73.03871, + 72.39872000000001, + 71.98, + 71.19304000000001, + 70.7869973822779, + 71.83630000000001, + 71.38642, + 71.65525, + 71.34763000000001, + 71.62803, + 71.48783, + 72.41619, + 72.84941, + 72.1999860704346, + 71.60643056913015, + 70.84221365018179, + 71.03141, + 70.86672, + 70.45324, + 69.72198, + 69.43728, + 69.64204, + 69.66823000000001, + 69.47199, + 69.56876831648658, + 68.6938, + 69.01362999999999, + 69.65276, + 70.09703, + 69.81743, + 69.87725, + 69.40000193956404, + 68.96364614529146 + ] + }, + { + "lon": [ + 180.00000000000006, + 178.7072, + 177.41128, + 178.31300000000002, + 178.90825, + 179.37034, + 179.48636000000002, + 179.22826460196347, + 177.36430000000001, + 174.56929, + 173.68013, + 172.15, + 170.6985, + 170.33085, + 168.9004195498388, + 166.29498, + 165.84000000000003, + 164.87673999999998, + 163.53929975815072, + 163.21711000000002, + 162.01733, + 162.05297, + 163.19191, + 163.05793379135196, + 162.12634451087916, + 161.70146, + 162.11749, + 160.36874393131512, + 160.02173000000002, + 158.53094000000002, + 158.23118, + 156.78979, + 156.42, + 155.99185346905801, + 155.4336446474412, + 155.91442, + 156.75816328351425, + 156.81035648012903, + 158.36433, + 160.15066938704342, + 161.87204, + 163.66967939682314, + 164.47355797755552, + 163.2583866722121, + 162.65790652898056, + 160.12148, + 159.30232, + 156.72068, + 154.21806, + 155.04375000000002, + 152.81185000000002, + 151.26573000000002, + 151.33815, + 149.78371, + 148.54481, + 145.48722, + 142.19782, + 138.95847456273992, + 135.12619, + 136.70171000000002, + 137.19342, + 138.16472456273675, + 138.80463, + 139.90151777563432, + 141.34531, + 141.3792053570204, + 140.59742, + 140.51308, + 140.0619730979006, + 138.55472659724347, + 138.21970828669527, + 136.86237511611694, + 135.51537723199698, + 134.86942182834855, + 133.5368933452703, + 132.90623416558026, + 132.27805545464025, + 130.93586347872343, + 130.78000735893113, + 130.40003055228902, + 129.96594852103726, + 129.66736209525482, + 129.70518924369247, + 129.18811486218, + 129.01039961152821, + 128.63336836152672, + 127.96741417858135, + 127.53343550019417, + 127.5021195822253, + 127.38543419811027, + 127.78334272675772, + 128.34971642467661, + 129.21291954968007, + 129.46044966035817, + 129.4683044780665, + 129.0913765809296, + 128.1858504578791, + 127.3865194031884, + 126.48574751190876, + 126.37391971242914, + 126.55923139862779, + 126.11739790253229, + 126.86014326386339, + 126.17475874237624, + 125.68910363169721, + 125.5684391622957, + 125.2753304383362, + 125.24008711151316, + 124.98103315643397, + 124.71216067921938, + 124.98599409393398, + 125.2219486837787, + 125.13285851450752, + 125.3865897970606, + 125.32111575734682, + 124.7374821310424, + 124.26562462778531, + 122.86757042856095, + 122.1313879741309, + 121.05455447803286, + 121.58599490772248, + 121.37675703337268, + 122.16859500538106, + 121.64035851449353, + 120.76862877816194, + 119.63960208544907, + 119.02346398323306, + 118.04274865119791, + 117.53270226447711, + 118.05969852098964, + 118.87814985562832, + 118.91163618375344, + 119.70280236214205, + 120.8234574728236, + 121.711258579598, + 122.35793745329849, + 122.5199947449658, + 121.10416385303307, + 120.63700890511453, + 119.66456180224606, + 119.1512081238586, + 120.22752485563373, + 120.62036909391655, + 121.22901411345023, + 121.90814578663003, + 121.89191938689038, + 121.26425744027328, + 121.50351932178467, + 122.0921138855891, + 121.93842817595306, + 121.68443851123851, + 121.12566124886649, + 120.39547326058232, + 119.5854968608395, + 118.65687137255452, + 117.28160647997088, + 115.89073530483512, + 114.76382734584624, + 114.15254682826564, + 113.80677981980074, + 113.24107791550159, + 111.84359215703248, + 110.78546552942407, + 110.5093583516886, + 110.44403934127168, + 109.88986128137361, + 109.62765506392466, + 109.86448815311832, + 108.5228129415244, + 108.05018029178294, + 106.7150679870901, + 105.88168216351903, + 105.66200564984631, + 106.42681684776602, + 107.36195356651974, + 108.26949507042963, + 108.87710656131748, + 109.33526981001722, + 109.20013593957398, + 108.36612999881545, + 107.22092858279524, + 106.40511274620343, + 105.15826378786511, + 104.79518517458239, + 105.07620161338562, + 104.33433475140347, + 103.4972799011397, + 103.09068973186726, + 102.5849324890267, + 101.68715783081996, + 100.83180952352487, + 100.9784672383692, + 100.09779747925111, + 100.01873253784456, + 99.47892052612363, + 99.15377241414316, + 99.22239871622676, + 99.87383182169813, + 100.27964684448622, + 100.45927412313276, + 101.01732791545273, + 101.62307905477806, + 102.14118696493638, + 102.37114708863521, + 102.96170535686673, + 103.38121463421217, + 103.43857547405612, + 103.33212202353486, + 103.42942874554049, + 103.50244754436889, + 103.8546741068703, + 104.24793175661145, + 104.22881147666348, + 103.51970747275439, + 102.57361535035477, + 101.39063846232919, + 101.27353966675582, + 100.69543541870664, + 100.55740766805502, + 100.19670617065775, + 100.30626020711652, + 100.0857568705271, + 99.69069054565576, + 99.51964155476963, + 98.9882528015123, + 98.503786248776, + 98.339661899817, + 98.15000939330582, + 98.25915001830626, + 98.55355065307305, + 98.45717410684873, + 98.76454552612078, + 98.42833865762985, + 98.50957400919268, + 98.1036039571077, + 97.77773237507517, + 97.59707156778276, + 97.1645398294998, + 96.505768670643, + 95.3693522481124, + 94.80840457558412, + 94.18880415240454, + 94.53348595579135, + 94.32481652219676, + 93.54098839719364, + 93.66325483599621, + 93.07827762245219, + 92.36855350135562, + 92.08288618364614, + 92.02521528520839, + 91.83489098507744, + 91.41708702999766, + 90.49600630082728, + 90.58695682166098, + 90.27297081905556, + 89.84746707556428, + 89.70204959509493, + 89.41886274613549, + 89.03196129756623, + 88.88876590368542, + 88.20849734899522, + 86.97570438024027, + 87.03316857294887, + 86.49935102737379, + 85.0602657409097, + 83.94100589390001, + 83.18921715691785, + 82.19279218946592, + 82.19124189649719, + 81.69271935417748, + 80.79199913933014, + 80.32489586784388, + 80.02506920768644, + 80.2332735533904, + 80.28629357292186, + 79.8625468281285, + 79.85799930208682, + 79.340511509116, + 78.88534549348918, + 79.1897196796883, + 78.2779407083305, + 77.94116539908435, + 77.53989790233794, + 76.59297895702167, + 76.13006147655108, + 75.7464673196485, + 75.39610110870959, + 74.86481570831683, + 74.61671715688354, + 74.44385949086723, + 73.5341992532334, + 73.11990929554943, + 72.82090945830865, + 72.8244751321368, + 72.6305334817454, + 71.17527347197395, + 70.4704586119451, + 69.16413008003883, + 69.6449276060824, + 69.34959679553435, + 68.1766451353734, + 67.44366661974547, + 67.14544192898907, + 66.37282758979327, + 64.53040774929113, + 62.90570071803461, + 61.49736290878419, + 59.616134067630846, + 58.525761346272304, + 57.39725141788239, + 56.970765822177555, + 56.492138706290206, + 55.723710158110066, + 54.71508955263727, + 53.49309695823135, + 52.48359785340961, + 51.52076256694742, + 50.85294803243954, + 50.115008579311585, + 49.576850213423995, + 48.94133344909855, + 48.567971225789755, + 47.974519077349896, + 48.18318851094449, + 48.09394331237642, + 48.416094191283946, + 48.80759484232718, + 49.29955447774583, + 49.47091352722566, + 50.15242231629088, + 50.212935418504685, + 50.11330325704594, + 50.239858839728754, + 50.527386509000735, + 50.66055667501689, + 50.81010827006958, + 50.74391076030369, + 51.013351678273494, + 51.28646162293606, + 51.58907881043726, + 51.60670047384881, + 51.38960778179063, + 51.57951867046327, + 51.757440626844186, + 51.79438927593287, + 52.57708051942561, + 53.404006788960146, + 54.00800092958758, + 54.69302371604863, + 55.43902469261414, + 56.07082075381456, + 56.36201744977927, + 56.48567915225374, + 56.39142133975335, + 56.261041701080956, + 56.396847365144005, + 56.845140415276006, + 57.4034525897574, + 58.13694786970825, + 58.72921146020542, + 59.18050174341033, + 59.45009769067703, + 59.80806033716286, + 59.806148309168066, + 59.442191196536385, + 59.28240766788991, + 58.86114139184656, + 58.48798587426694, + 58.034318475176605, + 57.826372511634105, + 57.665762160070955, + 57.788700392493325, + 57.694390903560645, + 57.234263950433814, + 56.60965091332193, + 56.51218916201947, + 56.28352094912793, + 55.66149173363064, + 55.26993940615512, + 55.27490034365513, + 54.79100223167404, + 54.23925296409371, + 53.570508253804576, + 53.10857262554751, + 52.38520592632588, + 52.19172936382509, + 52.1681649107, + 51.172515089732485, + 49.57457645040315, + 48.67923058451416, + 48.23894738138742, + 47.938914015500785, + 47.354453566279716, + 46.717076450391744, + 45.87759280781027, + 45.62505008319988, + 45.406458774605255, + 45.14435591002086, + 44.989533318874415, + 44.49457645038285, + 44.17511274595449, + 43.48295861183713, + 43.22287112811213, + 43.25144819516953, + 43.08794396339806, + 42.892245314308724, + 42.60487267433362, + 42.80501549660005, + 42.70243777850066, + 42.823670688657415, + 42.77933230975097, + 42.649572788266084, + 42.34798912941071, + 42.270887892431226, + 41.75438195167396, + 41.22139122901558, + 40.93934126156654, + 40.247652215339826, + 39.80168460466095, + 39.139399448408284, + 39.023695916506796, + 39.06632897314759, + 38.49277225114008, + 38.02386030452362, + 37.483634881344386, + 37.154817742671185, + 37.209491408036, + 36.93162723160259, + 36.639603712721225, + 36.249136590323815, + 35.64018151219639, + 35.13018680190788, + 34.63233605320798, + 34.787778761541944, + 34.832220493312946, + 34.95603722508426, + 34.92260257339143, + 34.64174116388509, + 34.42656049982173, + 34.15453576023731, + 33.92137169773639, + 33.5881103858861, + 33.136768426248864, + 32.42322024916268, + 32.32043582533416, + 32.73482913588268, + 33.348745151510144, + 34.104564650211074, + 34.47389611180108, + 34.79506513849509, + 35.692426385243465, + 35.493730503081224, + 35.525976596831356, + 36.690711704257865, + 36.86623, + 37.188717482254674, + 36.969402703607955, + 37.11471683121269, + 37.48177452978189, + 37.86273318863758, + 38.41008995947308, + 38.990622999839985, + 39.26611006038797, + 39.81429365414016, + 41.17927493669771, + 41.73495161313221, + 42.276830682144805, + 42.58957645037524, + 43.0812260272001, + 43.317852410664585, + 43.28638146339884, + 42.71587365089656, + 43.14530480324203, + 43.470659620951665, + 43.66666832863473, + 44.11780358254279, + 44.614259067570835, + 45.556940545439176, + 46.64540123880291, + 47.525657586462664, + 48.02159630716778, + 48.378783807169214, + 48.94820641459336, + 49.2677734718863, + 49.728623895065255, + 50.25877241394758, + 50.73202518087655, + 51.11122684103432, + 51.13386111837815, + 51.04151533387258, + 51.04528771342987, + 50.83418948751759, + 50.552397902229984, + 50.07092858256661, + 49.45272342305893, + 48.594532911987784, + 47.74078657409376, + 46.564734327995296, + 45.56396854023086, + 44.06814253111031, + 43.13595136899721, + 42.04159956235219, + 41.81096764503357, + 41.58514163591809, + 40.88477094906631, + 40.63785000000001, + 40.26304000000001, + 40.1211999855216, + 39.80008263525991, + 39.6049007504935, + 39.20222, + 38.74050906754732, + 38.79978193538611, + 39.440001255050134, + 39.4699735857794, + 39.19469323096061, + 39.25200239437228, + 39.18652835465849, + 39.535757684086974, + 39.949582553880276, + 40.31658857601719, + 40.47838748552303, + 40.437253045418686, + 40.56081139502857, + 40.59962039567975, + 40.775475294768995, + 40.4772506040126, + 40.08926395036522, + 39.45255862809705, + 38.53835086442152, + 37.41113284683888, + 36.28127933120936, + 35.89649661636406, + 35.198399692533144, + 34.78638349787005, + 34.70189253107284, + 35.176127150215365, + 35.37342776870574, + 35.385848253705404, + 35.562545536369086, + 35.533934767404304, + 35.37177412287238, + 35.60747033055563, + 35.45874555841962, + 35.04073489761066, + 34.21582400893547, + 33.01321007663901, + 32.574632195777866, + 32.66036339695009, + 32.91595503106569, + 32.830120477028885, + 32.580264926897684, + 32.46213260267845, + 32.20338870619304, + 31.521001417778876, + 31.325561150851, + 30.901762729625347, + 30.62281334811382, + 30.05571618014278, + 28.92555260591954, + 28.2197558936771, + 27.464608188595975, + 26.419452345492825, + 25.90966434093349, + 25.780628289500697, + 25.172861769315972, + 24.677853224392123, + 23.594043409934642, + 22.988188917744736, + 22.574157342222236, + 21.542799106541025, + 20.689052768647002, + 20.071261020597632, + 19.61640506356457, + 19.193278435958717, + 18.85531456876987, + 18.42464318204938, + 18.377410922934615, + 18.24449913907992, + 18.250080193767445, + 17.92519046394844, + 18.247909783611192, + 18.22176150887148, + 17.56691775886887, + 17.064416131262703, + 17.062917514726223, + 16.344976840895242, + 15.601818068105816, + 15.21047244635946, + 14.989710727608553, + 14.743214145576331, + 14.408144158595833, + 14.385716586981149, + 14.257714064194175, + 13.86864220546866, + 13.35249799973744, + 12.826845330464494, + 12.608564080463621, + 11.794918654028066, + 11.734198846085121, + 11.64009606288161, + 11.778537224991537, + 12.12358076340439, + 12.175618930722294, + 12.50009524908299, + 12.738478631245385, + 13.312913852601866, + 13.6337211442698, + 13.738727654686897, + 13.686379428775238, + 13.387327915102162, + 13.120987583069846, + 12.875369500386569, + 12.92906131353783, + 13.236432732809874, + 12.93304039882429, + 12.728298374083892, + 12.227347039446471, + 12.32243167486351, + 12.182336866920252, + 11.91496300624209, + 11.093772820691925, + 10.06613528813574, + 9.40524539555497, + 8.79799563969317, + 8.830086704146424, + 9.048419630579588, + 9.29135053878369, + 9.492888624721985, + 9.305613234096256, + 9.649158155972628, + 9.795195753629457, + 9.404366896206, + 8.948115675501072, + 8.744923943729418, + 8.48881554529089, + 8.500287713259695, + 7.462108188515941, + 7.0825964697644395, + 6.6980721370806, + 5.898172641634687, + 5.3628048030908815, + 5.033574252959369, + 4.325607130560684, + 3.574180128604553, + 2.6917016943562544, + 1.8652405127123188, + 1.0601216976049272, + -0.5076379052659377, + -1.0636246402941936, + -1.9647065901675944, + -2.856125047202397, + -3.3110843571000714, + -4.008819545904942, + -4.649917364917911, + -5.8344962223445265, + -6.528769090185847, + -7.5189412093304355, + -7.7121593896697505, + -7.974107224957251, + -9.004793667018674, + -9.913420376006684, + -10.765383876986645, + -11.438779466182055, + -11.70819454593574, + -12.428098924193819, + -12.949049038128194, + -13.124025437868482, + -13.246550258832515, + -13.685153977909792, + -14.074044969122282, + -14.33007585291237, + -14.579698859098258, + -14.693231980843505, + -14.839553798877944, + -15.130311245168173, + -15.664180467175527, + -16.085214199273565, + -16.314786749730203, + -16.30894731288123, + -16.61383826340328, + -16.677451951554573, + -16.841524624081273, + -16.71372880702347, + -17.126106736712615, + -17.62504269049066, + -17.18517289882223, + -16.700706346085923, + -16.463098110407884, + -16.549707810929064, + -16.270551723688357, + -16.14634741867485, + -16.256883307347167 + ], + "lat": [ + 64.97970870219841, + 64.53493, + 64.60821, + 64.07593, + 63.25197000000001, + 62.982620000000004, + 62.568940000000005, + 62.30410431583773, + 62.52190000000001, + 61.76915, + 61.65261, + 60.949999999999996, + 60.336180000000006, + 59.88177, + 60.57356395124748, + 59.78855, + 60.16, + 59.7316, + 59.868697414786325, + 59.21101, + 58.243280000000006, + 57.83912, + 57.615030000000004, + 56.15923391379492, + 56.11586812995312, + 55.28568, + 54.85514, + 54.34433177348818, + 53.20257, + 52.95868, + 51.94269, + 51.011050000000004, + 51.7, + 53.158951931361045, + 55.38101268169545, + 56.767920000000004, + 57.364715888083595, + 57.83202586529901, + 58.055749999999996, + 59.314777737049724, + 60.343, + 61.14089366316381, + 62.55060089786997, + 62.46626496036962, + 61.64249095320487, + 60.54423, + 61.773959999999995, + 61.43442, + 59.75818, + 59.14495, + 58.88385, + 58.78089, + 59.50396, + 59.65573, + 59.16448, + 59.33637, + 59.03998, + 57.0880402695929, + 54.72959, + 54.60355, + 53.977320000000006, + 53.75501373963166, + 54.25455, + 54.1896642116386, + 53.08957, + 52.23877553975579, + 51.23967, + 50.04553, + 48.44670726174584, + 46.999663804708796, + 46.30794892026593, + 45.143498033217, + 43.988994859384256, + 43.398204047207415, + 42.81146983496548, + 42.798499050460215, + 43.284541734381435, + 42.55275177669621, + 42.22000722916885, + 42.28000356705971, + 41.94136790625106, + 41.60110443782523, + 40.88282786718433, + 40.66180776627199, + 40.485436102859815, + 40.18984691015031, + 40.02541250259756, + 39.7568500839767, + 39.32393077245153, + 39.213472398427655, + 39.05089834243742, + 38.61224294692785, + 37.43239248305595, + 36.78418915460283, + 35.63214061130395, + 35.082484239231434, + 34.89037710218639, + 34.47567373304412, + 34.39004588473648, + 34.934560451795946, + 35.6845405136479, + 36.72548472751926, + 36.893924058574626, + 37.74968577732804, + 37.94001007745902, + 37.75208873142962, + 37.669070542952724, + 37.85722443292744, + 37.94882090916478, + 38.10834605564979, + 38.54847422947968, + 38.66585724543067, + 38.84855927179859, + 39.387957872061165, + 39.55138458918421, + 39.66034434667162, + 39.928493353834156, + 39.63778758397622, + 39.170451768544666, + 38.897471014962846, + 39.36085358332407, + 39.75026133885949, + 40.422442531896024, + 40.94638987890333, + 40.59338816991754, + 39.898055935214245, + 39.252333075511146, + 39.2042739934797, + 38.73763580988408, + 38.06147553156106, + 37.89732534438593, + 37.44846385349871, + 37.15638865818505, + 37.87042776137801, + 37.48112335870718, + 37.45448415786072, + 36.93061432550185, + 36.651329047180425, + 36.111439520811075, + 35.60979055433772, + 34.90985911716044, + 34.36033193616865, + 33.37672272392514, + 32.46031871187719, + 31.692174384074647, + 30.949351508095106, + 30.6762674016487, + 30.14291494396429, + 29.83252045340315, + 29.01802236583478, + 28.225512600206617, + 28.135673122667185, + 27.05320689544932, + 25.740780544532612, + 24.54739085540024, + 23.624501451099658, + 22.78287323657807, + 22.668074042241667, + 22.22376007739615, + 22.5483397486214, + 22.051367499270455, + 21.550493679281473, + 21.397143866455338, + 20.56541168871763, + 20.34103261970633, + 20.282457383703488, + 21.008227037026703, + 21.395050970947523, + 21.715212307211814, + 21.55237986906012, + 20.69685069425202, + 19.752050482659698, + 19.05816518806057, + 18.004120998603227, + 16.697456569887052, + 16.07974233648615, + 15.27669057867044, + 13.426028347217724, + 11.666859239137764, + 11.008320624226272, + 10.364483954301832, + 9.53083974856932, + 8.599759629750494, + 9.241038316276502, + 9.918490505406808, + 10.48654368737523, + 10.632555446815928, + 11.153660590047165, + 12.186594956913282, + 12.645740057826572, + 12.627084865769206, + 13.412721665902566, + 13.406856390837433, + 12.307001044153354, + 10.846366685423547, + 9.963061428258555, + 9.239255479362427, + 9.20786204674512, + 8.295152899606052, + 7.429572658717177, + 6.856868597842478, + 6.74062246340192, + 6.221636053894628, + 6.128205064310919, + 5.524495144061106, + 4.8550011255037475, + 4.181605536308339, + 3.726697902842986, + 3.3828687605890053, + 2.7910185815501762, + 2.515454006353764, + 1.6311410587590842, + 1.2930480004894918, + 1.2263337264006822, + 1.9671153833046873, + 2.760813706875581, + 3.270291652841152, + 3.9391397159948696, + 4.767280381688295, + 5.312492580583708, + 6.0405618351439045, + 6.4644894474502905, + 6.8482127954335965, + 7.34345388430276, + 7.907993068875328, + 8.382305202666288, + 7.794511623562386, + 8.350007432483878, + 8.973922837759801, + 9.932959906448545, + 10.67526601810515, + 11.441291612183749, + 12.032986761925685, + 13.122377631070677, + 13.640459703012851, + 14.837285874892642, + 16.10056793869977, + 16.92873444260934, + 16.42724050543285, + 15.7143899601826, + 15.80345429123764, + 16.037936102762018, + 17.277240301985728, + 18.2135139022499, + 19.366492621330025, + 19.726961574781996, + 19.855144965081976, + 20.670883287025347, + 21.19219513598577, + 21.701569729086767, + 22.182935695885565, + 22.76501902922122, + 22.80501658781513, + 22.392793687422866, + 21.83636770272011, + 22.039146023033425, + 21.857115790285306, + 21.9661789006373, + 22.055708319582976, + 21.690588487224748, + 21.703171698487807, + 21.49556163175521, + 20.743307806882413, + 20.151638495356607, + 19.4785788029711, + 18.302009792549725, + 17.67122142177898, + 17.016636053937816, + 16.556664130107848, + 16.310219224507904, + 15.951972357644493, + 15.89918488205835, + 15.136414903214147, + 13.835770778859981, + 13.006260687710835, + 12.056215318240888, + 10.35727509199711, + 10.30885427493962, + 9.546135972527722, + 9.216543687370148, + 8.933046779816934, + 8.252959092639742, + 7.965534776232332, + 8.89927623131419, + 10.299630031775521, + 11.308250637248307, + 11.781245022015824, + 12.741935736537897, + 13.99258291264968, + 14.617221787977698, + 15.99065216721496, + 17.928570054592498, + 19.208233547436166, + 20.419503282141534, + 21.356009426351008, + 20.757441311114235, + 20.877330634031384, + 22.0892980005727, + 22.450774644454338, + 22.84317963306269, + 23.69196503345671, + 23.94484365487699, + 24.663611151624647, + 25.42514089609385, + 25.23703868255143, + 25.21840932871021, + 25.0782370061185, + 25.380156561783778, + 25.60996165618573, + 25.73990204518364, + 26.966106268821363, + 27.143304755150197, + 26.964633490501043, + 26.480657863871514, + 26.81236888275305, + 27.580849107365495, + 27.865689602158298, + 28.814520575469388, + 30.147772528599717, + 29.985715236932407, + 30.317090359004037, + 29.926778265903522, + 29.975819200148504, + 29.534476630159762, + 29.306299343375002, + 28.55200429942667, + 27.689627997339883, + 27.46121816660981, + 27.109999294538085, + 26.689663194275997, + 26.277026882425375, + 25.94397227630425, + 25.608049628190926, + 25.327808335872103, + 24.999895534764022, + 24.754742539971378, + 25.482424221289396, + 26.006991685484195, + 26.11458201751587, + 25.80111277923338, + 25.21567047779874, + 24.62738597258806, + 24.245497137951105, + 24.29407298430547, + 24.019826158132506, + 24.177439276622707, + 24.15131684009917, + 24.121757920828216, + 24.79789236093509, + 25.43914520924494, + 26.05546417897398, + 26.39593435312898, + 26.309117946878633, + 25.895990708921246, + 25.71460643157677, + 24.924732163995486, + 24.241673081961505, + 23.878594468678813, + 23.74793060962881, + 23.56566783293536, + 22.992395331305474, + 22.6602709009656, + 22.533611965418217, + 22.310524807214193, + 21.714540513592027, + 21.43388580981485, + 21.114034532144302, + 20.428985907467094, + 20.481437486243337, + 20.24300242764863, + 19.73600495043307, + 19.067570298737678, + 18.94470958096376, + 18.947991034414287, + 18.574267076079465, + 18.087113348863966, + 17.876066799383963, + 17.884128322821496, + 17.632309068263197, + 17.22835439703762, + 16.95069692633338, + 17.044980577049913, + 16.707662665264706, + 16.651051133688952, + 16.382411200419654, + 15.93843313238402, + 15.597420355689948, + 15.175249742081492, + 14.708766587782748, + 14.00320241948566, + 13.948089504446372, + 14.007233181204427, + 13.592219753468383, + 13.39969920496502, + 13.347764390511685, + 13.290946153206763, + 13.026905422411433, + 12.95393830001531, + 12.69958690027471, + 12.721652736863348, + 12.585950425664876, + 12.636800035040084, + 13.220950425667425, + 13.767583726450852, + 14.06263031662131, + 14.802249253798749, + 15.213335272680595, + 15.261962795467255, + 15.718885809791999, + 15.911742255105267, + 16.347891343648683, + 16.774635321514964, + 17.075805568912003, + 17.474721787989125, + 17.833046169500975, + 18.67159963630121, + 19.486485297111756, + 20.17463450772649, + 20.338862209550058, + 21.291904812092934, + 21.986875311770195, + 22.57965566659027, + 23.688451036060854, + 24.078685614512935, + 24.285494696545015, + 24.85848297779731, + 25.084541530858107, + 25.60295949961018, + 25.826227525327223, + 26.57013560638488, + 27.376520494083422, + 28.06335195567472, + 28.058546047471566, + 28.6074272730597, + 28.957483425404845, + 29.356554673778845, + 29.501326198844524, + 29.09941274669448, + 28.343980821235732, + 27.823314927678965, + 27.648700262964724, + 27.97136790619518, + 28.4176455754678, + 29.85107229259593, + 29.760431830355984, + 28.705224921172075, + 27.699885769149816, + 26.142280585224313, + 25.59856700286538, + 25.033743597915205, + 23.926705227142534, + 23.7523747828059, + 23.102440293871012, + 22.204846503177325, + 22.0, + 21.018846543862676, + 20.837436428302052, + 19.807964382399504, + 18.614083767160352, + 18.367871405505724, + 17.998307399970386, + 16.840626125551694, + 15.922723496967292, + 15.435647284400234, + 14.491079616753225, + 13.921036892141572, + 13.343992010954366, + 13.000421250861848, + 12.699638576707, + 12.390148423710968, + 11.97492829024577, + 11.735640570518257, + 11.462039699748928, + 11.277709865763812, + 10.864169216348103, + 10.445538438351631, + 10.4422053084688, + 10.69802948652972, + 10.81654938399113, + 11.127228094929876, + 11.193063869669729, + 11.37548167566004, + 11.41062164961852, + 11.430336208537868, + 11.578905951376996, + 11.679571641481573, + 12.021902167199087, + 12.024641018110557, + 11.748146267132881, + 11.166502183471707, + 10.640901190631055, + 10.279734605343151, + 9.198741156445607, + 8.081729234240612, + 6.8046495630115515, + 5.339105943214022, + 4.21940684652985, + 2.8552782251051245, + 2.045766913252919, + 1.052804266764582, + 0.2921788598604991, + -0.9191683894933078, + -1.4464747045995878, + -1.6832561173609477, + -2.0825599096802563, + -2.49979, + -2.57309, + -3.2776807592944124, + -3.6811703426293576, + -4.346556084819518, + -4.67677, + -5.908941338732021, + -6.475676771676994, + -6.839995619334701, + -7.099979750195118, + -7.703922214390246, + -8.007831312698748, + -8.485528252804826, + -9.11236337650525, + -10.09840138106649, + -10.317096042525698, + -10.765440769089993, + -11.761710707245015, + -12.639176527561027, + -14.201975192931862, + -14.691764418194241, + -15.406294447493972, + -16.10077402106446, + -16.72089120856694, + -17.101023044505958, + -17.586368096591237, + -18.65968759529345, + -18.842260430580637, + -19.552811374593894, + -19.784011732667736, + -20.49704314543101, + -21.25436126066841, + -21.840837090748877, + -22.14, + -22.090000000000003, + -23.070787855727758, + -23.5353589820317, + -23.706563002214683, + -24.12260995859655, + -24.478350518493805, + -24.81631438568266, + -25.357573337507738, + -25.727318210556092, + -26.148584486599447, + -26.215867201443466, + -26.742191664336197, + -27.470157566031816, + -28.301011244420557, + -28.75240488049007, + -29.257386976846256, + -29.401977634398914, + -29.909956963828037, + -30.42377573010613, + -31.140269463832958, + -32.1720411109725, + -32.771952813448856, + -33.2269637997788, + -33.61495045342619, + -33.6670402971764, + -33.94464609144834, + -33.796851495093584, + -33.98717579522455, + -33.794474379208154, + -33.91643075941698, + -33.86408253350531, + -34.258838799782936, + -34.417175388325234, + -34.79513681410799, + -34.81916635512371, + -34.46259897230979, + -34.444305515278465, + -33.99787281670897, + -34.13652068454807, + -33.86775156019803, + -33.28143075941444, + -32.61129078545343, + -32.42913136162457, + -31.66163298922567, + -30.725721123987547, + -29.878641045859162, + -29.875953871379984, + -28.5767050106977, + -27.821247247022804, + -27.090955905874047, + -26.117371921495156, + -25.39292001719538, + -23.853014011329847, + -22.65665292734069, + -22.111208184499958, + -21.699036960539978, + -20.872834161057504, + -19.673165785401665, + -19.0453488094877, + -18.069129327061916, + -17.301889336824473, + -16.67314218512925, + -15.793816013250735, + -14.878316338767904, + -14.449143568583892, + -13.54769988368445, + -13.137905775609902, + -12.483630466362492, + -12.03864470789717, + -11.297863050993165, + -10.73107594161589, + -10.373578383020714, + -9.766897067914122, + -9.166933689005468, + -8.959091078327553, + -8.562629489784307, + -7.596538588087733, + -6.927122084178805, + -6.294447523629394, + -6.10009246177966, + -5.789930515163839, + -5.037986748884791, + -3.978826592630547, + -2.9694825171056816, + -2.144313246269043, + -1.111301364754496, + -0.7790735815500369, + -0.45935149496021666, + 0.2686660831676875, + 1.010119533691494, + 1.1609113631191832, + 2.2838660750377358, + 3.073404445809117, + 3.734526882335203, + 3.9041289331171356, + 4.35221527751996, + 4.495617377129918, + 4.7719829370268485, + 4.412108262546241, + 4.4646890324032285, + 4.240594183769517, + 4.262453314628985, + 4.887970689305959, + 5.611802476418234, + 6.2706511499234665, + 6.258300482605719, + 6.258817246928629, + 6.142157701029731, + 5.928837388528876, + 5.3434726017426755, + 5.000547797053812, + 4.710462144383371, + 4.994475816259509, + 4.984295559098015, + 5.179813340674315, + 5.168263658057086, + 4.993700669775137, + 4.705087795425015, + 4.338288479017308, + 4.364565944837722, + 4.355755113131963, + 4.8324185245922, + 5.593560695819207, + 6.140710760925558, + 6.7859168563057475, + 6.860098374860726, + 7.26294200279203, + 7.798645738145738, + 8.163946438016978, + 8.903048610871508, + 9.49474376061346, + 9.886166897008252, + 10.015719712763968, + 10.214467271358515, + 10.656300767454042, + 10.87657156009814, + 11.040411688679526, + 11.458474025920795, + 11.52459402103824, + 11.80651479740655, + 11.95870189050612, + 12.170911159712702, + 12.384851589401052, + 13.15139394780256, + 13.594958604379855, + 14.373515733289224, + 14.729540513564073, + 14.919477240452862, + 15.621527411354108, + 16.13503611903846, + 16.673892116761962, + 17.166962795474873, + 18.108481553616656, + 19.096715806550307 + ] + }, + { + "lon": [ + -177.55000973214604, + -179.99998938710377 + ], + "lat": [ + 68.19999766709829, + 68.96364614529146 + ] + }, + { + "lon": [ + -179.99998938710377, + -179.7933094961524, + -179.91735877186903, + -179.99998938710377 + ], + "lat": [ + -16.067132663642447, + -16.020882256741224, + -16.501783135649397, + -16.555216566639196 + ] + }, + { + "lon": [ + 125.94707238169826, + 126.64470421763855, + 126.95724328013983, + 127.33592817597463, + 126.96799197805655, + 125.9258850444586, + 125.08852013560109, + 124.43595014861933, + 123.57998172413669, + 123.459989048355, + 123.55000939340744, + 123.9800089865081, + 124.96868248911623, + 125.08624637258026, + 125.94707238169826 + ], + "lat": [ + -8.432094821815035, + -8.398246758663852, + -8.273344821814398, + -8.397316582882603, + -8.668256117388893, + -9.106007175333353, + -9.393173109579294, + -10.140000909061449, + -10.359987481327956, + -10.239994805546223, + -9.900015557497987, + -9.290026950724716, + -8.892790215697083, + -8.65688730228468, + -8.432094821815035 + ] + }, + { + "lon": [ + -180.0, + -179.94249935617904, + -179.05867733469117, + -177.2567718171058, + -176.0846728180777, + -175.8298821686626, + -174.38250281481567, + -173.1165594147455, + -172.8891055980128, + -169.95122290757138, + -168.99998898015872, + -168.5301985341933, + -167.02209937240343, + -164.1821435211551, + -161.92977454328147, + -158.0713795644249, + -155.19225297749932, + -150.94209896543805, + -148.5330728830716, + -145.8889190337772, + -143.10771928604473, + -142.89228023981988, + -146.82906836646325, + -150.06073157448398, + -150.9029282297608, + -153.58620113830017, + -153.40990698953644, + -153.03775916238652, + -152.66563717345275, + -152.86151669005508, + -154.52629879455392, + -155.29017981669242, + -156.83744971415953, + -154.40878658752223, + -152.09766150613277, + -150.6482926096426, + -148.86599829811203, + -147.2207498850195, + -146.41774980363607, + -146.77028642473124, + -148.0629465402963, + -149.5319008046251, + -151.5884161041125, + -153.39032162169784, + -155.3293763905858, + -155.97566769104412, + -157.26830196839302, + -158.0517683583701, + -158.36513424378805, + -157.8754742096064, + -156.97457312724603, + -155.3293763905858, + -153.74283240457683, + -152.9202469553548, + -151.3337804839943, + -150.00194963275197, + -148.7484860910803, + -147.61248308000805, + -146.1044097564343, + -146.14352881567925, + -146.49609127499056, + -146.20231075741125, + -144.90962480363004, + -144.3220379302553, + -142.7943534006268, + -141.63876502171593, + -140.2090073312805, + -138.8575911121996, + -137.50620073133481, + -136.42890214734612, + -135.21458350313554, + -134.4311946278069, + -133.7456550770229, + -132.25716712128778, + -130.9253104318293, + -129.55428300669362, + -128.24203752328992, + -126.890621304209, + -125.40208167204159, + -124.01149471728343, + -122.5621516590094, + -121.07361202684199, + -119.70255876349015, + -118.68414547409805, + -117.46980099167133, + -116.2163116117835, + -115.02155249719539, + -113.94433142785512, + -113.29798845096451, + -112.94545182986936, + -112.29908301476263, + -111.26105851931575, + -110.06632524294379, + -108.71490902386287, + -107.55934648316813, + -106.1491483223552, + -104.87607357462875, + -103.36794857462272, + -102.01650651732565, + -100.64553076862225, + -100.11669999876337, + -100.76304297565397, + -101.25270300983563, + -102.54533728718455, + -103.11331295450452, + -103.32875200072934, + -103.68128862182449, + -102.91748511433445, + -101.60523963093078, + -100.3125278389334, + -99.13737993040007, + -98.11888912635953, + -97.68803687212605, + -96.33659481482896, + -95.04396053748003, + -93.6729072741282, + -92.439003262079, + -91.42056413447077, + -90.08873328322845, + -89.22695126011301, + -88.4239511787296, + -87.26833696160259, + -86.01482174349862, + -85.19223629427657, + -83.8799908108729, + -82.66564632844616, + -81.4709130520742, + -80.6874466620971, + -80.295790981757, + -79.29688554555507, + -77.92585812041938, + -76.90736731637884, + -76.22187944202715, + -74.89004859078484, + -73.85202409533798, + -72.83353329129744, + -71.61921464708686, + -70.20904232449007, + -68.93591590033134, + -67.95662167018419, + -67.36906063502559, + -67.13403622096214, + -67.25154842799387, + -67.56494015162794, + -67.91747677272309, + -68.23084265814101, + -68.48545244004308, + -68.54420854355894, + -68.44628170436583, + -67.97623287623895, + -67.5844996812504, + -67.4278425767576, + -67.62367041692765, + -67.74118262395936, + -67.25154842799387, + -66.70318396672866, + -66.0568151516219, + -65.3713272772702, + -64.56827551945449, + -64.17654232446594, + -63.62815202498459, + -63.001394415932594, + -62.041685553624056, + -61.41492794457208, + -60.70985470238176, + -59.887269253159715, + -59.16258480491463, + -58.59455746116237, + -57.811142747617566, + -57.223581712458966, + -57.59572953960888, + -58.61414282900098, + -59.04507259788291, + -59.78934241396662, + -60.611927863188654, + -61.29741573754036, + -62.02210018578545, + -62.511760219967094, + -62.64885779483744, + -62.590127529537725, + -62.12007870141083, + -62.80556657576255, + -63.74569007023244, + -64.29410620792996, + -64.8816930813047, + -65.50842485214054, + -65.66508195663336, + -65.31254533553819, + -64.7837145656793, + -63.961103278241126, + -63.19729977075109, + -62.78595536970778, + -62.57051632348295, + -62.276735805903655, + -61.80666113956063, + -61.51290646019748, + -61.37580888532713, + -61.081976691315546, + -61.0036610581772, + -60.69026933454315, + -60.827366909413485, + -61.37580888532713, + -61.963369920485725, + -63.295200771728034, + -63.74569007023244, + -64.35283647322967, + -65.86098731145185, + -67.19281816269415, + -68.44628170436583, + -69.79772376166291, + -70.60072384304632, + -72.20677568224545, + -73.9695363023697, + -75.55597693551407, + -77.24037024606767, + -76.92697852243361, + -75.3992939928051, + -74.28287634957147, + -73.65611874051949, + -74.77253638375312, + -76.49610042998398, + -77.92585812041938, + -77.98466590036753, + -78.02378495961247, + -76.84863705107912, + -76.63322384307045, + -75.36009741891172, + -73.24485185412462, + -71.44294633653928, + -70.01316280788772, + -68.19164608424762, + -65.70427853052674, + -63.2560300360508, + -61.552025519442424, + -59.691415574773515, + -58.71212134462637, + -58.222487148660875, + -57.00811682801799, + -55.36289425314162, + -53.61977067728829, + -51.54364417174613, + -49.76134986021556, + -47.273930630062374, + -44.825707973802594, + -42.80836340999244, + -42.16202043310183, + -40.77143347834367, + -38.244817674297096, + -36.26666968438033, + -34.38639685722437, + -32.31029618989837, + -30.09709794770201, + -28.549802212018733, + -29.254901292425203, + -29.685805223090984, + -29.685805223090984, + -31.62480831554666, + -33.68132361503406, + -35.63991207532834, + -35.91410722506903, + -35.77700965019869, + -35.32654618991043, + -33.896762661258876, + -32.21236935070526, + -30.998050706494666, + -29.783732062284088, + -28.882779303491418, + -27.511751878355724, + -26.160335659274793, + -25.474821946706953, + -23.92755204923982, + -22.45859778491104, + -21.224693772861826, + -20.010375128651233, + -18.91354285325623, + -17.5229817367142, + -16.641588507544014, + -15.70149085129026, + -15.407710333710952, + -16.46532019699643, + -16.112783575901275, + -15.446855231172053, + -14.408804897509043, + -13.311972622114027, + -12.293507656289634, + -11.510067104528686, + -11.020432908563194, + -10.295774298534253, + -9.101015183946146, + -8.611380987980638, + -7.416621873392529, + -7.377451137715283, + -6.86823157391116, + -5.790984666354775, + -5.536374884452712, + -4.341667446296896, + -3.0489814925156793, + -1.7954921126278407, + -0.6594891015556072, + -0.22863684732209322, + 0.8681954280729087, + 1.8866862321134477, + 3.0226375667533887, + 4.139055209987021, + 5.1575460140275595, + 6.273911980828899, + 7.1357198421604835, + 7.7428662451577, + 8.487110223025269, + 9.525134718472117, + 10.249845004933347, + 10.817820672253333, + 11.953823683325595, + 12.404287143613857, + 13.422777947654367, + 14.73499759284192, + 15.126756626046614, + 15.949342075268646, + 17.026588982825047, + 18.201711053142247, + 19.259372592860018, + 20.375738559661357, + 21.452985467217758, + 21.92303429534462, + 22.56940311045139, + 23.6661837094141, + 24.841357456163593, + 25.977308790803562, + 27.09372643403719, + 28.092580193806807, + 29.150241733524577, + 30.031583286262475, + 30.97173261894855, + 31.990171746556772, + 32.75405276869526, + 33.302443068176615, + 33.8704187354966, + 34.90849490737574, + 35.30020226414814, + 36.162010125479725, + 37.20003462092657, + 37.90510786311691, + 38.649403517416744, + 39.66789432145728, + 40.02043094255245, + 40.92135786312897, + 41.959434035008115, + 42.93870242693913, + 44.113876173688624, + 44.89729088723342, + 45.719928012887756, + 46.50334272643255, + 47.4434403826863, + 48.34441897969512, + 48.99073611836956, + 49.930885451055644, + 50.75347090027768, + 50.94932457866386, + 51.79154707215682, + 52.61413252137888, + 53.61303795758079, + 54.533550245995905, + 55.414943475166126, + 56.35504113141988, + 57.158092889235576, + 57.2559680519964, + 58.13736128116659, + 58.74450768416381, + 59.93931847518422, + 60.6052209816973, + 61.42780643091933, + 62.38748945501172, + 63.19048953639515, + 64.052349074159, + 64.99244673041275, + 65.97171512234377, + 66.91186445502981, + 67.8911328469608, + 68.89003828316274, + 69.71262373238477, + 69.67345299670754, + 69.55594078967582, + 68.59625776558343, + 67.81273969917405, + 67.94988895047666, + 69.0663065937103, + 68.92915734240768, + 68.41998945503585, + 67.94988895047666, + 68.71376997261515, + 69.86930667509372, + 71.02489505400459, + 71.57328535348597, + 71.9062882831748, + 72.45462690622387, + 73.081410353492, + 73.33602013539405, + 73.8648767434691, + 74.49155683787262, + 75.62755984894488, + 76.62646528514679, + 77.64490441275504, + 78.13453860872053, + 78.42837080273213, + 79.11385867708384, + 80.09312706901483, + 80.93534956250778, + 81.48379153842143, + 82.05176720574141, + 82.77642581577035, + 83.77533125197226, + 84.67620649611649, + 85.6555265644798, + 86.7523588398748, + 87.47701744990374, + 87.98628869014016, + 88.35841067907394, + 88.82840783076853, + 89.67063032426148, + 90.63036502478616, + 91.59009972531084, + 92.60853885291908, + 93.54863650917284, + 94.17541995644096, + 95.01759077350161, + 95.7814717956401, + 96.68239871621662, + 97.75964562377298, + 98.68020958862044, + 99.718182407635, + 100.38418826701266, + 100.89335615438448, + 101.5788957051685, + 102.83241092327248, + 103.47867638551462, + 104.2425574076531, + 104.90845991416619, + 106.18156050010879, + 107.16088056847207, + 108.08139285688722, + 109.15863976444362, + 110.23583499556771, + 111.05847212122205, + 111.74395999557373, + 112.86037763880736, + 113.60467329310723, + 114.38808800665203, + 114.89730757045615, + 115.60238081264646, + 116.69916141160918, + 117.38470096239317, + 118.57946007698129, + 119.83292361865298, + 120.87099979053212, + 121.65441450407693, + 122.32036868702228, + 123.22129560759885, + 124.12227420460762, + 125.16024702362222, + 126.10039635630824, + 127.00142662974933, + 127.88276818248725, + 128.8032804709024, + 129.7042590679112, + 130.78145429903532, + 131.79994510307586, + 132.93589643771583, + 133.85646040256324, + 134.75738732313977, + 135.03158247288042, + 135.07075320855768, + 135.69748497939355, + 135.87380496637337, + 136.20670454319765, + 136.61804894424097, + 137.46027143773392, + 138.5962227723739, + 139.9084424175614, + 140.8094210145702, + 142.12169233619005, + 143.06184166887613, + 144.37406131406362, + 145.490427280865, + 146.19555219948762, + 145.99969852110138, + 146.64606733620815, + 147.72326256733226, + 148.83962853413362, + 150.1323144879148, + 151.48370486877957, + 152.5022473492524, + 153.63819868389237, + 154.28456749899914, + 155.1658573753047, + 155.9297900738755, + 156.81113162661342, + 158.02552778547243, + 159.1810128115187, + 159.6706986839165, + 160.80665001855647, + 161.57047936426267, + 162.68689700749624, + 163.84243370997484, + 164.91968061753124, + 166.11443973211937, + 167.3090954938429, + 168.4256164899411, + 169.4635893089557, + 170.50166548083484, + 171.20679039945747, + 171.08922651599346, + 170.5604215843507, + 170.10995812406242, + 169.75736982653495, + 169.28732099840812, + 167.97510135322057, + 167.38748864162966, + 166.09480268784847, + 165.64439090399247, + 164.95885135320847, + 164.23419274317956, + 163.82279666570395, + 163.5682385602342, + 163.4702600446088, + 163.48989708887976, + 164.0578727561997, + 164.27336347885682, + 164.74346398341595, + 166.60412560451715, + 166.9957812848573, + 165.19387576727195, + 163.66621707585955, + 161.76638471908115, + 160.9241622255882, + 160.7478939150406, + 160.31696414615868, + 159.78821089094822, + 161.12001590397438, + 161.62928714421082, + 162.4909916526778, + 163.70533613510452, + 165.09594892807883, + 166.60412560451715, + 168.89566531806796, + 169.40478152900755, + 172.28393395414923, + 172.47704878162398, + 173.2240832868353, + 175.98567182851303, + 178.2772115420639, + 180.0 + ], + "lat": [ + -84.71337999999999, + -84.7214433735525, + -84.13941171664914, + -84.45293263136392, + -84.09925912875835, + -84.11791432081571, + -84.53432301222364, + -84.11791432081571, + -84.06101856886238, + -83.88464690545021, + -84.11791432081571, + -84.23739023227454, + -84.57049651482794, + -84.8252096495946, + -85.13873056430938, + -85.3739100076697, + -85.09955982863215, + -85.29551685988292, + -85.60903777459774, + -85.31510222772157, + -85.040752048684, + -84.57049651482794, + -84.53127410271841, + -84.29614633579038, + -83.90423227328883, + -83.6886898741994, + -83.23801970818201, + -82.82652027784181, + -82.45419158317885, + -82.04269215283867, + -81.7683936502334, + -81.41565032340905, + -81.10212940869428, + -81.16093718864245, + -81.00415089306888, + -81.33730885205459, + -81.04337330517842, + -80.67104461051547, + -80.33793832796205, + -79.92643889762186, + -79.65208871858431, + -79.35820484814043, + -79.29939706819228, + -79.16224781688965, + -79.06426930126425, + -78.6919406066013, + -78.3784196918865, + -78.02567636506218, + -76.8892082660993, + -76.98723845815698, + -77.30075937287178, + -77.2027291808141, + -77.06557992951147, + -77.49666472769027, + -77.39873788849718, + -77.18314381297547, + -76.90884531037021, + -76.5757390278168, + -76.47776051219141, + -76.10543181752845, + -75.73315479929781, + -75.38041147247347, + -75.20403980906131, + -75.53719776804702, + -75.34124073679624, + -75.0864759255973, + -75.06689055775868, + -74.96891204213328, + -74.73378427520527, + -74.51824187611587, + -74.30269947702645, + -74.36145558054231, + -74.43984872832908, + -74.30269947702645, + -74.47901946400633, + -74.45943409616771, + -74.32228484486507, + -74.42026336049047, + -74.51824187611587, + -74.47901946400633, + -74.49860483184494, + -74.51824187611587, + -74.47901946400633, + -74.18508391713016, + -74.0283492979889, + -74.2438916970783, + -74.06752003366614, + -73.7148283832741, + -74.0283492979889, + -74.38104094838093, + -74.71419890736664, + -74.42026336049047, + -74.79254037872113, + -74.91010426218513, + -75.18445444122268, + -75.12569833770684, + -74.94932667429467, + -74.9884974099719, + -75.12569833770684, + -75.3020183246867, + -74.8709335265079, + -74.53782724395448, + -74.18508391713016, + -74.10674244577567, + -73.73441375111273, + -73.36208505644977, + -72.61753101998846, + -72.7546802712911, + -72.81343637480695, + -72.7546802712911, + -72.91141489043235, + -73.20535043730852, + -73.55804208770056, + -73.61684986764871, + -73.47970061634608, + -73.2837435850953, + -73.16617970163128, + -73.40130746855931, + -73.32291432077254, + -72.55872324004031, + -73.00939340605774, + -73.18576506946991, + -73.08778655384451, + -73.47970061634608, + -73.51887135202333, + -73.63643523548733, + -73.85197763457674, + -73.47970061634608, + -73.12695728952176, + -73.51887135202333, + -73.42089283639793, + -73.63643523548733, + -73.96954151804074, + -73.87161467884765, + -73.65602060332596, + -73.40130746855931, + -73.26415821725668, + -73.14654265736037, + -73.00939340605774, + -72.79385100696834, + -72.48033009225354, + -72.04924529407474, + -71.63774586373454, + -71.24583180123298, + -70.85391773873141, + -70.46205535266213, + -70.10931202583781, + -69.71739796333624, + -69.32553557726696, + -68.95320688260401, + -68.54170745226382, + -68.14984506619454, + -67.71876026801574, + -67.32684620551417, + -66.87617603949674, + -66.58224049262057, + -66.20996347438991, + -65.89639088324283, + -65.60250701279894, + -65.17142221462014, + -64.89707203558258, + -64.64230722438364, + -64.58355112086778, + -64.27003020615298, + -64.0740731749022, + -63.95650929143819, + -63.701744480239256, + -63.388223565524456, + -63.27065968206045, + -63.525424493259386, + -63.858530775812795, + -64.15246632268898, + -64.36800872177838, + -64.21122242620484, + -64.30920094183023, + -64.54432870875826, + -64.79909351995718, + -65.09302906683337, + -65.48494312933494, + -65.85722014756558, + -66.190326430119, + -66.42550587347932, + -66.5038473448338, + -66.83700530381951, + -67.150474542102, + -67.58161101671311, + -67.95388803494376, + -68.36533578885167, + -68.67890837999875, + -68.91398447049448, + -69.22755706164156, + -69.61941944771084, + -69.9917481423738, + -70.38366220487536, + -70.71676848742878, + -71.08904550565943, + -72.01007455839749, + -72.38235157662815, + -72.77426563912971, + -73.16617970163128, + -73.69524301543548, + -74.10674244577567, + -74.43984872832908, + -74.57699797963171, + -74.92974130645605, + -75.26284758900947, + -75.63512460724012, + -75.79191090281367, + -76.00745330190307, + -76.22299570099247, + -76.63449513133266, + -76.6736658670099, + -76.63449513133266, + -76.71288827911943, + -76.71288827911943, + -77.104802341621, + -77.28107065216858, + -77.55542083120613, + -77.90811248159817, + -78.22163339631297, + -78.12365488068757, + -78.3784196918865, + -78.78991912222669, + -79.18183318472826, + -79.51493946728168, + -79.88721648551234, + -80.25954518017528, + -80.41633147574883, + -80.6906299783541, + -81.00415089306888, + -81.31767180778367, + -81.47445810335722, + -81.74875660596248, + -82.04269215283867, + -82.37585011182436, + -82.84610564568042, + -83.21843434034338, + -82.86569101351904, + -82.57175546664286, + -82.25823455192807, + -82.00352141716142, + -81.72917123812387, + -81.70958587028525, + -81.84673512158787, + -82.08191456494819, + -81.65082976676938, + -81.3568942198932, + -81.33730885205459, + -81.12171477653291, + -80.9061723774435, + -80.76902312614087, + -80.5926514627287, + -80.33793832796205, + -79.98519500113773, + -79.6325033507457, + -79.26022633251503, + -79.29939706819228, + -79.45613168733352, + -79.45613168733352, + -79.08385466910288, + -78.33924895620927, + -78.12365488068757, + -77.88852711375955, + -77.65345102326381, + -77.35951547638764, + -77.06557992951147, + -76.6736658670099, + -76.49734588003003, + -76.3601449522951, + -76.28180348094062, + -76.24258106883109, + -76.10543181752845, + -75.90947478627767, + -75.67434701934965, + -75.43921925242162, + -75.12569833770684, + -74.79254037872113, + -74.49860483184494, + -74.10674244577567, + -73.87161467884765, + -73.46011524850746, + -73.14654265736037, + -72.95058562610959, + -72.71545785918157, + -72.40193694446677, + -72.01007455839749, + -71.53976734810915, + -71.2654171690716, + -71.32422494901975, + -71.65733123157317, + -71.6965019672504, + -71.32422494901975, + -70.93231088651818, + -71.03028940214357, + -71.40261809680652, + -71.46137420032238, + -71.2850542133425, + -71.1674386534462, + -71.22624643339435, + -71.63774586373454, + -71.30463958118114, + -71.12826791776897, + -70.99111866646633, + -70.85391773873141, + -70.61878997180338, + -70.46205535266213, + -70.24651295357273, + -69.8937696267484, + -70.14853443794733, + -70.01133351021241, + -70.48164072050075, + -70.83433237089278, + -70.63837533964201, + -70.24651295357273, + -69.97216277453518, + -70.03091887805104, + -70.40324757271398, + -70.03091887805104, + -69.91335499458702, + -69.87418425890978, + -69.8937696267484, + -70.01133351021241, + -70.07014129016056, + -70.40324757271398, + -70.69718311959015, + -70.520811456178, + -70.48164072050075, + -70.48164072050075, + -70.46205535266213, + -70.32485442492721, + -70.2072905414632, + -69.93294036242564, + -69.75662037544576, + -69.65864185982038, + -69.38429168078282, + -68.83564299914, + -68.50258839301888, + -68.65927133572784, + -69.01201466255216, + -69.24714242948019, + -69.16874928169342, + -69.52144093208545, + -69.7762057432844, + -69.54107797635636, + -69.10994150174527, + -68.93362151476539, + -68.60051523221198, + -68.46331430447705, + -68.26740894965856, + -68.05186655056916, + -67.81673878364113, + -67.60119638455173, + -67.71876026801574, + -67.36606861762371, + -67.09171843858616, + -67.11130380642477, + -66.87617603949674, + -66.52348438910471, + -66.24913421006715, + -66.05317717881637, + -65.89639088324283, + -65.81804941188835, + -65.8768055154042, + -65.9747840310296, + -66.24913421006715, + -66.68021900824596, + -67.01332529079937, + -67.28767546983693, + -67.40523935330094, + -67.6795895323385, + -67.95388803494376, + -68.01269581489191, + -67.81673878364113, + -67.40523935330094, + -67.62073007595805, + -67.73834563585436, + -67.85590951931837, + -67.93430266710514, + -67.93430266710514, + -68.97279225044264, + -69.22755706164156, + -69.678227227659, + -69.93294036242564, + -70.3052690570886, + -70.69718311959015, + -70.67754607531924, + -71.06946013782081, + -71.44178883248377, + -71.85328826282395, + -72.16680917753874, + -72.26478769316414, + -72.08841602975197, + -71.6965019672504, + -71.32422494901975, + -71.01070403430495, + -70.71676848742878, + -70.36402516060444, + -69.87418425890978, + -69.7762057432844, + -69.73703500760715, + -69.61941944771084, + -69.46268482856959, + -69.07077076606802, + -68.69844207140508, + -68.32621672960671, + -68.07150359484007, + -67.87554656358928, + -67.54238860460357, + -67.36606861762371, + -67.20928232205016, + -67.30726083767556, + -67.20928232205016, + -67.09171843858616, + -67.150474542102, + -66.87617603949674, + -66.20991179795762, + -66.48426197699517, + -66.95456918728351, + -67.150474542102, + -67.22886768988879, + -67.11130380642477, + -67.18969695421154, + -67.20928232205016, + -67.11130380642477, + -67.17011158637293, + -67.38565398546233, + -67.2485047341597, + -67.2485047341597, + -67.11130380642477, + -67.2485047341597, + -66.91534677517399, + -66.58224049262057, + -66.30789031358302, + -65.56328460068941, + -65.70048552842434, + -65.9747840310296, + -66.32752735785392, + -66.9349321430126, + -66.95456918728351, + -66.95456918728351, + -66.83700530381951, + -66.69980437608459, + -66.42550587347932, + -66.13157032660314, + -66.09234791449362, + -65.8768055154042, + -66.07276254665499, + -66.38628346136979, + -66.69980437608459, + -66.66063364040734, + -66.91534677517399, + -67.17011158637293, + -67.26809010199831, + -67.18969695421154, + -66.87617603949674, + -66.56265512478195, + -66.48426197699517, + -66.6214629047301, + -66.7193897439232, + -66.56265512478195, + -66.56265512478195, + -66.66063364040734, + -66.75861215603274, + -66.58224049262057, + -66.42550587347932, + -66.38628346136979, + -66.38628346136979, + -66.2883049457444, + -66.20996347438991, + -65.72007089626295, + -65.30857146592277, + -65.58286996852803, + -66.03359181097775, + -66.44509124131794, + -66.77819752387136, + -66.95456918728351, + -66.89576140733537, + -66.87617603949674, + -66.81736825954859, + -66.81736825954859, + -66.79778289170997, + -66.83700530381951, + -66.91534677517399, + -67.22886768988879, + -67.60119638455173, + -67.89513193142791, + -68.13025969835593, + -68.38502450955487, + -68.56129282010245, + -68.71813079210828, + -68.87481373481724, + -68.89450245552044, + -68.56129282010245, + -68.83564299914, + -69.14921559028708, + -69.38429168078282, + -69.48227019640821, + -69.59983407987222, + -69.9917481423738, + -70.22687590930181, + -70.57961923612615, + -70.7363538552674, + -70.71676848742878, + -70.77552459094464, + -70.75593922310601, + -70.83433237089278, + -70.97148162219543, + -71.20666106555574, + -71.40261809680652, + -71.6965019672504, + -72.08841602975197, + -72.44115935657629, + -72.89182952259372, + -73.24452117298577, + -73.65602060332596, + -73.8128068988995, + -74.16549854929153, + -74.38104094838093, + -74.7729550108825, + -75.14528370554545, + -75.45880462026025, + -75.87030405060044, + -76.24258106883109, + -76.69330291128081, + -77.06557992951147, + -77.45744231558074, + -77.82977101024369, + -78.18251433706801, + -78.31961191193835, + -78.75074838654946, + -78.90748300569071, + -79.12302540478011, + -79.16224781688965, + -79.73048186637108, + -80.20073740022713, + -80.57306609489008, + -80.94539478955303, + -81.27850107210645, + -81.69000050244662, + -82.06227752067728, + -82.39543547966299, + -82.70895639437781, + -83.02247730909258, + -83.33599822380738, + -83.82589080193435, + -84.04143320102375, + -84.11791432081571, + -84.4137102192544, + -84.15899708448775, + -84.47251799920255, + -84.71337999999999 + ] + }, + { + "lon": [ + -180.0, + -177.55000973214604, + -174.92825000000002, + -175.01425000000003, + -174.33983000000003, + -174.57182, + -171.85731, + -169.89958000000001, + -170.89107, + -172.53025000000002, + -172.555, + -172.95533, + -173.89184, + -174.65392000000003, + -175.98353, + -176.20716, + -177.22266, + -178.35993000000002, + -178.90332000000004, + -178.68610999999999, + -179.88377, + -179.43268, + -180.0 + ], + "lat": [ + 68.96363636363635, + 68.19999766709829, + 67.20589000000001, + 66.58435, + 66.33556, + 67.06219, + 66.91308000000001, + 65.97724, + 65.54138999999999, + 65.43791, + 64.46079, + 64.25269, + 64.2826, + 64.63125000000001, + 64.92288, + 65.35667000000001, + 65.52024, + 65.39052000000001, + 65.74044, + 66.11211, + 65.87456, + 65.40411, + 64.9797087021984 + ] + }, + { + "lon": [ + -180.0, + -179.871875, + -179.02433000000002, + -177.57794500000003, + -177.663575, + -178.69378000000003, + -180.0 + ], + "lat": [ + 71.51571433642827, + 71.55762000000001, + 71.55553, + 71.26948, + 71.13277000000001, + 70.89302, + 70.83219920854673 + ] + }, + { + "lon": [ + 180.00000000000006, + 178.90342499999997, + 178.7253, + 180.00000000000006 + ], + "lat": [ + 70.83219920854673, + 70.78114000000001, + 71.0988, + 71.51571433642829 + ] + }, + { + "lon": [ + 180.0, + 179.36414266196414, + 178.72505936299711, + 178.59683859511713, + 179.0966093629971, + 179.4135093629971, + 180.0 + ], + "lat": [ + -16.555216566639196, + -16.801354076946883, + -17.01204167436804, + -16.639150000000004, + -16.433984277547403, + -16.379054277547404, + -16.067132663642447 + ] + }, + { + "lon": [ + -61.19999999999999, + -60.00000000000003, + -59.14999999999995, + -58.55000000000004, + -57.75000000000003, + -58.05000000000004, + -59.400000000000006, + -59.85000000000002, + -60.69999999999999, + -61.19999999999999 + ], + "lat": [ + -51.84999999999999, + -51.249999999999964, + -51.5, + -51.10000000000005, + -51.549999999999976, + -51.89999999999996, + -52.199999999999974, + -51.84999999999999, + -52.300000000000004, + -51.84999999999999 + ] + }, + { + "lon": [ + 68.93499999999997, + 69.58000000000007, + 70.525, + 70.56000000000003, + 70.28000000000006, + 68.74500000000003, + 68.72000000000006, + 68.86750000000004, + 68.93499999999997 + ], + "lat": [ + -48.62500000000004, + -48.94000000000002, + -49.065, + -49.254999999999995, + -49.71, + -49.77500000000003, + -49.24250000000002, + -48.83000000000001, + -48.62500000000004 + ] + }, + { + "lon": [ + 178.12557000000007, + 178.3736000000001, + 178.71806, + 178.55271000000002, + 177.93266000000008, + 177.38146000000003, + 177.28504, + 177.67087, + 178.12557000000007 + ], + "lat": [ + -17.50481, + -17.339919999999985, + -17.62846000000001, + -18.150589999999973, + -18.287989999999994, + -18.164320000000018, + -17.72465000000002, + -17.381140000000023, + -17.50481 + ] + }, + { + "lon": [ + -61.68000000000001, + -61.10499999999993, + -60.89499999999998, + -60.934999999999974, + -61.76999999999998, + -61.95000000000002, + -61.65999999999997, + -61.68000000000001 + ], + "lat": [ + 10.760000000000034, + 10.89, + 10.85499999999999, + 10.110000000000042, + 10.000000000000028, + 10.08999999999999, + 10.36499999999998, + 10.760000000000034 + ] + }, + { + "lon": [ + -155.40213999999997, + -155.22452000000004, + -155.06226000000004, + -154.80740999999998, + -154.83146999999997, + -155.22217000000003, + -155.54211, + -155.68816999999999, + -155.93665000000001, + -155.90806000000003, + -156.07347000000001, + -156.02368, + -155.85008, + -155.91907, + -155.86108000000002, + -155.78504999999996, + -155.40213999999997 + ], + "lat": [ + 20.07974999999999, + 19.993020000000044, + 19.859100000000012, + 19.508710000000008, + 19.453279999999992, + 19.239720000000005, + 19.083479999999994, + 18.91619, + 19.059390000000022, + 19.33887999999999, + 19.70293999999997, + 19.814220000000006, + 19.977289999999982, + 20.17395000000002, + 20.267209999999977, + 20.248700000000028, + 20.07974999999999 + ] + }, + { + "lon": [ + -155.99566000000004, + -156.07925999999998, + -156.41445000000002, + -156.58672999999996, + -156.70166999999998, + -156.71055, + -156.61257999999998, + -156.25711, + -155.99566000000004 + ], + "lat": [ + 20.76403999999995, + 20.64397000000004, + 20.572410000000005, + 20.783000000000015, + 20.864300000000014, + 20.926760000000016, + 21.01249, + 20.917450000000017, + 20.76403999999995 + ] + }, + { + "lon": [ + -156.75824, + -156.78933000000004, + -157.32521000000003, + -157.25027, + -156.75824 + ], + "lat": [ + 21.176840000000013, + 21.068729999999974, + 21.09776999999997, + 21.219579999999965, + 21.176840000000013 + ] + }, + { + "lon": [ + -158.02520000000004, + -157.94161000000003, + -157.65283000000005, + -157.70702999999997, + -157.77860000000004, + -158.12667000000005, + -158.25380000000004, + -158.29265, + -158.02520000000004 + ], + "lat": [ + 21.716959999999986, + 21.652720000000045, + 21.322169999999986, + 21.26442000000003, + 21.27728999999998, + 21.312439999999967, + 21.53918999999999, + 21.579119999999975, + 21.716959999999986 + ] + }, + { + "lon": [ + -159.36569, + -159.34512000000004, + -159.46372000000002, + -159.80050999999997, + -159.74877, + -159.5962, + -159.36569 + ], + "lat": [ + 22.214939999999984, + 21.982000000000014, + 21.882989999999992, + 22.065330000000017, + 22.138199999999998, + 22.236179999999962, + 22.214939999999984 + ] + }, + { + "lon": [ + -78.19086999999995, + -77.88999999999999, + -77.54, + -77.53465999999995, + -77.77999999999997, + -78.03405000000001, + -78.40848000000003, + -78.19086999999995 + ], + "lat": [ + 25.210299999999975, + 25.17000000000003, + 24.340000000000003, + 23.75975000000004, + 23.71000000000005, + 24.286149999999978, + 24.575640000000007, + 25.210299999999975 + ] + }, + { + "lon": [ + -78.98000000000002, + -78.50999999999996, + -77.85, + -77.81999999999998, + -78.91000000000001, + -78.98000000000002 + ], + "lat": [ + 26.789999999999978, + 26.869999999999976, + 26.840000000000046, + 26.580000000000027, + 26.420000000000044, + 26.789999999999978 + ] + }, + { + "lon": [ + -77.78999999999995, + -77.00000000000001, + -77.17255000000003, + -77.35640999999995, + -77.34000000000003, + -77.78802, + -77.78999999999995 + ], + "lat": [ + 27.04000000000002, + 26.590000000000003, + 25.879179999999977, + 26.007350000000045, + 26.52999999999996, + 26.92516000000002, + 27.04000000000002 + ] + }, + { + "lon": [ + -64.01485999999994, + -63.66450000000003, + -62.9393, + -62.012080000000026, + -62.50391000000002, + -62.87432999999996, + -64.1428, + -64.39261000000005, + -64.01485999999994 + ], + "lat": [ + 47.03601000000005, + 46.55001000000006, + 46.41587000000003, + 46.44314000000003, + 46.03339, + 45.968180000000004, + 46.39265000000002, + 46.72746999999997, + 47.03601000000005 + ] + }, + { + "lon": [ + 46.68201000000002, + 47.675910000000016, + 48.64541, + 49.10116000000008, + 50.034083286342536, + 51.19194542827424, + 52.042022739475556, + 53.04273685080764, + 53.22086551291781, + 53.04087649924517, + 52.16738976421564, + 51.31689904155601, + 51.27850345236317, + 50.30564293803627, + 50.33912926616142, + 50.89129194520007, + 51.342427199108215, + 52.50142622255029, + 52.692112257707294, + 52.44633914572725, + 52.50246000000007, + 52.81468875510362, + 52.916749708880076, + 53.72171349469059, + 54.008310988181364, + 54.736845330632235, + 53.85813927594111, + 52.91525109234365, + 52.69397260926982, + 53.3578080584912, + 53.101027866432986, + 53.880928582581845, + 53.7355111021125, + 53.921597934795585, + 53.825789829326396, + 52.26402469260145, + 50.842354363819766, + 50.14777143738462, + 49.19961225769333, + 48.88327000000001, + 48.85653242370762, + 49.22322838725077, + 49.395259230350376, + 49.56920210144483, + 50.392821079312654, + 50.08482954285313, + 49.618914829309574, + 49.110263706260724, + 48.584370000000064, + 47.492519999999985, + 47.590940000000046, + 46.68201000000002 + ], + "lat": [ + 44.60919999999999, + 45.64149000000002, + 45.80628999999996, + 46.399330000000006, + 46.60898997658228, + 47.048704738953774, + 46.80463694923931, + 46.85300608986445, + 46.23464590105992, + 45.25904653582164, + 45.40839142514518, + 45.245998236667944, + 44.51485423438635, + 44.6098355169388, + 44.284015611338546, + 44.03103363705367, + 43.132974758469416, + 42.79229787858519, + 42.44389537207336, + 42.02715078385555, + 41.78333000000005, + 41.13537059179471, + 41.86811656347736, + 42.12319143327005, + 41.55121084244742, + 40.95101491959345, + 40.63103445084219, + 40.87652334244474, + 40.033629055332014, + 39.97528636327449, + 39.290573635407156, + 38.95209300389533, + 37.90613617609171, + 37.198918361961276, + 36.96503082940825, + 36.700421657857675, + 36.872814235983384, + 37.374566555321366, + 37.582874253889884, + 38.32026000000003, + 38.81548635513184, + 39.0492188583879, + 39.39948171646222, + 40.176100979160694, + 40.256561184239175, + 40.52615713150584, + 40.572924302729945, + 41.2822866888005, + 41.80888000000003, + 42.986579999999975, + 43.66016000000002, + 44.60919999999999 + ] + }, + { + "lon": [ + -64.51911999999999, + -64.17321999999996, + -62.85829000000001, + -61.83558500000001, + -61.80630499999995, + -62.29317999999995, + -63.58925999999997, + -64.51911999999999 + ], + "lat": [ + 49.87304000000002, + 49.95717999999998, + 49.706410000000005, + 49.28855000000006, + 49.10506000000001, + 49.08717000000003, + 49.400690000000026, + 49.87304000000002 + ] + }, + { + "lon": [ + -80.31539500000002, + -79.92939000000001, + -79.52001999999997, + -79.26581999999998, + -79.65752, + -80.09956, + -80.36215, + -80.31539500000002 + ], + "lat": [ + 62.085565, + 62.38559999999998, + 62.36370999999997, + 62.158675000000045, + 61.63307999999998, + 61.71810000000002, + 62.01649000000006, + 62.085565 + ] + }, + { + "lon": [ + -83.99366999999997, + -83.25047999999994, + -81.87699, + -81.89825000000003, + -83.06856999999998, + -83.77462000000004, + -83.99366999999997 + ], + "lat": [ + 62.45280000000005, + 62.914090000000016, + 62.90457999999998, + 62.710800000000035, + 62.159220000000005, + 62.18231, + 62.45280000000005 + ] + }, + { + "lon": [ + -75.21596999999997, + -75.86587999999998, + -76.98686999999997, + -77.23640000000002, + -76.81165999999996, + -75.89520999999999, + -75.11449999999999, + -75.10333000000003, + -75.21596999999997 + ], + "lat": [ + 67.44425000000004, + 67.14885999999998, + 67.09872999999999, + 67.58809, + 68.14856, + 68.28720999999999, + 68.01035999999996, + 67.58202000000003, + 67.44425000000004 + ] + }, + { + "lon": [ + -96.55740120380052, + -95.64768864557942, + -96.26951115534747, + -97.61740120380054, + -98.43180811173642, + -99.79740120380052, + -98.9174115459831, + -98.21825525529017, + -97.15740120380055, + -96.55740120380052 + ], + "lat": [ + 69.68003035832177, + 69.10769485484937, + 68.75704442353285, + 69.06003035832177, + 68.9507018535466, + 69.4000303583218, + 69.71003534964345, + 70.14352310192382, + 69.86003035832178, + 69.68003035832177 + ] + }, + { + "lon": [ + -106.52258806031243, + -105.40244971395374, + -104.77483944376897, + -104.46475501180161, + -102.78537431518025, + -100.98078162311575, + -101.08930213092869, + -102.7311657377061, + -102.09329769571134, + -102.43025387247052, + -104.24000000000004, + -105.96000000000004, + -107.12255143922104, + -108.99999999999996, + -111.53414887520022, + -113.31320000000005, + -113.85495703820634, + -115.22000000000004, + -116.1079461332674, + -117.33999999999997, + -116.6747332426447, + -115.1311323718703, + -113.72139929894799, + -112.41610429568752, + -114.34999142134632, + -116.48683773483144, + -117.90481319870432, + -118.43237789597205, + -116.11311377649665, + -117.6556811186252, + -119.40198279506447, + -118.56268001999595, + -117.86641760951147, + -115.18908749068568, + -114.16716020389764, + -114.666328701621, + -112.44101233605227, + -111.0503995430779, + -109.92033932171921, + -109.00654496950206, + -108.18835201702484, + -107.68597958049939, + -108.39640133343191, + -107.51645504436584, + -106.52258806031243 + ], + "lat": [ + 73.07600495064645, + 72.67259288195999, + 71.69841461860969, + 70.99297964139336, + 70.49776439074031, + 70.02430491808215, + 69.58448680284607, + 69.50402659776759, + 69.11960561794837, + 68.75280630154063, + 68.90999999999997, + 69.18000000000004, + 69.11924388292226, + 68.78, + 68.63005915681794, + 68.53554000000005, + 69.00744192165885, + 69.28, + 69.16820730251885, + 69.96000000000001, + 70.06652456326464, + 70.23731517198931, + 70.19235667589533, + 70.36635122342207, + 70.60000621202985, + 70.52045034451646, + 70.54055247667799, + 70.90921214464822, + 71.30918773058735, + 71.29518341743628, + 71.55857819282792, + 72.3078347846278, + 72.70595001900435, + 73.31459503853804, + 73.12145437284715, + 72.65277497017601, + 72.95539215767721, + 72.45041006132107, + 72.96112824166164, + 72.63334463163432, + 71.65087230090117, + 72.06547231717886, + 73.08954417590695, + 73.23599518502203, + 73.07600495064645 + ] + }, + { + "lon": [ + -79.77583312988281, + -80.8760986328125, + -80.83388519287114, + -80.35305786132808, + -78.06443786621091, + -76.33999999999996, + -76.25140380859372, + -77.31443786621097, + -78.39167022705078, + -79.48625183105473, + -79.77583312988281 + ], + "lat": [ + 72.80290222167974, + 73.33318328857422, + 73.69318389892578, + 73.75971984863287, + 73.65193176269534, + 73.1026849899531, + 72.82638549804685, + 72.85554504394537, + 72.87665557861328, + 72.74220275878906, + 72.80290222167974 + ] + }, + { + "lon": [ + 139.86312, + 140.81170999999998, + 142.06207000000003, + 143.48283, + 143.60385, + 142.08763000000002, + 140.03815500000005, + 139.86312 + ], + "lat": [ + 73.36983000000001, + 73.76506, + 73.85758000000004, + 73.47524999999999, + 73.21243999999999, + 73.20543999999998, + 73.31692000000007, + 73.36983000000001 + ] + }, + { + "lon": [ + 148.22223, + 150.73167000000004, + 149.57592500000007, + 147.97746500000002, + 146.1191900000001, + 146.358485, + 148.22223 + ], + "lat": [ + 75.345845, + 75.08406, + 74.68892, + 74.778355, + 75.17298000000005, + 75.49682000000001, + 75.345845 + ] + }, + { + "lon": [ + 138.83107500000003, + 141.471615, + 145.08628500000006, + 144.30000000000004, + 140.61381000000003, + 138.95544000000004, + 136.97439, + 137.51176, + 138.83107500000003 + ], + "lat": [ + 76.13676000000007, + 76.09288999999995, + 75.56262500000005, + 74.82000000000005, + 74.84768000000005, + 74.61147999999997, + 75.26167000000007, + 75.94917000000007, + 76.13676000000007 + ] + }, + { + "lon": [ + -98.57700069862696, + -98.50000000000001, + -97.73558500000001, + -97.704415, + -98.16, + -99.8087343005199, + -100.88365576862317, + -100.86290768105799, + -102.50208411335622, + -102.56551693399449, + -101.48974280475842, + -99.9834781563149, + -98.57700069862696 + ], + "lat": [ + 76.58860708282197, + 76.71999999999997, + 76.25656000000001, + 75.74343999999999, + 74.99999999999997, + 74.8974441596381, + 75.0573568793653, + 75.6407579617244, + 75.56381175404184, + 76.33658112253448, + 76.30536855743023, + 76.64632965769201, + 76.58860708282197 + ] + }, + { + "lon": [ + 102.83781500000006, + 105.37243000000004, + 105.07547000000002, + 99.43814000000006, + 101.26490000000004, + 102.08635000000007, + 102.83781500000006 + ], + "lat": [ + 79.28129000000001, + 78.71333999999999, + 78.30688999999998, + 77.92100000000008, + 79.23398999999998, + 79.34641000000002, + 79.28129000000001 + ] + }, + { + "lon": [ + 93.77766, + 95.94089499999998, + 97.88384999999997, + 100.18665500000006, + 99.93976000000006, + 97.75794000000005, + 94.97259000000005, + 93.31287999999998, + 92.5454, + 91.18107000000006, + 93.77766 + ], + "lat": [ + 81.02460000000002, + 81.25040000000004, + 80.74697499999999, + 79.780135, + 78.88093999999998, + 78.7562, + 79.044745, + 79.4265, + 80.14378999999997, + 80.34145999999998, + 81.02460000000002 + ] + }, + { + "lon": [ + -96.01643347856468, + -95.32345252153067, + -94.2984246488052, + -94.73542639848141, + -92.40983191605021, + -91.13288143590192, + -87.80999999999996, + -87.02000000000002, + -85.81434302442231, + -87.18756669793036, + -89.03536088739085, + -90.80434851760629, + -92.87667680537506, + -93.95115902380383, + -93.93573360876466, + -93.14523922399587, + -94.97399064815679, + -96.0761455960779, + -96.70972449419241, + -96.01643347856468 + ], + "lat": [ + 80.60231557893178, + 80.9072840441022, + 80.9772797716416, + 81.20646474885606, + 81.25739187287974, + 80.72344513622392, + 80.32000000000002, + 79.66000000000005, + 79.33691478140074, + 79.0393102078317, + 78.28721141225586, + 78.21532949493786, + 78.34333201772486, + 78.7510073920754, + 79.11372427033211, + 79.38011627879672, + 79.37246816681753, + 79.70500600861567, + 80.15776907014097, + 80.60231557893178 + ] + }, + { + "lon": [ + -91.58702000000002, + -90.09999999999995, + -88.93226999999999, + -86.97024000000002, + -85.50000000000001, + -84.26000500000004, + -83.18, + -82.42, + -81.09999999999997, + -79.30663999999996, + -76.24999999999999, + -75.71878000000004, + -72.83152999999999, + -70.66576500000002, + -68.50000000000003, + -65.82734999999997, + -63.67999999999998, + -61.849999999999966, + -61.893880000000024, + -64.334, + -66.75342, + -67.65754999999999, + -65.48031000000003, + -67.83999999999997, + -69.46970000000002, + -71.18, + -73.24280000000002, + -73.88, + -76.90772999999999, + -75.52923999999999, + -76.22046000000002, + -75.39344999999994, + -76.34354000000003, + -77.88850999999998, + -78.36268999999996, + -79.75951000000003, + -79.61965000000004, + -77.91089000000004, + -77.88910999999997, + -80.56125000000003, + -83.17438999999999, + -86.11184000000003, + -87.60000000000001, + -89.49068, + -89.6161, + -87.76739000000002, + -88.25999999999998, + -87.64999999999998, + -84.97634000000002, + -86.34000000000002, + -87.96192000000002, + -87.15198000000004, + -85.37867999999997, + -85.09495000000003, + -86.50733999999997, + -86.93179000000002, + -84.19844, + -83.4086956521739, + -81.84823, + -84.1, + -87.59895, + -89.36663000000003, + -90.19999999999999, + -91.36785999999996, + -91.58702000000002 + ], + "lat": [ + 81.89429000000004, + 82.0850000000001, + 82.11751000000004, + 82.27961000000005, + 82.65227345805701, + 82.60000000000002, + 82.31999999999996, + 82.86000000000004, + 83.02000000000004, + 83.13056, + 83.1720588235294, + 83.06403999999998, + 83.23324000000002, + 83.16978075838281, + 83.10632151676572, + 83.02801000000002, + 82.90000000000003, + 82.62860000000003, + 82.36165000000008, + 81.92775000000009, + 81.72527, + 81.50140999999999, + 81.50657000000007, + 80.90000000000009, + 80.61683000000002, + 79.79999999999998, + 79.63415000000003, + 79.43016220480209, + 79.32309000000001, + 79.19766000000007, + 79.01907, + 78.52580999999998, + 78.18295999999998, + 77.89990999999998, + 77.50859000000003, + 77.20967999999996, + 76.98336, + 77.02204499999999, + 76.77795499999999, + 76.17812000000004, + 76.45402999999999, + 76.29901000000004, + 76.41999999999996, + 76.47238999999996, + 76.95212999999998, + 77.17832999999999, + 77.89999999999998, + 77.9702222222223, + 77.53873000000002, + 78.18000000000004, + 78.37181000000004, + 78.75867000000002, + 78.99690000000001, + 79.34543000000002, + 79.73623999999998, + 80.25144999999998, + 80.20836000000003, + 80.1, + 80.46442000000002, + 80.58000000000004, + 80.51627000000002, + 80.85569000000001, + 81.26000000000005, + 81.55309999999997, + 81.89429000000004 + ] + }, + { + "lon": [ + -46.76379000000003, + -43.40644, + -39.89752999999996, + -38.62213999999997, + -35.08786999999995, + -27.100459999999998, + -20.84539000000001, + -22.69181999999998, + -26.517529999999965, + -31.89999999999995, + -31.39645999999999, + -27.856660000000005, + -24.844480000000033, + -22.903280000000024, + -22.07174999999998, + -23.169610000000034, + -20.62363000000002, + -15.76818000000003, + -12.77018000000001, + -12.208549999999946, + -16.28532999999996, + -16.849999999999937, + -20.046239999999983, + -17.730350000000044, + -18.899999999999977, + -19.70499000000001, + -19.67353, + -18.472849999999994, + -20.035029999999978, + -21.67944, + -19.83406999999997, + -19.59895999999995, + -20.66817999999998, + -19.372810000000015, + -21.594220000000035, + -20.43454, + -20.762339999999966, + -22.17220999999998, + -23.56592999999998, + -22.313109999999938, + -22.299540000000007, + -24.278340000000014, + -24.792959999999965, + -23.44296, + -22.132809999999978, + -21.75356000000002, + -23.536029999999954, + -24.307019999999966, + -25.543410000000023, + -25.20134999999999, + -26.36276000000001, + -23.727419999999967, + -22.349020000000024, + -25.02926999999997, + -27.74736999999996, + -30.67371, + -31.77664999999999, + -32.811049999999994, + -34.201960000000014, + -36.35283999999996, + -37.04378, + -38.375050000000016, + -39.812219999999996, + -40.66898999999995, + -40.68280999999999, + -41.18869999999998, + -42.81937999999997, + -42.41666000000001, + -42.86618999999996, + -43.3784, + -44.78749999999994, + -46.26363999999998, + -48.262940000000015, + -49.23308, + -49.90038999999996, + -51.63324999999995, + -52.14014, + -52.27659000000003, + -53.66166000000001, + -53.30160999999998, + -53.969109999999944, + -52.9804, + -51.47535999999994, + -51.08041000000003, + -50.87121999999994, + -52.01358499999998, + -52.557919999999996, + -53.45628999999997, + -54.68335999999999, + -54.75001000000003, + -54.35883999999996, + -53.431314999999984, + -51.390139999999974, + -53.10937000000001, + -54.004220000000004, + -54.99999999999994, + -55.83467999999996, + -54.718189999999964, + -55.32633999999993, + -56.120030000000014, + -57.32363000000001, + -58.59678999999997, + -58.585159999999945, + -61.268609999999995, + -63.39164999999994, + -66.06427000000002, + -68.50437999999997, + -69.66485, + -71.40257000000003, + -68.77671000000001, + -66.76397000000003, + -71.04293000000001, + -73.29699999999997, + -73.15937999999994, + -69.37345000000002, + -65.71069999999997, + -65.32389999999998, + -68.02297999999999, + -67.15128999999996, + -63.68924999999999, + -62.234440000000006, + -62.65116000000003, + -60.28248999999997, + -57.20743999999996, + -54.13441999999998, + -53.04328000000004, + -50.39060999999998, + -48.00386, + -46.59983999999997, + -44.523000000000025, + -46.9007, + -46.76379000000003 + ], + "lat": [ + 82.62796000000003, + 83.22516000000002, + 83.18017999999998, + 83.54905000000005, + 83.64513, + 83.51966000000004, + 82.72669000000005, + 82.34165000000002, + 82.29765, + 82.19999999999999, + 82.02154000000002, + 82.13177999999999, + 81.78697, + 82.09316999999999, + 81.73449, + 81.15271000000001, + 81.52462000000006, + 81.91244999999998, + 81.71885, + 81.29154000000003, + 80.58003999999997, + 80.35000000000005, + 80.17708000000007, + 80.12912000000003, + 79.40000000000003, + 78.75127999999998, + 77.63859, + 76.98565000000002, + 76.94433999999998, + 76.62795000000003, + 76.09808000000004, + 75.24838, + 75.15585000000004, + 74.29561000000004, + 74.22381999999999, + 73.81713000000002, + 73.46436, + 73.30955, + 73.30663000000007, + 72.62928000000002, + 72.18409, + 72.59787999999998, + 72.33020000000002, + 72.08016000000003, + 71.46898000000002, + 70.66369000000003, + 70.47100000000003, + 70.85649000000006, + 71.43094000000002, + 70.75226000000006, + 70.22646000000003, + 70.18401, + 70.12946000000005, + 69.25880000000004, + 68.47045999999997, + 68.12503000000001, + 68.12078, + 67.73547000000002, + 66.67973999999998, + 65.97889999999998, + 65.93768000000003, + 65.69213000000002, + 65.45848000000001, + 64.83997000000005, + 64.13901999999999, + 63.482459999999975, + 62.682330000000064, + 61.90092999999999, + 61.07404, + 60.09771999999998, + 60.036760000000015, + 60.85328000000007, + 60.85843000000003, + 61.406810000000064, + 62.38336000000001, + 63.62691000000004, + 64.27842000000001, + 65.17670000000001, + 66.09956999999997, + 66.83650000000003, + 67.18898999999999, + 68.35758999999999, + 68.72958, + 69.14781000000002, + 69.92910000000003, + 69.57492500000004, + 69.42616000000007, + 69.28362499999997, + 69.61003000000002, + 70.28932, + 70.82131500000006, + 70.83575500000003, + 70.56978000000001, + 71.20484999999996, + 71.54719000000006, + 71.40653696727259, + 71.65444, + 72.58625000000006, + 72.95861000000005, + 73.64976999999999, + 74.71026000000006, + 75.09861000000004, + 75.51727, + 76.10238000000001, + 76.17520000000002, + 76.13486000000006, + 76.06141000000005, + 76.37974999999997, + 77.00856999999999, + 77.32312000000005, + 77.37595000000005, + 77.63595000000007, + 78.04419000000004, + 78.43271000000004, + 78.91387999999998, + 79.39436000000003, + 79.75814000000003, + 80.11721000000003, + 80.51581999999999, + 81.21395999999999, + 81.32109999999997, + 81.77042000000003, + 82.03362999999999, + 82.19074000000003, + 82.19961999999998, + 81.88833000000002, + 82.43882999999997, + 82.06481000000005, + 81.98594499999999, + 81.66070000000002, + 82.19979000000004, + 82.62796000000003 + ] + }, + { + "lon": [ + -106.6, + -105.26, + -104.5, + -105.38000000000001, + -106.94, + -106.6 + ], + "lat": [ + 73.60000000000001, + 73.64, + 73.42, + 72.76, + 73.46000000000001, + 73.60000000000001 + ] + }] diff --git a/pydarn/utils/plotting.py b/pydarn/utils/plotting.py index 25aff0ce6..cb76aeab3 100644 --- a/pydarn/utils/plotting.py +++ b/pydarn/utils/plotting.py @@ -32,6 +32,34 @@ class MapParams(enum.Enum): POWER = "vector.pwr.median" SPECTRAL_WIDTH = "vector.wdt.median" +class TimeSeriesParams(enum.Enum): + """ + Enum class to hold the parameters that can be plotted + Members + ------------ + NUM_VECTORS: + the number of aviliable vectors in the map + IMF_BY: + The magnitude of the IMF By component in nT + IMF_BZ: + The magnitude of the IMF Bz component in nT + KP: + The Kp index + HMB_MAX: + The farthest equatorward extent of the HMB + + """ + NUM_VECTORS = 'num_vectors' + IMF_BY = 'IMF.By' + IMF_BZ = 'IMF.Bz' + IMF_BX = 'IMF.Bx' + IMF_Vx = 'IMF.Vx' + IMF_TILT = 'IMF.tilt' + KP = 'IMF.Kp' + LATMINN = 'latmin' + ERR = 'chi.sqr.dat' + CPP = 'pot.drop' + def find_record(dmap_data: List[dict], start_time: datetime, time_delta:int = 1): """ @@ -64,7 +92,7 @@ def find_record(dmap_data: List[dict], start_time: datetime, time_delta:int = 1) if time_diff.seconds/60 <= time_delta: return record_num record_num += 1 - raise plot_exceptions.NoDataFoundError(parameter, start_time=start_time) + raise plot_exceptions.NoDataFoundError('N/A', start_time=start_time) def check_data_type(dmap_data: List[dict], parameter: str, expected_type: str, index: int): diff --git a/pydarn/utils/range_estimations.py b/pydarn/utils/range_estimations.py index d0a2aabb2..564c4ec08 100644 --- a/pydarn/utils/range_estimations.py +++ b/pydarn/utils/range_estimations.py @@ -12,12 +12,73 @@ # # Modifications: # 2022-08-04 CJM added HALF_SLANT option and gate2halfslant method -# +# 2023-09-14 CJM moved GSMR to GSMR_BRISTOW and used new GSMR alg +# 2023-12-15 RAR added TIME_OF_FLIGHT option and gate2timeofflight method import enum import numpy as np +import warnings + +from pydarn import Re, C, standard_warning_format + +warnings.formatwarning = standard_warning_format + -from pydarn import Re, C +def gate2timeofflight(rxrise: int = 0, range_gate: int = 0, frang: int = 180, + rsep: int = 45, nrang: int = None, center: bool = True, + **kwargs): + """ + Calculate the time of flight for each range gate. + + Parameters + ---------- + frang: int + range from the edge of first the gate to the radar [km] + This should be given in fitacf record of the control program + rsep: int + Radar separation of the gates. Determined by control program. + rxrise: int + Use hardware value for this, avoid data file values + gate: int + range gate to determine the slant range [km], if nrang + is None + default: 0 + nrang: int + max number of range gates in the list of records. If + not None, will calculate all slant ranges + default: None + center: boolean + Calculate the slant range in the center of range gate + or edge + + Returns + ------- + tof: np.array + returns an array of times of flight, in ms + """ + # lag to the first range gate in microseconds + # 2 - two times for there and back + distance_factor = 2.0 + # C - speed of light m/s to km/ms + speed_of_light = C * 0.001 * 1e-3 + lag_first = frang * distance_factor / speed_of_light + # sample separation in microseconds + sample_sep = rsep * distance_factor / speed_of_light + # Range offset + # If center is true, calculate at the center + if center: + # 0.5 offset to the centre of the range gate instead of edge + range_offset = -0.5 * sample_sep + else: + range_offset = 0.0 + # Now calculate time of flight in ms + if nrang is None: + tof = lag_first - rxrise + range_gate * sample_sep + range_offset + else: + tof = np.zeros(nrang + 1) + for gate in range(nrang + 1): + tof[gate] = lag_first - rxrise + gate * sample_sep + range_offset + return tof def gate2halfslant(**kwargs): @@ -38,15 +99,15 @@ def gate2halfslant(**kwargs): return half_slant -def gate2groundscatter(reflection_height: float = 250, **kwargs): +def gate2gs_bristow(virtual_height: float = 250, **kwargs): """ Calculate the ground scatter mapped range (km) for each slanted range for SuperDARN data. This function is based on the Ground Scatter equation from Bristow paper at https://doi.org/10.1029/93JA01470 on page 325 Parameters ---------- - reflection_height: float - reflection height + virtual_height: float + virtual height default: 250 Returns @@ -55,15 +116,53 @@ def gate2groundscatter(reflection_height: float = 250, **kwargs): returns an array of ground scatter mapped ranges for the radar """ slant_ranges = gate2slant(**kwargs) - ground_scatter_mapped_ranges =\ - Re*np.arcsin(np.sqrt((slant_ranges**2/4)- - (reflection_height**2))/Re) + ground_scatter_mapped_ranges = Re * np.arcsin(np.sqrt((slant_ranges**2 / 4) + - (virtual_height**2)) / Re) + # Check to see if there is an issue with the sqrt and + # give user a warning if so, these values will be dealt with in + # the individual plotting algs as we need to return the full array + # of values for the complete beam*range gate array + if any(np.isfinite(ground_scatter_mapped_ranges)): + warnings.warn("Warning: Be aware that the range estimation" + " you have chosen has calculated some infinite" + " values. These values will not be plotted." + " You may use RangeEstimation.GSMR to avoid this" + " issue.") + return ground_scatter_mapped_ranges + + +def gate2groundscatter(virtual_height: float = 250, hop: float = 0.5, + **kwargs): + """ + Calculate the ground scatter mapped range (km) for each slanted range + for SuperDARN data. This function is based on the Ground Scatter equation + discussed in the issue github.com/SuperDARN/pydarn/issues/257 + Parameters + ---------- + virtual_height: float + virtual height + default: 250 + hop: float + hop number of returning data + default: 0.5 + + Returns + ------- + ground_scatter_mapped_ranges : np.array + returns an array of ground scatter mapped ranges for the radar + """ + slant_ranges = gate2slant(**kwargs) + + num = - Re**2 - (Re + virtual_height)**2\ + + (slant_ranges/2 * (0.5 / hop))**2 + den = 2 * Re * (Re + virtual_height) + ground_scatter_mapped_ranges = (hop/0.5) * Re * np.arccos(- num / den) return ground_scatter_mapped_ranges def gate2slant(rxrise: int = 0, range_gate: int = 0, frang: int = 180, - rsep: int = 45, nrang: int = None, center: bool = True, + rsep: int = 45, nrang: int = None, center: bool = False, **kwargs): """ Calculate the slant range (km) for each range gate for SuperDARN data @@ -74,7 +173,7 @@ def gate2slant(rxrise: int = 0, range_gate: int = 0, frang: int = 180, range from the edge of first the gate to the radar [km] This should be given in fitacf record of the control program rsep: int - Radar seperation of the gates. Determined by control program. + Radar separation of the gates. Determined by control program. rxrise: int Use hardware value for this, avoid data file values gate: int @@ -87,7 +186,9 @@ def gate2slant(rxrise: int = 0, range_gate: int = 0, frang: int = 180, default: None center: boolean Calculate the slant range in the center of range gate - or edge + or near-left corner see also: gate2geographic_location in + coordinates module + default: False (return corner values) Returns ------- @@ -103,13 +204,15 @@ def gate2slant(rxrise: int = 0, range_gate: int = 0, frang: int = 180, lag_first = frang * distance_factor / speed_of_light # sample separation in microseconds sample_sep = rsep * distance_factor / speed_of_light - # Range offset - # If center is true, calculate at the center + + # Across fov direction is corrected in coordinates module already + # 0.5 off set to the centre of the range gate instead of edge + # This assumes that frang is to the center of the range gate if center: - # 0.5 off set to the centre of the range gate instead of edge - range_offset = -0.5 * rsep - else: range_offset = 0.0 + else: + range_offset = -0.5 * rsep + # Now calculate slant range in km if nrang is None: slant_ranges = (lag_first - rxrise + @@ -138,7 +241,9 @@ class RangeEstimation(enum.Enum): RANGE_GATE = enum.auto() SLANT_RANGE = (gate2slant,) HALF_SLANT = (gate2halfslant,) + TIME_OF_FLIGHT = (gate2timeofflight,) GSMR = (gate2groundscatter,) + GSMR_BRISTOW = (gate2gs_bristow,) # Need this to make the functions callable def __call__(self, *args, **kwargs): diff --git a/pydarn/utils/recalculate_elevation.py b/pydarn/utils/recalculate_elevation.py new file mode 100644 index 000000000..09ec8f9c8 --- /dev/null +++ b/pydarn/utils/recalculate_elevation.py @@ -0,0 +1,142 @@ +# (C) Copyright SuperDARN Canada, University of Saskatchewan 2022 +# Author: Carley Martin 20221101 +# +# Disclaimer: +# pyDARN is under the LGPL v3 license found in the root directory LICENSE.md +# Everyone is permitted to copy and distribute verbatim copies of this license +# document, but changing it is not allowed. +# +# This version of the GNU Lesser General Public License incorporates the terms +# and conditions of version 3 of the GNU General Public License, +# supplemented by the additional permissions listed below. +# +# About: +# Modified from the RST elevation_v2.c code (Simon Shepherd's code). +# Method: https://agupubs.onlinelibrary.wiley.com/doi/full/10.1002/2017RS006348 +# THIS CODE IS DESIGNED TO AMEND ELEVATION +# AFTER FITACF FITTING (AT THE VISUALIZATION STEP TO QUICKLY CHECK THE EFFECTS +# OF DIFFERENT TDIFF VALUES) NOT TO REPLACE THE FITTING ITSELF +# +# Modifications: +# 20221221 - Bharat Kunduri: Updated to RST elevation code + +import numpy as np + +from typing import List +from copy import deepcopy + +from pydarn import (SuperDARNRadars, C) + + +def recalculate_elevation(dmap_data: List[dict], tdiff: float, + overwrite: bool = False, + interferometer_offset: list = None): + """ + Recalculates elevation values for a given tdiff Value + + Parameters + ----------- + dmap_data: list of dictionaries + fitacf data + tdiff: float + propagation time from interferometer array to phasing matrix + input minus propagation time from main array antenna, microseconds + overwrite: bool + If true then return a new dmap_data with new elevation to plot with + if false then return dictionary of new elevations for further use + interferometer_offset: list + select position of interferometer array wrt the main array + needs to be list of [X, Y, Z] e.g. [0.0, 100.0, 1.0] + + Raises + ------ + + Returns + ------- + elv_amended: dictionary of lists + amended elevation values for each record given + """ + if not overwrite: + # Make phi1 output into dictionary + elv_amended = {} + else: + dmap_amended = deepcopy(dmap_data) + + # Hardware config for radar + # Doesn't have to be in the loop, since we're accessing only the first rec + radar_hdw = SuperDARNRadars.radars[dmap_data[0]['stid']].hardware_info + if interferometer_offset is not None: + int_pos = interferometer_offset + else: + int_pos = radar_hdw.interferometer_offset + + # If inteferometer is infront (+1) or behind (-1) main array + if int_pos[1] < 0: + sgn = -1.0 + else: + sgn = 1.0 + + boff = (radar_hdw.beams / 2.0) - 0.5 + + # For each record in data, recalculate the elevation + for ind in range(0, len(dmap_data)): + # If there is no elevation data, append empty list and skip + if 'phi0' not in dmap_data[ind]: + print("No elevation data. 'phi0' parameter missing" + " from the record") + if not overwrite: + elv_amended[ind] = [] + continue + + # Beam direction off boresight in RADIANS + phi0 = np.radians(radar_hdw.beam_separation + * (dmap_data[ind]['bmnum'] - boff)) + # Cos and Sin of phi in shape of phi0 + cp0 = np.cos(phi0) + sp0 = np.sin(phi0) + + # Phase delay [radians] due to electrical path difference. + psi_ele = (-2.0 * np.pi * (dmap_data[ind]['tfreq']) + * 1000.0 * tdiff * 1.0e-6) + # Elevation angle (a0) where psi (phase difference) is maximum + a0 = np.arcsin(sgn * int_pos[2] * cp0 + / np.sqrt(int_pos[1]**2 + int_pos[2]**2)) + if a0 < 0: + a0 = 0 + ca0 = np.cos(a0) + sa0 = np.sin(a0) + + # maximum phase = psi_ele + psi_geo(a0) + psi_max = psi_ele + 2.0 * np.pi * (dmap_data[ind]['tfreq']) *\ + (1e3 / C) * (int_pos[0] * sp0 + int_pos[1] + * np.sqrt(ca0*ca0 - sp0*sp0) + int_pos[2] * sa0) + + # compute the number of 2pi factors necessary to map to correct region + dpsi = (psi_max - dmap_data[ind]['phi0']) + if int_pos[1] > 0: + n2pi = np.floor(dpsi / (2.0 * np.pi)) + else: + n2pi = np.ceil(dpsi / (2.0 * np.pi)) + d2pi = n2pi * 2.0 * np.pi + # map observed phase to correct extended phase + psi_obs = dmap_data[ind]['phi0'] + d2pi + # solve for the elevation angle + E = (psi_obs / (2.0*np.pi*dmap_data[ind]['tfreq']*1.0e3) + + tdiff*1e-6) * C - int_pos[0] * sp0 + + alpha = np.arcsin((E*int_pos[2] + + np.sqrt(E*E * int_pos[2]**2 + - (int_pos[1]**2 + int_pos[2]**2) + * (E*E - int_pos[1]*int_pos[1]*cp0*cp0))) + / (int_pos[1]*int_pos[1] + int_pos[2]*int_pos[2])) + + # Convert theta back to degrees + if overwrite: + dmap_amended[ind].update({'elv': np.degrees(alpha)}) + else: + elv_amended[ind] = np.degrees(alpha) + + if overwrite: + return dmap_amended + else: + return elv_amended diff --git a/pydarn/utils/superdarn_radars.py b/pydarn/utils/superdarn_radars.py index c912a37ea..7084b7c7d 100644 --- a/pydarn/utils/superdarn_radars.py +++ b/pydarn/utils/superdarn_radars.py @@ -444,6 +444,8 @@ class _Radar(NamedTuple): institution: str hemisphere: Hemisphere range_gate_45: int + geo_label: list + mag_label: list hardware_info: _HdwInfo @@ -468,91 +470,120 @@ class SuperDARNRadars(): # http://vt.superdarn.org/tiki-index.php?page=Radar+Overview radars = {209: _Radar('Adak Island East', 'University of Alaska Fairbanks', Hemisphere.North, - 75, read_hdw_file('ade')), + 75, [47, -172], [42, -106], read_hdw_file('ade')), 208: _Radar('Adak Island West', 'University of Alaska Fairbanks', - Hemisphere.North, 75, read_hdw_file('adw')), + Hemisphere.North, 75, [47, 178], [42, -116], + read_hdw_file('adw')), 33: _Radar('Blackstone', 'Virginia Tech', Hemisphere.North, - 100, read_hdw_file('bks')), + 100, [32, -78], [44, -5], read_hdw_file('bks')), 207: _Radar('Christmas Valley East', 'Dartmouth College', - Hemisphere.North, 100, read_hdw_file('cve')), + Hemisphere.North, 100, [38, -115], [48, -53], + read_hdw_file('cve')), 206: _Radar('Christmas Valley West', 'Dartmouth College', - Hemisphere.North, 100, read_hdw_file('cvw')), + Hemisphere.North, 100, [38, -125], [48, -63], + read_hdw_file('cvw')), 66: _Radar('Clyde River', 'University of Saskatchewan', - Hemisphere.North, 100, read_hdw_file('cly')), + Hemisphere.North, 100, [65, -68], [72, 17], + read_hdw_file('cly')), 205: _Radar('Fort Hays East', 'Virginia Tech', Hemisphere.North, - 100, read_hdw_file('fhe')), + 100, [34, -94], [45, -25], read_hdw_file('fhe')), 204: _Radar('Fort Hays West', 'Virginia Tech', Hemisphere.North, - 100, read_hdw_file('fhw')), + 100, [34, -104], [45, -35], read_hdw_file('fhw')), 1: _Radar('Goose Bay', 'Virginia Tech', Hemisphere.North, - 100, read_hdw_file('gbr')), + 100, [48, -60], [54, 23], read_hdw_file('gbr')), 10: _Radar('Hankasalmi', 'University of Leicester', - Hemisphere.North, 70, read_hdw_file('han')), + Hemisphere.North, 70, [57, 27], [54, 102], + read_hdw_file('han')), 40: _Radar('Hokkaido East', 'Nagoya University', - Hemisphere.North, 110, read_hdw_file('hok')), + Hemisphere.North, 110, [39, 149], [35, -139], + read_hdw_file('hok')), 41: _Radar('Hokkaido West', 'Nagoya University', - Hemisphere.North, 110, read_hdw_file('hkw')), + Hemisphere.North, 110, [39, 139], [35, -149], + read_hdw_file('hkw')), 211: _Radar('Iceland East', 'Dartmouth College', - Hemisphere.North, 100, read_hdw_file('ice')), + Hemisphere.North, 100, [61, -16], [60, 70], + read_hdw_file('ice')), 210: _Radar('Iceland West', 'Dartmouth College', - Hemisphere.North, 100, read_hdw_file('icw')), + Hemisphere.North, 100, [61, -26], [60, 60], + read_hdw_file('icw')), 64: _Radar('Inuvik', 'University of Saskatchewan', - Hemisphere.North, 75, read_hdw_file('inv')), + Hemisphere.North, 75, [63, -134], [66, -80], + read_hdw_file('inv')), 50: _Radar('Jiamusi East radar', 'National Space Science Center,' 'Chinese Academy of Sciences', - Hemisphere.North, 100, read_hdw_file('jme')), + Hemisphere.North, 100, [42, 130], [37, -155], + read_hdw_file('jme')), 3: _Radar('Kapuskasing', 'Virginia Tech', Hemisphere.North, - 75, read_hdw_file('kap')), + 75, [44, -82], [54, -7], read_hdw_file('kap')), 16: _Radar('King Salmon', 'National Institute of Information and' ' Communications Technology', Hemisphere.North, - 75, read_hdw_file('ksr')), + 75, [54, -162], [52, -99], read_hdw_file('ksr')), 7: _Radar('Kodiak', 'University of Alaska Fairbanks', - Hemisphere.North, 110, read_hdw_file('kod')), + Hemisphere.North, 110, [53, -152], [52, -92], + read_hdw_file('kod')), 90: _Radar('Longyearbyen', 'University of Centre in Svalbard', - Hemisphere.North, 70, read_hdw_file('lyr')), + Hemisphere.North, 70, [73, 16], [71, 108], + read_hdw_file('lyr')), 9: _Radar('Pykkvibaer', 'University of Leicester', - Hemisphere.North, 70, read_hdw_file('pyk')), + Hemisphere.North, 70, [58, -19], [56, 75], + read_hdw_file('pyk')), 6: _Radar('Prince George', 'University of Saskatchewan', - Hemisphere.North, 75, read_hdw_file('pgr')), + Hemisphere.North, 75, [49, -123], [55, -61], + read_hdw_file('pgr')), 65: _Radar('Rankin Inlet', 'University of Saskatchewan', - Hemisphere.North, 75, read_hdw_file('rkn')), + Hemisphere.North, 75, [58, -92], [66, -21], + read_hdw_file('rkn')), 5: _Radar('Saskatoon', 'University of Saskatchewan', - Hemisphere.North, 75, read_hdw_file('sas')), + Hemisphere.North, 75, [47, -107], [56, -41], + read_hdw_file('sas')), 2: _Radar('Schefferville', 'CNRS/LPCE', Hemisphere.North, - 75, read_hdw_file('sch')), + 75, [50, -67], [60, 14], read_hdw_file('sch')), 8: _Radar('Stokkseyri', 'Lancaster University', - Hemisphere.North, 75, read_hdw_file('sto')), + Hemisphere.North, 75, [58, -29], [56, 65], + read_hdw_file('sto')), 32: _Radar('Wallops Island', 'JHU Applied Physics Laboratory', - Hemisphere.North, 100, read_hdw_file('wal')), + Hemisphere.North, 100, [33, -75], [44, 5], + read_hdw_file('wal')), 24: _Radar('Buckland Park', 'La Trobe University', - Hemisphere.South, 75, read_hdw_file('bpk')), + Hemisphere.South, 75, [-30, 138], [-40, -146], + read_hdw_file('bpk')), 96: _Radar('Dome C East', 'Institute for Space Astrophysics and Planetology', - Hemisphere.South, 75, read_hdw_file('dce')), + Hemisphere.South, 75, [-80, 130], [-83, 0], + read_hdw_file('dce')), 97: _Radar('Dome C North', 'Institute for Space Astrophysics and Planetology', - Hemisphere.South, 75, read_hdw_file('dcn')), + Hemisphere.South, 75, [-75, 112], [-85, 90], + read_hdw_file('dcn')), 21: _Radar('Falkland Islands', 'British Antarctic Survey', - Hemisphere.South, 110, read_hdw_file('fir')), + Hemisphere.South, 110, [-47, -59], [-35, 10], + read_hdw_file('fir')), 4: _Radar('Halley', 'British Antarctic Survey', - Hemisphere.South, 100, read_hdw_file('hal')), + Hemisphere.South, 100, [-71, -27], [-58, 30], + read_hdw_file('hal')), 15: _Radar('Kerguelen', 'IRAP/CNRS/IPEV', Hemisphere.South, - 75, read_hdw_file('ker')), + 75, [-44, 70], [-53, 124], read_hdw_file('ker')), 20: _Radar('McMurdo', 'University of Alaska, Fairbanks', - Hemisphere.South, 75, read_hdw_file('mcm')), + Hemisphere.South, 75, [-78, 187], [-75, -36], + read_hdw_file('mcm')), 11: _Radar('SANAE', 'South African National Space Agency', - Hemisphere.South, 110, read_hdw_file('san')), + Hemisphere.South, 110, [-67, -3], [-60, 45], + read_hdw_file('san')), 22: _Radar('South Pole Station', 'University of Alaska, Fairbanks', Hemisphere.South, - 75, read_hdw_file('sps')), + 75, [-87, 12], [-74, 25], read_hdw_file('sps')), 13: _Radar('Syowa East', 'National Institute of Polar Research', - Hemisphere.South, 75, read_hdw_file('sye')), + Hemisphere.South, 75, [-64, 45], [-62, 82], + read_hdw_file('sye')), 12: _Radar('Syowa South', 'National Institute of Polar Research', - Hemisphere.South, 80, read_hdw_file('sys')), + Hemisphere.South, 80, [-66, 30], [-62, 68], + read_hdw_file('sys')), 14: _Radar('Tiger', 'La Trobe University', Hemisphere.South, - 75, read_hdw_file('tig')), + 75, [-38, 147], [-49, -133], read_hdw_file('tig')), 18: _Radar('Unwin', 'La Trobe University', Hemisphere.South, - 75, read_hdw_file('unw')), + 75, [-42, 168], [-49, -105], read_hdw_file('unw')), 19: _Radar('Zhongshan', 'Polar Research Institute of China', - Hemisphere.South, 70, read_hdw_file('zho'))} + Hemisphere.South, 70, [-67, 64], [-70, 99], + read_hdw_file('zho'))} diff --git a/pydarn/utils/terminator.py b/pydarn/utils/terminator.py new file mode 100644 index 000000000..7ec0928d4 --- /dev/null +++ b/pydarn/utils/terminator.py @@ -0,0 +1,304 @@ +# Copyright 2023 SuperDARN Canada, University of Saskatchewan +# Author: Carley Martin +# +# Disclaimer: +# pyDARN is under the LGPL v3 license found in the root directory LICENSE.md +# Everyone is permitted to copy and distribute verbatim copies of this license +# document, but changing it is not allowed. +# +# This version of the GNU Lesser General Public License incorporates the terms +# and conditions of version 3 of the GNU General Public License, +# supplemented by the additional permissions listed below. +# +# This code to calculate the solar terminator at given height in the ionosphere +# is converted from Carley Martin's JavaScript terminator.js code +# +# Modification: +# + +import aacgmv2 + +import numpy as np +import datetime as dt +import matplotlib.pyplot as plt + +from pydarn import Re + +""" +terminator.py is a group of methods used to calculated the part of a map where +the ionosphere is in the earth's shadow +""" + + +def antipode(psn): + """ + antipode calculates the opposite side of the Earth to the sub-solar + point + + Parameters + ---------- + psn : list + list containing the longitude/latitude of the sub solar point + + Returns + ------- + antipode: lise + list containing the logitude/latitude of the opposite side of the + sub-solar position + """ + antipode = [psn[0] + 180, -psn[1]] + return antipode + + +def eccentricity_earths_orbit(centuries): + """ + eccentricity of Earths orbit calculates the ellipse created by Earth in + it's orbit + + Parameters + ---------- + centuries: float + decimal value of centuries passed since Julian base + + Returns + ------- + eccentricity: float + eccentricity of Earth's orbit, likely small number as all dates in + SuperDARN operations are around 2000 + """ + # Eccentricity of Earth's orbit (unitless) = 0.016708634 + eccentricity = 0.016708634 - centuries * (0.000042037 + 0.0000001267 + * centuries) + return eccentricity + + +def mean_obliquity_ecliptic(centuries): + """ + mean obliquity ecliptic calculates the effect caused by the tilt of the + Earth on its axis + + Parameters + ---------- + centuries: float + decimal value of centuries passed since Julian base + + Returns + ------- + oblic: float (radians) + obliquity of Earths axis + """ + obliq = np.radians(23 + (26 + (21.448 - centuries * (46.8150 + centuries * + (0.00059 - centuries * 0.001813))) / 60) / 60) + return obliq + + +def obliquity_correction(centuries): + """ + obliquity correction corrects the obliquity of Earths axis, includes small + perturbations in obliquity over time + + Parameters + ---------- + centuries: float + decimal value of centuries passed since Julian base + + Returns + ------- + oblic: float (radians) + obliquity of Earths axis + """ + mean_ob = mean_obliquity_ecliptic(centuries) + obliq = mean_ob + np.radians(0.00256) * np.cos(np.radians(125.04 - 1934.136 + * centuries)) + return obliq + + +def solar_geometric_mean_anomaly(centuries): + """ + solar geometric mean anomaly calculates the apparent motion of the sun and + along the plane of the ecliptic + + Parameters + ---------- + centuries: float + decimal value of centuries passed since Julian base + + Returns + ------- + anomaly: float (radians) + angular distance from perihelion which Earth would have moved around + Sun if using constant angular velocity + """ + anomaly = np.radians(357.52911 + centuries + * (35999.05029 - 0.0001537 * centuries)) + return anomaly + + +def solar_geometric_mean_longitude(centuries): + """ + solar geometric mean longitude calculates where the mean Sun was at given + date time in reference to Julian base date + + Parameters + ---------- + centuries: float + decimal value of centuries passed since Julian base + + Returns + ------- + mean_long: float (radians) + solar meal longitude + """ + # Mean longitude of sun at base julian date = 280.46646 degrees + # Corrections from J.Meeus Astronomical Algorithms book + l = (280.46646 + centuries * (36000.76983 + centuries * 0.0003032)) % 360 + # Give value between 0 and 360 + if l < 0: + l = l + 360 + mean_long = np.radians(l) + return mean_long + + +def solar_equation_center(centuries): + """ + solar equation center calculates the angular difference between the + actual position of a body and it's position if it's motion was uniform in + a circular orbit - approx from Keppler's equation allowed as the + eccentricity is very small + + Parameters + ---------- + centuries: float + decimal value of centuries passed since Julian base + + Returns + ------- + solar_center: float (radians) + solar center angle + """ + m = solar_geometric_mean_anomaly(centuries) + solar_center = np.radians(np.sin(m) + * (1.914602 - centuries * (0.004817 + 0.000014 * centuries)) + + np.sin(m + m) * (0.019993 - 0.000101 * centuries) + + np.sin(m + m + m) * 0.000289) + return solar_center + + +def solar_true_longitude(centuries): + """ + solar true longitude calculates the true longitude of the Sun + + Parameters + ---------- + centuries: float + decimal value of centuries passed since Julian base + + Returns + ------- + true_long: float (radians) + the true longitude + """ + true_long = solar_geometric_mean_longitude(centuries)\ + + solar_equation_center(centuries) + return true_long + + +def solar_apparent_longitude(centuries): + """ + solar apparent longitude calculates the true longitude including + extra perturbations from the Moon etc. + + Parameters + ---------- + centuries: float + decimal value of centuries passed since Julian base + + Returns + ------- + apparent: float (radians) + the true apparent longitude + """ + apparent = solar_true_longitude(centuries) - np.radians(0.00569 + 0.00478 + * np.sin(np.radians(125.04 - 1934.136 * centuries))) + return apparent + + +def solar_declination(centuries): + dec = np.arcsin( np.sin(obliquity_correction(centuries))\ + * np.sin(solar_apparent_longitude(centuries))) + return dec + + +def equation_of_time(centuries): + # Equation from NOAA subsolar calculator + # http://www.esrl.noaa.gov/gmd/grad/solcalc/ + e = eccentricity_earths_orbit(centuries) + m = solar_geometric_mean_anomaly(centuries) + l = solar_geometric_mean_longitude(centuries) + y = np.tan(obliquity_correction(centuries) /2) + time_eq = y * np.sin(2 * l) - 2 * e * np.sin(m) + 4 * e * y * np.sin(m)\ + * np.cos(2 * l) - 0.5 * y * y * np.sin(4 * l)\ + - 1.25 * e * e * np.sin(2 * m); + return time_eq + + +def solar_position(date): + """ + solar position calculates the latitude and longitude of the sub-solar + position on Earth for a given date time + + Parameters + ---------- + date : datetime object + date time of interest + + Returns + ------- + psn: list + list containing the logitude/latitude of the + sub-solar position + """ + # Convert Greg date to Julian date (given in partial centuries) + # 86400 seconds = 1 days + # 36525 days = 100 years (a century) + centuries = (date - dt.datetime(2000,1,1,12,0)).total_seconds() / 86400 / 36525 + # Given days date but at midnight + datefloor = date.replace(hour=0, minute=0, second=0) + # Calculate the longitude at given time + longitude = (datefloor - date).total_seconds() / 86400 * 360 - 180 + # Calculate long lat of sub-solar position in degrees + long = longitude - np.degrees(equation_of_time(centuries)) + lat = np.degrees(solar_declination(centuries)) + return [long, lat] + + +def antisolar(date): + """ + antisolar calculates the latitude and longitude of the anti-sub-solar + position on Earth for a given date time + + Parameters + ---------- + date : datetime object + date time of interest + + Returns + ------- + antisolar_point: list + list containing the logitude/latitude of the + anti-sub-solar position + """ + antisolar_point = antipode(solar_position(date)) + return antisolar_point + + +def terminator(date, height): + # Get the anti-sub-solar point + antisolar_point = antisolar(date) + # Calculate the size of the great circle (radius from anti-sub-solar point) + arc_angle = 90 - np.degrees(np.arccos(Re / (Re + height))) + # Calculate arc in km + arc_length = Re * np.radians(arc_angle) + + return antisolar_point, arc_length, arc_angle + diff --git a/pydarn/version.py b/pydarn/version.py index ede714118..0a44759ef 100644 --- a/pydarn/version.py +++ b/pydarn/version.py @@ -17,4 +17,4 @@ This file contains the version number of pydarn """ -__version__='3.1.1' +__version__='4.0' diff --git a/setup.cfg b/setup.cfg index b26c5c613..6d497faba 100644 --- a/setup.cfg +++ b/setup.cfg @@ -10,11 +10,18 @@ url = https://pydarn.readthedocs.io/en/latest/ classifiers = Development Status :: 5 - Production/Stable License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3) - Programming Language :: Python :: 3.6 + Programming Language :: Python + Programming Language :: Python :: 3 Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + Programming Language :: Python :: 3.11 + Topic :: Scientific/Engineering :: Physics + Topic :: Software Development :: Libraries [options] -python_requires = >=3.6 +python_requires = >=3.7 packages = find_namespace: include_package_data = True install_requires = diff --git a/test/test_Fan.py b/test/test_Fan.py index a8602ad97..f07b63cbc 100644 --- a/test/test_Fan.py +++ b/test/test_Fan.py @@ -51,12 +51,13 @@ def test_fov_series(self): @pytest.mark.parametrize('line_alpha', [0.8, 1]) @pytest.mark.parametrize('date', [dt.datetime(2020, 4, 4, 6, 2)]) @pytest.mark.parametrize('grid', [True, False]) +@pytest.mark.parametrize('beam', [None, 7]) class TestFov: def test_fov_plot(self, stid, ranges, boundary, fov_color, alpha, radar_location, radar_label, line_color, date, grid, line_alpha, rsep, - frang): + frang, beam): """ this test will give bare minimum input needed for """ with warnings.catch_warnings(record=True): pydarn.Fan.plot_fov(stid=stid, ranges=ranges, @@ -65,7 +66,7 @@ def test_fov_plot(self, stid, ranges, boundary, fov_color, radar_location=radar_location, radar_label=radar_label, grid=grid, line_color=line_color, date=date, - line_alpha=line_alpha) + line_alpha=line_alpha, beam=beam) plt.close('all') @@ -78,10 +79,14 @@ def test_fov_plot(self, stid, ranges, boundary, fov_color, @pytest.mark.parametrize('zmax', [100]) @pytest.mark.parametrize('title', [False]) @pytest.mark.parametrize('channel', [1,2]) +@pytest.mark.parametrize('ball_and_stick', [True, False]) +@pytest.mark.parametrize('len_factor', [300, 100]) +@pytest.mark.parametrize('beam', [None, 7]) class TestFan: def test_fan_plot(self, parameter, cmap, groundscatter, colorbar, - colorbar_label, zmin, zmax, title, channel): + colorbar_label, zmin, zmax, title, channel, beam, + ball_and_stick, len_factor): """ """ @@ -89,4 +94,6 @@ def test_fan_plot(self, parameter, cmap, groundscatter, colorbar, pydarn.Fan.plot_fan(data, parameter=parameter, cmap=cmap, groundscatter=groundscatter, colorbar=colorbar, colorbar_label=colorbar_label, zmin=zmin, - zmax=zmax, title=title, channel=channel) + zmax=zmax, title=title, channel=channel, + beam=beam, ball_and_stick=ball_and_stick, + len_factor=len_factor) diff --git a/test/test_RTP.py b/test/test_RTP.py index b67002dc2..180b57775 100644 --- a/test/test_RTP.py +++ b/test/test_RTP.py @@ -32,6 +32,11 @@ def test_range_time_defaults(self): with warnings.catch_warnings(record=True): pydarn.RTP.plot_range_time(data) + def test_coord_time_defaults(self): + """ """ + with warnings.catch_warnings(record=True): + pydarn.RTP.plot_coord_time(data) + def test_normal_time_series(self): """ """ with warnings.catch_warnings(record=True): @@ -163,9 +168,9 @@ def test_parameters_time_series_channel1(self, parameters_scalar, gate, 'nave': (0, 30), 'elv': (0, 20), 'tfreq': (0, 15)}]) -@pytest.mark.parametrize('cmaps', [{'elv': plt.get_cmap('rainbow'), - 'p_l': plt.get_cmap('rainbow'), - 'vel': plt.get_cmap('rainbow')}]) +@pytest.mark.parametrize('cmaps', [{'elv':'rainbow', + 'p_l': 'rainbow', + 'vel': 'rainbow'}]) @pytest.mark.parametrize('lines', [{'nave': '--', 'tfreq': '-'}]) @pytest.mark.parametrize('plot_elv', [False]) @pytest.mark.parametrize('title', ['test test']) @@ -203,3 +208,48 @@ def test_beam9_channel2_summary_plots(self, fig_size, watermark, boundary, groundscatter=groundscatter, range_estimation=range_estimation) plt.close('all') + + +@pytest.mark.parametrize('background', ['w']) +@pytest.mark.parametrize('zmin', [0, -200]) +@pytest.mark.parametrize('zmax', [200, 1000]) +@pytest.mark.parametrize('groundscatter_params', [True, False]) +@pytest.mark.parametrize('colorbar_label', ['test']) +@pytest.mark.parametrize('yspacing', [150, 250]) +@pytest.mark.parametrize('range_estimation', [ + pydarn.RangeEstimation.SLANT_RANGE, + pydarn.RangeEstimation.HALF_SLANT]) +@pytest.mark.parametrize('ymin', [10]) +@pytest.mark.parametrize('ymax', [70]) +@pytest.mark.parametrize('parameters', ['v', 'p_l', 'w_l']) +@pytest.mark.parametrize('cmap', ['viridis']) +@pytest.mark.parametrize('start_time', [dt.datetime(2018, 4, 4, 6, 2)]) +@pytest.mark.parametrize('end_time', [dt.datetime(2018, 4, 4, 6, 4)]) +@pytest.mark.parametrize('date_fmt', ['%H:%M']) +@pytest.mark.parametrize('round_start', [False]) +@pytest.mark.parametrize('latlon', ['lat', 'lon']) +@pytest.mark.parametrize('plot_equatorward', [False]) +class TestCoordTime: + + def test_parameters_coord_time(self, groundscatter_params, + parameters, background, zmin, zmax, + start_time, end_time, ymin, ymax, + colorbar_label, yspacing, round_start, + range_estimation, cmap, date_fmt, + plot_equatorward, latlon): + """ this test will give bare minimum input needed for """ + with warnings.catch_warnings(record=True): + pydarn.RTP.plot_coord_time(data, beam_num=15, + parameter=parameters, channel=1, + groundscatter=groundscatter_params, + background=background, zmin=zmin, + zmax=zmax, start_time=start_time, + end_time=end_time, ymin=ymin, ymax=ymax, + colorbar_label=colorbar_label, + yspacing=yspacing, + round_start=round_start, + range_estimation=range_estimation, + cmap=cmap, date_fmt=date_fmt, + plot_equatorward=plot_equatorward, + latlon=latlon) + plt.close('all') \ No newline at end of file diff --git a/test/test_utils.py b/test/test_utils.py new file mode 100644 index 000000000..9fcb381ee --- /dev/null +++ b/test/test_utils.py @@ -0,0 +1,82 @@ +# Copyright (C) 2023 SuperDARN Canada, University of Saskatchewan +# Author: Carley Martin +# +# Modifications: +# +# Disclaimer: +# pyDARN is under the LGPL v3 license found in the root directory LICENSE.md +# Everyone is permitted to copy and distribute verbatim copies of this license +# document, but changing it is not allowed. +# +# This version of the GNU Lesser General Public License incorporates the terms +# and conditions of version 3 of the GNU General Public License, +# supplemented by the additional permissions listed below. + +import bz2 +import datetime as dt +import matplotlib.pyplot as plt +import pytest +import warnings + +import pydarn + + +with bz2.open('test/data/test.fitacf.bz2') as fp: + fitacf_stream = fp.read() +data = pydarn.SuperDARNRead(fitacf_stream, True).read_fitacf() + + +class TestUtils_citations: + def test_citations(self): + with warnings.catch_warnings(record=True): + pydarn.Citations.print_citations() + def test_acks(self): + with warnings.catch_warnings(record=True): + pydarn.Citations.print_acknowledgements() + + +class TestUtils_filters: + def test_boxcar(self): + with warnings.catch_warnings(record=True): + bx = pydarn.Boxcar(thresh=0.7, w=None) + bx.run_filter(data) + + +class TestUtils_general: + def test_greatcircle(self): + with warnings.catch_warnings(record=True): + pydarn.GeneralUtils.great_circle(100, 50, 110, 60) + def test_newcoord(self): + with warnings.catch_warnings(record=True): + pydarn.GeneralUtils.new_coordinate(100, 50, 100, 30) + + +class TestUtils_coastline: + def test_coastline(self): + with warnings.catch_warnings(record=True): + pydarn.coast_outline + + +@pytest.mark.parametrize('tdiff', [0.003, -0.003]) +@pytest.mark.parametrize('overwrite', [True, False]) +@pytest.mark.parametrize('interferometer_offset', [[0.0, 100.0, 0.0], + [1.0, -10.0, 2.0]]) +class TestUtils_tdiff: + def test_recalcelv(self, tdiff, overwrite, interferometer_offset): + with warnings.catch_warnings(record=True): + pydarn.recalculate_elevation(data, tdiff=tdiff, + overwrite=overwrite, + interferometer_offset= + interferometer_offset) + + +class TestUtils_terminator: + def test_terminator(self): + with warnings.catch_warnings(record=True): + pydarn.terminator(dt.datetime(2023,10,10,1,30), 300) + + +class TestUtils_calcazi: + def test_calculateazimuth(self): + with warnings.catch_warnings(record=True): + pydarn.calculate_azimuth(100, 50, 100, 110, 60, 100) \ No newline at end of file