пятница, 25 марта 2011 г.

Стрелки в Pylab

Pylab представляет собой очень мощную библиотеку для графопостроения. При проведении расчётов и анализа данных в Python, при помощи pylab не представляет труда вывести результат на график. Однако просто графики зачастую не являются информативными для неподготовленного читателя. В этом случае, помогают подсказки, сделанные на графиках, в частности, стрелки с указаниями. Кроме того, стрелки являются незаменимыми при построении графиков с несколькими y-осями. В этом случае весьма желательно указывать с помощью стрелок к какой оси относится тот или иной график.

Pylab.arrow

Казалось бы, при всей мощи, от pylab следовало бы ожидать удобной возможности нанесения такого рода деталей на графики. Но, надо признать, что здесь всё не очень очевидно. К примеру, имеется функция pylab.arrow, принимающая начальные координаты (x,y) и (dx,dy). Казалось бы, нет ничего проще.

import pylab as pl
import numpy as np
pl.figure(figsize=(4,4))
pl.title('pylab.arrow, square ratio')
z = np.arange(10)
pl.plot(z,z,'ro')
pl.arrow(2,2,3,4, head_width=0.5, head_length=1)
pl.show()

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

x = np.arange(0.1, 1000, 0.1)
y = np.log(x)

pl.figure(figsize=(6,4))
pl.title('pylab.arrow, different axis scale')
pl.plot(x, y, 'b-')
pl.arrow(400,2,200,3, head_width=0.5, head_length=1)
pl.arrow(200,2,300,4, head_width=0.5, head_length=100)
pl.ylim(ymin = 0)
pl.show()

Мало того, что форма стрелки искажённая, так ещё и надо вручную задавать размеры наконечника head_length и head_width под каждый масштаб.

Pylab.annotate

Однако оказалось, что есть более приличный способ отрисовки стрелок, pl.annotate. На самом деле основное предназначение pl.annotate состоит в том, чтобы отмечать стрелками заданные точки, и одновременно указывать подписи. Например, таким образом:

Для этого был использован следующий код:

pl.figure(figsize=(6,4))
pl.plot(x, y, 'b-')
pl.title('pylab.annotate example')
pl.annotate('Label', xy = (500, np.log(500)), xytext=(300,1),\
                arrowprops=dict(facecolor='red', width=0.5,\
                                    headwidth=10, shrink=0.05),\
                ha='center', va='baseline', fontsize='large')

В качестве аргументов передаются

  • строка с надписью
  • координаты точки, куда указывает стрелка
  • координаты надписи
  • свойства стрелки в ввиде словаря
  • остальные свойства, касающиеся свойств текста

Все свойства текста описаны в мануале по pylab.annotate, посмотреть который можно в интерактивном режиме питона. Например:

$ ipython
> import pylab as pl
> help(pl.annotate)

Что касается свойств стрелки, то их можно посмотреть так:

$ ipython
> import matplotlib
> help(matplotlib.lines.Line2D)

Из основных характеристик стрелок, на которые следует обратить внимание, отмечу следующие:

  • facecolor — цвет наконечника
  • width — толщина линии в пунктах
  • headwidth — ширина наконечника в пунктах
  • frac — доля длины, которую занимает наконечник
  • shrink — отступ, от заданной точки xy до конца наконечника (чтобы наконечник не втыкался точно в заданную точку, а оставил некоторое пространство). Измеряется в долях длины.

Что касается свойств текста, то я бы в первую очередь отметил следующие:

  • ha (horizontalalignment) — способ выравнивания по горизонтали ('center', 'right', 'left')
  • va (verticalalignment) — соответственно, по вертикали ('center', 'top', 'bottom', 'baseline')
  • rotation — поворот текста (угол в градусах, 'vertical', 'horizontal')
  • fontsize — размер шрифта (можно указать в пунктах, а можно и словами 'small', 'medium', 'large', 'x-large', 'xx-large')

Как видно, при использовании pylab.annotate форма стрелки получилась адекватной. А если вместо надписи оставить пустую строку, то просто получится стрелка от xytext до xy (при условии, что shrink = 0)

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

def my_arrow(label, xy_from, xy_to, color='blue', shrink=0.05, width=0.5, headwidth=10):
    pl.annotate(label, xy = xy_to, xytext=xy_from,\
                    arrowprops=dict(facecolor=color, width=width,\
                                        shrink=shrink, frac=0.1),\
                    ha='center', va='baseline', fontsize='large')

Теперь нет ничего проще, нарисовать стрелку:

pl.figure(figsize=(6,4))
pl.title('pylab.annotate')
pl.plot(x, y, 'b-')
my_arrow('Label', (100,1), (600, 5))
my_arrow('', (300,1), (800, 5))
# красные точки для понимания каким образом позиционируется текст
pl.plot([100,600],[1,5], 'ro')
pl.ylim(ymin = 0)

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

Стоит заметить, что этим вид стрелок не ограничивается. Можно также рисовать стрелки с рюшечками, стоит только в arrowprops упомянуть про arrowstyle.

pl.figure(figsize=(6,4))
pl.title('Fancy arrow')
pl.plot(x, y, 'b-')
pl.annotate('Fancy arrow', xy = (500, np.log(500)), xytext=(300,1),\
                arrowprops=dict(facecolor='red',arrowstyle='fancy',\
                           connectionstyle='angle3, angleA=0, angleB=90'),\
                fontsize='x-large')
pl.ylim(ymin = 0)

Для более детального ознакомления следует посмотреть в примеры mpl_examples/pylab_examples/annotation_demo2.py


Читать далее…

четверг, 3 марта 2011 г.

Однотипные срезы массивов в python

Известно, что в python есть такая замечательная вещь, как срезы массивов (списков, кортежей и т.д.). По сути, в качестве начала и конца среза передаются положения элементов в массиве. Например,

x = range(10)
print x
> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print x[1:3]
> [1, 2]
print x[0:5]
> [0, 1, 2, 3, 4]

Видно, что по сути отсчёт ведётся не по элементам, а по промежуткам между элементами, при этом на выходе даются все элементы, попадающие в заданный интервал промежутков. Особый интерес представляют отрицательные индексы, являющиеся по сути обратным отсчётом промежутков с конца массива.

print x[1:-1]
> [1, 2, 3, 4, 5, 6, 7, 8]
print x[0:-2]
> [0, 1, 2, 3, 4, 5, 6, 7]

Однако, что делать, если, скажем, имеется набор экспериментальных данных, которые мы хотим обрезать, основываясь на значениях, нежели на положении элементов в массивах? Допустим, есть список x,

from math import *
import numpy as np
x = np.arange(0, 2*pi, 0.1)
из которого надо вырезать 1.2<x<2.7.

Традиционный способ

В принципе, это можно осуществить перебором по всем элементам списка:

begin,end = 0,0
x0, x1 = 1.2, 2.7
for i in range(len(x)):
    if begin == 0:
        if x[i] > x0:
            begin = i
        else: pass
    else: pass
    if int(end) == 0:
        if x[i] > x1:
            end = i
        else: pass
    else: pass
print begin, end
print x[begin:end]

В результате получим:

> 12 28
[ 1.2  1.3  1.4  1.5  1.6  1.7  1.8  1.9  2.   2.1  2.2  2.3  2.4  2.5  2.6 2.7]

В принципе. то, чего и ожидали. Теперь можно этот цикл for оформить внутри функции, которая будет принимать в качестве аргументов список и границы.

def conventional_cut(x, (x0,x1)):
    begin,end = 0,0
    for i in range(len(x)):
        if begin == 0:
            if x[i] > x0:
                begin = i
            else: pass
        else: pass
        if end == 0:
            if x[i] > x1:
                end = i
            else: pass
        else: pass
    return x[begin:end]
print conventional_cut(x, (0.9, 1.4))
> [ 1.   1.1  1.2  1.3]

Несколько массивов

С практической точки зрения удобно резать сразу два списка: агрумент и функцию. Допустим, отснимали большой спектр y от x, из которого интерес представляет только часть. Таким образом, необходимо откусить часть от x, а также соответствующую часть y.

Сделать это легко, слегка модернизировав функцию:

def cut_xy((x,y), (x0,x1)):
    begin,end = 0,0
    for i in range(len(x)):
        if begin == 0:
            if x[i] > x0:
                begin = i
            else: pass
        else: pass
        if end == 0:
            if x[i] > x1:
                end = i
            else: pass
        else: pass
    return x[begin:end], y[begin:end]

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

from math import *
import numpy as np
import pylab as pl

x = np.arange(0, 4*pi, 0.01)
y = np.sin(x)/x
y = y + 0.1*(np.random.rand(len(y))-0.5)
# представим, что x,y - экспериментальные данные

xnew, ynew = cut_xy((x,y), (0.75*pi, 1.5*pi))
pl.plot(x, y, 'r-')
pl.plot(xnew, ynew, 'b-')

pl.xlabel("x")
pl.ylabel("Signal")
pl.show()

В результате получим то, что и следовало ожидать.

Выборочное соответствующее вырезание двух массивов
Выборочное соответствующее вырезание двух массивов

Разумеется, никто не запрещает резать не два, а три и более массивов одновременно, немного видоизменив функцию cut_xy.

Использование numpy.nonzero

Традиционный метод работает, однако может показаться корявым. По-видимому, более элегантное решение может быть получено с использованием функции nonzero из библиотеки numpy.

Пример работы numpy.nonzero:

from math import *
import numpy as np
x = np.arange(0, 2*pi, 0.1)
print x[np.nonzero(x<2.7)]
print x[np.nonzero(x>1.4)]
> [ 0.   0.1  0.2  0.3  0.4  0.5  0.6  0.7  0.8  0.9  1.   1.1  1.2  1.3  1.4
  1.5  1.6  1.7  1.8  1.9  2.   2.1  2.2  2.3  2.4  2.5  2.6]
> [ 1.4  1.5  1.6  1.7  1.8  1.9  2.   2.1  2.2  2.3  2.4  2.5  2.6  2.7  2.8
  2.9  3.   3.1  3.2  3.3  3.4  3.5  3.6  3.7  3.8  3.9  4.   4.1  4.2  4.3
  4.4  4.5  4.6  4.7  4.8  4.9  5.   5.1  5.2  5.3  5.4  5.5  5.6  5.7  5.8
  5.9  6.   6.1  6.2]

В скобках np.nonzero() указывается булево выражение, при этом nonzero возвращает индексы ненулевых элементов. Выражение x<2.7 является булевым и имеет следующий вид:

[ True  True  True  True  True  True  True  True  True  True  True  True
  True  True  True  True  True  True  True  True  True  True  True  True
  True  True  True False False False False False False False False False
 False False False False False False False False False False False False
 False False False False False False False False False False False False
 False False False]
То есть, если x[i]>2.7, то результат True, в противном случае False. Стало быть, передавая x<2.7 в качестве аргумента функции nonzero, и скармливая результат исходному массиву x в качестве индексов среза, получаем обрезанный x, где каждый элемент x не превышает 2.7.

Трудность заключается в том, что не удаётся в качестве аргумента nonzero затолкать сразу несколько условий. Таким образом, если надо откусить массив с двух краёв, то необходимо сначала откусить массив слева, а потом результат — справа:

X = x[np.nonzero(x>1.4)]
X = X[np.nonzero(X<2.7)]
print X
> [ 1.4  1.5  1.6  1.7  1.8  1.9  2.   2.1  2.2  2.3  2.4  2.5  2.6]

Замечу, что при использовании nonzero левая граница промежутка включается в искомый массив.

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

X = x[np.nonzero(x>1.4)]
X = X[np.nonzero(X<2.7)]
Y = y[np.nonzero(x>1.4)]
Y = Y[np.nonzero(X<2.7)]

print "X =", X
print "Y =", Y

На выходе:

X = [ 1.4  1.5  1.6  1.7  1.8  1.9  2.   2.1  2.2  2.3  2.4  2.5  2.6]
Y = [ 0.66167563  0.62029339  0.59024345  0.57468639  0.5094329   0.5281753
  0.4542492   0.39952115  0.37289637  0.36049412  0.266617    0.19706189
  0.247443  ]

Можно аналогичным образом затолкать это в функцию:

def cut((x,y),(x0,x1)):
    after = np.nonzero(x>x0)
    X = x[after]
    before = np.nonzero(X<x1)
    X = X[before]
    Y = y[after]
    Y = Y[before]
    return X,Y
которая принимает в качестве аргументов исходные (x,y) и интервалы x.

Графический пример:

from math import *
import numpy as np
import pylab as pl

x = np.arange(0, 2*pi, 0.1)
y = np.sin(x)/x
y = y + 0.1*(np.random.rand(len(y))-0.5)
# представим, что x,y - экспериментальные данные

pl.plot(x, y, 'r-')
X,Y = cut((x,y),(4,5))
pl.plot(X,Y,'g-')

pl.xlabel("x [channels]")
pl.ylabel("Signal [counts]")
pl.show()
Результат аналогичной процедуры при использовании numpy.nonzero
Результат аналогичной процедуры при использовании numpy.nonzero

Читать далее…

среда, 13 октября 2010 г.

Градиенты в PSTricks

Иногда для того, чтобы подчеркнуть некий переходный процесс или наличие размытой границы, на рисунках бывает полезным использовать градиенты (ну а кому-то интересны рюшечки). Поскольку большинство рисунков в своей работе я выполняю с использованием PSTricks, прямо не выходя из LaTeX (о рисовании примитивов уже было написано), то в данной заметке я опишу как создавать градиенты с помощью PSTricks.

Простые градиенты

Нам понадобится пакет pst-grad. Чтобы создать градиент, необходимо нарисовать требуемую физуру, а в качестве заливки в поле для дополнительных опций указать fillstyle=gradient. После этого нам окажутся доступны следующие параметры (из названий всё понятно):

  • gradbegin — начальный цвет.
  • gradend — конечный цвет.
  • gradlines — количество линий, используемых для рисования. градиента. Чем больше - тем ровнее, но страдает время отрисовки. По умолчанию 500.
  • gradangle — направление вектора градиента. На самом деле, перпендикуляра к вектору градиента (специально это так сделано, или нет - мне не понятно) .
  • gradmidpoint — обозначает положение средней точки градиента (от 0 до 1). Понять что это такое можно, взглянув на рисунок, который можно создать следующим кодом.
 
\documentclass[a4paper]{article} 
\usepackage[utf8]{inputenc} 
 
\usepackage[noxcolor]{pstricks} 
\usepackage{pst-grad} 
 
\begin{document} 
\begin{pspicture}(-2,-1)(2,10)
  % рисуем прямоуголник с градиентом
  \psframe[fillstyle=gradient, gradbegin=green, gradend=blue,
     gradlines=500, gradmidpoint=1, gradangle=10](-2,-1)(2,1)
  % вставляем подпись
  \uput[90](0,1){gradmidpoint=1}
 
  % повторяем то же, но со смещением относительно начальной точки
  \rput(0,3){
     \psframe[fillstyle=gradient, gradbegin=green, gradend=blue,
     gradlines=500, gradmidpoint=0, gradangle=10](-2,-1)(2,1)
     \uput[90](0,1){gradmidpoint=0}
  }
 
  \rput(0,6){
     \psframe[fillstyle=gradient, gradbegin=green, gradend=blue,
     gradlines=500, gradmidpoint=0.3, gradangle=10](-2,-1)(2,1)
     \uput[90](0,1){gradmidpoint=0.3}
  }
 
  \rput(0,9){
     \psframe[fillstyle=gradient, gradbegin=green, gradend=blue,
     gradlines=500, gradmidpoint=0.9, gradangle=10](-2,-1)(2,1)
     \uput[90](0,1){gradmidpoint=0.9, default}
  }
\end{pspicture} 

Цвета можно задавать исходя из стандартных имён, или в RGB формате. Для этого подключим пакет color и определим цвет посредством definecolor:

 
\usepackage{color} 
...
\begin{document} 
\begin{pspicture}(-2,-1)(2,11)
  \definecolor{mycolor}{rgb}{1,0.5,0.1}
  % а потом можем использовать цвет mycolor как захотим
\end{pspicture} 
\end{document} 

Радиальные градиенты

С помощью пакета pst-grad не удаётся создать радиальных градиентов. К примеру, если мы попытаемся использовать градиентную заливку в круге, то получим следующее:

 
\begin{pspicture}(-2,-2)(2,2)
  \definecolor{gradbegin}{rgb}{0.4,0.6,0.9}
  \definecolor{gradend}{rgb}{1,0.45,0.83}
  \pscircle[fillstyle=gradient,gradlines=1000,gradmidpoint=0](0,0){2}
\end{pspicture} 

То есть, обычный плоский градиент.

Для создания радиальных градиентов можно использовать пакет pst-slpe. В данном случае используется fillstyle=ccslope, а аргументы, задающие цвета, аналогичные: slopebegin, slopeend.

Особое внимание стоит уделить опции sloperadius. Из иллюстрации ниже должно быть понятно что к чему.

 
\begin{pspicture}(-2,-8)(8,4)
  \uput[90](0,3){red,yellow}
  \pscircle[fillstyle=ccslope,slopebegin=red, slopeend=yellow,
  sloperadius=1](0,0){2}
  \uput[90](0,2){sloperadius=1}
 
  \uput[90](5,3){yellow,blue}
  \rput(5,0){
     \pscircle[fillstyle=ccslope,slopebegin=yellow, slopeend=blue,
     sloperadius=1](0,0){2}
     \uput[90](0,2){sloperadius=1}
  }
 
  \rput(0,-5){
     \pscircle[fillstyle=ccslope,slopebegin=red, slopeend=yellow,
     sloperadius=2](0,0){2}
     \uput[90](0,2){sloperadius=2}
  }
 
  \rput(5,-5){
     \pscircle[fillstyle=ccslope,slopebegin=yellow, slopeend=blue,
     sloperadius=3](0,0){2}
     \uput[90](0,2){sloperadius=3}
  }
\end{pspicture} 

Стоит отметить, точку отсчёта градиента можно смещать.

 
\begin{pspicture}(-2,-2)(2,3)
  \pscircle[fillstyle=ccslope,slopebegin=yellow, slopeend=blue,
  slopecenter=0.1 0.3](0,0){2}
  \uput[90](0,2){slopecenter=0.1 0.3}
\end{pspicture} 

Более того, с помощью pst-slpe, можно создавать и такие вещи:

 
\begin{pspicture}(-2,-2)(2,2)
  \pscircle[fillstyle=radslope,slopebegin=yellow, slopeend=blue](0,0){2}
  \uput[90](0,2){fillstyle=radslope}
\end{pspicture} 

Напоследок могу посоветовать почитать документацию по пакетам pstricks (/usr/share/doc/texlive-pstricks-doc/generic/pstricks) и pst-slpe (/usr/share/doc/texlive-pstricks-doc/generic/pst-slpe).


Читать далее…

среда, 5 мая 2010 г.

Suspend и Hibernate на Acer Extensa 4220

Портативные компьютеры должны обладать способностью «засыпать» и «просыпаться». Хорошо, когда это работает. Однако известно, что в линуксе с этим зачастую не так гладко. Например, в моём случае с ноутбуком Acer Extensa 4220 были проблемы как со ждущим режимом suspend, так и со спящим hibernate в Ubuntu 8.04 - а именно никак не удавалось разбудить должным образом :) Не знаю как там в убунте сейчас, поскольку после небольшого эксперимента почти два года назад был поставлен дебиан, и только сейчас дошли руки написать как я настроил режим сна в Debian Lenny.

В рабочих средах вроде KDE или GNOME есть свои демоны, отвечающие за электрическую составляющую, вроде gnome-power-manager, которые позволяют, например, переводить ноутбук в спящий режим. У пользователей оконных менеджеров отдельно от рабочих сред резона запускать такие программы нет, поэтому имеет смысл поискать альтернативу. Здесь я опишу каким образом можно настроить спящий режим на Acer Extensa 4220.

Пересобирать или не пересобирать?

Пересобирать ядро не хотелось, ковыряться с этим некогда, ибо молодость красноглазая уже позади, поэтому был обращён взор в сторону готовых решений, которые могут работать, а могут, в принципе, и не работать. Надежда на то, что работать будут есть и весьма немалая, ввиду развития Linux, и по мере старения вашего оборудования будет только расти :) Но для любителей make menuconfig имеет смысл заглянуть на Tux on Ice.

Во время проведения тестов с Arch Linux на борту, выяснилось, что утилиты s2ram и s2both из комплекта uswsusp не очень корректно работают для данной модели ноутбука. При просыпании могло оказаться, что отваливались клавиатура и мышь, и единственной рабочей кнопкой оказывалась кнопка выключения компьютера на корпусе.

Другая альтернатива в виде pm-utils не собиралась из исходников из AUR'а, с причинами разобраться не удавалось. Однако в Debian этот комплекс утилит был в репозитории, поэтому удалось без проблем протестировать. Оказалось, что всё заработало «из коробки» - pm-suspend и pm-hibernate успешно переводили комп в соответствующий режим, а с просыпанием не возникало никаких проблем.

Чтобы перевести компьютер в ждущий режим, нужно скомандовать:

 
> sudo pm-suspend

Чтобы усыпить -

 
> sudo pm-hibernate

Доводим до ума

Поскольку F-клавиши на ноутбуке в комбинации с Fn должны осуществлять, по задумке создателей в ОС Windows, определённые действия, в частности засыпание по Fn-F4, имеет смысл и нам его навесить на эту комбинацию.

Но для начала надо позволить вводить эти команды без запроса пароля рута или sudo, для этого командуем от рута visudo (или внимательно правим /etc/sudoers) и добавляем такие строки:

 
username ALL=NOPASSWD: /usr/sbin/pm-suspend
username ALL=NOPASSWD: /usr/sbin/pm-hibernate

username надо заменить на имя пользователя.

После этого потрошим xbindkeys или другую прогамму, позволяющую создавать биндинги. Проверим что представляет собой комбинация Fn-F4, для чего запускаем

 
> xbindkeys -mk

и нажимаем интересующию комбинацию. Для Fn-F4 я получил на выходе «m:0x0+c:223». Теперь пропишем в ~/.xbindkeysrc соотвествующую строку:

 
"sudo pm-suspend" 
c:223

Осталось перезапустить xbindkeys.

Закрываем люк

Полезно добавить засыпание по закрытию крышки ноутбука. Для этого отредактирем файл /etc/acpi/events/lidbtn, заменив строку action=/etc/acpi/lid.sh на action=/etc/acpi/sleep.sh. В итоге должно получиться:

 
event=button[ /]lid
action=/etc/acpi/sleep.sh

Замечу, что у меня установлены пакеты acpi, acpi-support, acpi-support-base, acpid.


Читать далее…

среда, 14 апреля 2010 г.

PSTricks. Рисуем в LaTeX.

ЛаТеХ помимо вёрстки текста ещё и умеет рисовать. Сделать набросок схемы установки, подрисовать стрелки или кружочки в презентации, поиграть с текстом или даже построить какой-либо график можно с помощью PSTricks. PSTricks позволяет делать рисунки прямо в тексте, то есть в принципе не надо вылазить в графический редактор, создавать рисунок, а потом экспортировать в удобоваримый формат. PSTricks даёт возможность достаточно быстро и без особых усилий создавать хорошие рисунки. Кроме того, существует множество пакетов, в которых уже реализованы многие примитивы, что позволяет ими оперировать на более высоком уровне. Скажем, вам не придётся рисовать пружинку вручную — это сделает один из макросов в пакете pst-coil, для того, чтобы нарисовать мензурку над горелкой химикам поможет пакет pst-labo.

При этом, следует заметить, что наличие PSTricks не означает, что в его пользу навсегда можно отказаться от такого средств создания иллюстраций, как Metapost. Недостаток PSTricks, на мой взгляд, состоит в том, что нельзя добиться полной автоматизации и построения наиболее общего рисунка. В PSTricks нет в явном виде переменных, которыми можно было бы легко оперировать, а ведь это неоспоримое преимущество Metapost, поскольку очень здорово создать рисунок, в котором всё будет зависеть от пары-тройки переменных, передвинув которые можно добиться наиболее наглядного результата. В PSTricks же всё реализовано через декартовы или полярные координаты в явном виде.

Установка

Для начала установим pstricks. В Debian все как обычно:

> aptitude install texlive-pstricks texlive-pstricks-doc

Эта команда установит pstricks целиком, со всеми входящими в него пакетами и документацией к ним. В общем случае ничего руками доставлять не надо будет. Документация будет лежать в /usr/share/doc/texlive-pstricks-doc/ в виде pdf-файлов.

Синтаксис

Итак, начнём. Концепция всех макросов примерно такова: аргументы указываются в фигурных скобках, дополнительные опции — в квадратных, а координаты — в круглых. В частности, чтобы нарисовать вектор из (1,2) в (4,3) толщиной 2pt и красного цвета, нужно написать следующее:

\psline[linecolor=red, linewidth=2pt]{->}(1,2)(4,3)

Как видно, для макроса \psline, который строит отрезки со стрелками на концах или без них, обязательным аргументом является направление вектора. Если нужен не вектор, а просто отрезок, то фигурные скобки можно опустить.

Для окружности обязательным аргументом является её радиус. Для построения окружности с радиусом 1.8 с центром в точке (4,2), закрашенной красным, пишем следующее:

\pscircle[fillcolor=red, fillstyle=solid](4,2){1.8}

Можно представить, что надо построить несколько элементов, однаково закрашенных. Но при этом не хотелось бы каждый раз писать "fillcolor=red, fillstyle=solid". Для этого существует макрос \psset, благодаря которому можно задать перманентно для всего рисунка от текущего момента до момента переопределения различные графические параметры, такие как тип заполнения, цвет линии, цвет заполнения, тип линии, толщина линии, значение единицы длины (по умолчанию 1cm).

Очевидно, что именно задаёт следующая команда

\psset{linewidth=2pt, linecolor=blue, fillstyle=solid,
   fillcolor=yellow, linestyle=dashed, unit=2cm}

Однако, если для какого-то определённого элемента предустановленный вами параметр не подходит, его легко можно изменить, более подходящим параметром в квадратных скобках. Так, несмотря на определение, окружность будет красной, а не жёлтой, но при этом линия на границе будет хоть и штриховой, но чёрной.

\psset{linewidth=2pt, linecolor=blue, fillstyle=solid,
   fillcolor=yellow, linestyle=dashed}
\psline{->}(0,0)(1,2)
\pscircle[fillcolor=red, fillstyle=solid, linecolor=black](4,2){1.8}

Примитивы

Точки

В рисунке всё начинается с точки.

Нарисовать точку можно следующей командой:

\psdot[dotstyle=triangle](1,1)
Здесь «точка» будет нарисована треугольником (незакрашенным) в координате (1,1). Чтобы треугольник был закрашенным, надо указать triangle*. Аналогично будет и для других стилей точки.

По умолчанию, если не выбран dotstyle, точка будет нарисована закрашенным кружком. Немаловажным параметром является dotsize. Что он означает объяснять не надо.

Ряд точек рисуется с помощью макроса \psdots:

\psdots(x1,y1)(x2,y2)(x3,y3)(x4,y4)

Сетка

Пока мы не пошли дальше, следует отметить, что настоятельно рекомендуется (где это возможно) рисунки оформлять в окружении pspicture. В принципе, можно и без него, но могут в этом случае возникнуть проблемы с взаимодействием рисунков, переносами и пр.

Синтаксис следующий:

\begin{pspicture}(0,0)(3,4)
  ...ваш рисунок...
\end{pspicture}

Здесь (0,0) — это координаты нижней левой точки рисунка, а (3,4) — координаты правой верхней.

В случае, если координаты границ рисунка заданы, есть возможность нарисовать координатную сетку. Для этого используется макрос \psgrid.

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

\psgrid[subgriddiv=2]

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

\begin{pspicture}(0,0)(3,4)
  \psgrid[subgriddiv=2]
  \psdot(1,1)
  \psdot[linecolor=red, dotstyle=asterisk, dotsize=20pt](1,2)
  \psdot[linecolor=blue, dotstyle=diamond*, dotsize=10pt](1,3)
  \psdot[linecolor=green, dotstyle=square, dotsize=20pt](2,2)
  \psdot[dotstyle=o, dotsize=20pt](2,1)
  \psdot[dotstyle=pentagon*, dotsize=15pt](2,3)
\end{pspicture}

Далее я буду в основном при написании исходного кода опускать окружение pspicture, однако на практике про него не следует забывать.

Отрезки

Как мы уже видели, для создания отрезков или векторов используется следующая конструкция (при этом дополнительные опции, которые можно определить с помощью \psset я буду преимущественно опускать, чтобы не загромождать вид):

\psline{->}(1,2)(3,-5)

Чтобы поменять направление вектора, совсем не обязательно менять местами координаты — достаточно изменить направление с {->} на {<-}.

Кроме того, можно ввести радиус кривизны при соединении более, чем двух точек, опцией linearc. Можем соединить сразу несколько точек и увидеть как это будет выглядеть для различных радиусов кривизны:

\psline[linecolor=black](0,0)(1,1)(2,-1)(4,2)
\psline[linearc=0.3, linecolor=red](0,0)(1,1)(2,-1)(4,2)
\psline[linearc=0.5, linecolor=blue](0,0)(1,1)(2,-1)(4,2)
\psline[linearc=0.8, linecolor=green](0,0)(1,1)(2,-1)(4,2)

Окружность, эллипс, сектор, сегмент

Как было сказано, для окружности основными параметрами являются положение центра и радиус. А для эллипса положение центра и значения полуосей, также указанные в круглых скобках, как и координаты.

\psellipse[fillcolor=green, fillstyle=solid](2,3)(2,1)
\pscircle*(2,3){1}

Здесь использована конструкция \pscircle*, которая означает, что окружность следует залить тем же цветом, что и цвет линии linecolor.

Для секторов используется макрос \pswedge, для которого нужно задать положение центра окружности, радиус, начальный угол и конечный угол. Аналогичные параметры задаются и для \psarc, рисующего дуги. Сегмент можно нарисовать, с помощью \psarc*:

\pswedge[linecolor=red, linestyle=solid](2,2){2}{15}{135}
\psarc*[linecolor=blue](2,2){2}{190}{300}
\psarc[showpoints=true, arrowsize=10pt]{->}(2,2){2}{310}{360}

Прямоугольники

Для прямоугольников задаются левый нижний и правый верхний углы. Аналогично linearc для прямоугольников использутся framearc:

\psframe[linecolor=blue, framearc=0.5](0,0)(4,3)
\psframe[linecolor=black](1,1)(3,2)

Кроме того, есть возможность загнать в прямоугольник кусок текста:

\psframebox[linecolor=red]{Кусок текста}, \psovalbox{овальный кусок}

Это может оказаться весьма полезным в презентациях для выделения текста, на который следует обратить особое внимание.

Кривые

Кривые можно рисовать с помощью \psbezier и \pscurve.

\psbezier рисует кривые безье. Начальное направление кривой идёт по касательной к отрезку, соединяющему первую пару точек, а конечное, соответственно, по касательной к отрезку, соединяющему вторую пару. Дополнительный параметр showpoints позволяет понять принцип:

\psgrid
\psbezier[showpoints=true](0.5,1)(1,3)(2,0.5)(3,4)

\pscurve просто рисует кривую через заданные точки. А \psccurve рисует замкнутую кривую. Параметр curvature, принимающий три значения, определяет насколько «кривой» будет линия. Следует немного поиграть с параметрами, чтобы понять принцип:

\psgrid
\pscurve[curvature=1 0.1 0, showpoint=true](0.5,0.5)(2,0.5)(1,2)(2.5,2.8)
\pscurve[curvature=0.5 0.1 0, linecolor=red](0.5,0.5)(2,0.5)(1,2)(2.5,2.8)
\pscurve[curvature=0.2 0.1 0, linecolor=blue, arrowsize=10pt]{->}(0.5,0.5)(2,0.5)(1,2)(2.5,2.8)
\psccurve[linecolor=purple](0.5,0.5)(2,0.5)(1,2)(2.5,2.8)

Резюме

На этом я закончу первую статью по PSTricks. В принципе, уже описанных примитивов достаточно для создания простеньких и не очень рисунков.

Благодаря простоте синтаксиса и встроенности в LaTeX PSTricks оказывается весьма удобным инструментом для создания самых разнообразных иллюстраций и схем.

В дальнейшем мы посмотрим на операции с цветами, простейшую автоматизацию, рассмотрим некоторые дополнительные пакеты для PSTricks.

И, напоследок, что следует почитать:


Читать далее…

понедельник, 29 марта 2010 г.

Автодополнение в интерактивном Gnuplot с помощью rlwrap

В очень удобной программе построения графиков Gnuplot не работает автодополнение. По крайней мере, в сборке Debian Lenny.

> gnuplot --version
gnuplot 4.2 patchlevel 2

Очень непросто набивать полные названия файлов в интерактивном режиме без дополнения по TAB. Конечно, их можно копировать из вывода !ls с помощью мыши, но это весьма неудобно. Судя по всему, причина лежит в том, что gnuplot собран без поддержки readline.

Поскольку из сорцов пересобирать gnuplot не хотелось, надо было найти альтернативный путь. Оказалось, что существует такая замечательная программа rlwrap, которая позволяет связать readline с программами, в которой нет поддержки readline. Таким образом, программы, в которых не реализованы функции автодополнения, истории команд и т.п., начинают обладать таким функционалом.

Устанавливается эта прога в Debian стандартно:

> sudo aptitude install rlwrap

Запуск осуществляется, как следует из мана, таким образом:

> rlwrap [options] command

В нашем случае command есть gnuplot.

Если взглянуть на man-страницу, то следует обратить внимание на опцию -a, —always-readline. Что она делает более или менее ясно из её названия. Значит, будет использоваться readline независимо от настроек command. Для обеспечения автодополнения имён файлов есть опция -c, —complete-filenames.

Таким образом, запустив gnuplot следующим образом:

> rlwrap -a -c gnuplot
получим gnuplot с автодополнением.

Чтобы каждый раз не писать такую команду, имеет смысл сделать алиас, например, записав в файл ~/.bash_aliases:

alias gnuplot='rlwrap -a -c gnuplot'

Также rlwrap позволяет менять размер истории (см. опцию -s, —histsize), исключать из истории дубликаты (см. опцию -D, —history-no-dupes).

Описанное решение нашёл здесь, за что автору большое спасибо!


Читать далее…

четверг, 31 декабря 2009 г.

Ncmpcpp. MPD-клиент с двумя плюсами

MPD представляет собой клиент-серверную систему для прослушивания музыки. Основная особенность состоит в том, что где-то в фоне работает демон, играющий музыку, а этим самым демоном можно управлять с помощью различных клиентов. Этих самых клиентов в природе существует много, но находятся создатели новых клиентов, по-видимому, остающиеся недовольными уже созданными программами.

В данной заметке я бы хотел рассказать о клиенте Ncmpcpp, представляющим собой логическое продолжение клиента ncmpc, который является удобным консольным клиентом с псевдографическим интерфейсом (ncurses).

Ещё один?

Да, казалось бы, зачем огород городить? Но у ncmpcpp есть ряд преимуществ, по сравнению с любимым многими ncmpc.

Вот неполный список полезностей. Добавлены возможности:

  • Изменение стиля оформления плейлиста и списка песен в базе (положение полей, а также их цвет).
  • Чтение текста песен (не наших :).
  • Редактирование тегов, не выходя из клиента и без необходимости обновлять заново базу.
  • Удаление неугодныех файлов с диска.
  • Добавление в плейлист случайных песен. Может кому-нибудь и будет полезно, чтобы среди терабайтов музыки не забыть какая музыка ещё представлена на компьютере.
  • Поиск песни в браузере базы по песне в плейлисте.

Конфиг расположен по адресу ~/.ncmpcpp/config и прекрасно документирован.

Правка тегов

Особенно полезна, на мой взгляд, возможность редактирования тегов. К примеру в ncmpc нельзя было, изменив теги, во внешнем редакторе, добиться их изменения в базе - отображалось всё по-старому. Необходимо было переименовывать файлы (директории), обновлять базу, а потом возвращать прежние имена с последующим обновлением. Здесь же можно выбрать нужный файл (или директорию с файлами), подправить теги, и получить сразу же скорректированную базу.

Вот так это выглядит на скриншоте:

Как видно на скриншоте, есть возможность сделать первые буквы заглавными, а также все - строчными. Изменения вступают в силу после нажатия на «Save».

Если хочется подправить теги, скажем, текущей песни в плейлисте, то можно ткнуть на песне в плейлисте «e», откроется «Tiny tag editor», где и можно внести изменения.

Лирика

Лирика качается с двух ресурсов: lyricwiki.org и lyricsplugin.com. Но похоже, что c первой проблемы со скачиванием нахаляву, поэтому можно стягивать со второго ресурса. Для этого в конфиге надо указать lyrics_database = "2". После этого можно выставлять курсор на интересующую песню и давить «l» (латинская маленькая L).

Easy money!

Резюме

Данный клиент почти не отличается от старого-доброго ncmpc, но содержит некоторые рюшечки, которые могут оказаться полезными.

С Новым Годом!


Читать далее…