How to Draw a Box Around a Column of Data in a PDF Report
By Jodye Yates

I am often required to produce pdf reports that contain so much data on each page that they become difficult to read and comprehend. This issue can, of course, be dealt with in a number of ways. For example, shading the backcolor of specific columns or rows of data can be used to emphasize certain aspects of the report as well as to make the report more legible.

Recently however, I was asked to make a pdf report more clear by drawing boxes around certain columns of data while shading the inside of the box at the same time. This article will use a simple TABLE FILE CAR report to describe an example of the techniques that I used to accomplish this request.

All of the required images and source code can be downloaded here.

Before we go any further, please take a look at the pdf report called “final.pdf” included in the documentation. As you can see, a box is drawn around the Model column on each page of the pdf.

The box was created by using two simple 1x1 pixel images. An image of a black dot (black.gif), was used to draw the four lines of the box (left, right, top, bottom), while an image of a grey dot (grey.gif) was used to shade the inside of the box. As you can see, the size of the box changes on each page of the report, depending on the number of models on the page. This was accomplished by setting the values of the size and position of the images to be exactly what was needed on each individual page of the report.

In order to produce the final pdf, we need to answer one essential question: Exactly how should the size and position of the placement of the images change, depending on the number of records per page?

Here is a quick example that you can run, showing the box being displayed. Simply drop the two images into the correct directory and fix the path referenced in the code.

TABLE FILE CAR
SUM SALES
BY COUNTRY
BY MODEL
WHERE COUNTRY EQ 'ITALY';
ON TABLE PCHOLD FORMAT PDF
ON TABLE SET STYLE *
-*VERTICAL LINES
TYPE=REPORT, IMAGE=\path\to\black.gif, POSITION=(1.4 0.8),  SIZE=(0.04   1.04  ), $
TYPE=REPORT, IMAGE=\path\to\black.gif,  POSITION=(3.9 0.8), SIZE=(0.04   1.04   ), $
-*HORIZONTAL LINES
TYPE=REPORT, IMAGE=\path\to\black.gif, POSITION=(1.4 0.8),  SIZE=(2.5 0.04), $
TYPE=REPORT, IMAGE=\path\to\black.gif,  POSITION=(1.4   1.81   ), SIZE=(2.5 0.04), $
-*shading
TYPE=REPORT, IMAGE=\path\to\grey.gif,  POSITION=(1.44 0.84), SIZE=(2.45    .96   ), $
ENDSTYLE
END

The values for the size and the position of the images were determined by trial and error. You will need to experiment with different values until the box looks correct. Make sure that the box is wide enough to contain the maximum possible value for the column.

In the example above, the size and position of the images are hard coded. In our example, however, the length of the box must change depending on how many records appear on each page. In order to account for this, we need to figure out a formula to apply to the vertical lines in order to make them longer depending on the number of records. We will also need a formula for the position of the bottom horizontal line, which will move up and down depending on the number of records. Finally we need to know how long to make the shading.

Through trial and error, I came up with the following formulae for this simple example:

Vertical line length = (Number of Records * 0.18) + 0.32;
Vertical Position of bottom horizontal line = Vertical line length + 0.77
Shading length = Vertical line length - 0.08

These were determined by seeing how the values needed to be adjusted based on the number of records. For example, I hard coded the country to England, which has 4 models and then to France, which has 1 model, and then compared the required size and position values that were required in order to draw the box correctly.

Once we have our formula we are ready to go. Here is the final fex explained step by step. The complete source for this is contained in the file “drawing_boxes.fex”.

Step 1: Extract the data into a hold file.

As you will see below, we will be hitting our datasource many times. Whenever I need to do this, I prefer to extract one large dataset and then work against a hold file. If your table is small and/or very fast, then of course you will not need to do this.

TABLE FILE CAR
SUM
SALES
CNT.MODEL AS 'MODELCOUNT'
BY MODEL
BY COUNTRY
WHERE SALES NE 0;
ON TABLE HOLD AS MAINHOLD
END

