NCL Home> Application examples> Plot techniques || Data files for some examples

Example pages containing: tips | resources | functions/procedures

Plotting data on a map using gsn_csm_xxx functions

This page is an introduction to using the gsn_csm_xxxx_map functions to plot data (contours, vectors, streamlines) over a map.

All of the data files for the examples below can either be found on the data page, or via instructions included in the scripts.

KNOW YOUR DATA

To correctly plot data on a map, you must KNOW YOUR DATA.

What type of latitude (lat) / longitude (lon) structure is your data on?

  1. Rectilinear grid
  2. Curvilinear grid
  3. Random points
  4. Unstructured mesh

To determine what kind of lat/lon structure your data is on, use a UNIX command line tool like ncl_filedump on your data file, or use printVarSummary after you read a data variable. The examples below explain how to identify your lat/lon structure.

Is your data global or regional?

If your data is regional (i.e. it doesn't cover the full map), then you may need to:

  1. Set the special gsnAddCyclic resource to False.

  2. Set additional map resources to zoom in on the map area of interest.

Do your lat/lon arrays have units of "degrees_north" and "degrees_east"?

If your lat/lon arrays don't have "units" attributes, or they don't have "degrees" type of units, then your data may not plot correctly. See example 7 below for how to fix this.

Is your data large?

If you have a big grid or mesh that you want to generate contours for, then you may want to do "raster fill" contours instead of "area fill" contours for faster plotting. See examples 8 and 13.

Does your data need to be reordered to be plotted correctly?

If your data variable is a two-dimensional (2D) array ordered lon x lat, you will need to reorder it to be lat x lon. See example 8 below.

Is your lat/lon data not in degrees?

If your lat/lon data is in radians or meters or some units other than "degrees" you will need to convert it to degrees before you can plot your data. See example 13 below.

Is your data already projected onto a particular map projection?

If your data is already projected onto a particular map projection, this is called data on a native grid. If you know the exact parameters for the map projection, then you can plot the data without needing any lat / lon arrays at all. This can significantly speed up plotting because the data doesn't need to go through a mathematical transformation to be plotted correctly.

To plot data in its native projection, you first have to set up the map projection parameters EXACTLY as what your data are projected onto, and then set res@tfDoNDCOverlay to True.

It is possible to plot data on a native grid in a different map projection, if you have the lat/lon values for each data point. However, if you do this, you do NOT want to set tfDoNDCOverlay to True, because now you are not plotting in a native projection.

For examples of plotting data both in a native projection and a different projection, see examples 3, 4, and 10 below.

Is your data "packed" on the file?

Sometimes data is "packed" on a file to save space. This means you will need to unpack it before it will plot correctly. If your data is of type "short" or "byte" when you read it off the file, then this may be a indication that you need to unpack it. See example 9 below.

Does the data itself have errors?

If you have everything correct in your script and the data still is not being plotted correctly, then some possible sources of the problem can be:

  • Not having the correct units for your lat/lon arrays
  • Having NaN values in your data
  • Having data that needs to be "unpacked"
  • Not having the correct missing value (_FillValue attribute)

If you do have problems, LOOK AT YOUR DATA:

  • Use printVarSummary and printMinMax to look at your data, your lat/lon arrays, and your metadata.

  • Pay close attention to any warnings or errors that are produced when running your script.

For examples of fixing "bad" data, see examples 7 and 12 below.

dataonmap_1.ncl / dataonmap_grid_1.ncl
Rectilinear grid

Data: uv300.nc (NetCDF file, included with NCL distribution)

Data on a rectilinear grid is the simplest data to plot because the latitude and longitude coordinate arrays are automatically attached to the data variable when you read it in.

You can quickly tell if your data is on a rectilinear grid by looking at the printVarSummary output of your data variable:

   Variable: u
   Type: float
   Total Size: 32768 bytes
               8192 values
   Number of Dimensions: 2
   Dimensions and sizes : [lat | 64] x [lon | 128]
   Coordinates : 
            lat : [-87.8638..87.8638]
            lon : [-180..177.1875]
   Number Of Attributes : 5
   time : 1
   _FillValue : -999
   long_name : Zonal Wind
   units : m/s

Note the "Coordinates:" line, which is followed by two lines indicating the range of the "lat" and "lon" arrays. This means you have data on a rectilinear grid. If your data is on any other type of grid (curvilinear, unstructured mesh, random), then there will be no lat/lon arrays listed after the "Coordinates:" line.

To plot this data, simply read the "u" variable and pass it to gsn_csm_contour_map. This function will look for coordinate arrays attached to "u", and will use them for plotting:

  u = a->U(0,:,:)

  wks = gsn_open_wks("png","dataonmap")

  res              = True
  res@cnFillOn     = True
  res@tiMainString = "Plotting rectilinear data"

  plot = gsn_csm_contour_map(wks,u,res)

The second frame shows how easy it is to plot the data on a different map projection, simply by setting mpProjection to the desired projection, like "Robinson".

The third frame is from the dataonmap_grid_1.ncl script. It demonstrates how to call gsn_coordinates to add the lat/lon lines associated with your data.

dataonmap_2.ncl
Rectilinear grid

Data: uv300.nc (NetCDF file, included with NCL distribution)

This is the same rectilinear grid as the previous example, except a vector plot is drawn. Both "u" and "v" have coordinate arrays attached to them, so there's nothing special you need to do to correctly plot this over a map.

   Variable : u
   Type : float
   . . .
   Number of Dimensions: 2
   Dimensions and sizes: [lat | 64] x [lon | 128]
   Coordinates: 
               lat: [-87.8638..87.8638]
               lon: [-180..177.1875]
   Number Of Attributes: 5
    . . .
   
   Variable: v
   Type: float
   . . .
   Number of Dimensions: 2
   Dimensions and sizes: [lat | 64] x [lon | 128]
   Coordinates: 
               lat: [-87.8638..87.8638]
               lon: [-180..177.1875]
   Number Of Attributes:  5
   . . .
dataonmap_3.ncl
Curvilinear grid

Data: ruc.grb (GRIB file)

Data on a curvilinear grid is data whose latitude / longitude coordinates are represented by 2-dimensional (2D) latitude / longitude arrays.

When you read a data variable represented by 2D lat/lon arrays, these arrays will NOT be attached as coordinate arrays to the data like they are with rectilinear data.

First, note the output from printVarSummary. It has a "Coordinates" line, but there are no coordinate variables listed after it:

    Variable: temp
    Type: float
    Number of Dimensions: 3
    Dimensions and sizes: [lv_SPDY3 | 6] x [gridx_236 | 113] x [gridy_236 | 151]
    Coordinates: 
    Number Of Attributes: 13
    . . .
This means you don't have any lat/lon data attached to this variable, and hence this data is not rectilinear.

Second, note that there is a "coordinates" attribute attached to your variable with the string value "gridlat_236 gridlon_236":

    Variable: temp
    . . .
    Number Of Attributes: 13
    long_name : Temperature
    units : K
    _FillValue : 1e+20
    coordinates : gridlat_236 gridlon_236
    . . .

If you do have a "coordinates" attribute, then it most likely includes the names of the variables on the file that contain that variable's lat/lon coordinate information, in this case "gridlat_236" and "gridlon_236".

Doing a "ncl_filedump" on this file indeed shows these two variables exist on the file, and they are both 2-dimensional and the same size as the lat/lon dimensions of the data variable. This means you have data on a curvilinear grid.

   Variable: gridlat_236 (file variable)
   Type: float
   . . .
   Number of Dimensions: 2
   Dimensions and sizes: [gridx_236 | 113] x [gridy_236 | 151]
   Coordinates: 
   Number Of Attributes: 15
   . . .

   Variable: gridlon_236 (file variable)
   Type: float
   . . .
   Number of Dimensions: 2
   Dimensions and sizes: [gridx_236 | 113] x [gridy_236 | 151]
   Coordinates: 
   Number Of Attributes: 15
  . . .
To plot data on a curvilinear grid, you must read these 2D lat/lon variables from the file and attach them to the data variable as special attributes called "lat2d" and "lon2d":

  . . .
  temp       = a->TMP_236_SPDY   ; 6 x 113 x 151
  temp@lat2d = a->gridlat_236    ;     113 x 151
  temp@lon2d = a->gridlon_236    ;     113 x 151
  . . .
  res          = True
  res@cnFillOn = True

  plot = gsn_csm_contour_map(wks,temp(0,:,:),res)

In the second frame of this example, we simply zoom in on the area of interest, by setting the mpMinLatF / mpMaxLatF / mpMinLonF / mpMaxLonF resources.

The third frame is from the dataonmap_grid_3.ncl script. It demonstrates how to call gsn_coordinates to add the lat/lon lines associated with your data.

dataonmap_native_3.ncl / dataonmap_native_grid_3.ncl
Curvilinear grid in a native projection

Data: ruc.grb (GRIB file)

This script plots the same data as the previous example, except it plots the data on its native grid using map projection information attached as attributes to the lat/lon arrays on the file:

  a    = addfile("ruc.grb","r")
  lat  = a->gridlat_236      ; Needed only for projection information
  lon  = a->gridlon_236
  . . .
  res@mpLeftCornerLatF  = lat@corners(0)
  res@mpLeftCornerLonF  = lon@corners(0)
  res@mpRightCornerLatF = lat@corners(2)
  res@mpRightCornerLonF = lon@corners(2)

  res@mpProjection        = lat@mpProjection
  res@mpLambertMeridianF  = lat@mpLambertMeridianF
  res@mpLambertParallel1F = lat@mpLambertParallel1F
  res@mpLambertParallel2F = lat@mpLambertParallel2F
When plotting data natively, you must set the special tfDoNDCOverlay resource to True, to tell NCL not to do a map transformation.

The second frame is from the dataonmap_native_grid_3.ncl script. It demonstrates how to call gsn_coordinates to add the lat/lon lines associated with your data.

dataonmap_4.ncl
Curvilinear grid

Data: ruc2.bgrb.20020418.i12.f00 (GRIB file)

This GRIB file is similar to the previous one, in that the data variables contain a "coordinates" attribute indicating the name of the lat/lon variables on the file.

This time a vector plot is being drawn. The special "lat2d" / "lon2d" arrays must be attached to both the u and v data arrays.

  u       = f->U_GRD_252_HTGL
  v       = f->V_GRD_252_HTGL
  lat2d   = f->gridlat_252  
  lon2d   = f->gridlon_252  
  u@lat2d = lat2d
  u@lon2d = lon2d
  v@lat2d = lat2d
  v@lon2d = lon2d
dataonmap_native_4.ncl / dataonmap_nonnative_4.ncl
Curvilinear grid plotted in both native and non-native projections

Data: ruc2.bgrb.20020418.i12.f00 (GRIB file)

The "native" script plots the same curvilinear vector data as in the previous example, except using the Lambert Conformal native map projection parameters provided on the file. It also overlays the vectors on filled geopotential height contours, which are on the same lat/lon curvilinear grid.

As with example dataonmap_native_3.ncl, the map projection information is obtained from special attributes attached to the lat/lon arrays, and the special resource tfDoNDCOverlay is set to True.

The "nonnative" version of the script plots the exact same data in a basic cylindrical equidistant map projection.

dataonmap_5.ncl / dataonmap_5_640.ncl / dataonmap_grid_5.ncl
Random data

Data: pw.dat (ASCII file)

If you have a one-dimensional (1D) array of data represented by 1D lat/lon arrays of the same length, then this is considered to either be an "unstructured mesh" or "random points".

This example shows how to plot 32 random data points, given a lat/lon value for each point. The data are read off the ASCII file using asciiread.

To correctly plot random data over a map, you must set the special sfXArray and sfYArray resources to the one-dimensional longitude / latitude arrays, respectively:

  pwv = tofloat(str_get_field(lines(1:),4," "))
  lat = tofloat(str_get_field(lines(1:),2," "))
  lon = tofloat(str_get_field(lines(1:),3," "))
  . . .
  res          = True
  res@cnFillOn = True
  res@sfXArray = lon
  res@sfYArray = lat

  plot = gsn_csm_contour_map(wks,pwv,res)  

NCL will internally interpolate the data to a triangular mesh before plotting it.

You cannot currently plot vectors that are on random points or an unstructured mesh.

In NCL Version 6.4.0, you will be able to use special "lat1d" and "lon1d" attributes to plot the data (see dataonmap_5_640.ncl). There's no real advantage to this method over the sfXArray / sfYArray method, except that it's similar to the model for curvilinear data that uses the "lat2d" and "lon2d" attributes:

  pwv       = tofloat(str_get_field(lines(1:),4," "))
  pwv@lat1d = tofloat(str_get_field(lines(1:),2," "))
  pwv@lon1d = tofloat(str_get_field(lines(1:),3," "))
  . . .
  res          = True
  res@cnFillOn = True

  plot = gsn_csm_contour_map(wks,pwv,res)  

The second frame shows how to plot the 32 random lat/lon locations using gsn_coordinates.

dataonmap_6.ncl
Triangular mesh

Data: ctcbay.nc (NetCDF file, included with NCL distribution)

If you have 1D data and lat/lon arrays all the same length, and you also have a variable that contains a triangular mesh of your data, then you can set the special sfElementNodes resource to this connectivity mesh for faster plotting results:

  . . .
  x   = f->data     ; 1D array of data (length npts)
  lat = f->lat      ; 1D array of data (length npts)
  lon = f->lon      ; 1D array of data (length npts)
  ele = f->ele      ; n x 3 (triangular mesh that connects the cells)
  . . .
  res                = True
  res@sfYArray       = lat
  res@sfXArray       = lon
  res@sfElementNodes = ele
  res@cnFillOn       = True
  . . .
  plot = gsn_csm_contour_map(wks,depth,res)

Note that the leftmost dimension of the triangular mesh will likely be larger than the length of your 1D data arrays.

dataonmap_7.ncl / dataonmap_grid_7.ncl
Rectilinear grid

Data: Tstorm.cdf (NetCDF file, included with NCL distribution)

The data for this example is on a rectilinear grid, but if you try to plot it the usual way, you will get the following warnings and an incorrect plot:

  check_for_y_lat_coord: Warning: Data either does not contain a valid 
  latitude coordinate array or doesn't contain one at all.
  A valid latitude coordinate array should have a 'units' 
  attribute equal to one of the following values: 
  'degrees_north' 'degrees-north' 'degree_north' 'degrees north' 

This is due to the fact that the lat/lon arrays do not have "units" attributes of "degrees_north" and "degrees_east" respectively:

   Variable: lat (coordinate)
   . . .
   Number of Dimensions: 1
   Dimensions and sizes: [lat | 33]
   Coordinates: 
   Number Of Attributes: 0
   
   Variable: lon (coordinate)
   . . .
   Number of Dimensions: 1
   Dimensions and sizes: [lon | 36]
   Coordinates: 
   Number Of Attributes: 0
   
You can fix this by attaching the expected "units" attribute to both coordinate arrays, via the "t" data variable:

   t&lat@units = "degrees_north"
   t&lon@units = "degrees_east"

You will then get a second error:

   gsn_add_cyclic: Warning: The range of your longitude data is not 360.
   You may want to set the gsnAddCyclic resource to False to avoid a
   warning message from the spline function.

This can be fixed by setting the special gsnAddCyclic to resource to False as suggested.

The second frame shows the result of the plot once you add the missing "units" and turn off the cyclic point. The third frame simply zooms in on the map area of interest.

The last frame is from the dataonmap_grid_7.ncl script. It demonstrates how to call gsn_coordinates to add markers at lat/lon locations associated with your data. The red markers indicate areas where the data contains missing values.

dataonmap_8.ncl
Rectilinear grid

Data: 3B-MO.MS.MRG.3IMERG.20140701-S000000-E235959.07.V03D.HDF5 (HDF5 file)

The data for this example is on a rectilinear grid, but it is ordered longitude x latitude:

   Variable: p
   Type: float
   . . .
   Number of Dimensions: 2
   Dimensions and sizes: [lon | 3600] x [lat | 1800]
   Coordinates: 
               lon: [-179.95..179.95]
               lat: [-89.95..89.95]
   Number Of Attributes: 6
   . . .

In order to plot this data correctly, it must be reordered to be lat x lon. In this script, the reordering is done right inside the plotting call, but you could also do it earlier in the script, like when reading in the variable.

  plot = gsn_csm_contour_map(wks, p(lat|:,lon|:), res)

This is a rather large grid (3600 x 1800). In order to speed up the plotting, we are using "raster" fill for the contours (cnFillMode="RasterFill"). This can make things SIGNIFICANTLY faster for large grids.

The default contour fill mode is "AreaFill". If you try to contour this data using "AreaFill", you will get a fatal error:

  ContourPlotDraw: Workspace reallocation would exceed maximum size 100000000

You can increase the "workspace size", but it's not really worth it! Here are the timing results between using "RasterFill" and "AreaFill":

  AreaFill:   Elapsed time = 1070.93 CPU seconds.
  RasterFill: Elapsed time = 1.01304 CPU seconds.
dataonmap_9.ncl dataonmap_grid_9.ncl
Curvilinear grid

Data: slp.1963.nc (NetCDF file)

The data for this example is "packed" on the file. That is, it is of type "short" and you must multiple or divide a "scale factor" to it before it will plot correctly. Sometimes you must also add or subtract an "add offset" value.

When we see data that is type "short" or "byte", we assume that it has to be unpacked. You can usually further identify whether data needs to be unpacked by the examining the printVarSummary output for the presence of attributes "scale_factor" and/or "add_offset" or something similar:

   Variable: slp
   Type: short
   Number of Dimensions: 3
   Dimensions and sizes: [time | 365] x [lat | 73] x [lon | 144]
   Coordinates: 
        time: [17198568..17207304]
        lat: [90..-90]
        lon: [ 0..357.5]
   Number Of Attributes: 17
   long_name : mean Daily Sea Level Pressure
   units : Pascals
   add_offset : 119765
   scale_factor : 1
   valid_range : ( 87000, 115000 )
   actual_range : ( 94395, 111535 )
   missing_value : 32766
   _FillValue : 32766
   . . . 

You should also call printMinMax on "slp_short" to look at the min/max:

  mean Daily Sea Level Pressure (Pascals) : min=-25370   max=-8230

From these min/max values, you can see right away that these are not not valid numbers for pressure.

In this script, the short2flt function is used to unpack the data. This function also copies over the metadata. For a "cleaner" plot, we converted the values to "hPa" by mutiplying by 0.01 and updated the "units" attribute to reflect this change.

  slp_float = short2flt(slp_short)    ; unpack the data
  slp_float = slp_float * 0.01        ; convert to hPa
  slp_float@units = "hPa"             ; update the units

Calling printMinMax on "slp_float" results in reasonable values:

   mean Daily Sea Level Pressure (hPa) : min=943.95   max=1115.35

Important note: there is no "standard" way to unpack your data. Sometimes the metadata on the file will provide this information, or you may need to find some documentation on your file. Generally, the "scale_factor" attribute is the value that you multiply your data by, and the "add_offset" attribute is the value that you add after you multiple the scale factor. If you have a well-written file, then the metadata may also indicate a "valid range" for your data (see above output). This makes it easier to examine your results and make sure you are unpacking the data correctly.

The second frame is from the dataonmap_grid_9.ncl script. It demonstrates how to call gsn_coordinates to add the lat/lon lines associated with your data.

dataonmap_10.ncl
Curvilinear grid

Data: wrfout_d01_2003-07-15_00:00:00 (NetCDF WRF output file)

This example plots data on a WRF-ARW grid, which is on a curvilinear grid.

The first frame plots the data using the native map projection on the file. The second frame plots the data by reading the XLAT / XLONG arrays off the file and attaching them to "q2" via the special "lat2d" / "lon2d" attributes.

This is an older WRF-ARW file, whose variables do not contain any metadata that describes the lat / lon coordinates. WRF-ARW lat/lon arrays have names like "XLAT", "XLONG", "XLAT_U", "XLONG_U", "XLAT_V", "XLONG_V", etc. If you're not sure which ones to use, look at size of your data variable and pick the corresponding XLAT/XLONG variable that matches the size of your data variable.

"XLAT" and "XLONG" are used in this example, but these are the only lat/lon arrays on this particular file.

   Variable: q2
   Type: float
   . . .
   Number of Dimensions: 3
   Dimensions and sizes: [Time | 1] x [south_north | 160] x [west_east | 180]
   Coordinates: 
   Number Of Attributes: 5
   FieldType : 104
   MemoryOrder : XY 
   description : QV at 2 M

   float XLAT ( Time, south_north, west_east )
   FieldType :104
   MemoryOrder :XY 
   description :LATITUDE, SOUTH IS NEGATIVE
   units : degree

   float XLONG ( Time, south_north, west_east )
   FieldType : 104
   MemoryOrder : XY 
   description : LONGITUDE, WEST IS NEGATIVE
   units : degree

Newer WRF ARW files will have a "coordinates" attribute for the data variables that help you identify the correct lat/lon arrays associated with your data. For example:

   float SST ( Time, south_north, west_east )
   FieldType : 104
   MemoryOrder : XY 
   description : SEA SURFACE TEMPERATURE
   units : K
   coordinates : XLONG XLAT

   float V ( Time, bottom_top, south_north_stag, west_east )
   FieldType : 104
   MemoryOrder : XYZ
   description : y-wind component
   units : m s-1
   stagger : Y
   coordinates : XLONG_V XLAT_V
dataonmap_11.ncl
Curvilinear grid

Data: ctorca.nc (NetCDF file)

This example plots data on an ORCA (ocean model) grid, which is on a rather quirky, non-uniform curvilinear grid (see the second frame).

Note that the "sst" variable doesn't have a "coordinates" attribute, but it does have an "associate" attribute with the string value "time_counter nav_lat nav_lon":

   Variable: sst
   Type: float
   . . .
   Number of Dimensions: 2
   Dimensions and sizes: [y | 149] x [x | 182]
   Coordinates: 
   Number Of Attributes: 13
   time_counter : 43200
   units : C
   missing_value : 1e+20
   valid_min : 1e+20
   valid_max : -1e+20
   long_name : SST
   short_name : sosstsst
   associate : time_counter nav_lat nav_lon
   _FillValue : 1e+20

Based on an educated guess, we looked for "nav_lat" and "nav_lon" on the file, and were able to use these for the "sst" "lat2d" / "lon2d" data attributes.

The contours are drawn in "CellFill" mode. The second frame turns on the cell edges so you can actually see the structure of this non-uniform grid.

dataonmap_12.ncl
Rectilinear grid

Data: Download any one of the NetCDF files from:
ftp://podaac-ftp.jpl.nasa.gov/OceanCirculation/oscar/preview/L4/resource/LAS/oscar_third_deg_180/

This example plots streamlines on a relatively large rectilinear lat/lon grid (481 x 1081). Note the "NaN" ("not a number") values for the "_FillValue" and "missing_value" attributes when you do a printVarSummary of the data:

   Variable: u
   Type: double
   . . .
   Number of Dimensions: 4
   Dimensions and sizes:[time | 33] x [depth | 1] x [latitude | 481] x [longitude | 1081]
   Coordinates: 
            time: [8488..8650.667]
            depth: [15..15]
            latitude: [  80.. -80]
            longitude: [-180.. 180]
   Number Of Attributes: 4
   units : meter/sec
   long_name : Ocean Surface Zonal Currents
   missing_value : nan
   _FillValue : nan

The NaN values are suspicious, so we also used printMinMax to check the min/max of the data:

   Ocean Surface Zonal Currents (meter/sec) : min=nan   max=nan
   Ocean Surface Meridional Currents (meter/sec) : min=nan   max=nan

You cannot have any NaN values in your data when plotting with NCL, so you must use the replace_ieeenan function to replace these values with missing values. Once you do this, the min/max values look more reasonable:

   Ocean Surface Zonal Currents (meter/sec) : min=-3.518722   max=3.7021546
   Ocean Surface Meridional Currents (meter/sec) : min=-3.319664   max=3.662057
dataonmap_13.ncl / dataonmap_13_640.ncl
Hexagonal mesh

Data: MPAS.nc (NetCDF file)

This example shows how to create a filled contour plot of data on a hexagonal mesh (163,842 cells). The data and the lat/lon arrays are all one-dimensional arrays of the same length:

   Variable: sp
   Type: double
   Number of Dimensions: 1
   Dimensions and sizes: [nCells | 163842]

   Variable: latCell
   Type: double
   Number of Dimensions: 1
   Dimensions and sizes: [nCells | 163842]

   Variable: lonCell
   Type: double
   Number of Dimensions: 1
   Dimensions and sizes: [nCells | 163842]

A couple of notes:

  1. The lat/lon arrays on this file are in "radians" and must be converted to "degrees".

  2. Raster contours (cnFillMode="RasterFill") are used here for faster plotting.

As with the previous unstructured examples, you must set the special sfXArray and sfYArray resources to the one-dimensional lat / lon arrays, respectively, or use the "lat1d" / "lon1d" attributes if you have NCL V6.4.0 or later:

If you have NCL V6.3.1 or earlier:

  RAD2DEG = 180.0d/(atan(1)*4.0d)  ; Radian to Degree

  sp      = f->surface_pressure(0,:)    ; 163842 points
  lonCell = f->lonCell * RAD2DEG        ; ditto
  latCell = f->latCell * RAD2DEG        ; ditto
  . . .
  res          = True
  res@cnFillOn = True
  res@sfXArray = lonCell
  res@sfYArray = latCell

  plot = gsn_csm_contour_map(wks,x,res)  

If you have NCL V6.4.0 or later:

  RAD2DEG = 180.0d/(atan(1)*4.0d)  ; Radian to Degree

  sp       = f->surface_pressure(0,:)
  sp@lat1d = f->latCell * RAD2DEG
  sp@lon1d = f->lonCell * RAD2DEG
  . . .
  res          = True
  res@cnFillOn = True
  plot = gsn_csm_contour_map(wks,sp,res)