PyNGL > tutorial examples > 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11


Example 3 - vector plots

This example reads in three netCDF files and creates four vector plots, using data from all three files. Resources are used to change aspects of each vector plot.

To find out more about netCDF, see http://my.unidata.ucar.edu/content/software/netcdf/.

To run this example, you must have Numerical Python installed in your Python implementation. Numerical Python (also known as "NumPy") is a Python module allowing for efficient array processing. This example reads in a netCDF file, so you will need to have the Nio module (this module comes with PyNGL). netCDF is a self-documenting and network-transparent data format - see the netCDF User Guide for details.

There are two ways to run this example:

execute

    pynglex ngl03p
or download
ngl03p.py
and type:
python ngl03p.py

Output from example 3

Frame 1 Frame 2 Frame 3 Frame 4

(Click on any frame to see it enlarged.)


  0. #
  1. #  Import NumPy.
  2. #
  3. import numpy
  4. 
  5. #
  6. #  Import Nio.
  7. #
  8. import Nio
  9. 
 10. #
 11. #  Import Ngl support functions.
 12. #
 13. import Ngl
 14. #
 15. #  Open the netCDF files.
 16. #
 17. dirc  = Ngl.pynglpath("data")
 18. ufile = Nio.open_file(dirc + "/cdf/Ustorm.cdf","r")  # Open two netCDF files.
 19. vfile = Nio.open_file(dirc + "/cdf/Vstorm.cdf","r")
 20. 
 21. #
 22. #  Get the u/v variables.
 23. #
 24. u = ufile.variables["u"]
 25. v = vfile.variables["v"]
 26. lat = ufile.variables["lat"]
 27. lon = ufile.variables["lon"]
 28. ua = u[0,:,:]
 29. va = v[0,:,:]
 30. 
 31. wks_type = "ps"
 32. wks = Ngl.open_wks(wks_type,"ngl03p")
 33. 
 34. resources = Ngl.Resources()
 35. if hasattr(u,"_FillValue"):
 36.   resources.vfMissingUValueV = u._FillValue
 37. if hasattr(v,"_FillValue"):
 38.   resources.vfMissingVValueV = v._FillValue
 39. 
 40. vc = Ngl.vector(wks,ua,va,resources)
 41. 
 42. #----------- Begin second plot -----------------------------------------
 43. 
 44. resources.vcMinFracLengthF = 0.33
 45. resources.vcRefMagnitudeF  = 20.0
 46. resources.vcRefLengthF     = 0.045
 47. resources.vcMonoLineArrowColor  = False   # Draw vectors in color.
 48. 
 49. vc = Ngl.vector(wks,ua,va,resources)
 50. 
 51. #----------- Begin third plot -----------------------------------------
 52. 
 53. resources.tiMainString  = "~F22~wind velocity vectors - January 1996"
 54. resources.tiXAxisString = "longitude"
 55. resources.tiYAxisString = "latitude"
 56.  
 57. resources.vfXCStartV  = float(lon[0])            # Define X/Y axes range
 58. resources.vfXCEndV    = float(lon[len(lon[:])-1]) # for vector plot.
 59. resources.vfYCStartV  = float(lat[0])
 60. resources.vfYCEndV    = float(lat[len(lat[:])-1])
 61. 
 62. vc = Ngl.vector(wks,ua,va,resources)
 63. 
 64. #---------- Begin fourth plot ------------------------------------------
 65. 
 66. tfile = Nio.open_file(dirc+"/cdf/Tstorm.cdf","r")    # Open a netCDF file.
 67. temp = tfile.variables["t"]
 68. 
 69. tempa = temp[0,:,:]
 70. #
 71. #  Convert from degrees Kelvin to degrees F.
 72. #  If the data has a fill value, do the conversion  at those 
 73. #  values not equal to the fill value and fill in with the fill 
 74. #  value elsewhere.
 75. #
 76. if hasattr(temp,"_FillValue"):
 77.   tempa = ((tempa-273.15)*9.0/5.0+32.0) *  \
 78.           numpy.not_equal(tempa,temp._FillValue) + \
 79.           temp._FillValue*numpy.equal(tempa,temp._FillValue)
 80.   resources.sfMissingValueV = temp._FillValue
 81. else:
 82.   tempa = (tempa-273.15)*9.0/5.0+32.0
 83. 
 84. temp_units = "(deg F)"
 85. 
 86. cmap = numpy.array([[1.00, 1.00, 1.00], [0.00, 0.00, 0.00], \
 87.                     [.560, .500, .700], [.300, .300, .700], \
 88.                     [.100, .100, .700], [.000, .100, .700], \
 89.                     [.000, .300, .700], [.000, .500, .500], \
 90.                     [.000, .700, .100], [.060, .680, .000], \
 91.                     [.550, .550, .000], [.570, .420, .000], \
 92.                     [.700, .285, .000], [.700, .180, .000], \
 93.                     [.870, .050, .000], [1.00, .000, .000], \
 94.                     [.700, .700, .700]],'f')
 95. 
 96. rlist = Ngl.Resources()
 97. rlist.wkColorMap = cmap
 98. Ngl.set_values(wks,rlist)
 99. 
