SuperDARN / pydarn

Python library for visualizing SuperDARN Data
GNU Lesser General Public License v3.0
31 stars 11 forks source link

REF: Axes handling for projections - new geomagnetic zoomable plotting #382

Closed carleyjmartin closed 1 month ago

carleyjmartin commented 3 months ago

Scope

This PR amends some details in the projections module, updates the geographic plotting to allow the user to zoom in on areas and move the focus of the plot. A new projection is also made for the same thing in geomagnetic/MLT coordinates. I was unable to allow subplot usage with these plots - the projections are very specific for use with SuperDARN data so I don't recommend making your own axes to put in, it would be nice to have the ability to plot multiple plots on one figure, but that will require a lot of work that I can't do right now.

Zoomable convection map plots will come eventually - they're just very hard and there are a few issues I haven't solved yet so that will all be in another PR at a later date!

Whats new:

plot_center: list [float, float]
            Longitude and Latitude of the desired center of the plot
            Plot will still plot if data is on the other side of the Earth
            Remember to include negative latitude for Southern Hemisphere
            Default: None
            Example: [-90, 60] will show the Earth centered on Canada
plot_extent: list [float, float]
            Plotting extent in terms of a percentage of Earth shown in
            the x and y plotting field 
            Default: None
            Example: [30, 50] shows a plot centered on the pole or specified
                     plot_center coord that shows 30% of the Earth in x and 
                     50% of the Earth in y. See tutorials for plotted example.

issue: to close #357

Approval

Number of approvals: 2 at least please, lots of things to test

Test

matplotlib version: 3.8.2 Note testers: please indicate what version of matplotlib you are using

Also test with southern hemisphere data, different keyword combos etc...

FAN or BALL AND STICK Plot testing:

This tests the new geographic plotting and geomagnetic plotting defaults and zoom features

import matplotlib.pyplot as plt
import pydarn
import datetime as dt

SDarn_read = pydarn.SuperDARNRead('/Users/carley/Documents/data/20200101.0001.00.inv.fitacf')
fitacf_data = SDarn_read.read_fitacf()    
rtn = pydarn.Fan.plot_fan(fitacf_data, scan_index=50, coastline=True,
                        radar_label=True, groundscatter=True, colorbar=False,
                        coords=pydarn.Coords.GEOGRAPHIC, projs=pydarn.Projs.GEO,
                        plot_extent=[80,80], plot_center=[-120,75])
    plt.title('Geographic plot-extent: 80,80 plot-center: -120,75')
    plt.show()
    rtn = pydarn.Fan.plot_fan(fitacf_data, scan_index=100, coastline=True,
                        radar_label=True, groundscatter=True, colorbar=False,
                        coords=pydarn.Coords.GEOGRAPHIC, projs=pydarn.Projs.GEO)

    plt.title('Geographic default')
    plt.show()

    rtn = pydarn.Fan.plot_fan(fitacf_data, scan_index=50, coastline=True,
                        radar_label=True, groundscatter=True, colorbar=False,
                        coords=pydarn.Coords.AACGM_MLT, projs=pydarn.Projs.MAG,
                        plot_extent=[80,80], plot_center=[-120,75])

    plt.title('Geomagnetic plot-extent: 80,80 plot-center: -120,75')
    plt.show()
    rtn = pydarn.Fan.plot_fan(fitacf_data, scan_index=100, coastline=True,
                        radar_label=True, groundscatter=True, colorbar=False,
                        coords=pydarn.Coords.AACGM_MLT, projs=pydarn.Projs.MAG)
    plt.title('Geomagnetic default')
    plt.show()
Screenshot 2024-05-15 at 10 53 03 AM Screenshot 2024-05-15 at 10 54 32 AM Screenshot 2024-05-15 at 10 53 21 AM Screenshot 2024-05-15 at 10 55 26 AM

FOV plot testing:

This feature was specifically requested for plotting the new NSSC radars, so here is an example of doing jsut that in magnetic MLT coordinates.

import pydarn
from datetime import datetime
import matplotlib.pyplot as plt
stids = [51,52,53,54,55,56]
cols = ['salmon','salmon','gold','gold','cornflowerblue','cornflowerblue']
plt.figure(figsize=(8, 8))
rtn=pydarn.Fan.plot_fov(stids[0], datetime(2021, 2, 5, 18, 5),
                        fov_color= cols[0],radar_location=True,
                        radar_label=True, coastline=True,
                        coords=pydarn.Coords.AACGM_MLT, projs=pydarn.Projs.MAG,
                        plot_extent=[90,50], plot_center=[20,60])

