Pull to refresh

Анимированные графики с помощью gnuplot+bash+Avidemux

Reading time 6 min
Views 14K
Практически неотъемлемая часть любой презентации на естественно-научной конференции — это графики. Нередко интересно увидеть не только график какой-нибудь зависимости в некоторый момент времени, но и посмотреть, как эта зависимость меняется во времени. Очень наглядно это можно показать, сделав много-много графиков и собрав из них видео. Об одном из вариантов, как это сделать, и будет мой пост.

Красивые графики можно делать во многих программах: проприетарные Grapher и Origin, свободные gnuplot, QtiPlot, Veusz и другие. Большинство популярных программ для построения графиков имеют интерактивный графический интерфейс, позволяющий быстро сделать publication-quality график, не особо напрягая мозг. Однако, сейчас у нас другая задача — надо наштамповать очень много картинок с однотипными графиками. Редактировать каждый график вручную — дело неблагодарное, поэтому будем пользоваться не гламурным Origin, а невзрачным gnuplot. Его сила в возможности строить график по заданному заранее сценарию (т.е. gnuplot имеет свой скриптовый язык). Далее я покажу, как с помощью нехитрых скриптов быстро делать графики в любом необходимом количестве.

Установка gnuplot


Для пользователей Windows. Идем на сайт проекта. Там жмем «Download» и выбираем подходящий вариант для скачивания. Затем устанавливаем, как обычно.
Для линуксоидов. Устанавливаем пакет с помощью любимого пакетного менеджера. Для пользователей Ubuntu Lucid рекомендую этот PPA — в нем есть новая версия с дополнительными плюшками.

Пример 1. Меняющийся график


Сделаем анимацию того, как меняется парная корреляционная функция жидкости при переходе в стеклообразное состояние. Исходные данные — файл со значениями парной корреляционной функции в разные моменты времени. Выглядит примерно так:
0 100
1 0.0284366 0
2 0.0853097 0
...
99 5.60201 1.0403
100 5.65888 1.01337


1000 100
1 0.0284366 0
2 0.0853097 0
...

Первая строчка — момент времени и число точек N. Затем идут N строк в формате
номер координата_X координата_Y

Затем 2 переноса строки и снова так же. Переносы строк между блоками важны — gnuplot воспринимает блоки, разделенные несколькими переносами строк, как различные. Таким образом, можно строить график, соответствующий только одному блоку.

Теперь запускаем gnuplot — мы заходим в командный интерфейс программы. Набираем
plot "rdf.txt" using 2:3 with lines

Что это означает? plot — команда построить график; «rdf.txt» — путь к файлу, из которого мы хотим считать данные; using 2:3 значит «использовать столбец 2 как значения X, столбец 3 как значения Y»; with lines — просьба выводить на график только линии, соединяющие точки данных.

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

Как видим, нарисованы все графики, содержащиеся в файле. Чтобы нарисовать график только по части точек, используем ключевое слово index. Например, строим график, используя только первые 100 строчек с данными:
plot "rdf.txt" index 0 using 2:3 linewidth 5 with lines

Здесь linewidth 5 говорит о том, что линия будет толще обычного. Результат:

Будем считать, что такой вид графика нас устраивает. Теперь надо пробежать по всем записям во входном файле, построить по всем ним графики и экспортировать их в картинки. Я это делал с помощью пары скриптов на bash. На самом деле, можно обойтись встроенными средствами gnuplot (что лучше, т.к. не привязывает к Юниксам). Делаем скрипты animator.gp и animate.gp. В animator.gp настраиваем график и терминал:
#!/usr/bin/gnuplot
set xrange [2:5.66] #границы графика по X
set yrange [0:4.5] #границы графика по Y
set palette model RGB defined (0 "green", 0.5 "blue", 1 "dark-violet")
unset colorbox
set terminal png font "Droid, 14" size 750,750
set key off
set size square

iterations=100 #задаем число кадров
iterator=0
offset=0.0
load "animate.gp"

В animate.gp делаем, собственно, генерацию картинок.
iterator=iterator+1
offset=iterator/(iterations+1.0) #1.0 нужно, чтобы все выражение вычислялось как float
if (offset <= 1.0)\
   set output "figures/".iterator.".png";\
   plot "./rdf.txt" index iterator using 2:3 smooth csplines linewidth 5 linecolor palette frac offset;\
   reread 

Мне хотелось, чтобы график постепенно менял цвет, поэтому я задал некоторую палитру от зеленого к фиолетовому. Опции unset colorbox и set key off — отключение вывода палитры и легенды на график.

Главные команды в этих скриптах:
set terminal png font "Droid, 14" size 750,750
set output "figures/".iterator.".png"

