Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Вывод псевдо-объемной гистограммы

Вывод псевдо-объемной гистограммы

Автор: mike, www.codenet.ru
24 апреля 2005 года

В этом уроке мы рассмотрим пример построения универсальной псевдо-объемной гистограммы. Ее размер и размер подписи будет зависеть от размера изображения. (см. рисунки). Единственное, что не будет изменятся - это количество рядов гистограммы.


Что такое гистограмма?

Гистограмма- (от греч. histos, здесь - столб и ...грамма), столбчатая диаграмма, один из видов графического изображения статистического распределении каких-либо величин по количественному признаку. Г. представляет собой совокупность смежных прямоугольников, построенных на прямой линии. Площадь каждого прямоугольника пропорциональна частоте нахождения данной величины в изучаемой совокупности. Пусть, например, измерение диаметров стволов 624 сосен дало следующие результаты:

Диаметр, см 14-22 22-30 30-38 38-62
Число стволов 57 232 212 123


Рисунок 1


Рисунок 2

На горизонтальной оси откладываются границы групп, на которые стволы разбиты по их диаметру, и на отрезке, соответствующем каждой группе, строится как на основании прямоугольник с площадью, пропорциональной числу стволов, попавших в данную группу (рис. 1).

В виде Г. часто изображают гранулометрический состав горных пород. В этом случае на вертикальной оси откладывают процентное содержание полученных групп частиц т. н. фракций, а на горизонтальной оси - логарифмы их граничных размеров (рис. 2). Использование логарифмов вызвано тем, что при гранулометрическом анализе частицы подразделяются на фракции, размеры которых убывают в геометрической прогрессии. Иногда Г. строятся на произвольно выбранных равных отрезках, независимо от разности граничных размеров фракций. Тогда высоты столбиков пропорциональны содержанию размеров фракций.

Источник: БСЭ (Большая Советская Энциклопедия)

Псевдо-объемность

Традиционная гистограмма достаточно проста в построении, по этому мы несколько усложним задачу - добавим объемность. Гистограмма, которую будет строить наша программа будет выглядеть следующим образом:

Остальные графики построенные нашей программой приведены ниже

Пример 31:Вывод круговой диаграммы. Исходный текст с сокращенным количеством комментариев:

Код:
<?php
// Задаем входные данные ############################################

// Входные данные - три ряда, содержащие случайные данные.
// Деление на 2 и 3 взято для того чтобы передние ряды не
// загораживали задние.

// Массив $DATA["x"] содержит подписи по оси "X"

$DATA=Array();
for ($i=0;$i<20;$i++) {
    $DATA[0][]=rand(0,100*$i);
    $DATA[1][]=rand(0,100*$i)/2;
    $DATA[2][]=rand(0,100*$i)/3;
    $DATA["x"][]=$i;
    }

// Функция вывода псевдо-трехмерного куба ###########################

// $im - идентификатор изображения
// $x,$y - координаты верхнего левого угла куба
// $w - ширина куба
// $h - высота куба
// $dx - смещение задней грани куба по оси X
// $dy - смещение задней грани куба по оси Y
// $c1,$c2,c3 - цвета видимых граней куба

function imagebar($im,$x,$y,$w,$h,$dx,$dy,$c1,$c2,$c3) {

    if ($dx<0) {
        imagefilledpolygon($im,
            Array(
                $x, $y-$h,
                $x+$w, $y-$h,
                $x+$w+$dx, $y-$h-$dy,
                $x+$dx, $y-$dy-$h
            ), 4, $c1);
   
        imagefilledpolygon($im,
            Array(
                $x+$w, $y-$h,
                $x+$w, $y,
                $x+$w+$dx, $y-$dy,
                $x+$w+$dx, $y-$dy-$h
            ), 4, $c3);
        }

    imagefilledrectangle($im, $x, $y-$h, $x+$w, $y, $c2);
    }

// Задаем изменяемые значения #######################################

// Размер изображения
$W=500;
$H=300;

// Псевдо-глубина графика
$DX=30;
$DY=20;

// Отступы
$MB=20; // Нижний
$ML=10; // Левый
$M=5;   // Верхний и правый отступы. Они меньше, так как там нет текста

// Ширина одного символа
$LW=imagefontwidth(2);

// Подсчитаем количество элементов (столбиков) на графике
$count=count($DATA[0]);
if (count($DATA[1])<$count) $count=count($DATA[1]);
if (count($DATA[2])<$count) $count=count($DATA[2]);

// Подсчитаем максимальное значение
$max=0;
for ($i=0;$i<$count;$i++) {
    $max=$max<$DATA[0][$i]?$DATA[0][$i]:$max;
    $max=$max<$DATA[1][$i]?$DATA[1][$i]:$max;
    $max=$max<$DATA[2][$i]?$DATA[2][$i]:$max;
    }

// Увеличим максимальное значение на 10% (для того, чтобы столбик
// соответствующий максимальному значение не упирался в в границу
// графика
$max=intval($max+($max/10));

// Работа с изображением ############################################

// Создадим изображения
$im=imagecreate($W,$H);

// Задаем основные цвета

// Цвет фона (белый)
$bg[0]=imagecolorallocate($im,255,255,255);

// Цвет задней грани графика (светло-серый)
$bg[1]=imagecolorallocate($im,231,231,231);

// Цвет левой грани графика (серый)
$bg[2]=imagecolorallocate($im,212,212,212);

// Цвет сетки (серый, темнее)
$c=imagecolorallocate($im,184,184,184);

// Цвет текста (темно-серый)
$text=imagecolorallocate($im,136,136,136);

// Цвета для столбиков
$bar[2][0]=imagecolorallocate($im,255,128,234);
$bar[2][1]=imagecolorallocate($im,222,95,201);
$bar[2][2]=imagecolorallocate($im,191,65,170);
$bar[0][0]=imagecolorallocate($im,222,214,0);
$bar[0][1]=imagecolorallocate($im,181,187,65);
$bar[0][2]=imagecolorallocate($im,161,155,0);
$bar[1][0]=imagecolorallocate($im,128,234,255);
$bar[1][1]=imagecolorallocate($im,95,201,222);
$bar[1][2]=imagecolorallocate($im,65,170,191);

// Количество подписей и горизонтальных линий
// сетки по оси Y.
$county=10;

// Подравняем левую границу с учетом ширины подписей по оси Y
$text_width=strlen($max)*$LW;
$ML+=$text_width;

// Вывод фона графика
imageline($im, $ML, $M+$DY, $ML, $H-$MB, $c);
imageline($im, $ML, $M+$DY, $ML+$DX, $M, $c);
imageline($im, $ML, $H-$MB, $ML+$DX, $H-$MB-$DY, $c);
imageline($im, $ML, $H-$MB, $W-$M-$DX, $H-$MB, $c);
imageline($im, $W-$M-$DX, $H-$MB, $W-$M, $H-$MB-$DY, $c);

imagefilledrectangle($im, $ML+$DX, $M, $W-$M, $H-$MB-$DY, $bg[1]);
imagerectangle($im, $ML+$DX, $M, $W-$M, $H-$MB-$DY, $c);

imagefill($im, $ML+1, $H/2, $bg[2]);

// Вывод неизменяемой сетки (горизонтальные линии на
// нижней грани и вертикальные линии сетки на левой
// грани
for ($i=1;$i<3;$i++) {
    imageline($im, $ML+$i*intval($DX/3),
                   $M+$DY-$i*intval($DY/3),
                   $ML+$i*intval($DX/3),
                   $H-$MB-$i*intval($DY/3),
                   $c);
    imageline($im, $ML+$i*intval($DX/3),
                   $H-$MB-$i*intval($DY/3),
                   $W-$M-$DX+$i*intval($DX/3),
                   $H-$MB-$i*intval($DY/3),
                   $c);
    }

// Пересчитаем размеры графика с учетом подписей и отступов
$RW=$W-$ML-$M-$DX;
$RH=$H-$MB-$M-$DY;

// Координаты нулевой точки графика
$X0=$ML+$DX;
$Y0=$H-$MB-$DY;

// Вывод изменяемой сетки (вертикальные линии сетки на нижней грани графика
// и вертикальные линии на задней грани графика)
for ($i=0;$i<$count;$i++) {
    imageline($im,$X0+$i*($RW/$count),$Y0,$X0+$i*($RW/$count)-$DX,$Y0+$DY,$c);
    imageline($im,$X0+$i*($RW/$count),$Y0,$X0+$i*($RW/$count),$Y0-$RH,$c);
    }

// Горизонтальные линии сетки задней и левой граней.
$step=$RH/$county;
for ($i=0;$i<=$county;$i++) {
    imageline($im,$X0,$Y0-$step*$i,$X0+$RW,$Y0-$step*$i,$c);
    imageline($im,$X0,$Y0-$step*$i,$X0-$DX,$Y0-$step*$i+$DY,$c);
    imageline($im,$X0-$DX,$Y0-$step*$i+$DY,
                  $X0-$DX-($ML-$text_width)/4,$Y0-$step*$i+$DY,$text);
    }