100. resources.vcFillArrowsOn           = True  # Fill the vector arrows
101. resources.vcMonoFillArrowFillColor = False # in different colors
102. resources.vcFillArrowEdgeColor     = 1     # Draw the edges in black.
103. resources.vcFillArrowWidthF        = 0.055 # Make vectors thinner.
104. 
105. resources.tiMainString      = "~F22~wind velocity vectors colored by temperature " + temp_units
106. resources.tiMainFontHeightF = 0.02  # Make font slightly smaller.
107.
108. vc = Ngl.vector_scalar(wks,ua,va,tempa,resources) # Draw a vector plot of
109. 
110. del vc
111. del u
112. del v
113. del temp
114. del tempa
115. 
116. Ngl.end()

Explanation of example 3

Line 3:

  import numpy

Import the Numerical Python module. You must have this module installed in your Python implementation. This module is used for efficient array processing. The names of the functions in the Numerical Python package are not exposed by this import, meaning that all functions and attributes in that package will have to be qualified with "numpy".

The Numerical Python package is also known as "NumPy".

Line 8:

  import Nio

Import the Nio module for a netCDF reader. This module comes with the PyNGL package). netCDF is a self-documenting and network-transparent data format - see the netCDF User Guide for details.

Line 13:

  import Ngl

Import all of the Ngl functions. The Ngl module must be on your Python search path.

Line 17:

  dirc  = Ngl.pynglpath("data")

The built-in function Ngl.pynglpath returns the full pathname for a given PyNGL system directory, or the default value for a particular internal parameter.

Lines 18-19:

  ufile = Nio.open_file(dirc + "/cdf/Ustorm.cdf","r")  # Open two netCDF files.
  vfile = Nio.open_file(dirc + "/cdf/Vstorm.cdf","r")

This lines open sample netCDF files for reading.

Lines 24-27:

  u = ufile.variables["u"]
  v = vfile.variables["v"]
  lat = ufile.variables["lat"]
  lon = ufile.variables["lon"]

These assignments associate Python NumPy objects with netCDF variables. No data is actually read in making these assignments.

Lines 28-29:

  ua = u[0,:,:]
  va = v[0,:,:]

These lines read data from the netCDF variables into NumPy arrays.

Lines 31-32:

  wks_type = "ps"
  wks = Ngl.open_wks(wks_type,"ngl03p")

Open a workstation for drawing the vector plots.

Line 34:

  resources = Ngl.Resources()

Get ready to set up a list of resources for changing the look of the plot. See example 1 for an explanation of how resources are set. Vector plot resources are part of the "VectorPlot" group and all start with the letters "vc". They are documented in the VectorPlot resource descriptions section.