Первая включает экспорт графика в png с размером 750x750 и шрифтом Droid, когда дается команда plot, вторая задает имя файла. Во второй команде мы воспользовались тем, что gnuplot умеет «конкатенировать» целые числа (но не float!) со строками.

Команда if во втором скрипте выполняет последующие команды при выполнении условия (обратите внимание, что все команды в теле if-a должны быть на одной строчке и разделены точкой с запятой). Команда reread считывает весь скрипт с самого начала, т.е. получается своего рода цикл.
Скрипты выполняются либо простым добавлением прав на исполнение файлу animator.gp с последующим его запуском (в Юниксах) или командой
load "animator.gp"

в командной строке gnuplot (любая ОС).
Запустив скрипты, я получил в папке figures ряд картинок: 1.png, 2.png и т.д. Из них уже можно собирать анимацию. Я это делал с помощью свободного видеоредактора Avidemux.

Собрать анимацию проще простого. Открываем редактор, нажимаем «Открыть», выбираем первую картинку в последовательности (в моем случае было «1.png») — готово, анимация загружена. Можно нажать Play и проверить, что все нормально. Затем сохраняем анимацию в нужном нам формате. Вот мой результат:


Пример 2. Наложение графика на рисунки


Более сложная задача — сделать то же самое, но фон должен быть не белый, а являться картинкой, причем сам еще являться анимированным. У меня такая необходимость появилась, когда понадобилось визуализировать капиллярные флуктуации в двухфазной системе по результатам молекулярной динамики (МД). В принципе, можно накладывать, например, границы циклонов на карту, визуализацию какого-нибудь поля скоростей на видео работы сопла, да мало ли что еще. Итак, приступаем.

Нужен будет gnuplot версии не ниже 4.4 (у пользователей Ubuntu есть в репозитории для версий позднее 10.04. Для 10.04 скачиваем из указанного PPA). Дело в том, что в этой версии gnuplot умеет загружать на график png-файлы с альфа-каналом. У меня было около тысячи файлов со снимками МД ячейки в формате png и столько же файлов, содержащих координаты межфазной границы. animator.gp остается примерно таким же:
#!/usr/bin/gnuplot

set xrange [0:242.4]
set yrange [0:242.4]
set xtics 0 242.4 #делаем так, чтобы штрихи на координатной оси
#рисовались только в начале и в конце
set ytics 0 242.4
set terminal png font "Droid, 14" size 750,750
set key off
set size square
iterations=100 #задаем число кадров
iterator=0
load "animate.gp"

В animate.gp добавляем подгрузку картинки из png-файла:
iterator=iterator+1
if (iterator <= iterations)\
    plot "pic_".iterator.".png" binary filetype=png dx=0.327567568 dy=0.327567568 format='%uchar' using 1:2:3:(160) with rgbalpha;\ #собственно загрузка фонового рисунка
    replot "../surf_z/surface.".iterator.".cfg" using 2:3 smooth csplines linewidth 5;\ #replot означает отрисовку следующего графика поверх предыдущего
#smooth csplines - точки соединяются не отрезками, а сплайнами
    set output iterator.".png";\
    replot;\
    reread

Png загружается командой вида
plot "pic.png" binary filetype=png dx=0.327567568 dy=0.327567568 format='%uchar' using 1:2:3:(160) with rgbalpha

Опция with rgbalpha требует, чтобы график был с четырьмя «осями» (каналы R, G, B, alpha, как ни странно). У меня в фоновых картинках альфа-канала не было, и я просто задал его значение как (160). Значение прозрачности подбиралось методом научного тыка, чтобы и наложенный график было видно, и фон был не слишком блеклый.

Запускается все так же, как и в прошлый раз, генерируются картинки и собираются в видео все тем же Avidemux. Вот результат:


Конечно, можно добавить к графикам красивые подписи осей, легенды и т.д. Для этого нужно дописать несколько команд в скрипты. Интересующимся порекомендую следующие источники:
  1. Официальное руководство по gnuplot (англ.)
  2. Книга «Gnuplot in Action» — в ней описаны всякие хитрости, доступные в gnuplot.
  3. Блог «Записки дебианщика» — про gnuplot и не только.

Примечание: у Origin, QtiPlot и, возможно, других графических редакторов тоже есть свои скриптовые языки. Но автор из-за своей ярой приверженности gnuplot не удосужился их выучить и пишет о том, что знает.
UPD:сделал итерацию средствами gnuplot, а не через bash. Спасибо zeliboba за наводку.
Tags:
Hubs:
+32
Comments 12
Comments Comments 12

Articles