пятница, 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, но содержит некоторые рюшечки, которые могут оказаться полезными.

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


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

четверг, 26 ноября 2009 г.

Как удалить однотонный фон с картинки с помощью ImageMagick

Есть картинца с однотонным фоном.

Надо Этот тон удалить и заменить белым.

Нет ничего проще, если под рукой есть imagemagick.

convert with-background.png -transparent "#FFFFCC" \
   -background white -layers flatten white-background.png

Здесь "#FFFFCC" означает цвет фона моей картинки.

Конструкция -transparent $COLOR делает прозрачным всё, что обладает заданным цветом. А -background white совместно с -layers flatten делает фон белым. Хотите другой? Меняйте white на всё, что пожелаете, и всё.

Вы спросите, почему именно -layers flatten? Не знаю :) Работает, главное. Также работает -layers merge и -layers mosaic. Но поскольку здесь изображение одно, то разницы между ними, вроде как нет.

P.S. Мне это понадобилось, потому что не оказалось под рукой нужного графика. Исходных данных нет, всё что было, так это рисунок внутри PDF файла, который я оттуда успешно стянул :)
Читать далее…

суббота, 17 октября 2009 г.

Отображение текущих разделов в содержании презентации beamer.

И снова про презентации в beamer. Иногда полезно по ходу презентации акцентировать внимание на том, что именно вы планируете рассказать в данный конкретный момент по ходу презентации. Это особенно важно, если зрители во время докладов на конференции засыпают, а не хочется, чтобы они спали на вашем докладе. В настоящее время визуальный фактор стал играть основополагающую роль в презентации, а именно, на докладчика почти никогда зрители не смотрят (в большинстве своём), а некоторые не особо-то и слушают, поскольку целиком сфокусировали свой взгляд и внимание на изображении от проектора в полутёмном конференц-зале с мягкими креслами. А монотонная речь докладчика только помогает слушателям отдохнуть и набраться сил после вчерашнего фуршета по поводу успешного окончания третьего или четвертого дня конференции, вздремнув на вашем докладе.

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

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

Чтобы при появлении нового раздела (section) на экране отображалась часть содержания доклада, необходимо в преамбуле (до \begin{document}) написать следующее:

\AtBeginSection[]{
   \begin{frame}<beamer> \frametitle{Содержание}
     \tableofcontents[currentsection]
   \end{frame}
}

Если же хочется, чтобы при появлении каждого подраздела (subsection) происходило то же самое, то «AtBeginSection» надо заменить на «AtBeginSubsection».

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

\subsection{Очень важный подраздел}
\begin{frame}<beamer> \frametitle{Содержание}
  \tableofcontents[currentsection, currentsubsection]
\end{frame}

\begin{frame} \frametitle{Очень важный слайд}
  Очень важная информация!  Пора проснуться!
\end{frame}

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

В заключение прикладываю пример в исходном тексте и итоговый результат.

\documentclass[pdf,hyperref={unicode}]{beamer}
\usepackage[T2A]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[russian]{babel}

% Тема презентации
\usetheme{Warsaw}

\AtBeginSection[]{
   \begin{frame}<beamer> \frametitle{Содержание}
     \tableofcontents[currentsection, currentsubsection]
   \end{frame}
}

\begin{document}

\section{Введение}
\label{sec:introducion}

\subsection{Подраздел введения}
\begin{frame} \frametitle{Первый слайд}
  Докладчик занял место на трибуне, а зрители уже
  расположились поудобнее в мягких креслах.
\end{frame}

\subsection{Второй подраздел}

\begin{frame} \frametitle{Ещё один слайд}
  Внимание!  Начинается второй подраздел, ещё рано спать! \\
  \vspace{0.5cm}
  Если хотите разбудить слушателей в начале подраздела, то в преамбуле
  следует <<AtBeginSection>> заменить на <<AtBeginSubsection>>.
\end{frame}

\section{Вы ещё не спите?}

\begin{frame}[containsverbatim]
  \frametitle{Бодрящий слайд}

\begin{verbatim}
Проснись и пой,
Проснись и пой.
Попробуй в жизни хоть раз
Не выпускать улыбку из открытых глаз.
Пускай, капризен успех,
Он выбирает из тех,
Кто может первым посмеяться над собой.
Пой засыпая,
Пой во сне,
Проснись и пой.
\end{verbatim}

\end{frame}

\subsection{Очень важный подраздел}
\begin{frame}<beamer> \frametitle{Содержание}
  \tableofcontents[currentsection, currentsubsection]
\end{frame}

\begin{frame} \frametitle{Очень важный слайд}
  \alert{Очень важная информация!}  \\
  \vspace{0.5cm}
  Пора проснуться!
\end{frame}

\end{document}

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

пятница, 18 сентября 2009 г.

utf8gost или как подружить русскую библиографию в BibTeX с ГОСТом и юникодом

Недавно при прочтении моего сообщения про бибтех в емаксе у комментатора появился вопрос можно ли оформить по ГОСТу библиографию с помощью BibTeX. Значит это кому-нибудь нужно… Я пользовался для этого бибтеховским стилем gost. По сути, в бибтеховском файле надо было просто прописать в добавление ко всему что было поле language = "russian", например вот так:

@Book{Aleksandrov_Perovskites04,
  author =       {Александров, К. С. and Безносиков, Б. В.},
  title =        {Перовскиты. Настоящее и будущее. (Многообразие
                  прафаз, фазовые превращения, возможности синтеза
                  новых соединений)},
  address =      {Новосибирск},
  publisher =    {Издательство СО РАН},
  year =         2004,
  pages =        231,
  language =     "russian"
}
а в латеховском исходнике указать:
\bibliographystyle{gost71u}               % выбор стиля оформления библиографии
\bibliography{../../bibliography/biblio}  % относительный путь до бибтеховской базы (без расширения bib)
В данном случае используем стиль gost71u. U означает аналог unsrt - ссылки будут нумероваться в порядке упоминания в тексте. Для стиля gost71s ссылки будут нумероваться по алфавиту.

В пакете gost есть ещё стили gost780u и gost780s. Они соответствуют ГОСТу 7.80-00 от 2000 года, в то время как gost71 - ГОСТу 7.1-84 от 1984 года. Хотя чисто визуально «стандартным» везде в моём кругу считают стиль, как оказалось, 84 года. Вообще с нашими ГОСТами сам чёрт ногу сломит. Недавно вот наши чиновники придумали в очередной раз новый стандарт. В любом случае нам за этими глупыми обновлениями не угнаться, поэтому пока пользуемся тем что есть.

А как же юникод?

Всё бы ничего, но стиль корректно функционирует только для однобайтовых кодировок, то есть никак не для юникода. Как-то видел сообщение на ЛОРе, что нашёлся умелец, который как-то стиль пропатчил, но с некоторыми ограничениями в функциональности. Там же на ЛОРе обнаружил сообщение, о том, что теперь есть те гостовские стили, адаптированные под юникод! Архив со стилем можно скачать тут. В архиве помимо необходимых для функционирования стиля файлов есть pdf-файлы с примерами того, как это будет выглядеть на печати.

Установка стиля

Перейдите в директорию, где лежат бибтеховские стили (в моём случае, на Debian Lenny это /usr/share/texmf-texlive/bibtex/bst):

$ cd /usr/share/texmf-texlive/bibtex/bst
Распакуйте архив:
$ sudo unzip /path/to/utf8gost.zip

После этого от нормального рута, а не через sudo скомандуйте:

# texhash

Запускаем

Теперь можно копировать базу, на всякий случай, и конвертировать её в юникод, если до этого было что-то другое. И наконец, исправляем в латеховском исходнике используемый стиль на один из utf8gost7*. Например, на ГОСТ 84 года в порядке упоминания в тексте:

\bibliographystyle{utf8gost71u}

По мере короткого использования никаких багов не заметил. Ждём новый стиль под «самый новый ГОСТ». Только боюсь, он уже будет неактуален, потому что появится «вообще самый-самый новый»… :)


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

пятница, 4 сентября 2009 г.

Перемещение курсора в X-терминале при русской раскладке

