Creating a Smooth Curve Graphs with PHP and GD

# Creating a Smooth Curve Graphs with PHP and GD

7 93750

Smooth Curve Graphs with PHP and GD. Today I have new article for PHP. I will tell you about drawing graphs with GD. Plus – we will smooth our graph with curve lines using cubic splines interpolation method. You can read more about method at Wiki.

[sociallocker]

[/sociallocker]

### Step 1. HTML

Here are HTML layout for our example page:

#### index.html

```<!DOCTYPE html>
<html lang="en" >
<meta charset="utf-8" />
<title>Smooth Curve Graphs with PHP and GD | Script Tutorials</title>
<body>
<div class="container">
<img src="smooth_graph.php" alt="" />
</div>
<footer>
<h2>Smooth Curve Graphs with PHP and GD</h2>
<a href="https://www.script-tutorials.com/smooth-curve-graphs-with-php-and-gd/" class="stuts">Back to original tutorial on <span>Script Tutorials</span></a>
</footer>
</body>
</html>
```

### Step 2. CSS

Now, lets define all used styles:

#### css/main.css

```*{
margin:0;
}
body {
background-repeat:no-repeat;
background-color:#bababa;
color:#fff;
font:14px/1.3 Arial,sans-serif;
min-height:600px;
}
footer {
background-color:#212121;
bottom:0;
display:block;
height:70px;
left:0;
position:fixed;
width:100%;
z-index:100;
}
footer h2{
font-size:22px;
font-weight:normal;
left:50%;
margin-left:-400px;
position:absolute;
width:540px;
}
footer a.stuts,a.stuts:visited{
border:none;
text-decoration:none;
color:#fcfcfc;
font-size:14px;
left:50%;
line-height:31px;
margin:23px 0 0 110px;
position:absolute;
top:0;
}
footer .stuts span {
font-size:22px;
font-weight:bold;
margin-left:5px;
}
.container {
border:3px #111 solid;
margin:20px auto;
position:relative;
width:550px;
height:430px;
}
```

And first step and second – not very important of course, most important will now:

### Step 3. PHP

This is our image generator (of graph):

#### smooth_graph.php

```<?php
set_time_limit(100);
define('GRAPH_WIDTH',  500);
define('GRAPH_HEIGHT', 400);
include_once ('classes/Plot.php');
include_once ('classes/CubicSplines.php');
\$iPoints = 15;
\$dx = (GRAPH_WIDTH - 40) / (\$iPoints - 1);
\$x = 20;
for (\$i = 0; \$i < \$iPoints; \$i++) {
\$y = rand(20, GRAPH_HEIGHT - 20);
\$aCoords[\$x] = \$y;
\$x+= \$dx;
}
\$vImagegHeight = GRAPH_HEIGHT + 30;
\$vImage = imagecreatetruecolor(GRAPH_WIDTH + 50, \$vImagegHeight);
\$vBgColor = imagecolorallocate(\$vImage, 160, 160, 160);
\$vTextColor = imagecolorallocate(\$vImage, 0, 0, 0);
\$vAxisColor = imagecolorallocate(\$vImage, 0, 0, 0);
\$vDotColor  = imagecolorallocate(\$vImage, 192, 64, 64);
imagefill(\$vImage, 0, 0, \$vBgColor);
\$oPlot = new Plot(\$aCoords);
\$oPlot->drawDots(\$vImage, \$vDotColor, 10, GRAPH_HEIGHT, 8);
\$oCurve = new CubicSplines();
\$vColor = imagecolorallocate(\$vImage, 225, 64, 64);
\$iStart = microtime(1);
if (\$oCurve) {
\$oCurve->setInitCoords(\$aCoords, 1);
\$r = \$oCurve->processCoords();
if (\$r)
\$curveGraph = new Plot(\$r);
else
continue;
} else {
\$curveGraph = \$oPlot;
}
\$curveGraph->drawLine(\$vImage, \$vColor, 10, GRAPH_HEIGHT);
// unset(\$oCurve);
\$sTime = sprintf("%1.4f", microtime(1) - \$iStart);
imagefilledrectangle(\$vImage, 0, GRAPH_HEIGHT, GRAPH_WIDTH + 50, \$vImagegHeight, \$vBgColor);
\$oPlot->drawAxis(\$vImage, \$vAxisColor, 10, GRAPH_HEIGHT);
\$iPanelY = GRAPH_HEIGHT;
imagefilledrectangle(\$vImage, 10, \$iPanelY + 10, 20, \$iPanelY + 20, \$vColor);
imagerectangle(\$vImage, 10, \$iPanelY + 10, 20, \$iPanelY + 20, \$vAxisColor);
imagettftext(\$vImage, 10, 0, 30, \$iPanelY + 20, \$vTextColor, 'Ds-digib.ttf', 'Cubic splines in PHP for graphs:         ' . \$sTime . ' sec');
imagepng(\$vImage);
imagedestroy(\$vImage);
?>
```

