Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix broken array slicing inside addcyclic #559

Merged
merged 7 commits into from
Oct 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ https://keepachangelog.com/en/1.0.0/
https://semver.org/spec/v2.0.0.html


## [1.3.5]

### Fixed
- Fix broken array slicing inside `addcyclic` (PR [#559], solves issue
[#555], thanks to @fragkoul).

## [1.3.4] - 2022-08-10

### Changed
Expand Down Expand Up @@ -924,6 +930,10 @@ https://semver.org/spec/v2.0.0.html
- Fix glitches in drawing of parallels and meridians.


[#559]:
https://github.com/matplotlib/basemap/pull/559
[#555]:
https://github.com/matplotlib/basemap/issues/555
[#548]:
https://github.com/matplotlib/basemap/pull/548
[#547]:
Expand Down
198 changes: 109 additions & 89 deletions examples/fcstmaps.py
Original file line number Diff line number Diff line change
@@ -1,92 +1,112 @@
from __future__ import (absolute_import, division, print_function)
"""Make a multi-panel plot from numerical weather forecast in NOAA OPeNDAP."""
from __future__ import print_function

from __future__ import unicode_literals
# this example reads today's numerical weather forecasts
# from the NOAA OpenDAP servers and makes a multi-panel plot.
import netCDF4
import numpy as np
import matplotlib.pyplot as plt
import sys
import numpy.ma as ma
import datetime
from mpl_toolkits.basemap import Basemap, addcyclic
from netCDF4 import Dataset as NetCDFFile, num2date


# today's date is default.
if len(sys.argv) > 1:
YYYYMMDD = sys.argv[1]
else:
YYYYMMDD = datetime.datetime.today().strftime('%Y%m%d')

# set OpenDAP server URL.
try:
URLbase="http://nomads.ncep.noaa.gov:9090/dods/gfs/gfs"
URL=URLbase+YYYYMMDD+'/gfs_00z'
print(URL)
data = NetCDFFile(URL)
except:
msg = """
opendap server not providing the requested data.
Try another date by providing YYYYMMDD on command line."""
raise IOError(msg)


# read lats,lons,times.

print(data.variables.keys())
latitudes = data.variables['lat']
longitudes = data.variables['lon']
fcsttimes = data.variables['time']
times = fcsttimes[0:6] # first 6 forecast times.
ntimes = len(times)
# convert times for datetime instances.
fdates = num2date(times,units=fcsttimes.units,calendar='standard')
# make a list of YYYYMMDDHH strings.
verifdates = [fdate.strftime('%Y%m%d%H') for fdate in fdates]
# convert times to forecast hours.
fcsthrs = []
for fdate in fdates:
fdiff = fdate-fdates[0]
fcsthrs.append(fdiff.days*24. + fdiff.seconds/3600.)
print(fcsthrs)
print(verifdates)
lats = latitudes[:]
nlats = len(lats)
lons1 = longitudes[:]
nlons = len(lons1)

# unpack 2-meter temp forecast data.

t2mvar = data.variables['tmp2m']
t2m = np.zeros((ntimes,nlats,nlons+1),np.float32)
# create Basemap instance for Orthographic projection.
m = Basemap(lon_0=-90,lat_0=60,projection='ortho')
# add wrap-around point in longitude.
for nt in range(ntimes):
t2m[nt,:,:], lons = addcyclic(t2mvar[nt,:,:], lons1)
# convert to celsius.
t2m = t2m-273.15
# contour levels
clevs = np.arange(-30,30.1,2.)
lons, lats = np.meshgrid(lons, lats)
x, y = m(lons, lats)
# create figure.
fig=plt.figure(figsize=(6,8))
# make subplots.
for nt,fcsthr in enumerate(fcsthrs):
ax = fig.add_subplot(321+nt)
cs = m.contourf(x,y,t2m[nt,:,:],clevs,cmap=plt.cm.jet,extend='both')
m.drawcoastlines(linewidth=0.5)
m.drawcountries()
m.drawparallels(np.arange(-80,81,20))
m.drawmeridians(np.arange(0,360,20))
# panel title
plt.title('%d-h forecast valid '%fcsthr+verifdates[nt],fontsize=9)
# figure title
plt.figtext(0.5,0.95,
"2-m temp (\N{DEGREE SIGN}C) forecasts from %s"%verifdates[0],
horizontalalignment='center',fontsize=14)
# a single colorbar.
cax = plt.axes([0.1, 0.05, 0.8, 0.025])
plt.colorbar(cax=cax, orientation='horizontal')
plt.show()
from mpl_toolkits.basemap import Basemap
from mpl_toolkits.basemap import addcyclic


def main(date, verbose=True):
"""Main function."""

# Open dataset from OPeNDAP URL.
url = "http://nomads.ncep.noaa.gov/dods/gfs_0p25/gfs%Y%m%d/gfs_0p25_00z"
try:
data = netCDF4.Dataset(date.strftime(url), "r")
if verbose:
print("Data variables:")
print(sorted(data.variables))
except OSError as err:
err.args = (err.args[0], "date not found in OPeNDAP server")
raise

# Read lats, lons, and times.
latitudes = data.variables["lat"]
longitudes = data.variables["lon"]
fcsttimes = data.variables["time"]
times = fcsttimes[0:6] # First 6 forecast times.
ntimes = len(times)

# Convert times for datetime instances.
fdates = netCDF4.num2date(
times, units=fcsttimes.units, calendar="standard")

# Make a list of YYYYMMDDHH strings.
verifdates = [fdate.strftime("%Y%m%d%H") for fdate in fdates]
if verbose:
print("Forecast datetime strings:")
print(verifdates)

# Convert times to forecast hours.
fcsthrs = []
for fdate in fdates:
fdiff = fdate - fdates[0]
fcsthrs.append(fdiff.days * 24. + fdiff.seconds / 3600.)
if verbose:
print("Forecast datetime hours:")
print(fcsthrs)

# Unpack 2-meter temp forecast data.
lats = latitudes[:]
nlats = len(lats)
lons1 = longitudes[:]
nlons = len(lons1)
t2mvar = data.variables["tmp2m"]

# Create Basemap instance for orthographic projection.
bmap = Basemap(lon_0=-90, lat_0=60, projection="ortho")

# Add wrap-around point in longitude.
t2m = np.zeros((ntimes, nlats, nlons + 1), np.float32)
for nt in range(ntimes):
t2m[nt, :, :], lons = addcyclic(t2mvar[nt, :, :], lons1)

# Convert to Celsius.
t2m = t2m - 273.15

# Define contour levels.
clevs = np.arange(-30, 30.1, 2.0)
lons, lats = np.meshgrid(lons, lats)
x, y = bmap(lons, lats)

# Create figure.
fig = plt.figure(figsize=(6, 8))

# Make subplots.
for nt, fcsthr in enumerate(fcsthrs):
fig.add_subplot(321 + nt)
cs = bmap.contourf(x, y, t2m[nt, :, :], clevs,
cmap=plt.cm.jet, extend="both")
bmap.drawcoastlines(linewidth=0.5)
bmap.drawcountries()
bmap.drawparallels(np.arange(-80, 81, 20))
bmap.drawmeridians(np.arange(0, 360, 20))
# Set panel title.
plt.title(
"%d-h forecast valid " % fcsthr + verifdates[nt], fontsize=9)

# Set figure title.
plt.figtext(
0.5, 0.95,
"2-m temp (\N{DEGREE SIGN}C) forecasts from %s" % verifdates[0],
horizontalalignment="center", fontsize=14)

# Draw a single colorbar.
cax = plt.axes([0.1, 0.05, 0.8, 0.025])
plt.colorbar(cs, cax=cax, orientation="horizontal")
plt.show()


if __name__ == "__main__":

import sys
import datetime as dt

# Parse input date (default: today).
if len(sys.argv) > 1:
dateobj = dt.datetime.strptime(sys.argv[1], "%Y%m%d")
else:
dateobj = dt.datetime.today()
main(dateobj, verbose=True)
Loading