• No results found

Some Practical Uses for Graphics

This next exercise is another application of the technique that allowed us to create a doodle pad by adding an onDraw( ) method to a class that is a child class of

TextView. Rather than simply drawing a stick man or circles on the screen, we will produce a graphic representation of the Poisson distribution for an average the user provides. Depending on where you are in your academic career and what you are studying, there is a chance that you may never run into the Poisson distribution principle and formula. This is perfectly fine; most of the work is taken care of for us by existing classes and methods. However, graphing in an application is a worthwhile effort because it forces the programmer to deal with the screen dimensions of the device, specifically the TextView hosting the Canvas, the x,y coordinates of the Canvas, and mixing text and graphics on the Canvas.

Our exercise will apply the Poisson formula to a number the user enters and produce a series of values that represent the percentage probability that any number (starting with zero) will occur in place of the average. We will count up from zero, and for each value we will apply the formula and obtain the corresponding probability, save each probability, and accumulate a running total of the probabilities. When we cover 99 percent of the probabilities, we will stop calculating and place a dot on the screen in a spot corresponding to the counting value and the corresponding probability. We will treat the Canvasas a graph with the X-axis representing the count value and the Y-axis as the corresponding probability.

Note

Stopping at 99 percent is arbitrary, but the alternative is to continue calculating and producing ever-smaller probabilities for the higher numbers until the values are meaningless.

Let us look at an example. Suppose the number of phone calls an operator gets is 10 per hour. What is the likelihood that in some given hour he will only receive 8? Or the likelihood he will receive 12? Here is what we do to find answers. Using L to

represent the average of 10 (normally we use the Greek symbol lambda) and x to represent the experimental value, we apply the formula:

P(x) = (L^x * e^ − L) / x! e represents the constant, 2.71828 P(8) = (10^8 * 2.71828 ^ −10) / 8!

P(8) = .1125 or 11.25%

Likewise, P(12) is .0947 or 9.47%

That’s enough of the Poisson distribution for now. You can study more about it in a statistics or modeling book or on the Internet, such as at http://en.wikipedia.org/wiki/

Poisson_distribution. At any rate, the Poisson distribution gives us a challenging graphic subject, so let’s get to work. The easiest part of this application is the screen design. We just need an EditText to receive the user input, a Button to start the calculations, and a few appropriate labels in the XML file. Here is the main.xml file we will use:

<TextView

We added white to theLinearLayout, purely for aesthetics. We will add a TextView at run-time that also will be white. If we place white-on-white at run-time, the transition on the screen will be transparent. We also assign black to the text in the labels for clar-ity. No changes are necessary in the manifest file, so we don’t have to touch that.

The Java code is where the real work is. Before we get started on our own, we’ll see if there is a predesigned class that we can incorporate in our application to save some steps. In the previous exercise, we learned how to save a reusable doodle pad by creat-ing a.jar file so we could add it to subsequent projects. Allowing for possible licens-ing issues, occasionally we can find.jar files from other programmers. Of course, it is up to the developer to determine if someone else’s code is trustworthy. It so happens that a quick Google search yielded at least one package containing a Poisson distribu-tion calculator available as an open-source downloadable .jar. The JAR download can be found at www.java2s.com/Code/Jar/c/Downloadcommonsmath11jar.htm. Doc-umentation can be found at http://commons.apache.org/math/apidocs/org/apache/

commons/math/distribution/PoissonDistributionImpl.html.

The PoissonDistributionImpl class is derived from the PoissonDistribu-tion interface. We are interested in the probability( ) method that takes one argument, an integer, representing the average value that the distribution is built around. We can download theorg.apache.commons.math.distribution pack-age as a .jarfile. Using the downloaded package and the physical .jarfile involves two steps. The first and easiest is including an importstatement in our code to add the namespace to the Java code. You will see that in the code listing later. The second and more involved step is to tell Eclipse where the package actually is on your devel-opment machine so the code can be added to your project. We will address that first.

Once you have found the .jar file to download, make a note of where your com-puter is storing it. Although there is no strict requirement for a location, it is a good idea to move it to a “permanent” location and out of folders such as Downloads or the desktop; in other words don’t leave it in a location where it could be accidently lost when you periodically “clean house” on your computer. And don’t store it on a flash drive or CD, which may not be available in the future. Once you’ve stored the

.jarfile and you have started a project in Eclipse for this exercise, choose Properties under the Project menu, and you will see a screen like Figure 5.4.

Figure 5.4

Eclipse panel used to add components to a project.

Choose Java Build Path on the right side, and then click the Add External JARs button on the right. You will be asked to select the path and name for the .jar file you want to add to the project. In this case it will probably be the commons-math-2.2.jar file you see listed in the illustration. Once it appears in the window, click the OK button and move on.