In this file I using 2 another classes (as separated service classes):

#### classes/Plot.php

```<?php
class Plot {
private \$aCoords;
function __construct(&\$aCoords) {
\$this->aCoords = &\$aCoords;
}
public function drawLine(\$vImage, \$vColor, \$iPosX = 0, \$iPosY = false) {
if (\$iPosY === false)
\$iPosY = imagesy(\$vImage);
reset(\$this->aCoords);
list(\$iPrevX, \$iPrevY) = each(\$this->aCoords);
while (list (\$x, \$y) = each(\$this->aCoords)) {
imageline(\$vImage, \$iPosX + round(\$iPrevX), \$iPosY - round(\$iPrevY), \$iPosX + round(\$x), \$iPosY - round(\$y), \$vColor);
\$iPrevX = \$x;
\$iPrevY = \$y;
}
}
public function drawDots(\$vImage, \$vColor, \$iPosX = 0, \$iPosY = false, \$iDotSize = 1) {
if (\$iPosY === false)
\$iPosY = imagesy(\$vImage);
\$vBorderColor = imagecolorallocate(\$vImage, 0, 0, 0);
foreach (\$this->aCoords as \$x => \$y) {
imagefilledellipse(\$vImage, \$iPosX + round(\$x), \$iPosY - round(\$y), \$iDotSize, \$iDotSize, \$vColor);
imageellipse(\$vImage, \$iPosX + round(\$x), \$iPosY - round(\$y), \$iDotSize, \$iDotSize, \$vBorderColor);
}
}
public function drawAxis(\$vImage, \$vColor, \$iPosX = 0, \$iPosY = false) {
if (\$iPosY === false)
\$iPosY = imagesy(\$vImage);
\$vImageWidth = imagesx(\$vImage);
imageline(\$vImage, \$iPosX, \$iPosY, \$iPosX, 0, \$vColor);
imageline(\$vImage, \$iPosX, \$iPosY, \$vImageWidth, \$iPosY, \$vColor);
imagefilledpolygon(\$vImage, array(\$iPosX, 0, \$iPosX - 3, 5, \$iPosX + 3, 5), 3, \$vColor);
imagefilledpolygon(\$vImage, array(\$vImageWidth, \$iPosY, \$vImageWidth - 5, \$iPosY - 3, \$vImageWidth - 5, \$iPosY + 3), 3, \$vColor);
}
}
?>
```

#### and classes/CubicSplines.php