Известно, что оболочка bash (да и прочие shell'ы) имеют емаксо-подобные клавиатурные сокращения для перемещения курсора и прочей работы с текстом.

C-f и C-b перемещают курсор на символ вперёд и назад соответственно.

M-f и M-b перемещяют курсор на слово вперёд и назад соответственно.

C-a и C-e перемещают курсор в начало и конец строки соответственно.

C-w и M-Backspace удаляют слово перед курсором (немного разное поведение в bash).

M-d удаляет слово после курсором.

C-u вставляет текст из буфера обмена, а M-u перебирает различные варианты из буфера.

C-t переставляет местами буквы - до и после точки (до курсора и курсор).

M-t переставляет местами слова - до и после точки.

M-u переводит всё слово после курсора в верхний регистр.

M-l - в нижний регистр.

M-c - первую букву слова в верхний, а остальное в нижний.

Здесь C- означает нажать и удерживать Ctrl, а M- - нажать и удерживать Alt или нажать и отпустить Esc, а потом нажать следующую клавишу.

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

Но есть неприятный момент

Не все эти комбинации не работают у меня в иксах, в исковых терминалах (xterm, rxvt-unicode) если раскладка клавиатуры кириллическая. При этом в чистой консоли (tty) работает всё независимо от раскладки! В иксах у меня не работают все комбинации с участием клавиши Alt - вместо этого рисуются символы из расширенной ASCII-таблицы, а все Ctrl-сочетания работают независимо от используемого языка. Когда я нажимал на M-f, то получал знак «°», а если на M-b, то - «,».

Я не из тех, кто использует Emacs вообще для всего, мне он в основном интересен в качестве лишь текстового редактора для всего, поэтому запускать shell в Emacs - это не мой вариант. Итак, для меня было важно разрешить эту проблему, заставить в исковых терминалах функционировать вышеперечисленные комбинации с участием Alt (Meta).

Решение

Путь к решению был довольно долгим. Для начала я попробовал поковыряться в насройках терминала. Для rxvt-unicode пробовал править Xresources на предмет keysym. Даже добился какого-то результата, но не очень удачно - от запуска к запуску терминалы по-разному обрабатывали эти ресурсы, так что работало не всегда. Я просил помощи на линуксфоруме, но безрезультатно. Так что уже и забив на всё это, я был очень удивлён, что решение было настолько очевидным.

Насколько я понимаю, терминал обрабатывает escape-последовательности, давая в результате тот или иной результат. Надо его заставить при появлении определённой escape-последовательности генерить заданное действие. На помощь пришёл файл inputrc. Для общесистемных настроек нужно редактировать /etc/inputrc, для пользовательских - ~/.inputrc.

Пишем в inputrc русские буквы!

В этот файл я пытался вносить различные возможные записи последовательностей, в octal и hex-форматах. Но это не работало. И каково же было моё удивление, что можно просто написать в inputrc кириллические символы! Этого я ожидать никак не мог. В итоге, прочитав как называются команды в bash (man bash), получилось следующее:

"\eа": forward-word     # M-f
"\eи": backward-word    # M-b
"\eв": kill-word        # M-d
"\eе": transpose-words  # M-t
"\eг": upcase-word      # M-u
"\eд": downcase-word    # M-l
"\eс": capitalize-word  # M-c

Здесь \e - по сути Esc записано в латинской раскладке, а после неё русские буквы. Можно попробовать не \e, а \M-, что по идее должно было заработать, но не заработало в xterm (а в rxvt-unicode сработало удачно). Теперь можете запустить urxvt и проверить работоспособность.

Пинаем XTerm

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

XTerm*metaSendsEscape:  true
XTerm*eightBitInput:    false

После этого

$ xrdb ~/.Xresources
и запускайте новый XTerm.

Теперь должно всё работать. Отныне можно пользоваться всеми прелестями оболочки независимо от используемой иксовой раскладки.

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


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

вторник, 1 сентября 2009 г.

Wcd и CDargs. Удобные бродилки по файловой системе.

Известно, что для навигации по директориям файловой системы в Linux используется команда cd:

$ cd Directory/

Если же директория запрятана далеко, то неизбежно придётся набирать команду:

$ cd /path/to/deeply/hidden/directory/subdirectory/destination

Чтобы добраться до destination даже с учётом дополнения по TAB, придётся потрудиться.

Как это сделать проще?

Здесь мы рассмотрим три способа ускорения навигации в консоли по файловой системе.

Алиасы

Во-первых, для часто посещаемых директорий можно создать алиасы. Например, пропишем в ~/.bashrc (если используем оболочку bash):

if [ -f ~/.bash_aliases ]; then
    . ~/.bash_aliases
fi

Теперь в файле ~/.bash_aliases будем записывать алиасы:

alias destination='cd /path/to/deeply/hidden/directory/subdirectory/destination'

После обновления оболочки (source ~/.bashrc или простого перезапуска терминала) для того, чтобы пройти по предыдущему пути, в командной строке будет достаточно набрать

$ destination
Более того, будет работать автодополнение (если оно установлено, конечно).

К преимуществам можно отнести простоту и удобство в виде автодополнения. Недостаток же состоит в том, что кроме как перейти в назначенную директорию, мы будем не в состоянии.

Например, пусть в директории destination есть поддиректория subdirectory. Перейти в неё за одно действие описанным способом нельзя. Команда destination/subdirectory не сработает, алиасы bash этого не понимают. Алиасы в zsh поумнее, возможно, они с этим справятся, но я не специалист в этом вопросе.

Программа WCD

WCD (Wherever Change Directory) позволяет быстро менять директории. Программа кэширует дерево каталогов, после чего для перехода в destination из любой точки файловой системы достаточно скомандовать.

$ wcd destination

Здесь не будет работать автодополнение (по крайней мере у меня не работает. Если кто завёл - отзовитесь :) Зато будут функционировать wildcards * и ?. Более того, можно использовать неполное имя директории. Например, сработают варианты:

$ wcd dest
$ wcd *tion
$ wcd dest??ation

Если под запрос попадает несколько вариантов, будет выведен список, в котором можно будет выбрать нужный вариант (если вариантов очень много, то выведется постраничный листинг, для навигации в котором используются клавиши w и x):

a /usr/share/doc/texlive-latex-extra-doc/latex/datenumber
b /usr/share/doc/texlive-latex-extra-doc/latex/datetime
c /usr/share/icons/gnome/16x16/stock/data
d /usr/share/icons/gnome/24x24/stock/data
e /usr/share/icons/gnome/48x48/stock/data
f /usr/share/icons/hicolor/128x128/stock/data
g /usr/share/icons/hicolor/16x16/stock/data
h /usr/share/icons/hicolor/192x192/stock/data
i /usr/share/icons/hicolor/22x22/stock/data
j /usr/share/icons/hicolor/24x24/stock/data
k /usr/share/icons/hicolor/32x32/stock/data
l /usr/share/icons/hicolor/36x36/stock/data
m /usr/share/icons/hicolor/48x48/stock/data
n /usr/share/icons/hicolor/64x64/stock/data
o /usr/share/icons/hicolor/72x72/stock/data
p /usr/share/icons/hicolor/96x96/stock/data
q /usr/share/icons/hicolor/scalable/stock/data
r /usr/share/texmf-texlive/tex/latex/dateiliste
s /usr/share/texmf-texlive/tex/latex/datenumber
t /usr/share/texmf-texlive/tex/latex/datetime
u /usr/share/texmf-texlive/tex/latex/ucs/data
v /var/spool/openoffice/uno_packages/cache/registry/com.sun.star.comp.deploym

Wild match for 137 directories.       w=up x=down ?=help  Page 7/7
Please choose one (<Enter> to abort):

С применением wcd есть возможность заходить в поддиректории назначения, но здесь уже не будет работать автодополнение. То есть либо придётся по памяти набивать поддиректорию, используя wildcard, либо, в случае малой вложенности директорий, в качестве поддиректории сразу вколотить *

$ wcd destination/*
Установка WCD

В Debian пакет есть в репозиториях, поэтому просто:

$ sudo aptitude install wcd

После этого копируем бинарник программы куда-нибудь в $PATH (проверить можно по echo $PATH). В моём случае это ~/bin.

$ cp /usr/lib/wcd/wcd.exec ~/bin

Дальше всё по мануалу (man wcd). Лезем в ~/.bashrc (или какая там у вас оболочка?) и добавляем:

# WCD function
function wcd
{
   $HOME/bin/wcd.exeс $*

   . $HOME/bin/wcd.go
}
(Для csh будет alias wcd "$HOME/bin/wcd.exe \!* ; source $HOME/bin/wcd.go")

После этого перезапускаем оболочку и... ещё не радуемся. Надо же просканировать необходимые директории. Вся домашняя директория (пере)сканируется с использованием ключа -s, какой-то заданный путь - с ключом -A (добавляется, а не перезаписывается):

$ wcd -s
$ wcd -A /media
Можно объединить
$ wcd -s -A /media/

Теперь можно пользоваться программой. У wcd много дополнительных возможностей, например графический интерфейс, который строит дерево каталогов:

$ wcd -ga
        |         |       |        |- 700
        |         |       |        |- mm4b -+- 550_105min
        |         |       |        |        |- 550_30min
        |         |       |        |        |- 625
        |         |       |        |        `- 725
        |         |       |        `- old_MM4_PeaksCorrection -+- 350
        |         |       |                                    |- 400
        |         |       |                                    |- 450
        |         |       |                                    |- 500
        |         |       |                                    |- 550
        |         |       |                                    |- 600
        |         |       |                                    |- 625
        |         |       |                                    |-<650>

        |         |       |                                    |- 675
        |         |       |                                    `- 700
        |         |       `- results
        |         |- old_perovskites -+- Membrane -+- air -+- dat
        |         |                   |            |       `- raw
        |         |                   |            |- graphs -+- Air
        |         |                   |            |          `- Vacuum
        |         |                   |            |- photo -+- 280307
        |         |                   |            |         `- 290307
        |         |                   |            |- synchrotron -+- correct
        |         |                   |            |               `- uxd
        |         |                   |            `- vacuum --- Vac_dat
Однако для меня достаточно лишь быстрого хождения по директориям.

Программа CDargs

Эта программа предоставляет меньшую функциональность, нежели wcd, однако может оказаться более удобной. По сути она позволяет формировать закладки в файловой системе для быстрого доступа к ним.

$ cv bookmark
/path/to/buried/directory/with/bookmark
То есть, скомандовав перейти в bookmark из любой директории, мы прошли разом весь путь.

Какое же отличие от простых алиасов? Во-первых, есть возможность заходить в поддиректории, более того, с использованием автодополнения.

$ cv Music [TAB]
Music/Audiobooks/   Music/Foreign/      Music/Sounds/
Music/Classic/      Music/Fun/          Music/Soundtrack/
Music/Collections/  Music/Russian/
$ cv Music/Classic/ [TAB]
Music/Classic/Classic\ in\ rock/     Music/Classic/\М\у\с\о\р\г\с\к\и\й/
Music/Classic/PlanetClassic/         Music/Classic/\П\у\ч\ч\и\н\и/
Music/Classic/\В\и\в\а\л\ь\д\и/      Music/Classic/\Р\а\х\м\а\н\и\н\о\в/
Music/Classic/\Д\в\о\р\ж\а\к/        Music/Classic/\Р\о\с\с\и\н\и/
Music/Classic/\М\о\ц\а\р\т/          Music/Classic/\Ч\а\й\к\о\в\с\к\и\й/

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

$ cpb foo bookmark/subdirectory
Но тут, к сожалению, не работает дополнение по табу :(

В третьих есть псевдогуи, на ncurses.

Установка CDargs

В Debian Lenny, опять же, программа есть. Поэтому

$ sudo aptitude install cdargs

После этого можно запустить cdargs и почитать справку, нажав ?. Можно добавить закладки через GUI, а можно просто отредактировать файл ~/.cdargs:

cac /home/maxim/Documents/conferences/cac
Documents /home/maxim/Documents
Music /home/maxim/Music
Video /home/maxim/Video
devel /home/maxim/devel
python-dev /home/maxim/devel/python
Incomplete /home/maxim/p2p/Incomplete
p2p /home/maxim/p2p
data /media/data/

Для bash в ~/.bashrc пишем:

# CDargs function
if [ -e /usr/share/doc/cdargs/examples/cdargs-bash.sh ]; then

  . /usr/share/doc/cdargs/examples/cdargs-bash.sh
fi
function cv () {
    cdargs "$1" && cd "‘cat "$HOME/.cdargsresult"‘" ;
}

Теперь, после перезапуска оболочки бегаем по файловой системе со скоростью спринтера.

Резюме

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

Несомненно, программы wcd и cdargs существенно облегчат жизнь обитателям консоли. Напоследок хотелось бы отметить, что с cdargs я познакомился благодаря обзору на Debian Package of the Day.


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