Data associated with a vector plot is called a "VectorField." VectorField resources start with "vf" and are documented in the VectorField resource descriptions section.

Lines 35-38:

  if hasattr(u,"_FillValue"):
    resources.vfMissingUValueV = u._FillValue
  if hasattr(v,"_FillValue"):
    resources.vfMissingVValueV = v._FillValue

These lines set the U and V missing values for the vector field data based on the values in the netCDF files.

Line 40:

  vc = Ngl.vector(wks,ua,va,resources)

Create and draw a vector plot of the 2-dimensional arrays u and v. The first argument of the Ngl.vector function is the workstation object returned from the previous call to Ngl.open_wks. The next two arguments represent the 2-dimensional vector field to be vectorized (they must have the same dimensions, be of a NumPy type float, double, or integer, and be ordered Y x X). The last argument is the resource list indicating values that you have set that modify the plot.

The default vector plot drawn contains labeled tick marks and a "reference vector" label at the bottom right of the plot. Since no ranges have been defined for the X and Y axes in this plot, the range values default to 0 to n-1, where n is the number of points in that dimension. By default, vectors are drawn with lines and hollow arrow heads, but you can change them to filled vectors as you'll see in a later frame in this example.

Note that there are some areas in the vector plot where no vectors are drawn. This is due to the presence of the missing values in the data.

Line 42:

  #----------- Begin second plot -----------------------------------------

Draw the same vector plot, only this time set some resources to change the length of the vectors and draw them in color.

Line 44:

  resources.vcMinFracLengthF = 0.33

The vcMinFracLengthF resource sets the length of the minimum magnitude vector as a fraction of the length of the reference vector (the default is 0).

Lines 45-47:

  resources.vcRefMagnitudeF  = 20.0
  resources.vcRefLengthF     = 0.045
  resources.vcMonoLineArrowColor  = False   # Draw vectors in color.