Step 2: Convert the number of records to decimal format and apply the formulae.

The next step is to apply the formulae to the number of records in order to get our values for the size and position of the images on each page of the report. We are converting the values to ALPHA format so they can be –READ in later on. We will save this data in a second hold file called “myhold”.

                  
TABLE FILE MAINHOLD
SUM
COMPUTE MYCOUNT/D6=MODELCOUNT; NOPRINT
COMPUTE MYCOUNT2/D6.2=(MYCOUNT * 0.18)+0.32;  NOPRINT
COMPUTE MYCOUNT2A/A8=FTOA(MYCOUNT2, '(D6.2)', 'A8');
COMPUTE MYCOUNT3/D6.2=MYCOUNT2+0.77;   NOPRINT
COMPUTE MYCOUNT3A/A8=FTOA(MYCOUNT3, '(D6.2)', 'A8');
COMPUTE MYCOUNT4/D6.2=MYCOUNT2- 0.08;   NOPRINT
COMPUTE MYCOUNT4A/A8=FTOA(MYCOUNT4, '(D6.2)', 'A8');
BY COUNTRY
ON TABLE HOLD AS MYHOLD FORMAT ALPHA
END

Step 3: Loop through the data and create the pdf one page at a time.

This is the final step. We will create a loop and READ through the records stored in “mainhold”. Each record represents one page of the pdf. Inside each loop we will have 4 amper variables.

  1. &MYCOUNTRY: used to store the name of the current country.
  2. &LENGTH: used to store the Y length of the two vertical lines (i.e. how long they are).
  3. &YPOS: used to store the Y position of the two horizontal lines (i.e. how far down the place the lines).
  4. &LENGTH2: used to store the Y length of the inner shading of the box.

We will read the “mainhold” table for each iteration of the loop, while using the 4 parameters to display the images. A fifth parameter, called &OPENCLOSE, is used to close the pdf on the last page.

Here is the remaining code:

                  
-SET &MYRECS=&LINES;
-*READ THE DATA INTO A LOOP
-RUN
-SET &I=0;
-STRT_READ
-SET &I=&I+1;
-READ MYHOLD &MYCOUNTRY.A10. &LENGTH.A8.  &YPOS.A8. &LENGTH2.A8.
-*&OPENCLOSE IS USED TO CLOSE THE PDF ON THE LAST PAGE.
-SET &OPENCLOSE=IF &I EQ &MYRECS THEN 'CLOSE'  ELSE 'OPEN';

TABLE FILE MAINHOLD
SUM SALES
BY COUNTRY
BY MODEL
WHERE COUNTRY EQ '&MYCOUNTRY';
ON TABLE PCHOLD FORMAT PDF &OPENCLOSE
ON TABLE SET STYLE *
-*VERTICAL LINES
TYPE=REPORT, IMAGE=\path\to\black.gif, POSITION=(1.4 0.8),  SIZE=(0.04 &LENGTH), $
TYPE=REPORT, IMAGE=\path\to\black.gif, POSITION=(3.9 0.8),  SIZE=(0.04 &LENGTH), $
-*HORIZONTAL LINES
TYPE=REPORT, IMAGE=\path\to\black.gif, POSITION=(1.4 0.8),  SIZE=(2.5 0.04), $
TYPE=REPORT, IMAGE=\path\to\black.gif, POSITION=(1.4  &YPOS), SIZE=(2.5 0.04), $
-*shading
TYPE=REPORT, IMAGE=\path\to\grey.gif, POSITION=(1.44 0.84),  SIZE=(2.45 &LENGTH2), $
ENDSTYLE
END
-IF &I LT &MYRECS THEN GOTO STRT_READ;

Well that’s it. Please feel free to contact me if you have any questions or comments or suggestions for ways that we can improve this process.