- Подписка на печатную версию:
- Подписка на электронную версию:
- Подшивки старых номеров журнала (печатные версии)
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), но для неподготовленного человека он пока ничего не значит и не несет никакой полезной информации. Давайте снабдим его подписями и разъяснениями – добавим после строки 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.
Глядя на график, сложно понять, что означает каждая из линий, поэтому добавим легенду:
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.
Со строки 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. Из полученной гистограммы мы вряд ли извлечем какие-либо полезные данные, ведь нет ни подписей, ни легенды. По традиции, усовершенствуем ее, и начнем с установки ширины столбцов:
$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("Время");
Первая строка придает столбцам объем, а с остальными мы уже знакомы.
Очень часто значения посещаемости на выходных отличаются от показателей в будние дни, когда люди находятся на работе: здесь нам пригодятся сгруппированные гистограммы. Подготовим вторую гистограмму, имитирующую посещаемость нашего вымышленного сайта в нерабочее время:
$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);
Антиспаммер
В мире развелось слишком много спамеров, флудеров и просто «хороших людей», к тому же многие из них – это программы. Одним из способов защиты от таких «гостей» является ввод пользователем секретного кода с картинки, отображаемой на сайте (так называемой «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 задает время жизни, измеряемое в минутах.