for i, stid in enumerate(stids[1:]):
    rtn=pydarn.Fan.plot_fov(stid, datetime(2021, 2, 5, 18, 5), ax=rtn['ax'],
                            ccrs=rtn['ccrs'], fov_color= cols[i+1],
                            radar_location=True, radar_label=True,
                            coastline=True,
                        coords=pydarn.Coords.AACGM_MLT, projs=pydarn.Projs.MAG)
plt.show()
Screenshot 2024-05-15 at 10 40 29 AM

GRID plotting:

import matplotlib.pyplot as plt 
import datetime as dt
import pydarn

grid_file_s = "/Users/carley/Documents/data/grids/20150308.south.grid2"
grid_file = "/Users/carley/Documents/data/grids/20150301.2001.00.inv.grid"
grid_data = pydarn.SuperDARNRead(grid_file).read_grid()
grid_data_s = pydarn.SuperDARNRead(grid_file_s).read_grid()

pydarn.Grid.plot_grid(grid_data, record=10, coastline=True, lowlat=30,
                        coords=pydarn.Coords.AACGM_MLT, projs=pydarn.Projs.MAG)

plt.show()

pydarn.Grid.plot_grid(grid_data, record=10, coastline=True, lowlat=30,
                        coords=pydarn.Coords.AACGM_MLT, projs=pydarn.Projs.POLAR)

plt.show()

pydarn.Grid.plot_grid(grid_data, record=10, coastline=True, lowlat=30,
                        coords=pydarn.Coords.GEOGRAPHIC, projs=pydarn.Projs.GEO)

plt.show()

pydarn.Grid.plot_grid(grid_data_s, record=10, coastline=True, lowlat=30,
                        coords=pydarn.Coords.AACGM_MLT, projs=pydarn.Projs.MAG)

plt.show()

pydarn.Grid.plot_grid(grid_data_s, record=10, coastline=True, lowlat=30,
                        coords=pydarn.Coords.AACGM_MLT, projs=pydarn.Projs.POLAR)

plt.show()

pydarn.Grid.plot_grid(grid_data_s, record=10, coastline=True, lowlat=30,
                        coords=pydarn.Coords.GEOGRAPHIC, projs=pydarn.Projs.GEO)

plt.show()

Map plots only use the Polar projection.

KhanalKrishna commented 3 months ago

Matplotlib version: 3.9.0 Hi, Things look good to me. I think in the magnetic coordinate system, it would be useful to have a selected MLT (e.g. 0 or 12) at the top center or the bottom center of the plot.

import matplotlib.pyplot as plt import pydarn import datetime as dt

Reading fitacf data

SDarn_read = pydarn.SuperDARNRead('20210126.2000.00.pgr.a.fitacf') fitacf_data = SDarn_read.read_fitacf()

#Fan plot in geographic coordinate rtn = pydarn.Fan.plot_fan(fitacf_data, scan_index=50, coastline=True, radar_label=True, groundscatter=True, colorbar=False, coords=pydarn.Coords.GEOGRAPHIC, projs=pydarn.Projs.GEO, plot_extent=[50,30], plot_center=[-120,65]) plt.title('Geographic plot-extent: 50,30 plot-center: -120,65') plt.show()

image

#Fan plot in geomagnetic coordinate rtn = pydarn.Fan.plot_fan(fitacf_data, scan_index=50, coastline=True, radar_label=True, groundscatter=True, colorbar=False, coords=pydarn.Coords.AACGM_MLT, projs=pydarn.Projs.MAG, plot_extent=[60,30], plot_center=[-120,85]) plt.title('Geographic plot-extent: 60,30 plot-center: -120,85') plt.show()

image

#FOV plot in geomagnetic coordinate from datetime import datetime stids = [53,54,55] cols = ['blue','red','green'] plt.figure(figsize=(8, 8)) rtn=pydarn.Fan.plot_fov(stids[0], datetime(2021, 2, 5, 18, 5), fov_color= cols[0],radar_location=True, radar_label=True, coastline=True, coords=pydarn.Coords.AACGM_MLT, projs=pydarn.Projs.MAG, plot_extent=[90,50], plot_center=[20,60]) for i, stid in enumerate(stids[1:]): rtn=pydarn.Fan.plot_fov(stid, datetime(2021, 2, 5, 18, 5), ax=rtn['ax'], ccrs=rtn['ccrs'], fov_color= cols[i+1], radar_location=True, radar_label=True, coastline=True, coords=pydarn.Coords.AACGM_MLT, projs=pydarn.Projs.MAG) plt.show()

image

#FOV plot in geographic coordinate from datetime import datetime stids = [53,54,55] cols = ['blue','red','green'] plt.figure(figsize=(8, 8)) rtn=pydarn.Fan.plot_fov(stids[0], datetime(2021, 2, 5, 18, 5), fov_color= cols[0],radar_location=True, radar_label=True, coastline=True, coords=pydarn.Coords.GEOGRAPHIC, projs=pydarn.Projs.GEO, plot_extent=[90,90], plot_center=[80,70]) for i, stid in enumerate(stids[1:]): rtn=pydarn.Fan.plot_fov(stid, datetime(2021, 2, 5, 18, 5), ax=rtn['ax'], ccrs=rtn['ccrs'], fov_color= cols[i+1], radar_location=True, radar_label=True, coastline=True, coords=pydarn.Coords.GEOGRAPHIC, projs=pydarn.Projs.GEO,) plt.show()

image

#FOV plotting in geographic coordinate on the southern hemisphere from datetime import datetime stids = [19,18] cols = ['blue','red'] plt.figure(figsize=(8, 8)) rtn=pydarn.Fan.plot_fov(stids[0], datetime(2020, 2, 5, 18, 5), fov_color= cols[0],radar_location=True, radar_label=True, coastline=True, coords=pydarn.Coords.GEOGRAPHIC, projs=pydarn.Projs.GEO,plot_extent=[100,100], plot_center=[10,-90] ) for i, stid in enumerate(stids[1:]): rtn=pydarn.Fan.plot_fov(stid, datetime(2021, 2, 5, 18, 5), ax=rtn['ax'], ccrs=rtn['ccrs'], fov_color= cols[i+1], radar_location=True, radar_label=True, coastline=True, coords=pydarn.Coords.GEOGRAPHIC, projs=pydarn.Projs.GEO) plt.show()

image

carleyjmartin commented 3 months ago

Excellent! Thanks @KhanalKrishna ! I'll have a look into how we can set an MLT in a fixed spot!

hiyadutuje commented 3 months ago

I am using matplotlib: 3.7.2. The fist code I am getting the a geomag1 figure with following error: File ~/.local/lib/python3.11/site-packages/pydarn/plotting/fan.py:198 in plot_fan date = time2datetime(dmap_data[plot_beams[0][0]])

IndexError: index 0 is out of bounds for axis 0 with size 0.

For the second and third codes, I ma getting this error:

Cell In[7], line 10 coords=pydarn.Coords.AACGM_MLT, projs=pydarn.Projs.MAG,

File ~/anaconda3/lib/python3.11/enum.py:784 in getattr raise AttributeError(name) from None

AttributeError: MAG.

carleyjmartin commented 3 months ago

Thanks, @hiyadutuje !

The errors you're getting and the first plot not working correctly sounds like the correct branch might not be installed for testing?

You can install in a fresh environment using pip3 install git+https://github.com/superdarn/pydarn@ref/axes Or git clone and checkout the ref/axes branch then pip3 install .

carleyjmartin commented 2 months ago

Suggestions have been implemented, if you are testing and come across the numpy error, please downgrade numpy and test, fixing that is out of scope for this PR and is a pyDARNio issue.

pip3 uninstall numpy
pip3 install numpy==1.26.4

I recommend doing this in a virtual environment, as always.

PrestonXPitzer commented 1 month ago

Here's the results of my test runs OS: Win10, numpy version 1.25.0 I used the same code as the given tests, save for the decompression steps since my data is in .bz2 image image image image For the FOV plot image GRID plotting image image image image image image

Doreban commented 1 month ago

Tested with Python=3.9.2, Numpy=1.26.4, and matplotlib=3.9.0 on Windows 10. Everything seems to work well. Figures can be interacted with in the live editor and the plot_center and plot_extent options seem to work for the different plot types.

My only comment is that I've noted that the MAG projection defaults to 12 MLT at the bottom of the figure and the POLAR projections defaults 12 MLT to the top of the figure for both Northern and Southern hemisphere data. It might be nice to have the MAG and POLAR projections default to the same orientation if plot_center is not specified.

Fan plots and ball and stick plots: default_geo_fan default_mag_stick centered_mag_fan centered_geo_stick

FOV plots: fan_plot_geo_proj fan_plot_MAG_proj fan_plot_polar_proj

Lastly the grid plots: inv_grid_mag inv_grid_mag_centered inv_grid_polar south_grid_geo

carleyjmartin commented 1 month ago

I'm gonna merge this in now and sort out lots of merge conflicts. I have changed the default to be 0 MLT at bottom. We will also have some time before the release to test this within the release branch.

Thanks to all who tested! :D