Next is a listing of the Java code:

package com.sheusi.MoreGraphics;

public class MoreGraphicsActivity extends Activity { /** Called when the activity is first created. */

EditText avg=null;

public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

public void onClick(View v){

int lam=Integer.parseInt(avg.getText().toString());

PoissonDistributionImpl pdi=new PoissonDistributionImpl(lam);

double accum=0;

double prob=0;

int x=0;

do{

// after .99, the accum value will increase by ever-tinier amounts without end

private class PoissonView extends TextView{

Canvas myCanvas=null;

Paint myPaint=null;

int screenheight=0;

int screenwidth=0;

public PoissonView(Context c,ArrayList<Double> series){

super(c);

// make a square graph area as large as the screen width this.setHeight(screenheight);

protected void onDraw(Canvas myCanvas){

super.onDraw(myCanvas);

//below draws the y-axis scale for percentages values of probabilities for(int ct=9;ct>=0;--ct){

myCanvas.drawText("."+String.valueOf(ct*5),3,screenheight-((screenheight/10)*ct),myPaint);

}

double[] points= new double[series.size()];

for(int ct=0;ct<series.size();++ct){

points[ct]=series.get(ct).doubleValue();

}

int xjump=(int)(screenwidth/series.size());

myCanvas.drawText("First point is p(0)", 5.0f, 10.0f, myPaint);

//draw a border line on the bottom of the graph

myCanvas.drawLine(0f,screenheight-1.0f, screenwidth,screenheight-1.0f, myPaint);

myPaint.setColor(Color.BLUE);

//below, the constant 46 represents the number of positions on the scale 0-45 for(int ct=0;ct<series.size();++ct){

myCanvas.drawCircle((float)(xjump*ct),(float)(screenheight-((int)(points[ct]*100*(screenheight/46)))),(float) 4.0, myPaint);

} }

}//ends inner class PoissonView

@Override

If we start with the import statements, you will see that the import for the Poisson distribution class appears second to last. Below that is the package containing the

Log class, which is not really necessary unless you intend to make entries to the Log section in the debugger. In the onClick( ) method we get some important work done. First we get the average value to base the distribution on from an

EditText field on the screen. Next, we continually apply the correct method from the PoissonDistributionImpl class object to get the probabilities for all the values around the average starting with zero and finishing when we have accounted for 99 percent of probabilities. These are stored in a Java ArrayList and later con-verted to an array. All of this is well enough, but we are primarily interested in ren-dering the graphics. As you have seen before, the unit of graphics we use is the pixel.

The way we lay out the graph is based on how many pixels are available on the given device. Because the application could be used on any number of devices, we cannot hard-code values, but we must calculate everything at run-time based on the host device. We can determine the screen dimensions for any device that might host the application using the Android Display class. Look at the lines here:

Display display =

((WindowManager) c.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();

screenwidth=display.getWidth();

screenheight=display.getWidth();

We create an instance of the Display class called display (with a lowercase “d”) to determine the screen dimensions of the device. Then we make sure the graph area is square to reduce distortion by setting both the height and width to the same number.

We store these as separate variables for clarity. From here on, any plotting we do is based on a product or quotient of the height or width and the number of pieces we want to divide it into. For instance, the spacing left to right of the points on the graph is a result of the screen width divided by the number of points we need to graph. Likewise, the position of the points is a result of the screen height divided by the number of positions on our scale, namely 50. The scale itself on the left side is accomplished using a loop repeating a similar calculation.

Each “point” on the graph is actually a circle that is four pixels wide, which is what the 4.0 represents in the call to .drawCircle( ).

Maybe you have noticed that while plotting the scale and points we subtract the posi-tions from the screen height. For example, look at the lines that follow:

myCanvas.drawCircle((float)(xjump*ct),(float)(screenheight-((int)(points[ct]*100*(screenheight/46)))),(float) 4.0, myPaint);

Unlike graphs you may have done by hand on graph paper where the (0,0) position is in the lower-left corner of the graph (or at least the lower-left corner of the positive-x, positive-y quadrant), the (0,0) position is in the upper-left corner of the canvas. The y-value decreases from the bottom of the canvas to the top. To compen-sate, we subtract the position from the screen height. Java programmers are used to this from graphics on Frames or Panels.

Finally, the running application using an average of four (4) should look like Figure 5.5.

You can compare your results to the Poisson distribution examples shown on web pages such as www.wikipedia.org/wiki/Poisson_distribution or any other Poisson dis-tribution graphing tool. With some practice, you could graph histograms using the

drawLine( ) method, scatterplots, or other similar diagrams.