// Вывод кубов для всех трех рядов
for ($i=0;$i<$count;$i++)
    imagebar($im, $X0+$i*($RW/$count)+4-1*intval($DX/3),
                  $Y0+1*intval($DY/3),
                  intval($RW/$count)-4,
                  $RH/$max*$DATA[0][$i],
                  intval($DX/3)-5,
                  intval($DY/3)-3,
                  $bar[0][0], $bar[0][1], $bar[0][2]);

for ($i=0;$i<$count;$i++)
    imagebar($im, $X0+$i*($RW/$count)+4-2*intval($DX/3),
                  $Y0+2*intval($DY/3),
                  intval($RW/$count)-4,
                  $RH/$max*$DATA[1][$i],
                  intval($DX/3)-5,
                  intval($DY/3)-3,
                  $bar[1][0], $bar[1][1], $bar[1][2]);

for ($i=0;$i<$count;$i++)
    imagebar($im, $X0+$i*($RW/$count)+4-3*intval($DX/3),
                  $Y0+3*intval($DY/3),
                  intval($RW/$count)-4,
                  $RH/$max*$DATA[2][$i],
                  intval($DX/3)-5,
                  intval($DY/3)-3,
                  $bar[2][0], $bar[2][1], $bar[2][2]);

// Вывод подписей по оси Y
for ($i=1;$i<=$county;$i++) {
    $str=intval(($max/$county)*$i);
    imagestring($im,2, $X0-$DX-strlen($str)*$LW-$ML/4-2,
                       $Y0+$DY-$step*$i-imagefontheight(2)/2,
                       $str,$text);
    }

// Вывод подписей по оси X
$prev=100000;
$twidth=$LW*strlen($DATA["x"][0])+6;
$i=$X0+$RW-$DX;

while ($i<$X0-$DX) {
    if ($prev-$twidth<$i) {
        $drawx=$i+1-($RW/$count)/2;
        if ($drawx<$X0-$DX) {
            $str=$DATA["x"][round(($i-$X0+$DX)/($RW/$count))-1];
            imageline($im,$drawx,$Y0+$DY,$i+1-($RW/$count)/2,$Y0+$DY+5,$text);
            imagestring($im,2, $drawx+1-(strlen($str)*$LW)/2 ,$Y0+$DY+7,$str,$text);
            }
        $prev=$i;
        }
    $i-=$RW/$count;
    }

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

// Генерация изображения
ImagePNG($im)

imagedestroy($im);
?>

Результат работы этой программы выглядит следующим образом:


$W=500; $H=350; $DX=30; $DY=20;


$W=150; $H=150; $DX=30; $DY=20;


$W=500; $H=150; $DX=30; $DY=20;


$W=200; $H=500; $DX=30; $DY=20;


$W=300; $H=300; $DX=30; $DY=20;


$W=500; $H=300; $DX=30; $DY=120;


$W=500; $H=300; $DX=130; $DY=120;


$W=500; $H=300; $DX=130; $DY=20;

Результат работы программы для изображения 1024x768 можно посмотреть здесь.

Ссылки по теме


Назад | Оглавление | Далее

Оставить комментарий

Комментарий:
можно использовать BB-коды
Максимальная длина комментария - 4000 символов.
 

Комментарии

1.
12K
28 июня 2005 года
maximus_wand
1 / / 28.06.2005
Мне нравитсяМне не нравится
17 сентября 2011, 12:49:50
jpGraph бесплатный для не коммерческих. Или для локальных сетей, если у тебя на сайте не более 2-х пользователей.

Примеры хорошие. Сейчас такие редко встретишь.

Только тут ошибка и кубы всегда плоские:

function imagebar($im,$x,$y,$w,$h,$dx,$dy,$c1,$c2,$c3) {
if ($dx<0) {

Нужно изменить знак if ($dx>0) {
2.
Аноним
Мне нравитсяМне не нравится
26 мая 2005, 02:38:40
Не плохой скриптик, однако жаль, что не предусмотренно колличество столбцов диаграммы.
Но и это можно побороть ;)
3.
Аноним
Мне нравитсяМне не нравится
26 апреля 2005, 16:01:54
Не всегда есть возможность таскать с собой большие библиотеки. Особенно в универсальных скриптах. (Которые распространяются, переносятся, продаются и т.п.)
4.
Аноним
+0 / -1
Мне нравитсяМне не нравится
26 апреля 2005, 15:42:38
Красиво, но не лучше использовать jpgraph?
разработка сокращается в разы
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог