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


Example 10 - publication-quality XY plot

This example creates an XY plot and shows how to draw text strings on it using calls to Ngl.text. It also shows how to use various text function codes to create subscripts, line feeds, and change the default font.

This example produces a publication-quality plot.

There are two ways to run this example:

execute

    pynglex ngl10p
or download
ngl10p.py
and then type:
python ngl10p.py

Output from example 10

Frame 1

(Click on the frame to see it enlarged.)


  0. #
  1. #  Import NumPy.
  2. #
  3. import numpy
  4. 
  5. #
  6. #  Import PyNGL support functions.
  7. #
  8. import Ngl
  9. 
 10. #
 11. #  The function "wigley" performs computations on the input array
 12. #  based on where the values are less than 1953, are between
 13. #  1953 and 1973 inclusive, or greater than 1973.
 14. #  
 15. def wigley(time):
 16.   y = numpy.zeros(time.shape).astype(type(time))
 17.   numpy.putmask(y,numpy.less(time,1953.),         \
 18.                 ((time-1860.)/(1953.-1860.)) * 35.0)
 19.   numpy.putmask(y,numpy.logical_and(numpy.greater_equal(time,1953.),  \
 20.                                     numpy.less_equal(time,1973.)),    \
 21.                 ((time-1953.)/(1973.-1953.)) * (68. - 35.) + 35.)
 22.   numpy.putmask(y,numpy.logical_and(numpy.greater(time,1973.),        \
 23.                                     numpy.less_equal(time,1990.)),    \
 24.                 ((time-1973.)/(1990.-1973.)) * (75. - 68.) + 68.)
 25.   return y
 26. 
 27. #
 28. #  Main program.
 29. #
 30. time1 = numpy.array([1990,  1985,  1980,  1970,  1960,  1950,  1940,  1930, \
 31.                      1920,  1910,  1900,  1890,  1880,  1870,  1860],
 32.                      'i')
 33. y1    = numpy.array([68.065, 65.00, 70.67, 63.06, 43.42, 28.28, 23.00,  \
 34.                      20.250, 17.77, 15.36, 10.01,  6.40,  3.98,  2.18,  \
 35.                       1.540], 'f')
 36. 
 37. time2 = numpy.arange(min(time1),max(time1)+1,1)
 38. 
 39. y2 = wigley(time2)      # Calculate proposed values as a function of time.
 40. 
 41. maxdim = max(y1.shape[0],y2.shape[0])
 42. y    = -999.*numpy.ones((2,maxdim),'f')  # Create 2D arrays to
 43. time = -999.*numpy.ones((2,maxdim),'f')  # hold 1D arrays above.
 44. 
 45. y[0,0:y1.shape[0]] = y1
 46. y[1,0:y2.shape[0]] = y2
 47. 
 48. time[0,0:time1.shape[0]] = time1.astype('f')
 49. time[1,0:time2.shape[0]] = time2.astype('f')
 50. 
 51. #
 52. #  Define a color map and open a workstation.
 53. #
 54. cmap = numpy.zeros((2,3),'f')
 55. cmap[0] = [1.,1.,1.]
 56. cmap[1] = [0.,0.,0.]
 57. rlist = Ngl.Resources()
 58. rlist.wkColorMap = cmap
 59. wks_type = "ps"
 60. wks = Ngl.open_wks(wks_type,"ngl10p",rlist)
 61. 
 62. resources = Ngl.Resources()
 63. 
 64. resources.caXMissingV = -999.
 65. resources.caYMissingV = -999.
 66. 
 67. resources.vpWidthF     = 0.8
 68. resources.vpXF         = 0.13
 69. 
 70. resources.tiMainString  = "~F22~Sulfur Emissions" # "~F22~" changes
 71. resources.tiXAxisString = "~F22~Year"             # the font to "22"
 72. resources.tiYAxisString = "~F22~Tg s/yr"          # which is helvetica
 73.                                                     # bold.
 74. resources.tmXBLabelFont = "helvetica"
 75. resources.tmYLLabelFont = "helvetica"
 76. 
 77. resources.trXMinF              = 1855 # Set minimum X axes value.
 78. 
 79. resources.xyDashPatterns       = [16,0]   # ( dash, solid )
 80. resources.xyMarkLineModes      = ["MarkLines","Lines"]
 81. resources.xyMarker             = 1
 82. resources.xyMarkerSizeF        = 0.05 # Default is 0.01
 83. 
 84. resources.nglFrame             = False # Don't advance the frame.
 85. 
 86. xy = Ngl.xy(wks,time,y,resources)  # Create and draw XY plot.
 87. 
 88. txresources               = Ngl.Resources()
 89. txresources.txFontHeightF = 0.015
 90. txresources.txJust        = "CenterLeft" # Default is "CenterCenter".
 91. txresources.txFuncCode    = "~"          # Default is "~"
 92. 
 93. strings = ["Wigley (Moller/IPCC)",\
 94.        "~F22~CSM-proposed:~F~~C~(Orn et.al./GEIA + Smith)",\
 95.        "~F22~CSM SO~B~4~N~ Scaling Factor: ~V1Q~~F22~S~B~emis~N~ (yr)~H-7Q~~V-1Q~---------------~H-9Q~~V-1Q~S~B~emis~N~ (1985)"]
 96. 
 97. xpos = [1885.,1940.,1860.]   # Define X/Y locations for text.
 98. ypos = [30.,18.,70.]
 99. 
100. #
101. #  Loop through text strings and plot them.
102. #
103. for i in xrange(0,len(strings)):
104.   Ngl.text(wks,xy,strings[i],xpos[i],ypos[i],txresources)
105. 
106. Ngl.frame(wks)
107. 
108. Ngl.end()

Explanation of example 10

Line 15:

  def wigley(time):

Define a Python function called wigley to calculate some values as a function of time. These calculated values are returned in a NumPy float array of the same shape as the input variable time.

Lines 30-35:

  time1 = numpy.array([1990,  1985,  1980,  1970,  1960,  1950,  1940,  1930, \
                       1920,  1910,  1900,  1890,  1880,  1870,  1860],
                       'i')
  y1    = numpy.array([68.065, 65.00, 70.67, 63.06, 43.42, 28.28, 23.00,  \
                       20.250, 17.77, 15.36, 10.01,  6.40,  3.98,  2.18,  \
                        1.540], 'f')

Define some data for the XY plot. These data are from a number of sources and were compiled to show the total global annual emissions of sulfur.

Line 37:

  time2 = numpy.arange(min(time1),max(time1)+1,1)

Set time2 to an array of time values spanning time1 in unit increments.

Line 39:

  y2 = wigley(time2)      # Calculate proposed values as a function of time.

Interpolate the data using the wigley function defined above.

Lines 41-49:

  maxdim = max(y1.shape[0],y2.shape[0])
  y    = -999.*numpy.ones((2,maxdim),'f')  # Create 2D arrays to
  time = -999.*numpy.ones((2,maxdim),'f')  # hold 1D arrays above.
  
  y[0,0:y1.shape[0]] = y1
  y[1,0:y2.shape[0]] = y2
  
  time[0,0:time1.shape[0]] = time1.astype('f')
  time[1,0:time2.shape[0]] = time2.astype('f')

To create an XY plot that draws the actual data values (y1) and the interpolated data values (y2) as two separate curves, define a 2-dimensional array y to hold the values for both of these curves, where the first dimension is the number of curves (2) and the second dimension is the number of points. The two curves might not have the same number of points, so the second dimension of y is set to the maximum of the dimensions of y1 and y2.

Multiplying by -999.0 in the initial array creations sets that as the initial value for all array elements. This will be specified as the coordinate array missing value for the curves so that Ngl.xy does not plot any such values.

Lines 54-60:

  cmap = numpy.zeros((2,3),'f')
  cmap[0] = [1.,1.,1.]
  cmap[1] = [0.,0.,0.]
  rlist = Ngl.Resources()
  rlist.wkColorMap = cmap
  wks_type = "ps"
  wks = Ngl.open_wks(wks_type,"ngl10p",rlist)

Define a color map with a black foreground and a white background and open a workstation. Details on defining color maps are given in example 2.

Lines 64-65:

  resources.caXMissingV = -999.
  resources.caYMissingV = -999.

Specify the coordinate array missing values for X and Y.

Line 77:

  resources.trXMinF              = 1855 # Set minimum X axes value.

Change the minimum value of the left bound of the X axis (the actual minimum of the X axis is 1860). This is to provide extra space around the curves.

Lines 79-82:

  resources.xyDashPatterns       = [16,0]   # ( dash, solid )
  resources.xyMarkLineModes      = ["MarkLines","Lines"]
  resources.xyMarker             = 1
  resources.xyMarkerSizeF        = 0.05 # Default is 0.01

Set some resources so that the actual data values are drawn with a dashed line and round markers and the interpolated values are drawn with a solid line. The marker size is increased by a factor of 5, since the default size is 0.01.

Line 84:

  resources.nglFrame             = False # Don't advance the frame.

Since you are drawing text strings on the XY plot with separate calls to Ngl.text, you don't want the frame to be advanced yet.

Line 86:

  xy = Ngl.xy(wks,time,y,resources)  # Create and draw XY plot.

Call Ngl.xy to draw the XY plot with the two curves.

Line 90:

  txresources.txJust        = "CenterLeft" # Default is "CenterCenter".

Change the resource that determines how strings are centered with respect to the X/Y position they are drawn at. By setting the txJust resource to "CenterLeft", strings are centered vertically about the Y coordinate location, and flush left horizontally with respect to the X coordinate location. The default of txJust is "CenterCenter".

Line 91:

  txresources.txFuncCode    = "~"          # Default is "~"

As noted in example 5, PyNGL allows text function codes to be embedded in strings to get sub/superscripting, different fonts, carriage returns, etc. By default, each function code is preceded and succeeded with a colon, so use the txFuncCode resource to set the function code to something other than a colon. This is only necessary if you want to use a colon as part of one or more of the text strings. In this case, you are changing the function code to "~".

Lines 93-95:

  strings = ["Wigley (Moller/IPCC)",\
         "~F22~CSM-proposed:~F~~C~(Orn et.al./GEIA + Smith)",\
         "~F22~CSM SO~B~4~N~ Scaling Factor: ~V1Q~~F22~S~B~emis~N~ (yr)~H-7Q~~V-1Q~---------------~H-9Q~~V-1Q~S~B~emis~N~ (1985)"]

Define three strings to draw on the plot. You are using text function codes to change the font to Helvetica-bold ("~F22~"), to change the vertical and horizontal spacing ("~V1Q~", "~V-1Q~", "~H-7Q~", and "~H-9Q~"), to add a carriage return ("~C~"), and to do subscripting ("~B~"). The function codes "~F~" and "~N~" are used to return to the default font and to get out of subscript mode.

Lines 97-98:

  xpos = [1885.,1940.,1860.]   # Define X/Y locations for text.
  ypos = [30.,18.,70.]

Create two arrays to define the X and Y positions of each of the three text string you created above. The X and Y positions are specified in the same data space as the curves in the XY plot you created.

Lines 103-104:

  for i in xrange(0,len(strings)):
    Ngl.text(wks,xy,strings[i],xpos[i],ypos[i],txresources)

Loop through the list of text strings you created and draw each one using Ngl.text.