Windows and Viewports

A window defines a rectangular area in world coordinates. You define a window with a GWINDOW statement. You can define the window to be larger than, the same size as, or smaller than the actual range of data values, depending on whether you want to show all of the data or only part of the data.

A viewport defines in normalized coordinates a rectangular area on the display device where the image of the data appears. You define a viewport with the GPORT call. You can have your graph take up the entire display device or show it in only a portion, such as the upper-right part.

Mapping Windows to Viewports

A window and a viewport are related by the linear transformation that maps the window onto the viewport. A line segment in the window is mapped to a line segment in the viewport such that the relative positions are preserved.

You do not have to display all of your data in a graph. In Figure 16.4, the graph on the left displays all of the ACME stock data, and the graph on the right displays only a part of the data. Suppose that you wanted to graph only the last 10 years of the stock data—say, from 1977 to 1986. You would want to define a window where the YEAR axis ranges from 77 to 86, while the PRICE axis could range from 120 to 160. Figure 16.4 shows stock prices in a window defined for data from 1977 to 1986 along the horizontal direction and from 120 to 160 along the vertical direction. The window is mapped to a viewport defined by the points (20, 20) and (70, 60). The appropriate GPORT and GWINDOW specifications are as follows:

   call gwindow({77 120, 86 160});
   call gport({20 20, 70 60});

The window defines the portion of the graph that is to be displayed, and the viewport specifies the area on the device on which the image is to appear.

Figure 16.4: Window to Viewport Mapping


Understanding Windows

Because the default world coordinate system ranges from (0,0) to (100,100), you usually need to define a window in order to set the world coordinates that correspond to your data. A window specifies which part of the data in world coordinate space is to be shown. Sometimes you want all of the data shown; other times, you want to show only part of the data.

A window is defined by an array of four numbers, which define a rectangular area. You define this area by specifying the world coordinates of the lower-left and upper-right corners in the GWINDOW statement, which has the following general form:

CALL GWINDOW (minimum-x minimum-y maximum-x maximum-y) ;

The argument can be either a matrix or a literal. The order of the elements is important. The array of coordinates can be a $2 \times 2$, $1 \times 4$, or $4 \times 1$ matrix. These coordinates can be specified as matrix literals or as the name of a numeric matrix that contains the coordinates. If you do not define a window, the default is to assume both $x$ and $y$ range between 0 and 100.

In summary, a window

  • defines the portion of the graph that appears in the viewport

  • is a rectangular area

  • is defined by an array of four numbers

  • is defined in world coordinates

  • scales the data relative to world coordinates

In the previous example, the variable YEAR ranges from 71 to 86, while PRICE ranges from 123.625 to 159.50. Because the data do not fit nicely into the default, you want to define a window that reflects the ranges of the variables YEAR and PRICE. To draw the graph of these data to scale, you can let the YEAR axis range from 70 to 87 and the PRICE axis range from 100 to 200. Use the following statements to draw the graph, shown in Figure 16.5.

   call gstart;
   xbox={0 100 100 0};
   ybox={0 0 100 100};
   call gopen("stocks1");        /* begin new graph STOCKS1 */
   call gset("height", 2.0);
   year=do(71,86,1);                     /* initialize YEAR */
   price={123.75 128.00 139.75          /* initialize PRICE */
          155.50 139.750 151.500
          150.375 149.125 159.500
          152.375 147.000 134.125
          138.750 123.625 127.125
          125.50};
   call gwindow({70 100 87 200});                /* define window */
   call gpoint(year,price,"diamond","green"); /* graph the points */
   call gdraw(year,price,1,"green");            /* connect points */
   call gshow;                                  /* show the graph */

The example shows how to do the following:

  • Use the GOPEN call to associate the name STOCKS1 with this graphics segment.

  • Use the GWINDOW call to define a window that reflects the actual ranges of the data.

  • Use the GPOINT call to associate a diamond plotting symbol and the color green with the graphics segment.

  • Use the GDRAW call to connect the points with line segments. The GDRAW call requests that the line segments be drawn in style 1 and be green.

Figure 16.5: Stock Data


Understanding Viewports

A viewport specifies a rectangular area on the display device where the graph appears. You define this area by specifying the normalized coordinates, the lower-left corner and the upper-right corner, in the GPORT call, which has the following general form:

CALL GPORT (minimum-x minimum-y maximum-x maximum-y) ;

The argument can be either a matrix or a literal. Note that both $x$ and $y$ must range between 0 and 100. As with the GWINDOW call, you can give the coordinates either as a matrix literal enclosed in braces or as the name of a numeric matrix that contains the coordinates. The array can be any matrix that contains four elements. If you do not define a viewport, the default is to span the entire display device.

In summary, a viewport

  • specifies where the image appears on the display

  • is a rectangular area

  • is specified by an array of four numbers

  • is defined in normalized coordinates

  • scales the data relative to the shape of the viewport

The following statements create the graph shown in Figure 16.6. The statements define a viewport in order to display the stock price data in a smaller area on the display device. The statements also add axis labels and a title.

   /* module centers text strings */
   start gscenter(x,y,str);
      call gstrlen(len,str);               /* find string length */
      call gscript(x-len/2,y,str);                 /* print text */
   finish gscenter;

   call gopen("stocks2");                  /* open a new segment */
   call gset("font","swiss");              /* set character font */
   call gpoly(xbox,ybox);                  /* draw a border      */
   call gwindow({70 100,87 200});          /* define a window    */
   call gport({15 15,85 85});              /* define a viewport  */
   call ginclude("stocks1");          /* include segment STOCKS1 */
   call gxaxis({70 100},17,18, ,           /* draw x-axis        */
                ,"2.",1.5);
   call gyaxis({70 100},100,11, ,                 /* draw y-axis */
                ,"dollar5.",1.5);
   call gset("height",2.0);              /* set character height */
   call gtext(77,89,"Year");            /* print horizontal text */
   call gvtext(68,200,"Price");          /* print vertical text  */
   call gscenter(79,210,"ACME Stock Data");      /* print title  */
   call gshow;

Figure 16.6: Stock Data with Axes and Labels


The following list describes the statements that generate this graph:

  • The GOPEN call begins a new graph and names it STOCKS2.

  • The GPOLY call draws a box around the display area.

  • The GWINDOW call defines the world coordinate space to be larger than the actual range of stock data values.

  • The GPORT call defines a viewport. It causes the graph to appear in the center of the display, with a border around it for text. The lower-left corner has coordinates (15, 15) and the upper-right corner has coordinates (85, 85).

  • The GINCLUDE call includes the graphics segment STOCKS1. This saves you from having to plot points you have already created.

  • The GXAXIS call draws the $x$ axis. It begins at the point (70, 100) and is 17 units (years) long, divided with 18 tick marks. The axis tick marks are printed with the numeric 2.0 format, and they have a height of 1.5 units.

  • The GYAXIS call draws the $y$ axis. It also begins at (70, 100) but is 100 units (dollars) long, divided with 11 tick marks. The axis tick marks are printed with the DOLLAR5.0 format and have a height of 1.5 units.

  • The GSET call sets the text font to be Swiss and the height of the letters to be 2.0 units. The height of the characters has been increased because the viewport definition scales character sizes relative to the viewport.

  • The GTEXT call prints horizontal text. It prints the text string Year beginning at the world coordinate point (77, 89).

  • The GVTEXT call prints vertical text. It prints the text string Price beginning at the world coordinate point (68, 200).

  • The GSCENTER call runs the module to print centered text strings.

  • The GSHOW call displays the graph.

Changing Windows and Viewports

You can change windows and viewports for the graphics segment while the segment is active. Using the stock price example, you can first define a window for the data during the years 1971 to 1974 and map this to the viewport defined on the upper half of the normalized device; then you can redefine the window to enclose the data for 1983 to 1986 and map this to an area in the lower half of the normalized device.

Notice that the viewport affects the appearance of the curve. Changing the viewport can affect the height of any printed characters as well. In this case, you can modify the HEIGHT parameter.

