Линукс, Vim, LaTeX, полезные скрипты, визуализация данных, численные расчёты, немного ФП

20080215

Как построить график с изолиниями в gnuplot, gri и pylab

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

Я покажу как это делается на примере сразу трёх свободных инструментов: gnuplot, gri и matplotlib (он же pylab). Именно этими тремя программами я пользуюсь чаще всего. В тексте буду давать ссылки на полный скрипт, используемый для построения графика, пояснять же буду самое основное. Все графики я буду строить в чёрнобелом варианте, сохраняя в формате EPS. Иллюстрации к этой статье получены последующей конвертацией EPS в PNG.

Итак, дано: файл с данными sampledata.txt, значения x, y, z в три колонки, массив 80×80 точек, каждый следующий «столбец» сетки (следующее значение x) отделён от предыдущего пустой строкой. Файлы такого формата использует gnuplot (для gri и для pylab потребуется преобразовать формат). Задача: построить график с изолиниями постоянного значения z.

Итак, способ первый,

строим график с изолиниями в gnuplot

Здесь всё просто. Отключаем построение поверхности, включаем построение изолиний, включаем «вид сверху», велим выбирать уровни автоматически:
unset surface
set contour
set view map
set cntrparam levels auto 10
Можно задать уровни изолиний и вручную:
set cntrparam levels discrete уровень1, уровень2, уровень3, …
Теперь команда
splot 'sampledata.txt' w l
будет строить график с изолиниями. И вот какой результат получается по-умолчанию в gnuplot:
график с изолиниями, построенный в gnuplot
(Запускал gnuplot так: $ gnuplot plotiso_gnulot.txt)


Способ второй,

строим график с изолиниями в gri

Честно говоря, я считаю, что gri справляется с изолиниями лучше, чем gnuplot. Во всяком случае, здесь, в отличие от gnuplot, значения можно надписать прямо на изолиниях, и есть реальная возможность управлять цветами изолиний при сохранении EPS (пользователей gnuplot в этом месте ждёт сюрприз). При этом gri остаётся инструментом достаточно простым для понимания.

Небольшое препятствие состоит лишь в том, что необходимо преобразовать формат данных. Gri хочет, чтобы каждая строка данных отделялась была отдельной строкой в файле, а точки были разделены пробелами. Здесь я использую такую возможность gri, как чтение данных из юниксового «пайпа», и делаю все нужные преобразования на лету с помощью awk:
open "awk ' /[^s]/ { printf($3 \" \"); } /^\s*$/ { print ; }' sampledata.txt |"
read grid data 80 80 bycolumns
close
Построение же собственно изолиний уже совсем просто:
draw contour
Вот что получает в gri:
график с изолиниями, построенный в gri
(gri я запускал так: $ gri -b -output iso_gri.eps < plotiso_gri.txt)


Способ третий,

строим изолинии в matplotlib/pylab

matplotlib — это библиотека для python. Её можно использовать как интерактивно, запуская ipython -pylab, так и внутри обычного скрипта; синтаксис команд построения графиков приближен к синтаксису matlab, но при этом можно использовать на полную возможности Python. А возможности у matplotlib весьма приличные.

Изолинии строятся одной командой:
cset=contour(X,Y,Z)
Здесь X, Y, Z — должны быть двумерными массивами одной и той же размерности. Кроме того, в скрипте я отключил раскраску изолиний по умолчанию, чтобы нарисовать все изолинии чёрным цветом (параметр colors='black'). Другие варианты использования contour можно прочитать в help contour, если запустить ipython -pylab.
Ещё одна команда добавляет к изолиниям подписи:
clabel(cset,fmt="%1.1f",fontsize=9)
Сохранить результат в файл нужного формата тоже просто:
savefig('pylab.eps')
Остальные строчки в скрипте — это преобразование формата данных средствами Python.
Дополнение: в новых версиях SciPy этот скрипт можно значительно упростить, если воспользоваться функцией loadtxt(), загружающей данные из текстового файла. То, что нам надо.
Вот что получается в итоге:
график с изолиниями, построенный в matplotlib/pylab
(скрипт я запускал так: $ python plotiso_pylab.txt)

☙ ☙ ☙

Конечно, выбор конкретного инструмента — вопрос удобства (имеющегося формата данных, требований к тонкостям настройки графики, имеющегося времени, опыта использования). Я хотел показать, что выбирать есть из чего, и построить на графике изолинии с любой из трёх рассмотренных программ — дело двух–трёх строчек. Совершенствовать же результат и настраивать тонкости отображения можно долго. На мой взгляд, в случае построения изолиний, gri и matplotlib предоставляют больше возможностей.

Хочу также заметить, что этими тремя программами список инструментов пригодных для построения графиков с изолиниями не исчерпывается. Надо отметить ещё Tioga, plotmtv, GMT, Asymptote. Есть и пакеты, ориентированные на 3D-данные, но которые можно использовать и для 2D: OpenDX, VTK, MayaVi. Вроде бы можно построить изолинии и в R (приличных примеров я не видел). Судя по документации, есть такая возможность и в scilab (но примеров того, что получается — я тоже не видел). Octave, как я понимаю, предоставляет лишь альтернативный интерфейс для gnuplot. Возможно, эту статью я в будущем дополню ещё какими-то примерами. Если кто-то активно строит графики с изолиниями в чём-то другом — предлагаю поделиться ссылкой на подобные инструкции. Ссылки буду добавлять ниже.

См. также:

Сравнение 9 программ для построения графиков
Цветные поверхности в gnuplot в режиме pm3d

9 коммент.:

  1. Анонимный15/2/08 17:25

    Очипятка, ссылка в сторке "(скрипт я запускал так: $ python plotiso_pylab.txt)" ведет не на тот файл...

    ОтветитьУдалить
  2. Спасибо за замечание. Исправил.

    ОтветитьУдалить
  3. Спасибо за пост, очень полезно

    ОтветитьУдалить
  4. Анонимный3/3/08 14:54

    Замечательно. Скачал файл sampledata.txt
    В нем есть разделитель - пустая строка. Я так понимаю, Вы так описываете отдельные изолинии. Да вот вопрос. У меня просто данные (таблица). Может ли gnuplot для них построить изолинии? Или я должен сначала расчитать изолинии где-то ещё, а уже потом передать их на визуализацию? Если gnuplot по данным (а не по аналитически заданной финкции) может строить изолинии, то как это селать?

    ОтветитьУдалить
  5. Пустые строки в файле с данными разделяют «столбцы» сетки с данными друг от друга, то есть задают сетку. Не изолинии.

    В данном случае каждое следующее значение «x» отделено от другого пустой строкой. Файл такого формата будет адекватно отрисован в gnuplot с помощью комманд splot 'filename' with lines и with pm3d.

    Файл без пустых строк-разделителей будет восприниматься gnuplot как описание одной длинной зигзагообразной линии.

    Подробнее об этом написано в help datafile («Single blank records designate discontinuities in a `plot`; no line will join points separated by a blank records (if they are plotted with a line style)»).

    В общем, формат данных, используемый в примере — такой:
    x1 y1 z(x1,y1)
    x1 y2 z(x1,y2)
    ...
    x1 yM z(x1,yM)
    пустая строка
    x2 y1 z(x2,y1)
    x2 y2 z(x2,y2)
    ...
    x2 yM z(x2,yM)
    пустая строка
    ...


    Положение изолиний рассчитывают все программы для построения графиков самостоятельно, интерполируя данные на сетке. Им только нужно дать эти самые данные в том формате, который они понимают. И указать, какие изолинии строить.

    Я хочу заметить, что есть и другой формат данных, поддерживаемый gnuplot — в виде таблицы (matrix). В этом случае данные записаны в файле так:
    z11 z12 z13 z14 ... (конец строки)
    z21 z22 z23 z24 ... (конец строки)
    z31 z32 z33 z34 ... (конец строки)


    При использовании файлов такого формата после имени файлов в gnuplot нужно добавлять ключевое слово matrix.

    ОтветитьУдалить
  6. Это вопрос и просьба.
    Не могли бы Вы указать бесплатные программы для построения изолиний в меркаторной проекции?
    Геннадий

    ОтветитьУдалить
  7. Уважаемый Геннадий!

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

    1. Это умеет делать описанный в данной заметке Pylab. Для преобразования координат от физических (широта-долгота) к экранным в нём служит класс Basemap.

    Документация по классу Basemap доступна здесь:
    http://matplotlib.sourceforge.net/matplotlib.toolkits.basemap.basemap.html

    Вот один из примеров его использования (не изолинии, к сожалению):
    http://matplotlib.sourceforge.net/screenshots/plotmap.py

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

    2. PyNGL. Другая библиотека для Pyhton, с явным уклоном в картографию. С весьма широкими возможностями.

    Буквально на днях в дружественном блоге появилась статья о его использовании:
    http://koldunov.net/?p=148 (в статье пример отрисовки морских течений)

    3. GMT. Это целый набор инструментов для отрисовки карт. Как я понимаю, кривая обучения довольно крутая, но возможности GMT серьёзные.

    Для ознакомления можете посмотреть примеры его использования:
    http://gis-lab.info/qa/gmt.html
    http://koldunov.net/?p=51

    ОтветитьУдалить
  8. Мне данный пост очень помог.
    Огромное спасибо автору за проделанную работу.
    Но поскольку я уже довольно давно пользуюсь gnuplot, то после прочтения статьи у меня осталось чувтсво неудовлетворенности от того что gnuplot по умолчанию не позволяет ставить label со значениями прямо на изолиниях. :)
    Те не менее очень скоро был найден неплохой workaround для данной проблемы.
    Для того чтобы изобразить значения на изолиниях, нужно воспользоваться awk скриптом, который генерит нужные нам labels. Скрипт можно взять на оффициальном сайте:
    http://www.gnuplot.info/scripts/files/label_contours.awk

    Рисунок с изолиниями и подписями можно получить после прогонки gnuplot скрипта:

    # isolines-plot.gp
    set contour base;.
    set isosamples 100;.
    set cntrparam levels 10;.
    unset surface
    set table "contour.dat";.
    splot 'sampledata.txt';.
    set out;
    set term pop
    !awk -f label_contours.awk -v nth=200 textcolor=-1 inclt=1 center=1 contour.dat >tmp.gp
    reset;.
    load 'tmp.gp'
    pause -1;


    Обратите внимание, что в файле tmp.gp сгенерились все значения, изображенные на изолиниях.

    ОтветитьУдалить
  9. Здравствуйте, Юрий!

    Я очень рад, что пост Вам помог. Способ разместить подписи на изолиниях, предложенный Вами, я раньше не видел. Спасибо, что его здесь описали. Попробую :)

    Сергей

    ОтветитьУдалить