National Weather Service

National Weather Service Standard Color Curves

Compiled by Brian Blaylock
May 8, 2018
[email protected]


This notebook shows how I made the National Weather Service's (NWS) standard color curves for Python. The NWS wants to standardized these colors throughout the industry. I will use these color curves moving forward, and I hope other people who want to use the NWS color curves in their own Python=generated figures find this notebook useful.

These color maps came from Joe Moore who said:

While these colors are not "official" just yet, they've gone through years of development and refinement using cartographic best practices balanced with internal feedback and customer needs. They're not perfect, but we think they do a good job of visualized various weather elements across the areas our agency covers. You can see these colors used by most NWS offices on our websites and social media.

These color maps can be imported from pyBKB_v2/BB_cmap.NWS_standard_cmap.py

Hopefully by using these color scales, your maps will be consistent with colors used in NWS products.


Below is a summary of the proposed codes that I gleaned from a PowerPoint presnetation published in April 2018 that I came across.

Mission: Design standard color curves for use with public and NWS partners to improve communication consistency across the agency.

Process: Color curves were developed and iterated using best practices and internal feedback, including over a thousand responses from field office employees.


When using these color scales in plots such as pcolormesh or contourf plots, you need to pay special attention to the vmax and vmin value. The color scales are defined by English units (MPH, F, inches, etc.), so I have inclued the appropriate ranges for metric units. Use the appropriate vmax and vmin values to scale the colors to the appropriate bounds. I will demonstrate the color scales with archived HRRR data.


Let's get started...

Import some required modules

In [1]:
%matplotlib inline

# Two modules required for making custom colormaps
import numpy as np
import matplotlib.colors as colors

# My custom functions that retrieve HRRR data and draws the HRRR CONUS basemap
import sys
sys.path.append('/uufs/chpc.utah.edu/common/home/u0553130/pyBKB_v2')
from BB_downloads.HRRR_S3 import get_hrrr_variable
from BB_basemap.draw_maps import draw_CONUS_HRRR_map

# Other modules needed for plotting the examples
from datetime import datetime
import matplotlib.pyplot as plt
import matplotlib as mpl
mpl.rcParams['figure.figsize'] = [10,8]

Draw basemap object for CONUS HRRR domain with imported function

In [2]:
# Create a mpa object for the HRRR model domain
m = draw_CONUS_HRRR_map()

Temperature

Colors intuitivly indicate which is colder and which is warmer, paying special consideration for smaller regional maps where temperature may not change too dramatically.

Range of values:

  • Celsius: -50 through 50 C
  • Fahrenheit: -60 through 120 F
In [3]:
# The range of temperature bins in Fahrenheit
a = np.arange(-60,121,5)

# Bins normalized between 0 and 1
norm = [(float(i)-min(a))/(max(a)-min(a)) for i in a]

# Color tuple for every bin
C = np.array([[145,0,63],
              [206,18,86],
              [231,41,138],
              [223,101,176],
              [255,115,223],
              [255,190,232],
              [255,255,255],
              [218,218,235],
              [188,189,220],
              [158,154,200],
              [117,107,177],
              [84,39,143],
              [13,0,125],
              [13,61,156],
              [0,102,194],
              [41,158,255], 
              [74,199,255], 
              [115,215,255], 
              [173,255,255],
              [48,207,194], 
              [0,153,150], 
              [18,87,87],
              [6,109,44],
              [49,163,84],
              [116,196,118],
              [161,217,155],
              [211,255,190],  
              [255,255,179], 
              [255,237,160], 
              [254,209,118], 
              [254,174,42], 
              [253,141,60], 
              [252,78,42], 
              [227,26,28], 
              [177,0,38], 
              [128,0,38], 
              [89,0,66], 
              [40,0,40]])/255.

# Create a tuple for every color indicating the normalized position on the colormap and the assigned color.
COLORS = []
for i, n in enumerate(norm):
    COLORS.append((n, C[i]))

cmap = colors.LinearSegmentedColormap.from_list("Temperature", COLORS)
2 m Temperature
In [4]:
fxx = 0
H = get_hrrr_variable(datetime(2018, 1, 1), 'TMP:2 m', fxx=fxx, verbose=False)
In [5]:
m.drawcoastlines(); m.drawcountries(); m.drawstates()
m.pcolormesh(H['lon'], H['lat'], H['value']-273.15,  #Convert from Kelvin to Celsius
             cmap=cmap,
             vmax=50, vmin=-50,                      #Use the approriate vmax and vmin values
             latlon=True)
cb = plt.colorbar(orientation='horizontal', pad=.01, shrink=.95, extend='both')
cb.set_label('%s (%s)' % (H['name'], 'C'))

plt.title('HRRR F%02d' % fxx, loc='left', fontweight='semibold')
plt.title('Valid: %s' % H['valid'].strftime('%Y-%m-%d %H:%M UTC'), loc='right')
Out[5]:
<matplotlib.text.Text at 0x2b522922ce90>
In [6]:
fxx = 0
H = get_hrrr_variable(datetime(2017, 7, 30, 18), 'TMP:2 m', fxx=fxx, verbose=False)
In [7]:
m.drawcoastlines(); m.drawcountries(); m.drawstates()
m.pcolormesh(H['lon'], H['lat'], H['value']-273.15,  #Convert from Kelvin to Celsius
             cmap=cmap,
             vmax=50, vmin=-50,                      #Use the correct vmax and vmin values
             latlon=True)
cb = plt.colorbar(orientation='horizontal', pad=.01, shrink=.95, extend='both')
cb.set_label('%s (%s)' % (H['name'], 'C'))

plt.title('HRRR F%02d' % fxx, loc='left', fontweight='semibold')
plt.title('Valid: %s' % H['valid'].strftime('%Y-%m-%d %H:%M UTC'), loc='right')
Out[7]:
<matplotlib.text.Text at 0x2b5229f50050>
700 mb Temperature
In [8]:
fxx = 0
H = get_hrrr_variable(datetime(2018, 5, 1), 'TMP:700 mb', fxx=fxx, verbose=False)
In [9]:
m.drawcoastlines(); m.drawcountries(); m.drawstates()
m.pcolormesh(H['lon'], H['lat'], H['value']-273.15,
             cmap=cmap,
             vmax=50, vmin=-50,
             latlon=True)
cb = plt.colorbar(orientation='horizontal', pad=.01, shrink=.95, extend='both')
cb.set_label('700 mb %s (%s)' % (H['name'], 'C'))

plt.title('HRRR F%02d' % fxx, loc='left', fontweight='semibold')
plt.title('Valid: %s' % H['valid'].strftime('%Y-%m-%d %H:%M UTC'), loc='right')
Out[9]:
<matplotlib.text.Text at 0x2b522a68d550>