GRAFLIB is a subroutine call library that NERSC users have used to produce line and contour plots. NCAR has similar capabilities. This transition guide will concentrate on converting GRAFLIB line and contour plots to NCAR from a FORTRAN program using the low-level routines in NCAR. If you are creating a new graphics program from scratch, you might want to check out the high-level routines in NCAR (HHL). Also, if you are new to using NCAR, check out the NCAR tutorial at http://www.nersc.gov/training/
The type of graphics routine (i.e., line, text, etc.) organizes this document. Throughout the document there are code fragments demonstrating the concepts.
There are a few things that are important to know about NCAR.
The way GRAFLIB and NCAR are initialized and how you define what device you want to plot to are similar. GRAFLIB calls the devices you plot to view surfaces, NCAR calls them workstations. GRAFLIB uses a separate subroutine call for specifying each device, where NCAR specifies the device by a number within the "open" workstation routine.
Special Notes:
|
Graflib: |
NCAR: |
|
|
Open Graphics System call gnglxx (wrkarray, length) wrkarray (real array) - work arraylength (int) - size of work array |
call gogks (ier, idum) ierr (int) - fortran unit number for error messagesidum (int) - dummy, not used. |
|
|
Close Graphics System: call geglxx (dummy) dummy (int) - dummy variable |
call gclks |
|
|
Open device: call gndevice (0)
|
call gopwk (iwkid, iconid, iwktype)
iwkid (int) - workstation identifier (similar to vs_num in GRAFLIB gnvsxx)iconid (int) - Depends on the device specified by iwktype. In most cases it is ignored. If used (e.g., CGM), it is the fortran logical unit that is used internally for writing to a file. Be careful not to use this same unit number elsewhere in your program for reads or writes.iwktype (int) - workstation typeExamples:
|
|
|
Activate device: call gnvsxx (vs_num, ....) vs_num (int) - view surface number(see gopwk for how this identifier is defined in NCAR.) ... rest of arguments dependent on device opened. |
call gacwk (iwkid) iwkid - workstation identifier specified in gopwk. |
|
|
Deactivate device: call gdusxx (vs_num) vs_num (int) - view surface number |
call gdawk (iwkid) iwkid - workstation identifier specified in gopwk. |
|
|
Reactivate device: call gcvsxx (vs_num) vs_num (int) - view surface number |
See "gacwk" for reconnecting the workstation. |
|
|
Close device: call gevsxx (vs_num) vs_num (int) - view surface number |
call gclwk (iwkid) iwkid - workstation identifier specified in gopwk |
|
|
Misc. Routines: call gsvsfn - FR80 file name. call gsvskp - keep /give file status. |
There is no correspondence in NCAR for these routines. Comment them out. |
|
The order of the subroutine calls to open, initialize, and close NCAR are important. The minimum calls needed are:
call gopks (ier, idum) call gopwk (iwkid, iconid, iwktype) call gacwk (iwkid) < graphics calls > call gdawk (iwkid) call gclwk (iwkid) call gclks
Here are two ways to change the name of the file that NCAR will be creating. The first is the easiest to do and change. When the environment variable NCARG_GKS_OUTPUT is defined, NCAR will use this filename when creating the CGM. For example,
% setenv NCARG_GKS_OUTPUT mycgm.1
The other way is within your Fortran code, after you open GKS (gopks) and before you open the workstation (gopwk):
character*80 fname, cdum fname = "mycgm.1" call gopks (…) call gesc (-1391, 1, fname, 1, 1, cdum) call gopwk (…)
How you define where to place your plot on the frame and how the limits of your data are defined is similar between the two systems. Only the Names are different.
|
Graflib: |
|
|
Define coordinate systems: call gswd2d(type,xmin,xmin,ymin,ymax) xmin ,... defines the user coordinate system.vxmin ,...defines where on the frame the data is plotted.type defines the type of transformationlinlin$ or 0 loglin$ or 1 linlog$ or 2 loglog$ or 3 |
call set(vxmn,vxmx,vymn,vymx,xmn,xmx,ymn,ymx,itype)
vxmn,... defines where on the frame the data is plotted..xmn,.... defines the user coordinate system.itype (int) defines the transformation.1 = linlin 2 = linlog 3 = loglin 4 = loglog |
|
Changing Coordinate System: call gscpvs( x,y) set current positioncall gscp2d (x,y) set current position |
|
|
Misc. Routines: call gswdnx(nice)
0=nothing, 1=modify the limits of the user coords. to create "nice" values.
|
The nice feature in GRAFLIB modified the limits of your data so that when you called the routine to plot a grid, nice tick labels were produced starting at the endpoints of the grid. If you use thc method described in "Grids and Labels", a somewhat similar capability is available. See "Grids and Labels" for how to do this. |
Routines that advance to the next frame, flush buffers, clip, etc.
|
Graflib: |
Paste: |
||
|
Advance Frame: call gxglfr(dummy) ilvs (int) - advances frame for only the specified view surface. |
call frame advances to the next frame for all activated workstations. |
||
|
Clipping: call gsvtcl(iclip) iclip (int)"on$" or 1 to clip "off$" or 0 to not clip |
call gsclip (clip) clip (int )0 = clip 1 = no clip |
||
|
Update plotting: call gxglup(dummy) ilvs (int) - updates only the specified view surface. |
call sflush Updates all open workstations. |
||
|
Misc. routines. gsuskp (<get/keep status of file>) |
This routine has no correspondence in NCAR. Comment it out. |
NCAR has at least two ways to produce a grid, ticks, labels, etc. The first method used the features of NCAR called "Autograph". This method is recommended because it best matches the capabilities of GRAFLIB, and is the easiest to use. Autograph also has the capability to draw complete line graphs. We do not recommended using Autograph for drawing lines for GRAFLIB users because the DASHPACK routines support curve smoothing better. "Here better" means that you do not need to change the libraries you load, and smoothing is turned off and on by a flag similar to GRAFLIB.
The second method would be to use the grid routines in NCAR, e.g., GRIDAL. These routines have a lot of flexibility, but you need to provide more information. If you are interested in using these routines, see "man gridall" and "man gridall_params".
|
Graflib: |
NCAR: |
|
|
Draw a grid: call gpgr80 (type) type - type of transformationlinlin$ or 0 loglin$ or 1 linlog$ or 2 loglog$ or 3 |
See the examples at the end of this section for how to duplicate drawing grids, labels, etc. |
|
Individual parameter setting routines |
call agsetc ("name", "char_value")
|
|
xm, xn (int) - type of major and minor lines for x.or call gsgrxm(value) and call gsgrnx(value) where value: Ticks = 0, Grid = 1 |
call agsetr ('BACKGROUND.' , val) val (real) where:1.0 = perimeter background (default) 2.0 = grid background 3.0 = half-axis background 4.0 = no background. |
|
|
ym, yn (int) - type of major and minor lines for y.or call gsgrym(value) and call gsgrny(value) where value is an integer: Ticks = 0, Grid = 1 |
Defined by the agsetr call immediately above. |
|
|
call agsetr ('AXIS/TICKS/MINOR/SPACING.). value )where value (real) means: -1. Suppresses minor ticks >=1. Specifies the number of minor ticks 0. specifies the NCAR will choose the number of minor ticks. |
|
|
|
|
|
call gswdnx( nice)call gswdny(nice)
0=nothing, 1=modify user coords. to create "nice" values. |
call agsetr ('X/NICE.', value)
where value (real) -1. x/y forces major-tick positions at the endpoints of the axis (default - similar to GRAFLIB's nice). +1. Forces major tick positions at the endpoints of the top (x) or right (y) axis. 0.0 specifies that the major ticks are not forced at the ends of either axis (same as GRAFLIB's no nice). |
|
To create a grid with axis, ticks, and tick labels without drawing lines and axis titles, do:
c specifies no frame advance after the call to ezxmy so you can add your curves, contours, etc.
call agseti ('frame.', 2)
c don't have ezxmy draw the curves nor change the limits of the data defined by the call to set.
call agseti ('SET.', -4)
c I don't think the next calls are needed because of the previous call, but I do it for completeness.
data_x(1) = xmin ! set the values of data_x and data_y to the limits of your data,
data_x(2) = xmax ! defined in the call to set.
data_y(1) = ymin
data_y(2) = ymax
c suppress x and y axis titles, NOTE that the call order is critical.
call agsetc ('LABEL/NAME.', 'B') ! x axis
call agseti ('LABEL/SUPPRESSION FLAG.', 1)
call agsetc ('LABEL/NAME.', 'L') ! y axis
call agseti ('LABEL/SUPPRESSION FLAG.', 1)
C draw grid, also suppressing the graph title
call ezmxy (data_x, data_y, 1, 1, 1, '')
To have the titles plotted (x and y axis titles, and graph titles) do:
call agseti ('frame.', 2)
call agseti ('SET.', -4)
c I don't think the next calls are needed because of the previous call, but I do it for completeness.
data_x(1) = xmin ! set the values of data_x and data_y to the limits of your data,
data_x(2) = xmax ! defined in the call to set.
data_y(1) = ymin
data_y(2) = ymax
c specify the x and y axis titles, NOTE that the call order is critical.
call agsetc ('LABEL/NAME.', 'B') ! x axis
call agseti ('LINE/NUMBER.', -100)
call agseti ('LINE/TEXT.', xlabel) ! xlabel is a character string
call agsetr ('LIN/CH.', .03) ! increase the size of the characters
call agsetc ('LABEL/NAME.', 'L') ! y axis
call agseti ('LINE/NUMBER.', -100)
call agsetr ('LIN/CH.', .03) ! increase the size of the characters
call agseti ('LINE/TEXT.', ylabel) ! ylabel is a character string
C draw grid with the graph title
call ezmxy (data_x, data_y, 1, 1, 1, 'My Title')
Expect to see differences when you plot text, especially if you used a lot of the bells and whistles of GRAFLIB. The fonts are different and each package has some unique parameters that can be changed. Some special things to be aware of are:
|
Graflib: |
NCAR: |
|
|
Plot Text: call gptx2d ("string$") where string contains the characters to plot. The string must end with a "$". before the call to gptx2d, calls could be made to: |
call plchhq(xpos,ypos,chrs,size,ang,cntr) xpos,ypos (real) defines the position to plot the textchrs (string) is the character string to plotsize (real) is the approximate size of the character string. To get the approximate width as in GRAFLIB, pass 1/(characters per line). For example, GRAFLIB's default was 72 character per line, which would be 1/72. This will give you about the same height. The width will be different, because NCAR uses proportional fonts.ang (real) is the angle to plot the string. Same as in GRAFLlB.cntr (real) defines the position of the string, where:-1. left justified; 1. right justified; 0. centered |
|
Individual text parameter setting routines |
Similar NCAR Parameters |
|
|
Parameters to settx (and alternative calls) Font: 'ift' - font number orcall gstxft(ifont) where ifont is the number of the font to use. |
|
|
|
Text line width: |
|
|
|
'fan' (real) - angle to plot textor call gstxan(angle) |
Passed as an argument in the call to plchhq. |
|
|
'ixj' , 'iyj' (int) - justification of stringor call gstxjf(just,just) where ixj can be 'left', 'right', or 'center' and iyj can be 'top', 'bottom', or 'center'. |
Passed as an argument in the call to plchhq. |
|
|
'fno' (int) - number of characters per line, i.e., character width.or call gstxno(size) |
Passed as an argument in the call to plchhq. |
|
By changing parameters, GRAFLIB could plot lines, markers, and disjoint lines with or without smoothing. NCAR has a more than one way to draw lines and markers. The examples below show how to use the DASHPACK routines in NCAR. These routines are recommended over curve and curved because smoothing can be done without loading anything special, and because parameters can be set through subroutine calls. Some special notes are:
|
|
||
|
|
||
|
Plot a line when n points
|
|
||
|
Paramter setting routines: Parameters can be set by calling setcv, or the individual grid parameter routines. call setcv("xx=value, xx=value....$")
|
|
||
|
Some Parameters & alternate calls |
|
||
|
|
||
|
|
||
|
|
||
|
>=0. Desired tension to be used on the cubic splines used to do the smoothing. |
||
|
nc (int) - 0= off , nice orientation of labels |
NCAR alreadys does a really nice orientation of labels. The parameter 'SAF' gives you quite a bit of control over orientation, but is different then the GRAFLIB nice factor. |
||
|
call gslnst(value) sets line style (int), which varies from 1-20, where 1=solid line. |
call gsln (itype) where itype can be:
If you need more line styles, you can create almost any style you want by setting various parameters. Check out "man dashpack" or the example at the end of this section. |
||
|
call gslnsz (size) set line size (width), where 0. is the default. |
call gslwsc (size) Sets the line width scale factor. A value of 1.0 is the default line width. A value of 0.0 produces no lines, where 2.0 will double the line width on most devices. That is, the displayed line width is dependent on the hardware capabilities of the graphics device being used. A simple way of going from graflib to ncar size is: ncar_size = graf_size*10. + 1. |
Defining line styles in NCAR via the dashpack parameters:
subroutine dashpat(num)
c routine that produces 10 dash line patterns
c It is a simple routine, because previous states are not
c saved and restored. '$' represent a solid line, '_'
c represent a blank. The line patterns are stored in dashpt
c and their length in dashsz.
integer dashsz(10)
character*10 dashpt(10)
data dashpt /'$', '$_', '$$__', '$$$$___',
x '$$$$$$____', '$$_$_$$_$_', '$$$$_$_',
x '$$$$$__$__', '$$_$_$_', '$$$$$_$_$_'/
data dashsz/1, 2, 4, 7, 10, 10, 7, 10, 7,10/
c
c If num is greater than 10, make it 10
num_dash = num
if (num_dash .gt. 10) num_dash = 10
call dpseti ('DPS', 0)
call dpsetc ('DPT', dashpt(num_dash))
call dpseti ('DPL', dashsz(num_dash))
c
return
end
It is difficult to give a one-to-one correspondence between contouring for GRAFLIB and NCAR. They both have a rich set of routines and options. The best way to convert is to look at the examples shown here, or use the examples of contouring in ncargex (execute 'ncargex -conpack'). You might want to use the higher level routines in NCAR (see how to run these examples by executing ng4ex -contourplot'), but I have not. looked them over or tried them out.
An on-line version of NCAR's contouring package (CONPACK) and a tutorial is accessible from the web at: http://ngwww.ucar.edu/ngdoc/ng4.0.1/conmaptutor/tutorhome.html. These web pages have important information and examples. It has a lot of useful information in it that this simple guide cannot duplicate.
Some things to note:
|
|
||
call gpctv1 (…) |
|
||
|
Smooth Labeled Contours on a Rectangular Grid:
|
|
||
|
Rectangular Mesh with X & Y spacing supplied (No Labels): call gpctv2(…) |
|
||
|
|
||
|
|
||
|
Smooth Contour from random (irregular) mesh: call gpcts3 (…) |
|
||
|
Random X,Y, Z Points: call gpctvx (…) |
|
||
|
call gpctsx () |
|
||
|
Parameters to setcv (and alternative calls) Font: 'ilb' - contour label switch (0=off, 1=on) |
|
||
|
fmn,fmx - min & max label for label mode 4. (See the description of imd immediately following.) |
|
||
|
imd - format of labels if ilb is turned on. The possible values of imd and their meanings are:1 = label the contour lines alphabetically (A-Z) 2 = use E format 3 = use F format (default) 4 = use G format, where fmn & fmx define the range. Labels above and below fmn & fmx are plotting in E format. Otherwise, labels are plotted in F format. 5 = use integer format 0 = if 0, then use the text labels defined in itx = the format to use, e.g., "xf.w" |
To simulate the GRAFLIB behavior:
data clab/ 'A', 'B', 'C', 'D'/
call cpseti ('LLP', 2)
do I = 1, ncl
call cpseti ('PAI', I)
call cpsetc ('LLT', clab(I))
call cpseti ('CLU', 3)
endo
E format labels: call cpseti ('NET', 0)
F format labels default G format call cpseti('LLP', 2)
do i = 1,ncl
call cpseti('PAI',I)
call cpgetr('CLV', clv)
if ( clv .gt. fmx or
clv .lt. fmn) then
call cpseti('NET',0)
endif
enddo
Integer Format call cpseti ('SFS', -4)
Specified format character*10 clab
call cpseti('LLP',2)
do i = 1,ncl
call cpseti('PAI',I)
call cpgetr('CLV',clv)
write(clab,imd)clv
call cpsetc('LLT',clab)
call CPSETI('CLU',3)
enddo |
||
|
itx - the text for the labels if imd = 0. For example,itx = "lab1:lab2:lab3$" |
To simulate "lab1:lab2:lab3$" do:
data clab/"lab1","lab2","lab3"/
call cpseti('LLP',2)
do i = 1,ncl
call cpseti('PAI',I)
call cpsetc('LLT', clab(i))
call CPSETI('CLU',3)
enddo |
||
|
isl, ftn - smoothing switch (0=off, 1=on) and smoothing tension factor |
|
||
|
inc - nice orientation of labels0 = use user's current justification 1= on |
To use the current justification, do nothing. To set justification do: call cpseti('LLP', 2)
call cpseti ('LLO', 1) |
||
|
fft - adjustment to the first solid pattern defined by fdl. |
call cpseti ('LLP', 2)
call cpsetr ('RC1', fft*fdl) |
||
|
fdl - length of lines between labels |
cpsetr ('RC2', fdl)
cpsetr ('RC3',0.) |
||
|
irt - rotate labels, if 1, the labels with follow the lines |
call cpseti('LLP', 2)
call cpseti ('LLO',1) |
||
|
ipz, fpv - "phony" value switch and the value to ignore0 = off 1 = on (when on, fpv is the value to ignore) |
To turn off this feature: call cpsetr ('SPV - Special value',0.) To turn on this feature and supply the value to ignore: call cpsetr ('SPV',fpv) Note: In NCAR, you cannot ignore the value of 0.0. |
||
|
izc, isv - zone centering switch and zone centering array mode.izc = 0, switch is off, ignore isvizc = 1, switch is on, and isv informs the main contour routines to adjust their indexing mode. |
To simulate izc = 1, ! Adjust X,Y coordinates
! Compute data values at the center of the grid box
MM1=M-1
JM1=N-1
DO 20 J=1,N
DO 10 I=1,MM1
Z(I,J)=0.5*(Z(I,J)+Z(I+1,J))
10 CONTINUE
Z(M,J)=Z(MM1,J)
20 CONTINUE |
||
|
fsc - scale applied to contour levels before labeled |
call cpsetr ('SFS', fsc) |
||
|
isk - step for labeled contour lines |
call cpseti ('LIU', isk) |
||
|
fst - stagger labels from level to level |
cpseti ('LLP',2)
do i = 1,ncl
call cpseti('PAI',I)
if (mod(i,3).eq.0) then
call cpsetr
('RC1',fst+fft*fdl)
end if
enddo |
** Below is a code fragment demonstrating how you can choose your own contour levels
data clevels/-1.,0.,5.,10./
INCL = 4
call cpseti('CLS - Contour Level Selector', 0)
call cpseti('NCL - No. of contour levels',INCL)
DO I = 1,INCL
call cpseti('PAI - Parameter Array Index', I)
call cpsetr('CLV - Contour level value',clevel(i))
enddo
** If you change the mapping function (call cpseti ("MAP -- Mapping Function', …) you need to add either include a routine, like cpmpx below, to:
SUBROUTINE CPMPXY (IMAP,XINP,YINP,XOTP,YOTP)
C
C This version of CPMPXY implements four different mappings:
C
C IMAP = 1 implies an EZMAP mapping. XINP and YINP are assumed to be
C the longitude and latitude, in degrees, of a point on the globe.
C
C IMAP = 2 implies a polar coordinate mapping. XINP and YINP are
C assumed to be values of rho and theta (in degrees).
C
C IMAP = 3 implies an orthogonal, but unequally-spaced mapping. XINP
C is assumed to lie in the range from 1 to M, YINP in the range from
C 1 to N, where M and N are the dimensions of the grid. The common
C block CPMPC1 contains arrays XFOI and YFOJ giving the X coordinates
C associated with I = 1 to M and the Y coordinates associated with
C J = 1 to N.
C
C IMAP = 4 implies a generalized distortion. XINP is assumed to lie
C in the range from 1 to M, YINP in the range from 1 to N, where M
C and N are the dimensions of the grid. The common block CPMPC2
C contains arrays XFIJ and YFIJ, giving the X and Y coordinates
C associated with index pairs (I,J).
C
C Declare common blocks.
C
Parameter (M=<data column dimension >, N=<data row dimension>)
COMMON /CPMPC1/ XFOI(M),YFOJ(N)
COMMON /CPMPC2/ XFIJ(M,N),YFIJ(M,N)
C
C Do the mapping.
C
IF (IMAP.EQ.1) THEN
CALL MAPTRN (YINP,XINP,XOTP,YOTP)
ELSE IF (IMAP.EQ.2) THEN
XOTP=XINP*COS(.017453292519943*YINP)
YOTP=XINP*SIN(.017453292519943*YINP)
ELSE IF (IMAP.EQ.3) THEN
I=MAX(1,MIN(32,INT(XINP)))
J=MAX(1,MIN(32,INT(YINP)))
XOTP=(REAL(I+1)-XINP)*XFOI(I)+(XINP-REAL(I))*XFOI(I+1)
YOTP=(REAL(J+1)-YINP)*YFOJ(J)+(YINP-REAL(J))*YFOJ(J+1)
ELSE IF (IMAP.EQ.4) THEN
I=MAX(1,MIN(32,INT(XINP)))
J=MAX(1,MIN(32,INT(YINP)))
XOTP=(REAL(J+1)-YINP)*
+ ((REAL(I+1)-XINP)*XFIJ(I,J )+(XINP-REAL(I))*XFIJ(I+1,J ))
+ +(YINP-REAL(J))*
+ ((REAL(I+1)-XINP)*XFIJ(I,J+1)+(XINP-REAL(I))*XFIJ(I+1,J+1))
YOTP=(REAL(J+1)-YINP)*
+ ((REAL(I+1)-XINP)*YFIJ(I,J )+(XINP-REAL(I))*YFIJ(I+1,J ))
+ +(YINP-REAL(J))*
+ ((REAL(I+1)-XINP)*YFIJ(I,J+1)+(XINP-REAL(I))*YFIJ(I+1,J+1))
ELSE
XOTP=XINP
YOTP=YINP
END IF
C
C Done.
C
RETURN
C
END