CPSC 124, Fall 2001
Lab 13: Making Bar Charts with Arrays

For this lab, you will write an applet that can display simple bar charts, like this one:

The applet takes the data for the bar chart from its applet parameters. Although we haven't used them before, applet parameters are discussed at the end of Section 6.2, and they are discussed below. The applet doesn't do anything except display the chart. It is not interactive in any way.

This lab is due next Wednesday, December 5. You should turn in a printout of your BarChart.java file. You should also add your applet to your Web page for this course. (Copy the full <applet> tag from BarChart.java to your page's HTML file.)

You will find the file you need for this lab in the directory /home/cs124/lab13. You should copy this directory into your account, as usual.

Use the file BarChart.java as a starting point for your work. This file includes an <applet> tag, so you can use "appletviewer BarChart.java" to view the applet.


Parameters Everywhere

We first encountered parameters in the context of subroutines. But in fact, parameters are an important general concept. In the previous lab, you saw how command-line parameters can be used to provide information to stand-alone programs. It's also possible to provide information to an applet through the mechanism know as "applet parameters". Applet parameters are part of the applet tag. They are provided by the user of an applet (the author of a Web page) rather than by the programmer. An applet that uses parameters in this way can be "customized" by its user, giving the user more control and making the applet more useful. Applet parameters are included in <param> tags that are nested inside the applet tags. Each param has a name and a value. The name is known to the applet and is how the applet identifies the parameter. The value is the information that is provided by the Web page author. There can be as many params as you like, provided they all have different names. Here, for example, is an applet tag that includes two params:

       <applet source="MessageViewer.class width=250 height=50>
          <param name="Message" value="Bananas, only 39 cents per pound!">
          <param name="Color"   value="red">
       </applet>

These params will only have an effect if the applet code actually uses them. Usually, the applet reads its params in the init() method. It can do this by calling the predefined applet method

          String getParameter(String paramName)

This method is called with the name of the param as its parameter. It looks for a corresponding param in the applet tag. If it finds one, it returns the value specified in the tag. If no param is found with the given name, the method returns the value null. (Warning: Param names are case sensitive!) It's a good idea to check whether the return value is null and to use a default value in that case. For example:

             message = getParameter("Message");
             if (message == null)  // No value provided in applet tag.
                message = "Hello, World!";   // Use default value.

Note that the value returned by getParameter() is always a String. If you want to use a number or Color value as a param, you have to convert the String value to the appropriate type. Since this is a fairly common situation, I have found it convenient to write some methods to do this. You will find these subroutines in BarChart.java:

            int getIntParameter(String paramName, int defaultValue)
                  // Gets an int value from the applet param named paramName.
                  // If no such param exists or if the value is not a valid int,
                  // then defaultValue is returned as the value of this method.

            double getDoubleParameter(String paramName, double defaultValue)
                  // Gets a double value from the applet param named paramName.
                  // If no such param exists or if the value is not a valid double,
                  // then defaultValue is returned as the value of this method.

            Color getColorParameter(String paramName, Color defaultValue)
                  // Gets a Color value from the applet param named paramName.
                  // If no such param exists or if the value is not a valid Color,
                  // then defaultValue is returned as the value of this method.
                  // Colors can be represented by the standard color names such
                  // as red, green, black, yellow, etc.  Alternatively, a color
                  // can be given a sequence of three ints in the range 0 to
                  // 255, separated by spaces or commas.

These methods make it very convenient to get an applet param and provide a default value at the same time. For example, I can simply say:

            setBackground( getColorParam("BackgroundColor", new Color(230,230,230)) );

to set the background color of my applet. If the user provides a param named BackgroundColor, that color will be used. If not, a default light gray color is used.


There is only one problem with the methods I provided. The getColorParam() is incomplete. It does not handle the case of colors represented by color names. The applet does include two arrays, color and colorNames, that can be used in the method. The colorNames array contains names of colors while the color array contains the corresponding Color values. The idea is to search the array colorNames for the parameter value, which is stored in the variable named param. If you find param, you should return the Color in the corresponding position in the color array. If you don't find param, you should return the defaultValue.

You should complete the getColorParam() method by filling in the part labeled "You have to complete this part", near the bottom of the file BarChart.java. This will be just a few lines. It's an application of the general technique called "linear search".

Once you have made the change, you should be able to compile BarChart.java, run the applet with the command "appletviewer BarChart.java", and see a red bar in the applet, instead of the default light blue.


Getting the Bar Chart Data

The real point of this lab is to draw bar charts like the one shown at the top of this page. After you complete the lab, your applet should look just like the one on this page, when you view BarChart.java with appletviewer. However, your applet should also be able to work with any other valid set of applet param values. All the data for the bar chart is take from applet params. Several color params are already handled by the applet. The params that provide data for the bars are as follows:

        Param Name   Type   Description
      ------------- ------  ----------------------------------------
      
        BarCount     int     The number of bars in the histogram.
        
        Data1       double   The data value for the first bar.

        Label1      String   A label for the first bar. 

        Data2       double   The data value for the second bar.

        Label2      String   A label for the second bar. 
          .
          .
          .

There is one "Data" param and one "Label" for each bar in the chart. The "Data" params determine the length of the bars. The "Labels" are strings that are drawn as text on top of the bars. Since you don't know how many bars there will be, you can't use individual variables for the param values. You have to use arrays.

To begin, declare two instance variables, of type double[] and String[] to hold the Data and Labels. These must be instance variables since they are used in both the init() method and the paint() method.

Next, you can complete the init() method. First, read the number of bars from the applet param named "BarCount" by calling getIntParam("BarCount",0). Then you can create the two arrays, using the number of bars as the length of the arrays. Finally, use a for loop to read the information from the "Data" and "Label" params into the arrays.

One interesting problem is, what to use for the names of the "Data" and "Label" params. You want to use the names "Data1", "Label1", "Data2", "Label2", "Data3", "Label3", and so on. However, you want to do this in a loop in which the name has to change in each iteration of the loop. The trick is to compute the name based on the for loop variable. For example, if i is the for loop variable, then "Data"+(i+1) will be "Data1" the first time through the loop, "Data2" the second time through the loop, and so on.


Drawing the Bars

The paint method of the applet must use the data in the arrays and in the Color variables borderColor, textColor, and barColor, to draw the bar chart. You can assume that each bar is 30 pixels high, and that there is a gap of 20 pixels at the top of the applet, at the bottom of the applet, and between the bars. This means that the y-coordinate of the top of the first bar is 20; the top of the second bar is at y-coordinate 70; the top of the third bar is at 120; and, in general, the top of bar number N is at y-coordinate 20+50*N. You will need this information to draw the bars in the correct positions.

The widths of the rectangles that represent the bars depend on the values in the data array. The bar corresponding to the largest data value should stretch all the way across the applet. The other bars should be sized proportionately. Suppose maxWidth is the width of the longest bar, maxValue is the largest data value, and val is one of the other data values. Then the width of the bar that represents val should be (int)(maxWidth*val/maxValue).

Complete the paint() method so that it draws all the bars in appropriate colors and sizes. You will first have to determine the maximum data value by looking through the data array. Then, use a loop to draw the individual bars.


David Eck, 29 November 2001