```<?php
class CubicSplines {
protected \$aCoords;
protected \$aCrdX;
protected \$aCrdY;
protected \$aSplines = array();
protected \$iMinX;
protected \$iMaxX;
protected \$iStep;
protected function prepareCoords(&\$aCoords, \$iStep, \$iMinX = -1, \$iMaxX = -1) {
\$this->aCrdX = array();
\$this->aCrdY = array();
\$this->aCoords = array();
ksort(\$aCoords);
foreach (\$aCoords as \$x => \$y) {
\$this->aCrdX[] = \$x;
\$this->aCrdY[] = \$y;
}
\$this->iMinX = \$iMinX;
\$this->iMaxX = \$iMaxX;
if (\$this->iMinX == -1)
\$this->iMinX = min(\$this->aCrdX);
if (\$this->iMaxX == -1)
\$this->iMaxX = max(\$this->aCrdX);
\$this->iStep = \$iStep;
}
public function setInitCoords(&\$aCoords, \$iStep = 1, \$iMinX = -1, \$iMaxX = -1) {
\$this->aSplines = array();
if (count(\$aCoords) < 4) {
return false;
}
\$this->prepareCoords(\$aCoords, \$iStep, \$iMinX, \$iMaxX);
\$this->buildSpline(\$this->aCrdX, \$this->aCrdY, count(\$this->aCrdX));
}
public function processCoords() {
for (\$x = \$this->iMinX; \$x <= \$this->iMaxX; \$x += \$this->iStep) {
\$this->aCoords[\$x] = \$this->funcInterp(\$x);
}
return \$this->aCoords;
}
private function buildSpline(\$x, \$y, \$n) {
for (\$i = 0; \$i < \$n; ++\$i) {
\$this->aSplines[\$i]['x'] = \$x[\$i];
\$this->aSplines[\$i]['a'] = \$y[\$i];
}
\$this->aSplines[0]['c'] = \$this->aSplines[\$n - 1]['c'] = 0;
\$alpha[0] = \$beta[0] = 0;
for (\$i = 1; \$i < \$n - 1; ++\$i) {
\$h_i = \$x[\$i] - \$x[\$i - 1];
\$h_i1 = \$x[\$i + 1] - \$x[\$i];
\$A = \$h_i;
\$C = 2.0 * (\$h_i + \$h_i1);
\$B = \$h_i1;
\$F = 6.0 * ((\$y[\$i + 1] - \$y[\$i]) / \$h_i1 - (\$y[\$i] - \$y[\$i - 1]) / \$h_i);
\$z = (\$A * \$alpha[\$i - 1] + \$C);
\$alpha[\$i] = - \$B / \$z;
\$beta[\$i] = (\$F - \$A * \$beta[\$i - 1]) / \$z;
}
for (\$i = \$n - 2; \$i > 0; --\$i) {
\$this->aSplines[\$i]['c'] = \$alpha[\$i] * \$this->aSplines[\$i + 1]['c'] + \$beta[\$i];
}
for (\$i = \$n - 1; \$i > 0; --\$i) {
\$h_i = \$x[\$i] - \$x[\$i - 1];
\$this->aSplines[\$i]['d'] = (\$this->aSplines[\$i]['c'] - \$this->aSplines[\$i - 1]['c']) / \$h_i;
\$this->aSplines[\$i]['b'] = \$h_i * (2.0 * \$this->aSplines[\$i]['c'] + \$this->aSplines[\$i - 1]['c']) / 6.0 + (\$y[\$i] - \$y[\$i - 1]) / \$h_i;
}
}
private function funcInterp(\$x) {
\$n = count(\$this->aSplines);
if (\$x <= \$this->aSplines[0]['x'])  {
\$s = \$this->aSplines[1];
} else {
if (\$x >= \$this->aSplines[\$n - 1]['x']) {
\$s = \$this->aSplines[\$n - 1];
} else {
\$i = 0;
\$j = \$n - 1;
while (\$i + 1 < \$j) {
\$k = \$i + (\$j - \$i) / 2;
if (\$x <= \$this->aSplines[\$k]['x']) {
\$j = \$k;
} else {
\$i = \$k;
}
}
\$s = \$this->aSplines[\$j];
}
}
\$dx = (\$x - \$s['x']);
return \$s['a'] + (\$s['b'] + (\$s['c'] / 2.0 + \$s['d'] * \$dx / 6.0) * \$dx) * \$dx;
}
}
?>
```

### Conclusion

I hope that you got interesting lesson for today. Good luck in your work!

0 115100

### 9 Best PHP Frameworks to Build Awesome Responsive Websites

0 33795

1. what if I have to input some values from user and then evaluate it and prepare a graph?

• Hello Abhinav Pandey,

Then – firstly you should prepare some form for input initial values, secondly – add PHP code for accepting these values.
You need to fill \$aCoords array with these coordinates. And – finally – draw results.

• Have look at this example:
function imagelinethick(\$image, \$x1, \$y1, \$x2, \$y2, \$color, \$thick = 1)
{
/* this way it works well only for orthogonal lines
imagesetthickness(\$image, \$thick);
return imageline(\$image, \$x1, \$y1, \$x2, \$y2, \$color);
*/
if (\$thick == 1) {
return imageline(\$image, \$x1, \$y1, \$x2, \$y2, \$color);
}
\$t = \$thick / 2 – 0.5;
if (\$x1 == \$x2 || \$y1 == \$y2) {
return imagefilledrectangle(\$image, round(min(\$x1, \$x2) – \$t), round(min(\$y1, \$y2) – \$t), round(max(\$x1, \$x2) + \$t), round(max(\$y1, \$y2) + \$t), \$color);
}
\$k = (\$y2 – \$y1) / (\$x2 – \$x1); //y = kx + q
\$a = \$t / sqrt(1 + pow(\$k, 2));
\$points = array(
round(\$x1 – (1+\$k)*\$a), round(\$y1 + (1-\$k)*\$a),
round(\$x1 – (1-\$k)*\$a), round(\$y1 – (1+\$k)*\$a),
round(\$x2 + (1+\$k)*\$a), round(\$y2 – (1-\$k)*\$a),
round(\$x2 + (1-\$k)*\$a), round(\$y2 + (1+\$k)*\$a),
);
imagefilledpolygon(\$image, \$points, 4, \$color);
return imagepolygon(\$image, \$points, 4, \$color);
}

Basically, you can substitute the ‘imageline’ function to the ‘imagelinethick’ function.

2. Nice Tutorial,

Can you please let me know how I would add a colour to the bottom part of the curve.

Thanks