Keeping it Small and Simple

2007.05.19

Plotting trigonometrical functions in PHP

Filed under: Graphics Programming, Mathematics, PHP Programming — Lorenzo E. Danielsson @ 02:48

If you’ve ever tried software applications like MRTG or Zabbix you will have seen that these programs are able to generate graphs that are displayed on a web page. If you wonder how it’s done, I hope that this short tutorial will give you an idea.

I’m going to use PHP for this example, but it wouldn’t be difficult to adapt to mod_perl, mod_ruby or possibly mod_pascal (is there such a thing??). To begin with we will need a web server (I’m using Apache2 with PHP support. If you are using Debian or one of its derivates, aptitude install libapache2-mod-php5 should do the trick (you could also use libapache2-mod-php4 if you prefer). You will also need the PHP GD (www.libgd.org library for dynamically creating images. You get that with aptitude install php5-gd.

The GD library allows to create an image, use various functions to draw on the image and finally stream the image to the client (web browser). GD itself is written in C, but there are bindings for several languages available. There are also various utility libraries available that build on top of GD, that make it easier to use GD for specific purposes, but it’s always a good idea to understand how things work at a lower level, so in this tutorial I will look at GD itself.

The procedure is quite simple:

  1. Create an image (either a new blank image or load an existing image)
  2. Perform drawing operations on the image
  3. Stream the image data to the client

In this example, I’m going to plot the two trigonometrical functions sine and cosine. We will create two files. I called the first on trigplot.php (you can call it whatever you want), and it looks like this:

<?php

header("Content-type: image/png");

function draw_axes($image, $width, $height, $color) {
    $xaxis = $height / 2;
    $yaxis = $width / 2;

    imageline($image, $yaxis, 0, $yaxis, $height-1, $color);
    imageline($image, 0, $xaxis, $width-1, $xaxis, $color);
}

function plot_sin($image, $height, $color) {
    for ($x = 0; $x < 360; ++$x) {
        $amplitude = $height/2 - 10;
        $y = $height/2 + $amplitude * sin(deg2rad($x-180));
        imagesetpixel($image, $x, $y, $color);
    }
}

function plot_cos($image, $height, $color) {
    for ($x = 0; $x < 360; ++$x) {
        $amplitude = $height/2 - 10;
        $y = $height/2 + $amplitude * cos(deg2rad($x-180));
        imagesetpixel($image, $x, $y, $color);
    }
}

$width = 360;
$height = 200;
$image = imagecreate($width, $height) or die("Failed to create stream");
$bgcolor = imagecolorallocate($image, 255, 255, 255);
$axiscolor = imagecolorallocate($image, 0, 0, 0);
$curvecolor1 = imagecolorallocate($image, 0, 0, 255);
$curvecolor2 = imagecolorallocate($image, 0, 255, 0);

draw_axes($image, $width, $height, $axiscolor);
plot_sin($image, $height, $curvecolor1);
plot_cos($image, $height, $curvecolor2);
imagepng($image);
imagedestroy($image);

?>

(Sorry for the lack of line numbering, Vim gave me errors when I tried to run :TOhtml with line numbering enabled.)

Notice the header call. This is important. We are sending image data to the web browser, so we must notify it of the content type, so that it will now what to do with the incoming data. The rest should be fairly straightforward I hope (make sure you have you PHP documentation open so that you can read up on the functions that are used). Of course you don’t have separate code this short into functions, but I did it just to show that this is a PHP file like any other and that you can use normal PHP constructs in it.

You could now upload this file to a location where you web server is able to serve it, and you should see a very simple graph containing to curves in different colors. As far as the web browser is concerned, this is an image it is displaying, similar to the way the browser will display any other image. The browser is not at all concerned with the fact that this image is, in fact, dynamically created.

If, instead of seeing an image in your browser, you get something about the image not being displayed because it contains errors then skip down to the section called A little note on debugging.

But how about if you would want to include the graph in an existing web page? That is not a problem at all. Here is a sample, you could call it index.html if you want.

<html>
<head>
<title>Trigonometry plotter</title>
</head>

<body>
<center><b>Trigonometry Functions</b></center>
<img src="trigplot.php">
</body>
</html>

Notice that I am using a normal HTML IMG tag, and pay attention to the SRC attribute. That is really all there is to it (I’m not calling the blog Keeping it Small and Simple for nothing).

A little note on debugging

If a syntax error creeps into your image generation code, then you will just get a blank image if you browse index.html. If you browse trigplot.php, on the other hand, you will get a message that the image cannot be displayed because it contains errors. To get some useful information about the error, browse trigplot.php and get your browser to view the source. It will contain error messages from PHP, along with line numbers. With that your debugging almost becomes trivial.

You will not see any error messages if you try to view the source of index.html. You must browse something like http://localhost/phpsamples/trigplot/trigplot.php to be able to see the error messages that PHP sends you.

Ideas for exercises

For those who feel so inclined I’ve added a few ideas for exercises based on my sample. You can try them if you don’t have anything better to do. Feel free to post your solutions as comments. (No, I’m not going to give you a degree in computer science. 😀 )

  1. Add a border around the graph.
  2. Add labels to the curves (something like y = sin(x) and y = cos(x)). Make sure these get well positioned.
  3. The axes are currently just straight lines. Make them look more like the ones you would find in your average school math book. Add arrows, labels etc.
  4. All drawing in the original is done by GD. Use a drawing program to create an image that contains labeled axes and has a border around it. In your PHP code, use the imagecreatefrompng() function to load the image and then perform you function plotting on it. Make sure you get your positioning right.
  5. Add y = tan(x) to the graph. What special condition do you need to take into consideration when plotting this function?
  6. Add a grid. Choose a light gray color so that it doesn’t dominate the graph.
  7. Create a form that asks the user for information like amplitude, start angle, end angle, wavelength etc, and uses this information to plot the functions.
  8. In the plot functions, highlight the maximum and minimum points of the sine and cosine functions.
  9. Write a Perl program that uses an Inline Asm section to dynamically generate PHP code that dynamically creates graphs of trigonometric functions. 😉

These are just a few examples that I can think of.

Addendum

Spot the error in the code? Hint: think Cartesian vs. screen coordinates. You can fix that by changing $y = $height/2 + ... to $y = $height/2 - ... in the two functions plot_sin and plot_cos.


Update 2007.05.23: Noticed an error in the code.

Advertisements

2007.05.12

Is it divisible by three?

Filed under: Mathematics, Ruby Programming — Lorenzo E. Danielsson @ 18:16

If you want to know whether or not a really big number is divisible by three, you don’t need a calculator to find it out. Simply add the digits together. If the sum of the digits is divisible by three, then the number itself is divisible by three as well.

Not following? Let’s look at an example. Is the number 12,345 divisible by three? Let’s try it.


1 + 2 + 3 + 4 + 5 = 15

Now 15/3 is exactly 5, so 12,345 is divisible by three. The really neat thing about this is that it is recursive so:


1 + 2 + 3 + 4 + 5 = 15
1 + 5 = 6

..and of course 6/3 is exactly 2. Let’s try another one. Is 987,654,321 divisible by three? Hm, let’s see..

9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 = 45
4 + 5 = 9

So 987,654,321 is divisible by three (you can use your calculator to confirm it). Last example, is 287,765,982,173,888,234 divisible by three?


2 + 8 + 7 + 7 + 6 + 5 + 9 + 8 + 2 + 1 + 7 + 3 + 8 + 8 + 8 + 2 + 3 + 4 = 98
9 + 8 = 17
1 + 7 = 8

The number 8 is not divisible by three, so the number 287,765,982,173,888,234 is not divisible by three.

I wanted to write a little program to test this theorem, and came up with the following in Ruby:

#! /usr/bin/ruby -w

def sum_digits(str)
  sum = 0
  for i in 0..str.length-1
    sum += str[i, 1].to_i
  end

  if sum.to_s.length > 1
    sum_digits(sum.to_s)
  else
    return sum
  end
end

# Test with a few numbers. Add any numbers you like.
for num in [ 6, 15, 21, 99, 100, 2005, 4141, 12345, 20000, 32000 ] do
  puts "#{num.to_s.rjust(5)} : #{sum_digits(num.to_s)} : #{(num % 3)}"
end

Note that the sum_digits method (yes, in Ruby functions are actually methods) recurses down until there is only a single digit left. Also you can see that I created an array with a few random and a few not-so-random numbers. You could easily modify the program to allow the user to enter a number to be tested or one the takes the number(s) to be tested as command-line arguments.

There is obviously More Than One Way of Doing This in Ruby. Feel free to add your own implementations in the comments section. The same goes for if you’ve written an implementation in another language.

Create a free website or blog at WordPress.com.