The following statements generate the graph in Figure 16.7:

   reset clip;                          /* clip outside viewport */
   call gopen;                             /* open a new segment */
   call gset("color","blue");
   call gset("height",2.0);
   call gwindow({71 120,74 175});             /* define a window */
   call gport({20 55,80 90});               /* define a viewport */
   call gpoly({71 74 74 71},{120 120 170 170}); /* draw a border */
   call gscript(71.5,162,"Viewport #1 1971-74",,   /* print text */
                  ,3.0,"complex","red");
   call gpoint(year,price,"diamond","green");     /* draw points */
   call gdraw(year,price,1,"green");           /* connect points */
   call gblkvpd;
   call gwindow({83 120,86 170});           /* define new window */
   call gport({20 10,80 45});             /* define new viewport */
   call gpoly({83 86 86 83},{120 120 170 170});   /* draw border */
   call gpoint(year,price,"diamond","green");     /* draw points */
   call gdraw(year,price,1,"green");           /* connect points */
   call gscript(83.5,162,"Viewport #2 1983-86",,   /* print text */
                  ,3.0,"complex","red");
   call gshow;

Figure 16.7: Multiple Viewports


The RESET CLIP statement is necessary because you are graphing only a part of the data in the window. You want to clip the data that falls outside of the window. See the section Clipping Your Graphs for more about clipping. The following list describes the statements that create Figure 16.7

  • Use the GOPEN call to open a new segment.

  • Use the GWINDOW call to define the first window for the first four years of data.

  • Use the GPORT call to define a viewport in the upper part of the display device.

  • Use the GPOLY call to draw a box around the viewport

  • Use the GSCRIPT call to add text

  • Use the GPOINT call to plot the points and the GDRAW command to connect them.

  • Use the GWINDOW call to define the second window for the last four years of data.

  • Use the GPORT, GPOLY, GPOINT, GDRAW, and GSCRIPT calls to create the second plot.

  • Use the GSHOW call to display the graph.

Stacking Viewports

Viewports can be stacked. That is, a viewport can be defined relative to another viewport so that you have a viewport within a viewport.

A window or a viewport is changed globally through the PROC IML graphics calls: the GWINDOW call for windows, and the GPORT, GPORTSTK, and GPORTPOP calls for viewports. When a window or viewport is defined, it persists until another window- or viewport-altering statement is encountered. Stacking helps you define a viewport without losing the effect of a previously defined viewport. When a stacked viewport is popped, you are placed into the environment of the previous viewport.

Windows and viewports are associated with a particular segment; thus, they automatically become undefined when the segment is closed. A segment is closed whenever PROC IML encounters a GCLOSE call or a GOPEN call. A window or a viewport can also be changed for a single graphics subroutine. Either one can be passed as an argument to a graphics primitive, in which case any graphics output associated with the call is defined in the specified window or viewport. When a viewport is passed as an argument, it is stacked, or defined relative to the current viewport, and popped when the graphics call is complete.

For example, suppose you want to create a legend that shows the low and peak points of the data for the ACME stock graph. Use the following statements to create a graphics segment showing this information:

   call gopen("legend");
   call gset('height',5);   /* enlarged to accommodate viewport later */
   call gset('font','swiss');
   call gscript(5,75,"Stock Peak:  159.5 in 1979");
   call gscript(5,65,"Stock Low:   123.6 in 1984");
   call gclose;

Use the following statements to create a segment that highlights and labels the low and peak points of the data:

   /* Highlight and label the low and peak points of the stock */
   call gopen("labels");
   call gwindow({70 100 87 200}); /* define window */
   call gpoint(84,123.625,"circle","red",4) ;
   call gtext(84,120,"LOW","red");
   call gpoint(79,159.5,"circle","red",4);
   call gtext(79,162,"PEAK","red");
   call gclose;

Next, open a new graphics segment and include the STOCK2 segment that was created earlier in the chapter, placing the segment in the viewport {10 10 90 90}, as shown in the following statements:

   call gopen;
   call gportstk ({10 10 90 90}); /* viewport for the plot itself */
   call ginclude('stocks2');

To place the legend in the upper-right corner of this viewport, use the GPORTSTK call instead of the GPORT call to define the legend’s viewport relative to the one used for the plot of the stock data, as follows:

   call gportstk ({70 70 100 100});   /* viewport for the legend */
   call ginclude("legend");

Now pop the legend’s viewport to get back to the viewport of the plot itself and include the segment that labels and highlights the low and peak stock points. Finally, display the graph, as follows:

   call gportpop;   /* viewport for the legend */
   call ginclude ("labels");
   call gshow;

Figure 16.8: Stacking Viewports