LXF115:JpGraph

Материал из Linuxformat.

Перейти к: навигация, поиск
JpGraph Добавьте графики в свои PHP-сценарии!


JpGraph

Содержание

Графики и диаграммы

ЧАСТЬ 1 Большие начальники любят яркие графики – но даже если вы работаете на себя (или еще учитесь), от них тоже бывает польза. Какая? Спросите у Никиты Шультайса.

Каждый день мы имеем дело с «тоннами» визуальной информации: часть ее представлена простым текстом, часть – в виде таблиц, а часть – в виде графиков и диаграмм. И так уж вышло, что оптимальными для восприятия являются именно «картинки» – грамотно построенная диаграмма может сэкономить массу времени и нервов как для понимания информации, так и для ее объяснения. Поэтому сегодня мы будем говорить о графическом представлении данных с помощью PHP-библиотеки JpGraph (http://www.aditus.nu/jpgraph/), работающей поверх стандартной GD. JpGraph – мощный инструмент, позволяющий создавать:

  • гистограммы
  • круговые диаграммы
  • линейные графики
  • биржевые диаграммы
  • сетчатые диаграммы
  • диаграммы Ганта
  • антиспам-изображения (Capthca)

JpGraph – свободное ПО, распространяющееся по дуальной лицензии: довольно редкой сейчас Q Public License (QPL) 1.0 для применения в открытых проектах и обучения, а также традиционной коммерческой. Но, в отличие от инструментария Qt, «породившего» QPL, свободная и коммерческая версии различаются по функционалу. Последняя носит название JpGraph Professional и, в дополнение к перечисленному выше, умеет отрисовывать «розы ветров», а также линейные и квадратные штрих-коды, широко применяемые в торговле.

Первый график

Первое, что нам потребуется – это скачать библиотеку или взять ее с LXFDVD. Обратите внимание, что в настоящее время доступны две ветки: JpGraph 1.x для PHP4 и JpGraph 2.x для PHP 5.1 и выше; мы воспользуемся последней. Как и с большинством PHP-библиотек, для установки достаточно поместить JpGraph в корень вашего сайта, а затем подключить его из любого скрипта. Однако это простое действие выполняется в два этапа:

1 Подключение ядра:

include ( "./jpgraph/src/jpgraph.php");

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

include ("./jpgraph/src/jpgraph_line.php");

Перейдем от слов к делу и создадим наш первый график. Для примера возьмем среднее число посетителей интернет-сайта в день и проследим динамику в течение года. Создадим файл visits.php и добавим в него следующий код (номера строк, разумеется, добавлены только для удобства восприятия):

1 <?
  2 include ( "./jpgraph/src/jpgraph.php");
  3 include ("./jpgraph/src/jpgraph_line.php");
  4
  5 $ydata = array(124, 235, 478, 432, 511, 512 , 533, 780, 789, 806, 933, 987);
  6 $graph = new Graph(650, 450);
  7 $graph->SetScale("textlin");
  8 $lineplot = new LinePlot($ydata);
  9 $lineplot->SetColor("blue");
  10 $graph->Add($lineplot);
  11 $graph->Stroke();
  12 ?>

Как правило, диаграммы и графики строятся по набору данных, представлением которого в языках программирования является массив: его мы и объявляем в строке 5. Конечно, пример наигран, и для изменения графика требуется правка исходных текстов – в реальной ситуации информация может поступать из базы данных или считываться из файла. В строке 6 мы создаем объект класса Graph, передавая ему 2 параметра – ширину и высоту изображения. Следующая строка отвечает за масштабирование. В строке 8 мы создаем график-линию, передавая в конструктор класса данные нашего массива, а в строке 9 указываем его цвет. Наконец, в строке 10 мы добавляем наш график к изображению, а в строке 11 непосредственно генерируем (отрисовываем) его.

Рис. 1 Рис. 1. Наш «первый блин»: все бы неплохо, но чего-то не хватает.

Ну вот, наш первый график готов (рис. 1), но для неподготовленного человека он пока ничего не значит и не несет никакой полезной информации. Давайте снабдим его подписями и разъяснениями – добавим после строки 7 следующий код:

$graph->title->Set(‘Посещаемость сайта в 2008 году’);

В результате у графика появится заголовок.

А теперь по-русски

После обновления страницы вместо читаемого текста мы увидим «любимые крякозябры». Пока что наша библиотека не настроена на работу с кириллицей, но это поправимо: определим в файле jpg-config.inc.php константу TTF_DIR, содержащую путь до каталога с TTF-шрифтами:

 DEFINE("TTF_DIR","/путь/до/TTF/шрифтов/");

Там же настроим кодировки, сообщив системе, что в наших скриптах мы собираемся использовать UTF-8:

 DEFINE("LANGUAGE_CYRILLIC",true);
 DEFINE("CYRILLIC_FROM_WINDOWS",false);
 DEFINE(‘LANGUAGE_CHARSET’, ‘utf-8’);

И самое последнее – нужно указать нашему объекту graph, какой шрифт следует применять для какого названия. Нас интересует заголовок графика (title), поэтому можно добавить нечто вроде

 $graph->title->SetFont(FF_VERDANA,FS_NORMAL);

Здесь я использую шрифт verdana.ttf.

Продолжим наши усовершенствования – добавим на график дополнительную информацию:

1 $graph->img->SetMargin(80,30,30,60);
  2 $graph->xaxis->title->margin = 15;
  3 $graph->xaxis->title->Set("Месяцы");
  4 $graph->xaxis->title->SetFont(FF_VERDANA,FS_NORMAL);
  5 $graph->yaxis->title->margin = 25;
  6 $graph->yaxis->title->Set("Посещаемость");
  7 $graph->yaxis->title->SetFont(FF_VERDANA,FS_NORMAL);

В строке 1 мы указываем внутренние отступы для нашего изображения, а затем задаем дополнительные параметры координатных осей: так, в строках 2 и 5 определяется расстояние между подписью к оси и самой осью, в строках 3 и 6 – текст подписей, а в 4 и 7 – шрифты. Заметьте, что нам нужно задавать шрифты для каждого из объектов нашего графика, иначе мы будем наблюдать все те же «крякозябры».

То, что мы сейчас сделали, относится к изображению в целом и к осям; давайте обогатим информацией и нашу ломаную:

1 $lineplot->mark->SetType(MARK_SQUARE);
  2 $lineplot->value->Show();
  3 $lineplot->value->SetColor("blue");
  4 $lineplot->value->SetFont(FF_VERDANA, FS_NORMAL);
  5 $lineplot->value->SetFormat("%d");

В первой строке мы определяем маркер, обозначающий точку на графике (квадрат), в строках 3 и 4 задаются цвет и шрифт подписи к каждой точке, а в строке 5 – формат вывода значения (число).

Дайте два!

Зачастую нас и наших потенциальных рекламодателей интересует не только количество уникальных посетителей (хостов), но количество показанных страниц (хитов), поэтому изображение можно немного расширить, добавив еще одни график:

1 $hits = array(604, 1205, 2078, 2032, 2510, 2502 , 2503, 3580, 3709, 4006, 4533, 4670);
  2 $lineplot2 = new LinePlot($hits);
  3 $lineplot2->SetColor("red");
  4 $lineplot2->SetWeight(2);
  5 $graph->Add($lineplot2);

Как и в предыдущем случае, мы создаем объект графика-линии (LinePlot). Новым параметром здесь является толщина линии, которую мы установили равной двум в строке 4. График нужно не забыть добавить к изображению – это происходит в строке 5.

Глядя на график, сложно понять, что означает каждая из линий, поэтому добавим легенду:

Рис. 2 Рис. 2. После некоторой доводки график выглядит уже весьма профессионально.

1 $lineplot->SetLegend("Хост");
  2 $lineplot2->SetLegend("Хит");
  3 $graph->legend->SetFont(FF_VERDANA,FS_NORMAL);
  4 $graph->img->SetMargin(80,130,30,80);

Обратите внимание, что в строке 4 мы изменяем внутренние поля изображения, которые задавали в примерах выше: это необходимо, чтобы наша легенда не закрывала ни один из графиков. Кроме того, давайте заменим безликие номера месяцев их названиями:

1 $months = array("январь","февраль","март","апрель","май", "июнь","июль","август","сентябрь","октябрь","ноябрь","декабрь");
  2 $graph->xaxis->SetFont(FF_VERDANA,FS_NORMAL);
  3 $graph->xaxis->SetTickLabels($months);
  4 $graph->xaxis->SetLabelAngle(90);

В строке 4 мы определяем угол, на который будут повернуты подписи. Теперь можно удалить строку

 $graph->xaxis->title->Set("Месяцы");

так как названия месяцев говорят сами за себя. И, наконец, завершим наши старания добавлением координатной сетки и ее раскрашиванием:

$graph->ygrid->Show(true);
$graph->xgrid->Show(true);
$graph->ygrid->SetFill(true,’#EFEFEF@0.5’,’#BBCCFF@0.5’);

Окончательный результат можно видеть на рис. 2.

В помощь математикам

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

1 <?
 2 include ( "./jpgraph/src/jpgraph.php");
 3 include ("./jpgraph/src/jpgraph_line.php");
 4 include ("./jpgraph/src/jpgraph_utils.inc.php");
 5 $f = new FuncGenerator(cos($x)+1.5*cos(2*$x));
 6 list($datax,$datay) = $f->E(0,10);
 7 $tickPositions = array();
 8 $tickLabels = array();
 9 $tickPositions[0] = 0;
 10 $tickLabels[0] = ‘0’;
 11 for($i=1; $i/2*M_PI < 11 ; ++$i ) {
 12 $tickPositions[$i] = $i/2*M_PI;
 13     if( $i % 2 ) $tickLabels[$i] = $i.’/2’.SymChar::Get(pi);
 14     else $tickLabels[$i] = ($i/2).SymChar::Get(pi);
 15 }
 16 $n = count($datax);
 17 $xmin = $datax[0];
 18 $xmax = $datax[$n-1];
 19 $graph = new Graph(650, 450);
 20 $graph->SetScale(‘linlin’,0,0,$xmin,$xmax);
 21 $graph->title->Set(cos(x)+1.5*cos(2*x));
 22 $graph->title->SetFont(FF_VERDANA,FS_NORMAL,12);
 23 $graph->xaxis->SetPos(min);
 24 $graph->xaxis->SetMajTickPositions($tickPositions,$tickLabels);
 25 $graph->xaxis->SetFont(FF_VERDANA,FS_NORMAL,10);
 26 $graph->yaxis->SetFont(FF_VERDANA,FS_NORMAL,10);
 27 $graph->xgrid->Show();
 28 $p1 = new LinePlot($datay,$datax);
 29 $p1->SetColor(‘teal’);
 30 $graph->Add($p1);
 31 $graph->Stroke();
 32 ?>

Разберемся, что происходит в этих строках. В первую очередь, мы подключаем библиотеку jpgraph_utils.inc.php, которая содержит вспомогательные утилиты, в том числе и класс генерации данных для функций (нормальных и параметрических), и уже в 5-й строке создаем объект этого класса. Обратите внимание, что самая функция представлена строкой, содержащей PHP-конструкцию с переменной $x: это необходимо для безопасности вашего приложения. В строке 6 мы вычисляем значения функции в виде пар (x,y=f(x)) на некотором множестве точек в диапазоне от 0 до 10.

Рис. 3 Рис. 3. Гладкая кривая JpGraph тоже по плечу.

Со строки 7 по 15 мы создаем разметку. Особое внимание тут стоит уделить конструкции SymChar::Get(‘pi’) – вызов статической функции Get класса SymChar, которая возвращает символы греческого алфавита, в нашем случае это «пи». В строке 24 вызывается метод SetMajTickPositions(), который расставляет наши метки (разметку) в соответствии с вычисленными позициями.

Вернувшись чуть-чуть назад, обратим внимание на строку 20, где в качестве первого параметра метода SetScale() используется не ‘textlin’, а ‘linlin’. Вообще, первый параметр отвечает сразу за две величины, а именно, за масштабируемость по осям x и y. Соответственно, в случае с textlin по x было текстовое масштабирование, а по y – линейное. В случае linlin они оба линейны, что лучше подходит для математических графиков. Помимо изменения первого параметра добавилось еще четыре, отвечающих за минимальные и максимальные значения по x и по y.

В строках 22, 25 и 26 мы задаем шрифты. Единственным заметным новшеством здесь является явное указание размера: 12, 10 и 10. Все остальные параметры и функции мы рассмотрели в примерах выше, так что теперь самое время смотреть результаты (рис. 3).

Гистограммы

Графики готовы – они наглядны и несут необходимую информацию, но останавливаться на достигнутом мы не будем. Дадим себе и посетителям больше информации о сайте, создав гистограмму посещений в зависимости от времени суток.

Модуль построения гистограмм находится в файле jpgraph_bar.php; добавим в наш скрипт эту библиотеку:

include ("./jpgraph/src/jpgraph_bar.php");

Работа с гистограммами во многом похожа на работу с графиками: здесь также нужен массив исходных данных, названия и шрифты, но есть и некоторые тонкости. Создадим новое изображение с гистограммой:

1 include ( "./jpgraph/src/jpgraph.php");
 2 include ("./jpgraph/src/jpgraph_bar.php");
 3 $visits = array(120, 343, 681, 2354, 1890, 511);
 4 $graph = new Graph(650, 450);
 5 $graph->SetScale("textlin");
 6 $graph->title->SetFont(FF_VERDANA,FS_NORMAL);
 7 $graph->title->Set(‘Посещаемость сайта в течение суток’);
 8 $bplot = new BarPlot($visits);
 9 $graph->Add($bplot);
 10 $graph->Stroke();

Основное отличие этого кода от виденного нами ранее кроется в строке 8: мы используем класс BarPlot вместо LinePlot. Из полученной гистограммы мы вряд ли извлечем какие-либо полезные данные, ведь нет ни подписей, ни легенды. По традиции, усовершенствуем ее, и начнем с установки ширины столбцов:

Рис. 4 Рис. 4. Обратите внимание — пик посещаемости приходится на середину рабочего дня. К чему бы это?

$bplot->SetWidth(0.9);

Максимально возможное значение – 1.0, мы берем чуть меньше (0.9). Теперь добавим в центры столбцов значения посещаемости:

$bplot->value->Show();
$bplot->value->SetFormat(‘%d’);
$bplot->value->SetFont(FF_VERDANA,FS_NORMAL);
$bplot->SetValuePos(‘center’);

Если убрать нижние три строчки, то значения будут отображаться над столбцами, причем у самого высокого столбца цифры будут выходить за пределы области построения диаграммы. Чтобы избежать этого, можно добавить следующую строку:

$graph->yaxis->scale->SetGrace(4);

Теперь украсим диаграмму финальными штрихами (рис. 4):

$bplot->SetShadow();
$times = array("0-4","4-8","8-12","12-16","16-20","20-24");
$graph->xaxis->SetFont(FF_VERDANA,FS_NORMAL);
$graph->xaxis->SetTickLabels($times);
$graph->xaxis->title->SetFont(FF_VERDANA,FS_NORMAL);
$graph->xaxis->title->Set("Время");

Первая строка придает столбцам объем, а с остальными мы уже знакомы.

Очень часто значения посещаемости на выходных отличаются от показателей в будние дни, когда люди находятся на работе: здесь нам пригодятся сгруппированные гистограммы. Подготовим вторую гистограмму, имитирующую посещаемость нашего вымышленного сайта в нерабочее время:

Рис. 5 Рис. 5. Гистограммы можно выводить вместе – это позволяет быстрее находить в них различия.

$visits2 = array(183, 225, 454, 2123, 2456, 1345);
$bplot2 = new BarPlot($visits2);
$bplot2->value->Show();
$bplot2->value->SetFormat(‘%d’);
$bplot2->value->SetFont(FF_VERDANA,FS_NORMAL);
$bplot2->SetValuePos(‘center’);
$bplot2->SetFillColor("orange");

Она аналогична первой, но имеет другие значения столбцов и оранжевый цвет. Теперь создадим объект группированных гистограмм и добавим его в изображение:

$gbplot = new GroupBarPlot(array($bplot,$bplot2));
$graph->Add($gbplot);

Не забудьте закомментировать строку

$graph->Add($bplot);

которая добавляла «отдельно стоящую» гистограмму. Наконец, изменим угол наклона надписей и добавим легенду:

$bplot->value->SetAngle(90);
$bplot2->value->SetAngle(90);
$bplot->SetLegend("Будние дни");
$bplot2->SetLegend("Выходные");
$graph->legend->SetFont(FF_VERDANA,FS_NORMAL);
$graph->img->SetMargin(80,130,30,80);

Антиспаммер

Рис. 6 Рис. 6. Антиспаммер

В мире развелось слишком много спамеров, флудеров и просто «хороших людей», к тому же многие из них – это программы. Одним из способов защиты от таких «гостей» является ввод пользователем секретного кода с картинки, отображаемой на сайте (так называемой «captcha»). Программе тяжело распознавать нестандартные кривые символы, а человеку это под силу, и, как вы уже догадались, в JpGraph есть возможность создавать их. Чтобы объяснить, как это работает, достаточно пяти строк:

1 require_once "./jpgraph/src/jpgraph_antispam.php";
 2 $spam = new AntiSpam();
 3 $chars = $spam->Rand(5);
 4 $spam->Set($chars);
 5 $spam->Stroke();

В первой строке мы по обыкновению подключаем дополнительный модуль. Обратите внимание, что ядро библиотеки здесь не требуется. Затем создаем объект AntiSpam, а в строке 3 генерируем пять символов. Далее вставляем их в изображение и выводим. Все максимально просто и эффективно. LXF

Дополнительные возможности

Если вам по-прежнему кажется, что вашим графикам чего-то недостает, обратите внимание на следующие функции:

  • Ступенчатое отображение
    В данном режиме точки соединяются двумя отрезками (горизонтальным и вертикальным), в результате чего график получается ступенчатым. Чтобы активировать его, нужно вызвать метод SetStepStyle():
     $lineplot->SetStepStyle();
  • Заливка
    Для заливки области, расположенной под графиком, предназначен метод SetFillColor().
     $lineplot2->SetFillColor(‘red’);
  • При этом важно следить за порядком: если некий график находится выше других, но построен последним, его заливка автоматически перекроет все другие графики. Двигайтесь сверху вниз.
  • Свои изображения
    На первом графике мы отмечали точки с помощью квадратиков, но если вы считаете, что этого недостаточно, то с помощью метода SetTYPE() можно установить собственный маркер:
    $lineplot2->mark->SetTYPE(MARK_IMG, "image.jpg", 1.5);
  • Первый параметр сообщает, что мы будем использовать изображение, второй задает его местоположение, а третий отвечает за масштаб. Можно использовать и одно из встроенных изображений, например:
     $lineplot2->mark->SetTYPE(MARK_IMG_BALL,’red’,1.0);

Технический аспект

Обратите внимание, что все наши скрипты генерируют не html-файл, а картинку, то есть в заголовке передаваемого сервером ответа будет значиться “Content-Type: image/png”, и если вы попытаетесь вывести в вашей программе какой-либо текст, то получите ошибку. А как же тогда вставлять изображение на сайт? Очень просто: добавьте в html-документ тэг <img>, в атрибуте src которого укажите URL вашего скрипта, а уж он сгенерирует файл «на лету» и передаст его в html-документ, не сохраняя на жестком диске. Впрочем, если график обновляется достаточно редко, его кэширование может иметь смысл. Откройте файл jpg-config.inc.php и раскомментируйте строку:

DEFINE("CACHE_DIR","/путь/до/каталога/где/будет/кэш/");

а затем активируйте систему кэширования:

DEFINE("USE_CACHE",true);

Создавая объект изображения, мы передаем ему ширину и высоту. Еще два параметра управляют процессом кэширования:

$graph = new Graph(650, 450,"auto",60);

Значение "auto" указывает на имя файла кэша; в нашем случае оно будет совпадать с именем скрипта. Число 60 задает время жизни, измеряемое в минутах.

Личные инструменты
  • Купить электронную версию
  • Подписаться на бумажную версию