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/розрахунки/".$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="Енергія" />';
// ...
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/розрахунки/GoodCalc/prob.res' u 1:6 wi li

Перевірити роботу можна направивши браузер за адресою 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. Питання навантаження і безпеки тут не розглядалися і потребують додаткової уваги...

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.