Skip to content

Commit

Permalink
Merge pull request #343 from SuperDARN/ehn/standardize_plot_return
Browse files Browse the repository at this point in the history
EHN: Standard Plot Return Values
  • Loading branch information
carleyjmartin authored Nov 23, 2023
2 parents 2a92b41 + 4db88b3 commit 74e95f3
Show file tree
Hide file tree
Showing 11 changed files with 252 additions and 94 deletions.
2 changes: 1 addition & 1 deletion docs/user/coordinates.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ import matplotlib.pyplot as plt
import numpy as np

# North Winter
_,_,ax1,ccrs1=pydarn.Fan.plot_fov(66, dt.datetime(2023, 12, 21, 0, 0),
pydarn.Fan.plot_fov(66, dt.datetime(2023, 12, 21, 0, 0),
lowlat= 5, boundary=True, line_color='red', coastline=True, nightshade=250)

# Test to plot terminator if ever required - plot line not fill!
Expand Down
32 changes: 16 additions & 16 deletions docs/user/fan.md
Original file line number Diff line number Diff line change
Expand Up @@ -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()
```
Expand All @@ -64,23 +64,23 @@ 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()

```
![](../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

Expand Down Expand Up @@ -139,13 +139,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()
```
Expand All @@ -155,12 +155,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()
```

Expand Down
52 changes: 28 additions & 24 deletions docs/user/fov.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,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()
```
Expand All @@ -94,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()
```

Expand All @@ -114,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()
```

Expand All @@ -135,25 +135,29 @@ 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()
```
Expand Down
7 changes: 4 additions & 3 deletions docs/user/grid.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,17 @@ 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
Expand Down
7 changes: 4 additions & 3 deletions docs/user/map.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,17 @@ 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):
```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:
![](../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
Expand Down
14 changes: 13 additions & 1 deletion pydarn/plotting/acf.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
# 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
#
# Disclaimer:
# pyDARN is under the LGPL v3 license found in the root directory LICENSE.md
Expand Down Expand Up @@ -348,7 +350,17 @@ 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': ax,
'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}
}

@classmethod
def __found_scan(cls, scan_num: int, count_num: int,
Expand Down
28 changes: 24 additions & 4 deletions pydarn/plotting/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
# 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
Expand Down Expand Up @@ -462,13 +463,25 @@ def plot_fan(cls, dmap_data: List[dict], ax=None, ranges=None,

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)
ax.set_title(title)
return ax, beam_corners_lats, beam_corners_lons, scan, grndsct

plt.title(title)
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: int, date: dt.datetime,
ax=None, ccrs=None, ranges: List = None, boundary: bool = True,
Expand Down Expand Up @@ -680,7 +693,14 @@ def plot_fov(cls, stid: int, 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):
Expand Down
40 changes: 29 additions & 11 deletions pydarn/plotting/grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#
# Modifications:
# 20220308 MTS added partial record exception
# 20230628 CJM refactored return values
# 20230713 CJM corrected geographic quivers
#
# Disclaimer:
Expand Down Expand Up @@ -186,9 +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)
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(
Expand Down Expand Up @@ -356,9 +359,9 @@ def plot_grid(cls, dmap_data: List[dict], record: int = 0,
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_thetas[i]):
plt.plot([thetas[i], end_thetas[i]],
[rs[i], end_rs[i]],
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 the vector crosses the meridian then amend so that
Expand All @@ -371,8 +374,8 @@ def plot_grid(cls, dmap_data: List[dict], record: int = 0,
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_thetas[i]],
[rs[i], end_rs[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)
# TODO: Add a velocity reference vector
Expand All @@ -392,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} -"\
Expand All @@ -406,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}
}
Loading

0 comments on commit 74e95f3

Please sign in to comment.