Gnuplot на домашней страничке

от автора

Зачем?

При разработке доступной онлайн базы данных для хранения результатов расчётов возникло непреодолимое желание представлять информацию не только в табличном виде, но и в виде графиков. Можно пойти различными путями, например, рисовать кривые в PHP, но правильнее (в смысле UNIX-way) будет использовать внешнюю программу, уже умеющую строить графики, такую как Gnuplot.

Особенно интригует возможность вывода графиков в виде набора JS комманд для рисования на HTML5-холсте (canvas), чем мы и займёмся.

О Gnuplot много писали, в том числе и на Хабре (1, 2), поэтому нет необходимости в подробном описании его синтаксиса.

К своему удивлению, я не обнаружил хорошего туториала о том, как связать вывод gnuplot с динамически формируемой страничкой. Возможно, это связано с недостатком знаний о Java Script и на самом деле всё очевидно, но тем не менее, есть надежда, что эта статья окажется полезной.

Вывод Gnuplot в HTML5 Canvas

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

#!/usr/bin/gnuplot set terminal canvas set output "output.html" plot sin(x) with lines 

Здесь первая строка задает интерпретатор команд, вторая — устанавливает формат вывода canvas. Для особо удачных графиков здесь можно было бы заменить canvas на pdf и сразу вставить результат в статью для, скажем, Nature. Третья строка указывает имя файла для записи, если ее не будет — то поток будет направлен в stdout, чем мы воспользуемся при генерации html-странички. Последняя строка содержит собственно команду для построения графика синуса.

Открыв сгенерированный файл output.html, можно увидеть график:

Хорошо, но такой результат вполне можно было бы получить, вставляя рисунки, полученные и терминалом png, а хотелось бы интерактивности! Для этого нужно всего лишь указать параметры терминала enhanced mousing:

set terminal canvas enhanced mousing  set output "output.html" set xlabel 'Time' set ylabel 'Energy' plot sin(4*x)/x with lines linewidth 2 

В результате появится панелька с управляющими кнопками, возможность ставить точки и приближать интересующую область:

Уже больше похоже на примеры с сайта разработчиков, но с удаленного компьютера работать не будет, поскольку за вспомогательными JS-скриптами идет обращение в локальную файловую систему, так как сгенерированный файл содержит строки типа:

<script src="/usr/share/gnuplot/gnuplot/4.6/js/gnuplot_common.js"></script> 

То есть, нужно разместить файлы из /usr/share/gnuplot/gnuplot/4.6/js на своем сайте, скопировав их или создав ссылку. Для работы достаточно иметь файлы canvastext.js, gnuplot_common.js, gnuplot_mouse.js, gnuplot_mouse.css и png-иконки. Также необходимо указать путь к этим файлам в параметрах терминала:

set terminal canvas enhanced mousing jsdir 'js' 

Взаимодействие PHP и gnuplot

Итак, есть путь к папке расчётов, нужно построить график согласно выбранным пунктам на html-страничке.
Разобьем задачу на несколько частей, как показано на диаграмме:

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

  • shell-скрипт имеет доступ к файлам на диске и запуску gnuplot, но не должен быть доступен снаружи,
  • php и html — наоборот, доступны снаружи и не должны иметь доступа к файлам за пределами сайта,
  • отдельный .gp файл позволяет повторить построение графика, но в более удобном для публикации формате выбором pdf или png терминалов.

PHP/HTML

html-форма и php-скрипт объединены в один файл plot_calc.php:

<?php // получаем и устанавливаем управляющие переменные: $path = $_GET['path'];                        // user-friendly путь, $fullpath = "/srv/calculations/".$path."/";   // полный путь в локальной ФС $nSites = $_GET['nsites'];                    // параметр расчета - число 'сайтов'  $fSite = 1;                                   // текущий 'сайт' if (isset($_POST["fSite"])) { $fSite = $_POST["fSite"]; }  // опущено описание заголовка и стилей echo '<a href=index.html>Back</a>'; echo '<h1>Plot Calculation Data</h1>'; echo '<form id="form_plots" method="post" action=plot_calc.php?path='.$path.'&nsites='.$nSites.'>'; echo '    <input id="plotProb"  type="submit" name="plotProb" value="Prob" />'; echo '    <input id="plotEnergy" type="submit" name="plotEnergy" value="Energy" />'; // ... echo '    <label>Site number to plot</label>'; echo '    <input id="fSite" name="fSite"  type="text" value='.$fSite.' />'; echo '</form>';  if (isset($_POST["plotProb"])) {   // если нажата кнопка plotProb         $input='./plot_calc.sh'.' '.'p '.$nSites.' '.$fullpath.' '.$fSite;         echo "Probability plot for Site #".$fSite;     } if (isset($_POST["plotEnergy"])) { // если нажата кнопка plotEnergy         $input='./plot_calc.sh'.' '.'E '.$nSites.' '.$fullpath.' '.$fSite;         echo "Energy plot for Site #".$fSite;     } // ...   $output = shell_exec($input); // запуск скрипта оболочки echo $output;                 // вывод результата работы скрипта  echo '</body>'; echo '</html>'; ?> 

SHELL

Задача скрипта plot_calc.sh — формирование команд для gnuplot согласно заданным внешним параметрам. Скрипт создает файл во временной директории /tmp, содержимое которого передается gnuplot, а результат выполнения возвращается обратно, где его уже ждет php-скрипт.

#!/bin/bash # параметры: # 1 - тип # 2 - число сайтов # 3 - путь # 4 - сайт для рисования (требуется для p) #  -------------- # тип   значение    # E	energy # p     probaility # .... #------------------------------#  # создадим новый файл во временном каталоге: TFILE="/tmp/$(basename $0).$$.gp" # запишем в него команды gnuplot: echo "# Automatically generated Gnuplot script " > $TFILE echo "set terminal canvas enhanced mousing jsdir 'js'" >> $TFILE  ### Probability ### if [ $1 == 'p' ] then     echo "set xlabel 'Time'">>$TFILE     echo "set ylabel 'Probability'">>$TFILE     let icol=$4+1     echo "plot '$3prob.res' u 1:$icol wi li">>$TFILE fi  # ...  ### Energy ### if [ $1 == 'E' ] then     let col=$4*2     let col1=$4*2+1     echo "set xlabel 'Time'">>$TFILE     echo "set ylabel 'Energy'">>$TFILE     echo "plot '$3Energ.res' u 1:$col:$col1 wi err">>$TFILE fi  /usr/bin/gnuplot $TFILE 

Этому файлу потребуются права на исполнение:

 chmod +x plot_calc.sh 

Gnuplot

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

# Automatically generated Gnuplot script  set terminal canvas enhanced mousing jsdir 'js' set xlabel 'Time' set ylabel 'Probability' plot '/srv/calculations/GoodCalc/prob.res' u 1:6 wi li 

Проверить работу можно направив браузер по адресу http://servername/plot_calc.php?path=GoodCalc&nsites=10.
В результате появится возможность построить графики по данным файлов prob.res и Energy.res, и должна получится страничка, похожая на:

Генерируемые файлы в /tmp надо время от времени подчищать, для этого сгодится задание cron (от root’а):

crontab -e 

0 */1 * * * rm -v /tmp/plot*.gp >> /var/log/rmplotgp.log 

Заключение

  1. Тестирование и демонстрация проводились на Debian Jessie, но должно работать и на прочих системах;
  2. JS-файлы gnuplot должны быть доступны из внешней сети;
  3. Есть возможность формирования не только html-страничек, но и js-скриптов, управляемых пользовательским кодом.
  4. Вопросы нагрузки и безопасности здесь не рассматривались и потребуют дополнительного внимания…

ссылка на оригинал статьи http://habrahabr.ru/post/248383/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *