Resource files

What are resource files?

Resource files are ASCII files containing lines of data in which values are assigned to resources. A PyNGL resource file allows you to set PyNGL resources in a manner similar to X11 resources that you set in .Xdefaults or .Xresources files.

For example, in the PyNGL tutorial, example 9 has a resource file associated with it called "ngl09p.res" that contains the lines:

*vpXF                        : 0.05
*cnFillOn                    : True
*mpProjection                : Stereographic
These resources change the X position of the plot in the viewport, turn contour fill on, and change the map projection to "Stereographic."

There are three levels of resource files: 1) a system resource file, 2) a user resource file, and 3) an individual script resource file. Each one of these, if they exist, are loaded in the order listed, each one overriding any resources set in the previous resource file.

The first resource file loaded, the system resource file, is called "sysresfile" and must reside in the directory echoed by running:

import Ngl
print  Ngl.pynglpath("sysresfile")
This resource file will be loaded every time somebody imports Ngl from that system. If you look at this file, you will see certain resources being set: If you want different defaults for users of PyNGL on that system, then you can set or change them in this "sysresfile" file.

The second resource file loaded (if it exists) is a user resource file called ".hluresfile" that should reside in a user's home directory. This resource file will be loaded every time that user runs PyNGL, and will be loaded after the system resource file. Thus, if the user sets any of the same resources as the ones in "sysresfile", these resource values will override the ones in "sysresfile". This file is particularly useful if the user doesn't like the defaults set in the "sysresfile".

The third resource file loaded (if it exists), is the individual script resource file. This file needs to have the same name as the name argument to Ngl.open_wks, with a ".res" appended. Any resources set in this file will override resources set in the ".hluresfile" or "sysresfile" files.

Any resources you set in any of these resource files that are misspelled or don't apply to the kind of plots you are creating are ignored. No error messages are printed, so you must be careful to spell the resource names correctly.

Why (or why not) to use resource files

There are many reasons why you may want to use a resource file rather than setting resources directly in your PyNGL script:
  1. They allow you to see all or most of your resources in one location. You can view your resources easier this way, since they are not interspersed with other lines in your PyNGL script.

  2. They may speed up the processing of your PyNGL script, especially if you have lots of resources. This is because PyNGL can generally load a resource file faster than it can process resources scattered throughout a PyNGL script.

  3. One resource file can apply to many PyNGL scripts, saving you the task of entering the same resource in multiple PyNGL scripts.

  4. A resource file that contains the line:

    *Font : name_of_font
    
    allows you to change all of the fonts in your plot to a particular font. There is currently no way to change all the fonts in your plot with one line inside a PyNGL script.

  5. Resource files can be used to create stylized plots.

There are also some reasons why you may not want to use a resource file:
  1. You may forget that you have a resource file, and spend a lot of time trying to figure out why your PyNGL script is behaving differently than you expect.

  2. Some people prefer to have their PyNGL code and resources in one place, rather than split between two files.

  3. If you misspell a resource in the resource file, you don't get an error message (like you do in a PyNGL script). This makes resource files difficult to debug.

  4. If you load other scripts that set resources for you, then these settings will override any that you set in a resource file.

  5. Some special resources, like the ngl and skt cannot be set in a resource file.

How to create resource files

General format

The simplest way to set a resource in a resource file is to start off with an asterisk ("*"), immediately followed by the name of the resource, followed by a colon (":"), followed by the value of the resource. There must be no space between the asterisk and resource name, but you can have as many spaces as you want before and after the colon. Only one resource can be set per line, and comments begin with the "!" character. For example, in the following five lines:

! This is a comment.
*tiMainFont        : 25
*tiMainString      : This is a title
*mpFillOn          : True
*cnLevelSpacingF   : 0.10
the first line is a comment, and the next four lines set the resources for changing the title font to 25 ("times-roman"), creating a title, turning map fill on, and setting the contour level spacing to 0.10. Note that the string "This is a title" does not require double quotes around it as it would in a PyNGL script. If you put quotes around the string, then the quotes will appear as part of the title.

Resource types

Resources can have four different types: float, integer, string, and logical, and can be scalars or multi-dimensioned arrays.

Setting scalar resources

To set a scalar resource, succeed the ":" character with the value of the resource as a float, integer, string, or logical. You've already seen how to do this in the example above:

*tiMainFont        : 25
*tiMainString      : This is a title
*cnLevelSpacingF   : 0.10
*mpFillOn          : True
The first resource is being set with the integer "25", the second resource with the string "This is a title", the third resource with the float "0.10", and the fourth resource with the logical "True".

The number "25" that is being used to set the font is an enumerated value (an integer that represents a predefined string). When used with a font resource, the number "25" is an index into a font table and represents the font "times-roman". This resource could also be set with:

*tiMainFont        : times-roman
Again, note that there are no quotes around "times-roman". If you had put quotes around this resource:

*tiMainFont        : "times-roman"
then you would have gotten an error message that looks like the following:

   fatal:NhlCvtStringToEnum: Unable to convert string ""times-roman"" to requested type 
Logical values can be set with the strings True or False, or the integers 0 or 1. Both True and False must be capitalized and must not have quotes around them.

Setting array resources

The processor for resource files expects array syntax compatible with the underlying legacy code. For example, to set the resource xyExplicitLabels to a 1-dimensional string array, do the following:

*xyExplicitLabels:  (/curve 1, curve 2, curve 3, curve 4/)

And to set the resource wkColorMap to a 15 x 3 float array, do the following:

*wkColorMap:   (/(/ 0.00, 0.00, 0.00 /),(/ 0.66, 0.66, 0.66 /),\
                 (/ 0.40, 0.40, 0.40 /),(/ 0.00, 1.00, 1.00 /),\
                 (/ 0.20, 0.56, 0.80 /),(/ 0.00, 0.00, 1.00 /),\
                 (/ 0.50, 0.00, 1.00 /),(/ 1.00, 0.00, 1.00 /),\
                 (/ 0.14, 0.56, 0.14 /),(/ 0.00, 1.00, 0.00 /),\
                 (/ 1.00, 1.00, 0.00 /),(/ 0.86, 0.58, 0.44 /),\
                 (/ 0.65, 0.16, 0.16 /),(/ 1.00, 0.50, 0.00 /),\
                 (/ 1.00, 0.00, 0.00 /)/)
Note: The "\" character is used as a continuation line in a resource file.

Wildcards

In a resource file, the asterisk in front of the resource name serves as a wildcard character. In other words, the line:

*cnFillOn : True
causes contour fill to be turned on for all contour plots in an PyNGL script to which the resource file is applied, unless cnFillOn is set to False for a particular contour plot within the PyNGL script. Resources set in a PyNGL script override resources set in a PyNGL resource file.

You can force resources in a resource file to only apply to certain plots by replacing the wildcard asterisk character with "qualifiers". Whenever you call a PyNGL function that creates a plot, a name is given internally to that plot (in addition to the function returning a reference to the plot), and this name can be used as a qualifier in a resource file. The name given to a plot created by a call to a PyNGL function is the second string passed to Ngl.open_wks, followed by an underscore ("_"), followed by a string indicating type of plot being created.

For example, if you create a contour plot and a vector plot with the following calls:

  . . .
  wks = Ngl.open_wks("x11","myplot")
  . . .
  contour = Ngl.contour(wks,cdata,cnresources)
  vector  = Ngl.vector(wks,vdata,vcresources)
  . . .
then the function Ngl.contour assigns the name "myplot_contour" to the contour plot, and the function Ngl.vector assigns the name "myplot_vector" to the vector plot. If you call a PyNGL function that creates two plots, like Ngl.contour_map, then this function assigns the name "xxx_contour" to the contour plot and "xxx_map" to the map plot, where xxx is the second string passed to Ngl.open_wks.

For example, in the following two lines in the resource file for example 9:

*ngl09n_contour.pmLabelBarDisplayMode : Always
*ngl09n_map.pmLabelBarDisplayMode     : Never
the strings "ngl09n_contour" and "ngl09n_map" are internal names assigned by Ngl.contour_map to the contour and map plots. These strings are used as qualifiers to force a label bar to be drawn for the contour plot and not for the map plot. If you had just set:

*pmLabelBarDisplayMode : Always
then you would have gotten a label bar with both the map plot and the contour plot.

You can fully qualify a resource to the point where there are no wildcard characters. Here's a basic template for what a fully-qualified resource name would look like in a resource file:

application_name.workstation_name.plot_name.resource_name : resource_value
In the PyNGL suite of functions, application_name is the second string passed to Ngl.open_wks and workstation_name is the same string with "_x11", "_ps", "_pdf", or "_ncgm" appended, depending on what kind of workstation was opened in the call to Ngl.open_wks.

Any place where you don't want to use one of the qualifying names, you can just replace it with a wildcard character. For example, let's assume you opened two workstations with the following lines:

  xwks = Ngl.open_wks("x11","example")
  pswks = Ngl.open_wks("ps","example")
Let's further assume you want to draw a contour plot, but that you only want to have a title drawn with it in the PostScript file. Then, you would have an entry in your resource file that looks like this:
*example_ps*tiMainString   : This is a title
The string "example_ps" is the name given to the PostScript workstation by the call to Ngl.open_wks. Note that a wildcard character appears between this qualifier and the resource name. This is because normally the qualifier plot_name would appear after the workstation name, but since you don't need it in this case, you can replace it with a wildcard character.

The fully qualified path of the above resource would be:

example.example_ps.example_contour.tiMainString  : This is a title
The documentation for the PyNGL functions contains information about the internal names given to the various plots, workstations, and data objects.

It is important to note that this internal naming scheme of the PyNGL functions and procedures is somewhat limiting. For example, if you create two separate contour plots with a call to Ngl.contour and they are both being drawn to the same workstation, then they will both have the same internal name. This means that if you want to set the same resource for both of them, but with different values, you can't do it from a resource file because there is no way to distinguish the two contour plots from each other.

Where to put individual resource files

By default, the PyNGL interpreter looks for an individual resource file in the same directory where PyNGL is being executed. In the PyNGL suite of functions, if you want to change this default directory, create an attribute of the second string passed to Ngl.open_wks called "appUsrDir" and set its value to whatever directory you want PyNGL to look in for the resource file. For example, if your PyNGL script is in "/usr/home/smith/scripts/plotxy.py", and your resource file is in "/usr/home/smith/resfiles/plotxy.res", then set appUsrDir as follows in the "/usr/home/smith/scripts/plotxy.py" file:
  . . .
  resname = "plotxy"
  resname.appUsrDir = "/usr/home/smith/resfiles"
  wks = Ngl.open_wks("x11",resname)
  . . .
Remember, PyNGL looks for a resource file by the name resname.res, where resname is the second argument (a string) passed to Ngl.open_wks.