The vcRefMagnitudeF resource indicates which magnitude to use for the reference magnitude (the default is 0, a special value that indicates that the maximum magnitude in the vector field is used as a reference magnitude). vcRefLengthF sets the length of the reference magnitude in NDC coordinates (this resource is normally set dynamically according to the number of elements in the vector field and the size of the plot's viewport).

Line 49:

  vc = Ngl.vector(wks,ua,va,resources)

Draw the new vector plot using the resources you just set.

Line 51:

  #----------- Begin third plot -----------------------------------------

Draw the same vector plot, only set some resources to change the the X and Y axis ranges, and add a label bar and a title.

Lines 53-55:

  resources.tiMainString  = "~F22~wind velocity vectors - January 1996"
  resources.tiXAxisString = "longitude"
  resources.tiYAxisString = "latitude"

Create a title and labels for the X and Y axes. PyNGNGL allows special text functions to be embedded in strings to indicate you want things like sub/superscripting, different fonts, carriage returns, etc. By default, each special function is preceded and succeeded with a tilde (~). In the string for the tiMainString resource, the "~F22~" part is a text function indicating that you want to use font 22, which is Helvetica-bold.

If you happen to have a tilde as part of the string, and you don't want it to be interpreted as a function code, then you can use the txFuncCode resource to change the function code character. The various text function codes are documented in the "Text function codes" section.

Lines 57-60:

  resources.vfXCStartV  = lon[0][0]            # Define X/Y axes range
  resources.vfXCEndV    = lon[len(lon[:])-1][0] # for vector plot.
  resources.vfYCStartV  = lat[0][0]
  resources.vfYCEndV    = lat[len(lat[:])-1][0]

The resources vfXCStartV and vfXCEndV indicate the starting and ending data locations along the X axis of the vector field you are plotting. Likewise, vfYCStartV and vfYCEndV indicate the starting and ending data locations along the Y axis of the vector field. If you don't set these resources, then the vf*StartV resources default to 0.0 and the vf*EndV resources default to the number of data elements in that direction minus 1.

Line 62:

  vc = Ngl.vector(wks,ua,va,resources)

Draw the third vector plot with the new resources that you added.

Line 64:

  #---------- Begin fourth plot ------------------------------------------

Create your own color map, color the vectors according to a separate temperature scalar field, and fill the vector arrows.

Lines 66-69:

  tfile = Nio.open_file(dirc+"/cdf/Tstorm.cdf","r")    # Open a netCDF file.
  temp = tfile.variables["t"]
  
  tempa = temp[0,:,:]

Open a netCDF file containing temperature data, read in the first level of the temperature data

Lines 76-82:

  if hasattr(temp,"_FillValue"):
    tempa = ((tempa-273.15)*9.0/5.0+32.0) *  \
            numpy.not_equal(tempa,temp._FillValue) + \
            temp._FillValue*numpy.equal(tempa,temp._FillValue)
    resources.sfMissingValueV = temp._FillValue
  else:
    tempa = (tempa-273.15)*9.0/5.0+32.0

Convert the temperatures from Kelvin to Fahrenheit making sure that the missing values retain their settings. The attribute _FillValue of the netCDF temperature variable is only an attribute of temp and not of tempa.

Line 84:

  temp_units = "(deg F)"

Define the temperature units to be in degrees F for later use.

Lines 86-94:

  cmap = numpy.array([[1.00, 1.00, 1.00], [0.00, 0.00, 0.00], \
                      [.560, .500, .700], [.300, .300, .700], \
                      [.100, .100, .700], [.000, .100, .700], \
                      [.000, .300, .700], [.000, .500, .500], \
                      [.000, .700, .100], [.060, .680, .000], \
                      [.550, .550, .000], [.570, .420, .000], \
                      [.700, .285, .000], [.700, .180, .000], \
                      [.870, .050, .000], [1.00, .000, .000], \
                      [.700, .700, .700]],'f')

Define your own color map. Details on creating your own color map are covered in example 2.

Lines 96-98:

  rlist = Ngl.Resources()
  rlist.wkColorMap = cmap
  Ngl.set_values(wks,rlist)

These calls reset the color map of wks to cmap.

Lines 100-103:

  resources.vcFillArrowsOn           = True  # Fill the vector arrows
  resources.vcMonoFillArrowFillColor = False # in different colors
  resources.vcFillArrowEdgeColor     = 1     # Draw the edges in black.
  resources.vcFillArrowWidthF        = 0.055 # Make vectors thinner.

Setting the vcFillArrowsOn resource to True produces filled vector arrows instead of vector arrows drawn with lines. Setting vcMonoFillArrowFillColor to False fills the vector arrows using multiple colors.

By default, the vcFillArrowEdgeColor resource is set to the background color (index 0). By changing this to the foreground color (index 1), you are making the vector arrows more visible. The vcFillArrowWidthF resource sets the width of the arrows as a fraction of the vcRefLengthF. The default is 0.1.

There's a handy vector arrow diagram in the description of VectorPlot that shows the various components of a vector arrow.

Lines 105-106:

  resources.tiMainString      = "~F22~wind velocity vectors colored by temperature " + temp_units
  resources.tiMainFontHeightF = 0.02  # Make font slightly smaller.

Change the title for the plot and decrease the size of the font. Also, change the font of the title to 26 (Times-bold). Remember that predefined strings, like those listed in the font table, are case-insensitive and you could have specified the above fonts with "times-roman" or "HELVETICA" or any another combination of uppercase and lower case characters.

Line 108:

  vc = Ngl.vector_scalar(wks,ua,va,tempa,resources) # Draw a vector plot of

Use the Ngl.vector_scalar function to draw a vector plot and color the vectors according to the scalar field temp. The Ngl.vector_scalar function is the same as the Ngl.vector function, only it has a scalar field as an additional argument (the fourth argument). The scalar field must have the same dimensions as the U and V arrays.

Line 116:

  Ngl.end()

Required to end the script.