15.09.2009

Подсветка синтаксиса в блоге. Используем онлайновые маркеры синтаксиса

О том, как вставить в блог фрагмент кода с подсвеченным синтаксисом, используя редактор Vim, я уже писал. А недавно мне подсказали еще более простое решение, не требующее для своей реализации ни чего кроме браузера - в сети имеются специальные (абсолютно бесплатные) сервисы, позволяющие разукрашивать, перед публикацией, практически любой код. Принцип работы с клиентом у таких сервисов-маркеров общий: пользователь вводит в форму фрагмент кода, выбирает из выпадающего списка тип оформляемого кода, включает (если нужно) пару дополнительных опций и, нажав соответствующую кнопку, отправляет запрос сервису. Сервис возвращает подсвеченный код в виде блока тегов html, который можно скопировать и вставить в свою страницу. Список поддерживаемых языков кода у сервисов весьма обширный, разукрасить можно практически все что угодно.

Вот два таких онлайновых маркера.

Online syntax highlighting

Online syntax highlighting, способен автоматически угадывать тип введенного кода, позволяет выбрать несколько стилей оформления. Вставляем код в редактор Source code, выбираем язык программирования в списке Type, стиль оформления в списке Style, жмем кнопку Highlight, в появившемся редакторе выделяем и копируем блок html тегов.

Примеры подсвеченного кода при различных стилях оформления:

Стиль: white

# -*- coding: UTF-8 -*-

import matplotlib.pyplot as plt

# Значения по оси X
X = [20.0, 40.0, 60.0, 80.0, 100.0]
# Набор значений по оси Y
Y_10 = [0.97252, 0.94238, 0.89927, 0.85197, 0.79784]
Y_20 = [0.96864, 0.93518, 0.89113, 0.84344, 0.78934]
Y_30 = [0.96395, 0.92770, 0.88278, 0.83473, 0.78075]

# Строим диаграмму
plt.plot(X, Y_10, 'bD:',  label = u'Температура 10 \u00b0C')
plt.plot(X, Y_20, 'r^:',  label = u'Температура 20 \u00b0C')
plt.plot(X, Y_30, 'go:',  label = u'Температура 30 \u00b0C')
# Задаем подписи
plt.title(u'Зависимость плотности водных растворов этилового спирта от температуры')
plt.xlabel(u'Массовая доля этилового спирта, %')
plt.ylabel(u'Плотность, г/мл')
# Включаем легенду
plt.legend(loc = 'best')
# Сохраняем построенную диаграмму в файл
plt.savefig('spirit.png', format = 'png')

Стиль: navy

# -*- coding: UTF-8 -*-

import matplotlib.pyplot as plt

# Значения по оси X
X = [20.0, 40.0, 60.0, 80.0, 100.0]
# Набор значений по оси Y
Y_10 = [0.97252, 0.94238, 0.89927, 0.85197, 0.79784]
Y_20 = [0.96864, 0.93518, 0.89113, 0.84344, 0.78934]
Y_30 = [0.96395, 0.92770, 0.88278, 0.83473, 0.78075]

# Строим диаграмму
plt.plot(X, Y_10, 'bD:',  label = u'Температура 10 \u00b0C')
plt.plot(X, Y_20, 'r^:',  label = u'Температура 20 \u00b0C')
plt.plot(X, Y_30, 'go:',  label = u'Температура 30 \u00b0C')
# Задаем подписи
plt.title(u'Зависимость плотности водных растворов этилового спирта от температуры')
plt.xlabel(u'Массовая доля этилового спирта, %')
plt.ylabel(u'Плотность, г/мл')
# Включаем легенду
plt.legend(loc = 'best')
# Сохраняем построенную диаграмму в файл
plt.savefig('spirit.png', format = 'png')

Стиль: Bred3

# -*- coding: UTF-8 -*-

import matplotlib.pyplot as plt

# Значения по оси X
X = [20.0, 40.0, 60.0, 80.0, 100.0]
# Набор значений по оси Y
Y_10 = [0.97252, 0.94238, 0.89927, 0.85197, 0.79784]
Y_20 = [0.96864, 0.93518, 0.89113, 0.84344, 0.78934]
Y_30 = [0.96395, 0.92770, 0.88278, 0.83473, 0.78075]

# Строим диаграмму
plt.plot(X, Y_10, 'bD:',  label = u'Температура 10 \u00b0C')
plt.plot(X, Y_20, 'r^:',  label = u'Температура 20 \u00b0C')
plt.plot(X, Y_30, 'go:',  label = u'Температура 30 \u00b0C')
# Задаем подписи
plt.title(u'Зависимость плотности водных растворов этилового спирта от температуры')
plt.xlabel(u'Массовая доля этилового спирта, %')
plt.ylabel(u'Плотность, г/мл')
# Включаем легенду
plt.legend(loc = 'best')
# Сохраняем построенную диаграмму в файл
plt.savefig('spirit.png', format = 'png')

Стиль: black

# -*- coding: UTF-8 -*-

import matplotlib.pyplot as plt

# Значения по оси X
X = [20.0, 40.0, 60.0, 80.0, 100.0]
# Набор значений по оси Y
Y_10 = [0.97252, 0.94238, 0.89927, 0.85197, 0.79784]
Y_20 = [0.96864, 0.93518, 0.89113, 0.84344, 0.78934]
Y_30 = [0.96395, 0.92770, 0.88278, 0.83473, 0.78075]

# Строим диаграмму
plt.plot(X, Y_10, 'bD:',  label = u'Температура 10 \u00b0C')
plt.plot(X, Y_20, 'r^:',  label = u'Температура 20 \u00b0C')
plt.plot(X, Y_30, 'go:',  label = u'Температура 30 \u00b0C')
# Задаем подписи
plt.title(u'Зависимость плотности водных растворов этилового спирта от температуры')
plt.xlabel(u'Массовая доля этилового спирта, %')
plt.ylabel(u'Плотность, г/мл')
# Включаем легенду
plt.legend(loc = 'best')
# Сохраняем построенную диаграмму в файл
plt.savefig('spirit.png', format = 'png')

Во всех примерах использован код из поста Пакет matplotlib. Строим банальный график

Syntax Highlighter

В целом порядок работы с сервисом Syntax Highlighter аналогичен описанному выше. Имеются опции: Line numbers - включить/выключить автоматическую нумерацию строк кода, Use <font> tag (for Habrahabr) - если включена, код оформляется посредством тега <font>, в противном случае с помощью классов css (внешний вид подсвеченного кода при этом несколько отличается).

Примеры:

При включенной опции Use <font> tag (for Habrahabr):

  1. # -*- coding: UTF-8 -*-
  2.  
  3. import matplotlib.pyplot as plt
  4.  
  5. # Значения по оси X
  6. = [20.040.060.080.0100.0]
  7. # Набор значений по оси Y
  8. Y_10 = [0.972520.942380.899270.851970.79784]
  9. Y_20 = [0.968640.935180.891130.843440.78934]
  10. Y_30 = [0.963950.927700.882780.834730.78075]
  11.  
  12. # Строим диаграмму
  13. plt.plot(X, Y_10, 'bD:',  label = u'Температура 10 \u00b0C')
  14. plt.plot(X, Y_20, 'r^:',  label = u'Температура 20 \u00b0C')
  15. plt.plot(X, Y_30, 'go:',  label = u'Температура 30 \u00b0C')
  16. # Задаем подписи
  17. plt.title(u'Зависимость плотности водных растворов этилового спирта от температуры')
  18. plt.xlabel(u'Массовая доля этилового спирта, %')
  19. plt.ylabel(u'Плотность, г/мл')
  20. # Включаем легенду
  21. plt.legend(loc = 'best')
  22. # Сохраняем построенную диаграмму в файл
  23. plt.savefig('spirit.png', format = 'png')

При выключенной опции Use <font> tag (for Habrahabr):

  1. # -*- coding: UTF-8 -*-
  2.  
  3. import matplotlib.pyplot as plt
  4.  
  5. # Значения по оси X
  6. X = [20.0, 40.0, 60.0, 80.0, 100.0]
  7. # Набор значений по оси Y
  8. Y_10 = [0.97252, 0.94238, 0.89927, 0.85197, 0.79784]
  9. Y_20 = [0.96864, 0.93518, 0.89113, 0.84344, 0.78934]
  10. Y_30 = [0.96395, 0.92770, 0.88278, 0.83473, 0.78075]
  11.  
  12. # Строим диаграмму
  13. plt.plot(X, Y_10, 'bD:', label = u'Температура 10 \u00b0C')
  14. plt.plot(X, Y_20, 'r^:', label = u'Температура 20 \u00b0C')
  15. plt.plot(X, Y_30, 'go:', label = u'Температура 30 \u00b0C')
  16. # Задаем подписи
  17. plt.title(u'Зависимость плотности водных растворов этилового спирта от температуры')
  18. plt.xlabel(u'Массовая доля этилового спирта, %')
  19. plt.ylabel(u'Плотность, г/мл')
  20. # Включаем легенду
  21. plt.legend(loc = 'best')
  22. # Сохраняем построенную диаграмму в файл
  23. plt.savefig('spirit.png', format = 'png')

Ну вот на этом и все. Спасибо за внимание.

Предыдущий пост по теме: Как вставить в блог фрагмент кода с подсветкой синтаксиса


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

11.09.2009

Пакет NumPy. Краткое введение

Введение. Пакет NumPy - зачем нужен, где взять

Пакет (библиотека) языка Pyton NumPy предоставляет программисту средства для высокоэффективной работы с огромными многомерными массивами данных. Как составная часть и основа, пакет NumPy входит в большинство проектов, использующих язык Python и требующих мало-мальски громоздких вычислений. В частности, с его использованием написаны популярные пакеты вычислительной математики и научной графики SciPy и mathplotLib.

Python интерпретируемый язык программирования, как следствие, математические алгоритмы, написанные на Python'е, часто работают заметно медленнее по сравнению с теми же алгоритмами, реализованными на компилируемых языках. Авторы NumPy постарались разрешить эту проблему в части обработки массивов, предложив модуль, включающий набор функций для создания многомерных массивов и работы с ними, причем исполняемый код функций реализован на языках C и Fortran. Кроме того, в пакете определены функции линейной алгебры, преобразования Фурье и генерации случайных чисел.

Сейчас я постараюсь дать самое краткое описание основ использования пакета.

Взять дистрибутив NumPy можно из репозитория SourceForge. На момент написания крайняя версия 1.3.0, выпущена 05 апреля 2009 года. Установка пакета не должна вызвать каких-либо затруднений, какой-либо особой настройки пакет так же не требует.

Модуль NumPy предназначен для работы с массивами, соответственно основной тип данных определенных в модуле - массив (nump.ndarray). Массив - контейнер, содержащий элементы одного типа (и одной длинны, если элементы вложенные массивы), организованные в упорядоченную многомерную таблицу. Доступ к элементам осуществляется по индексу - кортежу целых чисел.

Создать массив можно несколькими способами.

Способы создания массивов

Массив может быть создан на основе имеющегося списка:

>>> import numpy as np

>>> a = np.array([.1, .2, .3, .4, .5])
>>> a
array([ 0.1,  0.2,  0.3,  0.4,  0.5])
>>> type(a)
<type 'numpy.ndarray'>

Имя класса numpy.ndarray выбрано специально, чтобы не было путаницы со стандартным классом Python array.

Аналогично можно создать многомерный массив:

>>> a3 = np.array([ [ [1, 2], [3, 4], [5, 6] ], [ [7, 8], [9, 10], [11, 12] ] ])
>>> a3
array([[[ 1,  2],
        [ 3,  4],
        [ 5,  6]],

       [[ 7,  8],
        [ 9, 10],
        [11, 12]]])
>>> type(a3)
<type 'numpy.ndarray'>

Массивы NumPy во многом аналогичны стандартным спискам Python.

Доступ к элементам массива получают по индексу (разумеется, индекс первого элемента 0):

>>>print a[0]
0.1

>>>print a[3]
0.4

Для индексации многомерных массивов используют кортежи (индексы перечисляют через запятую):

>>> a3[1]
array([[ 7,  8],
       [ 9, 10],
       [11, 12]])

>>> a3[1, 1]
array([ 9, 10])

>>> a3[1, 1, 1]
10

От массивов можно брать срезы:

>>> a[2:4]
array([ 0.3,  0.4])

>>> a3[0, 1:]
array([[3, 4],
       [5, 6]])

Массивы можно использовать в различных итерациях:

>>> for i in a:
...     print i
...
0.1
0.2
0.3
0.4
0.5

>>> for i in a3:
...     for j in i:
...             print j
...
[1 2]
[3 4]
[5 6]
[7 8]
[ 9 10]
[11 12]

Каждый объект numpy.ndarray имеет атрибут shape - кортеж целых чисел, который определяет шаблон массива. Здесь под шаблоном подразумевается количество элементов каждой размерности массива, так для матрицы с n строк и m столбцов шаблон (n, m).

>>> a.shape
(5,)

>>> a3.shape
(2, 3, 2)

Изменяя атрибут shape, можно изменять размерность и структуру массива, но при этом число элементов массива должно оставаться неизменным:

>>> a3.shape = (6, 2)
>>> a3
array([[ 1,  2],
       [ 3,  4],
       [ 5,  6],
       [ 7,  8],
       [ 9, 10],
       [11, 12]])

>>> a3.shape = (12)
>>> a3
array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12])

>>> a3.shape = (3, 3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: total size of new array must be unchanged

Массив может быть создан с помощью функции numpy.arange().

Функция arange() в самом простом варианте вызова принимает в качестве аргумента целое положительное число n, возвращает массив из n элементов от 0 до n-1:

>>> b = np.arange(5)
>>> b
array([0, 1, 2, 3, 4])
>>> type(b)
<type 'numpy.ndarray'>

Полный формат вызова функции: numpy.arange([start,] stop[, step,], dtype = None),

где:

start - опциональный аргумент, начальное значение интервала, по умолчанию равен 0;

stop - обязательный аргумент, конечное значение интервала, не входящее в сам интервал, интервал замыкает значение stop - step;

step - опциональный аргумент, шаг итерации, разность между каждым последующим и предыдущим значениями интервала, по умолчанию равен 1;

dtype - тип элементов массива, по умолчанию None, в этом случае тип элементов определяется по типу переданных функции аргуметов start, stop.

Массив может быть создан с помощью функции numpy.linspace().

Функция linspace() в простейшем случае принимает три аргумента - числа: начальный элемент массива, конечный элемент массива, количество элементов массива. Возвращает массив чисел равномерно распределенных от начального до конечного значения.

>>> c = np.linspace(-3.0, 3.0, 7)
>>> c
array([-3., -2., -1.,  0.,  1.,  2.,  3.])
>>> type(c)
<type 'numpy.ndarray'>

Полный формат вызова функции: numpy.linspace(start, stop, num = 50, endpoint = True, retstep = False),

где:

start - обязательный аргумент, первый член последовательности элементов массива;

stop - обязательный аргумент, последний член последовательности элементов массива;

num - опциональный аргумент, количество элементов массива, по умолчанию равен 50;

endpoint - опциональный аргумент, логическое значение, по умолчанию True. Если передано True, stop, последний элемент массива. Если установлено в False, последовательность элементов формируется от start до stop для num + 1 элементов, при этом в возвращаемый массив последний элемент не входит;

>>> d = np.linspace(1.0, 6.0, 5, endpoint = False)
>>> d
array([ 1.,  2.,  3.,  4.,  5.])

retstep - опциональный аргумент, логическое значение, по умолчанию False. Если передано True, функция возвращает кортеж из двух членов, первый - массив, последовательность элементов, второй - число, приращение между элементами последовательности.

>>> f = np.linspace(.5, -.5, 5, retstep = True)
>>> f
(array([ 0.5 ,  0.25,  0.  , -0.25, -0.5 ]), -0.25)

Массив может быть создан с помощью функций numpy.zeros(), numpy.ones(), numpy.empty().

Функции принимают один обязательный аргумент - кортеж, размерность массива и возвращают массив затребованной структуры содержащий: нули (функция numpy.zeros()), единицы numpy.ones(), произвольный мусор (неинициализированный массив, функция numpy.empty()):

>>> z = np.zeros((3,3))
>>> z
array([[ 0.,  0.,  0.],
       [ 0.,  0.,  0.],
       [ 0.,  0.,  0.]])

>>> o = np.ones((3, 3))
>>> o
array([[ 1.,  1.,  1.],
       [ 1.,  1.,  1.],
       [ 1.,  1.,  1.]])

>>> e = np.empty((3,3))
>>> e
array([[  8.32475314e-306,   8.32468797e-306,   8.32462278e-306],
       [  8.32455759e-306,   8.32449240e-306,   5.99491582e+197],
       [  5.30481132e+180,   5.51965256e-311,   0.00000000e+000]])

Полный формат вызова функций:

numpy.zeros(shape, dtype = float, order = 'C')

numpy.ones(shape, dtype = float, order = 'C')

numpy.empty(shape, dtype = float, order = 'C')

где:

shape - обязательный аргумент, кортеж, требуемая размерность массива;

dtype - опциональный аргумент, тип элементов массива, по умолчанию float;

order - опциональный аргумент, строка, способ представления данных массива в памяти, два возможных значения 'C' и 'F', пока я не сталкивался с необходимостью изменять умолчальное значение.

Ну и последний из рассматриваемых способов с помощью функций numpy.zeros_like(), numpy.ones_like(), numpy.empty_like().

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

>>> d
array([ 1.,  2.,  3.,  4.,  5.])

>>> dz = np.zeros_like(d)
>>> dz
array([ 0.,  0.,  0.,  0.,  0.])

>>> do = np.ones_like(d)
>>> do
array([ 1.,  1.,  1.,  1.,  1.])

>>> de = np.empty_like(d)
>>> de
array([  2.24122267e+201,   6.32526950e-317,   0.00000000e+000,
         2.24686637e+201,   6.34874355e-321])

Полный формат вызова функций:

numpy.zeros_like(a)

numpy.ones_like(a)

numpy.empty_like(a)

где:

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

О массивах чуть подробней

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

Многомерную таблицу можно представить как некое расширение обычной, "двумерной" таблицы, включающей кроме строк и столбцов еще произвольное число "измерений", вместе образующих некую многомерную решетку. В документации NumPy такие измерения именуют осями (axis), а число осей у конкретного массива рангом (rank) массива (при этом термин ранг применяется и в контексте матриц, что, разумеется, не одно и тоже). Для еще большей путаницы вместо числа осей или ранга используют термин размерность (dimension). В разделе документации официального сайта проекта есть Numpy Glossary, там для слова axis приводиться одно значение, для слова rank два, а для слова dimension - три. На текущем уровне просветления моё воображение позволяет представить массив с размерностью не большей четырех, а в практической деятельности, я не сталкивался с массивами имеющими более трех осей :) Так вектор это одномерный массив, матрица, растровый черно-белый рисунок, таблица Excel двумерный, цветной растровый рисунок трехмерный.

Каждый объект класса numpy.ndarray имеет атрибут ndarray.ndim - число осей, ранг, размерность массива. По определению ранга массива значение ndarray.ndim должно быть равно числу элементов в кортеже ndarray.shape.

Общее число элементов массива можно узнать, обратившись к атрибуту ndarray.size.

>>> import numpy as np

>>> vector = np.array([1, 3, 5, 7, 9])
>>> print vector.ndim
1
>>> print vector.shape
(5,)
>>> vector.size
5

>>> bwimage = np.array([ [255, 247, 236, 12, 149], [123, 34, 147, 45, 102], [34, 69, 108, 81, 94] ])
>>> print bwimage.ndim
2
>>> print bwimage.shape
(3, 5)
>>> bwimage.size
15

>>> rgbimage = np.array([ [ [234, 126, 34, 45, 18], [123, 123, 49, 34, 56], [255, 233, 233, 233, 233] ],
... [ [12, 12, 12, 12, 12], [14, 15, 16, 17, 17], [13, 12, 14, 12, 12] ],
... [ [67, 56, 56, 57, 56], [56, 57, 56, 57, 58], [59, 58, 58, 59, 57] ] ])
>>> print rgbimage.ndim
3
>>> print rgbimage.shape
(3, 3, 5)
>>> rgbimage.size
45

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

>>> good = np.array([ [1, 2, 3], [4, 5, 6], [7, 8, 9] ])
>>> wrong = np.array([ [1, 2, 3], [4, 5, 6], [7, 8] ])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: setting an array element with a sequence.

Операции над массивами

Все вышесказанное было бы абсолютно бесполезной белибердой, если бы над массивами (над данными содержащимися в массивах) невозможно было б производить каких либо содержательных действий. Разумеется это не так. Цель создания пакета NumPy - предоставить пользователю Python инструменты для "быстрой" работы с большими наборами данных.

Объекты класса numpy.ndarray можно использовать как операнды в выражениях, при этом все операции с массивами будут выполняться поэлементно, то есть итогом операции будет новый массив, содержащий результаты применения операции к каждому элементу исходного массива:

>>> import numpy as np

>>> a = np.arange(6)
>>> print a
[0 1 2 3 4 5]

>>> print a + 1
[1 2 3 4 5 6]

>>> print a * 3
[ 0  3  6  9 12 15]

>>> print a ** 3
[  0   1   8  27  64 125]

>>> print a < 3
[ True  True  True False False False]

>>> a += 2
>>> print a
[2 3 4 5 6 7]

В пакете NumPy определены основные математические функции, так же позволяющие проводить поэлементные вычисления:

>>> t = np.linspace(0.0, 2 * np.pi, 4)
>>> print t
[ 0.          2.0943951   4.1887902   6.28318531]

>>> print np.cos(t)
[ 1.  -0.5 -0.5  1. ]

>>> print np.sin(t)
[  0.00000000e+00   8.66025404e-01  -8.66025404e-01  -2.44929360e-16]

>>> print np.tan(t)
[  0.00000000e+00  -1.73205081e+00   1.73205081e+00  -2.44929360e-16]

>>> s = np.linspace(2.0, 6.0, 5)
>>> print s
[ 2.  3.  4.  5.  6.]

>>> s = np.exp(s)
>>> print s
[   7.3890561    20.08553692   54.59815003  148.4131591   403.42879349]

>>> s = np.log(s)
>>> print s
[ 2.  3.  4.  5.  6.]

>>> print np.sqrt(s ** 2)
[ 2.  3.  4.  5.  6.]

Привожу список самых полезных (на мой взгляд) математических функций пакета NumPy:

Во всех определениях ниже a массив или скаляр.

numpy.abs(a) - абсолютное значение a;

numpy.around(a, decimals = 0, out = None) - округляет a до заданного количества десятичных разрядов, по умолчанию до целого. Придерживается следующего правила округления. Если значение a находиться точно по середине между двумя целыми, округление производиться до ближайшего четного целого. Так если a равно 1.5 или 2.5 будет возвращено 2, если a равно -0.5 или 0.5 будет возвращено 0.0. Аргумент decimals - целое, десятичный разряд после запятой, до которого производиться округление, если decimals отрицательное, разряд отсчитывается влево от запятой.

>>> print np.around(np.array([0.5, 1.8, 2.5, 3.5]))
[ 0.  2.  2.  4.]

>>> print np.around(np.array([1, 5, 15, 45]), decimals = 1)
[ 1  5 15 45]

>>> print np.around(np.array([1, 5, 15, 45]), decimals = -1)
[ 0  0 20 40]

Аргумент out - массив, в который будет передан результат, структура массива out, должна совпадать со структурой возвращаемого массива. Если None (по умолчанию) будет создан новый массив.

numpy.fix(a, out = None) - отбрасывает дробную часть a;

numpy.ceil(a, out = None) - округляет a до меньшего из целых больших или равных a;

>>>  print np.ceil(np.array([-2.7, -1.2, -0.5, 1.8, 2.4, 3.6]))
[-2. -1. -0.  2.  3.  4.]

numpy.floor(a, out = None) - округляет a до большего из целых меньших или равных a;

>>> print np.floor(np.array([-2.7, -1.2, -0.5, 1.8, 2.4, 3.6]))
[-3. -2. -1.  1.  2.  3.]

numpy.sign(a) - возвращает -1 если a < 0, 0 если a == 0, 1 если a > 0;

numpy.degrees(a) - конвертирует a из радиан в градусы;

numpy.radians(a) - конвертирует a из градусов в радианы;

numpy.cos(a), numpy.sin(a), numpy.tan(a) - возвращает косинус, синус, тангенс a. a в радианах;

numpy.cosh(a), numpy.sinh(a), numpy.tanh(a) - возвращает гиперболические косинус, синус, тангенс a. a в радианах;

numpy.arccos(a), numpy.arcsin(a), numpy.arctan(a) - возвращает арккосинус, арксинус, арктангенс a в радианах. Для арккосинуса в диапазоне [0, nump.pi], для арксинуса [-numpy.pi/2, numpy.pi/2], для арктангенса [-numpy.pi/2, numpy.pi/2];

numpy.arccosh(a), numpy.arcsinh(a), numpy.arctanh(a) - возвращает гиперболические косинус, синус, тангенс a. a в радианах;

numpy.exp(a) - возвращает основание натурального логарифма (число e) в степени a;

numpy.log(a), numpy.log10(a), numpy.log2(a) - возвращает натуральный логарифм a, логарифм a по основанию 10, логарифм a по основанию 2;

numpy.log1p(a) - возвращает натуральный логарифм a + 1;

numpy.sqrt(a) - возвращает положительный квадратный корень a;

numpy.square(a) - возвращает квадрат a.

В выражения можно включать несколько массивов. В случае если атрибуты ndarray.shape этих массивов совпадают, результат очевиден - действия над массивами будут производиться поэлементно:

>>> a1 = np.array([ [1.0, 2.0], [3.0, 4.0] ])
>>> a2 = np.array([ [5.0, 6.0], [7.0, 8.0] ])
>>> a3 = np.array([ [9.0, 10.0], [11.0, 12.0] ])

>>> print a1 + a2 + a3
[[ 15.  18.]
 [ 21.  24.]]

>>> print a1 * a2
[[  5.  12.]
 [ 21.  32.]]

>>> print a3 / a1
[[ 9.          5.        ]
 [ 3.66666667  3.        ]]

>>> print (a3 - a1) * a2
[[ 40.  48.]
 [ 56.  64.]]

Если атрибуты ndarray.shape не совпадают - действия над массивами производятся в соответствии с концепцией транслирования (broadcasting).

Операция транслирования - расширение одного или обоих массивов операндов до массивов с равной размерностью.

Для начала несколько примеров:

>>> a2 = np.array([1, 2])
>>> print a2
[1 2]
>>> print a2.shape
(2,)

>>> a22 = np.array([ [1, 2], [3, 4] ])
>>> print a22
[[1 2]
 [3 4]]
>>> print a22.shape
(2, 2)

>>> a32 = np.array([ [1, 2], [3, 4], [5, 6] ])
>>> print a32
[[1 2]
 [3 4]
 [5 6]]
>>> print a32.shape
(3, 2)

>>> a222 = np.array([ [ [1, 2], [3, 4] ], [ [5, 6], [7, 8] ] ])
>>> print a222
[[[1 2]
  [3 4]]

 [[5 6]
  [7 8]]]
>>> print a222.shape
(2, 2, 2)

>>> print a22 + a2
[[2 4]
 [4 6]]
 
>>> print a32 + a2
[[2 4]
 [4 6]
 [6 8]]

>>> print a222 + a2
[[[ 2  4]
  [ 4  6]]

 [[ 6  8]
  [ 8 10]]]

>>> print a32 + a22
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: shape mismatch: objects cannot be broadcast to a single shape

>>> print a222 + a22
[[[ 2  4]
  [ 6  8]]

 [[ 6  8]
  [10 12]]]

>>> print a222 + a32
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: shape mismatch: objects cannot be broadcast to a single shape

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

>>> a = np.ones((7, 3, 4, 9, 8))
>>> b = np.ones((4, 9, 8))
>>> c = np.ones((4, 3, 8))

>>> print (a + b).shape
(7, 3, 4, 9, 8)

>>> print (a + c).shape
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: shape mismatch: objects cannot be broadcast to a single shape

>>> d = np.ones((9, 7, 1, 6, 1))
>>> e = np.ones((7, 2, 1, 4))
>>> print (d + e).shape
(9, 7, 2, 6, 4)

В случае если в массивах присутствуют оси единичной длины, расширяться могут оба массива.

>>> f = np.array([1, 2])
>>> print f
[1 2]
>>> print f.shape
(2,)

>>> g = np.array([ [3], [4], [5] ])
>>> print g
[[3]
 [4]
 [5]]
>>> print g.shape
(3, 1)

>>> h = f + g
>>> print h
[[4 5]
 [5 6]
 [6 7]]
>>> print h.shape
(3, 2)

Трансляция массивов происходит и при вызове некоторых функций.

Например, функция numpy.power(a1, a2), где a1, a2 массив или скаляр, возвращает a1 в степени a2:

>>> print np.power(np.array([-2.0, -1.0, 0.0, 2.0, 3.0, 4.0]), 4)
[  16.    1.    0.   16.   81.  256.]

>>> print np.power(np.array([-2.0, -1.0, 0.0, 2.0, 3.0, 4.0]), -4)
[ 0.0625      1.                 Inf  0.0625      0.01234568  0.00390625]

в случае если у переданных массивов не совпадает структура, проводит трансляцию.

>>> print np.power(np.array([3, 7]), np.array([ [1], [2], [3] ]))
[[  3   7]
 [  9  49]
 [ 27 343]]

Некоторые полезные функции

Здесь я приведу еще один набор полезных функций.

numpy.min(a, axis = None, out = None),

numpy.max(a, axis = None, out = None) -

возвращает минимальное, максимальное значение элементов массива соответственно:

>>> import numpy as np

>>> print np.min(np.array([ [1.0, -0.5, 3.0], [4.0, 3.0, -0.5] ]))
-0.5

axis - опциональный аргумент, индекс оси (измерения) массива по которому проводится поиск минимального, максимального значения. Под индексом оси понимается индекс в кортеже ndarray.shape.

>>> a = np.array([ [ [1.0, 2.0, 3.0], [4.0, 5.0, 6.0] ], [ [7.0, 8.0, 9.0], [11, 12, 13] ] ])
>>> print a
[[[  1.   2.   3.]
  [  4.   5.   6.]]

 [[  7.   8.   9.]
  [ 11.  12.  13.]]]
>>> print a.shape
(2, 2, 3)

>>> print np.min(a, axis = 0)
[[ 1.  2.  3.]
 [ 4.  5.  6.]]

>>> print np.min(a, axis = 1)
[[ 1.  2.  3.]
 [ 7.  8.  9.]]

>>> print np.min(a, axis = 2)
[[  1.   4.]
 [  7.  11.]]

out - опциональный аргумент, массив, в который будет помещен результат. Структура массива out должна соответствовать структуре массива результата. Если out = None (по умолчанию) будет создан новый массив.

numpy.argmin(a, axis = None),

numpy.argmax(a, axis = None) -

возвращает индекс минимального, максимального значения элементов массива соответственно:

>>> print np.argmin(np.array([ [1.0, -0.5, 3.0], [4.0, 3.0, -0.5] ]))
1

>>> print np.argmin(a, axis = 0)
[[0 0 0]
 [0 0 0]]

>>> print np.argmin(a, axis = 1)
[[0 0 0]
 [0 0 0]]

>>> print np.argmin(a, axis = 2)
[[0 0]
 [0 0]]

numpy.sum(a, axis = None, dtype = None, out = None),

numpy.prod(a, axis = None, dtype = None, out = None) -

возвращает сумму, произведение элементов массива соответственно:

>>> print np.sum(np.array([ [1.0, -0.5, 3.0], [4.0, 3.0, -0.5] ]))
10.0
>>> print np.sum(a, axis = 0)
[[  8.  10.  12.]
 [ 15.  17.  19.]]
>>> print np.sum(a, axis = 1)
[[  5.   7.   9.]
 [ 18.  20.  22.]]
>>> print np.sum(a, axis = 2)
[[  6.  15.]
 [ 24.  36.]]

Ну вот пожалуй на сегодня и все. Разговор о пакете NumPy продолжим в следующий раз.


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

01.09.2009

Дополнение Firefox gTranslate. Мгновенный доступ к сервису Переводчик Google

Иконка дополнения Firefox gTranslate

Среди многочисленных сервисов Google скромно существует Google Переводчик - попытка всемогущего поисковика создать свою собственную систему автоматического перевода. Насколько удачная? Настолько, насколько были удачны все подобные попытки предпринятые до Google.

Сервис полностью бесплатен. Поддерживает все, более менее значимые, мировые языки.

А дополнение Firefox gTranslate предназначено для максимального упрощения доступа к указанному сервису.

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

Дополнение Firefox gTranslate. Пример перевода

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

Настроек дополнение минимум, но они несколько путанные.

Дополнение Firefox gTranslate. Окно настроек

Чекбокс Page language включает алгоритм автоматического распознавания языка страницы.

Чекбокс Browser default language включает механизм определения языка перевода по локализации браузера.

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

Зачем тогда нужен самый верхний выпадающий список в окне настроек (в котором так же присутствует пункт Detect language и повторяющий его пункт в контекстном меню?

На сколько я понял автора дополнения, он реализовал два механизма распознавания переводимого языка. Один включается установкой чекбокса, другой выбором пункта списка/меню. Причем сам автор отдает предпочтение второму.

В общем я выключил оба чекбокса, выбрав из списков пункты Detect language и Russian.

Возможность выбора языка исходного текста и языка перевода присутствует и в контекстном меню.

Дополнение Firefox gTranslate. Выбор языка перевода

Можно задать автоматическое распознавание языка источника (пункт меню Detect language), можно назначить исходный язык принудительно, ну и указать соответствующий ему язык перевода.

Вот еще несколько примеров перевода :)

Арабский

Дополнение Firefox gTranslate. Пример перевода. Арабский

Китайский

Дополнение Firefox gTranslate. Пример перевода. Китайский

Хинди

Дополнение Firefox gTranslate. Пример перевода. Хинди

Я использую дополнение gTranslate (и сервис Переводчик Google соответственно) не как собственно переводчик (усилия по пониманию результатов автоматического перевода сопоставимы с непосредственным чтением английского текста), а как бесплатный словарь с относительно удобным интерфейсом.


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

24.08.2009

Дополнение Firefox Lazarus. Восстановление данных веб-форм

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

Иконка дополнения Firefox Lazarus

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

Скачать последнюю версию Lazarus можно с официального репозитория дополнений addons.mozilla.org, домашняя страница дополнения lazarus.interclue.com.

После установки Lazarus будет автоматически сохраняет все данные вводимые пользователем в веб формы. При этом поддерживаются как "обычные" html формы, так и (частично) формы WYSIWYG редакторов, формы AJAXified, текстовые поля Richtext. Ввод в приложения Java и Flash дополнение перехватывать не способно.

Lazarus хранит собранную информацию в базе данных (на основе SQLite, файл lazarus.sqlite в папке профиля) в зашифрованном виде (авторы дополнения настаивают на более чем достаточной надежности принятого способа шифрования), и каждой форме, с которой сталкивался пользователь (URL страницы содержащей форму), в базе данных соответствует запись, включающая историю пользовательского ввода.

Как использовать дополнение?

И так, для того, что бы восстановить потерянные данные веб формы, необходимо повторно открыть страницу с злополучной формой. Кликнут правой кнопкой мыши на поле ввода формы (или на любом участке страницы охваченном тегом <form>), в появившемся меню найти два пункта относящихся к Lazarus - Recover Form и Recover Text.

Пример восстановления данных веб формы посредством дополнения Firefox Lazarus

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

Пункт Recover Form задействует механизм реализующий восстановление данных обычных html форм, пункт Recover Text механизм восстановления содержимого форм других поддерживаемых типов.

Строка примера текста может заканчиваться символами (A) или (S). В первом случае ввод был сохранен в базу данных Lazarus по ходу набора текста, во втором случае после того как пользователь инициировал отправку содержимого формы на сервер.

Утерянное содержимое можно восстановить и не открывая страницу с формой. После установки Lazarus в строке состояния браузера появляется иконка с крестом. По клику на иконке всплывет меню в котором присутствует пункт Search Lazarus...

Меню дополнения Firefox Lazarus

Lazarus предоставляет пользователю возможность проводить поиск по своей базе данных.

Окно поиска дополнения Firefox Lazarus

База поискового индекса Lazarus зашифрована, в следствие чего адекватные результаты поиска будут получены только при подстановке в поле поиска целых слов и фраз.

Поиск по базе данных Lazarus возможен только по целым словам и фразам

Выбрав из результатов поиска самую приглянувшиюся запись, можно просмотреть весь сохраненный текст, кликнув на кнопку в поле Recover

Окно просмотра сохраненного текста базы данных дополнения Firefox Lazarus

Забавно, если ввод в форму содержал теги html, окно просмотра будет содержать две вкладки - исходный код и его вид в браузере.

Окно просмотра сохраненного текста базы данных дополнения Firefox Lazarus

Ну а если кликнуть по ссылке на страницу с формой (поле Url)будет открыта эта страница, а сохраненный ввод помещен в форму.

Ввод можно удалить из базы, для чего предусмотрены соответствующие чекбоксы и кнопка Delete Selected.

Не много о настройках.

Окно настроек дополнения разбито на три вкладки: General, Security и Database.

Вкладка General.

Окно настроек дополнения Firefox Lazarus. Вкладка General

Радиочекбоксы Show text in menu, Show saved time in menu - выбор, что показывать в меню Lazarus, начальный фрагмент текста или время сохранения.

Чекбокс Show icon in context menu - смысл прост, показывать/не показывать иконку Lazarus в контекстном меню.

Чекбокс Show icon in status bar - аналогичен предыдущему, показывать/не показывать иконку Lazarus в строке состояния.

Чекбокс Show Restore Notification - если он включен то после восстановления формы, ранее содержавшей обширный ввод, пользователь увидит вот такое сообщение с просьбой пожертвовать небольшие деньги на нужды развития проекта .

Пример сообщения дополнения Firefox Lazarus с просьбой пожертвовать деньги на развитие проекта

Вкладка Security.

Окно настроек дополнения Firefox Lazarus. Вкладка Security

Чекбокс Save passwords - если включить, Lazarus будет сохранять содержимое форм ввода паролей. Авторы дополнения рекомендуют этого не делать!

Чекбокс Remove saved forms after - установить время по прошествии которого сохраненный ввод будет автоматически удален из базы данных.

Чекбокс Require a password to restore forms - если установить, будет запрошен пароль, который, в дальнейшем, потребуется вводить при попытке восстановить содержимое любой формы.

Окно ввода пароля расширения Firefox Lazarus

Меню дополнения Firefox Lazarus при включенном пароле на восстановление содержимого форм

Чекбокс Disable Search Indexing - во включенном состоянии запрещает ведение поискового индекса. Авторы расширения заявляют, если злопыхатель получит доступ к папке профиля ни чего не подозревающего человека, то, используя зашифрованный файл поискового индекса и пользуясь каким то, не совсем мне понятным, хакерским методом атаки с помощью словаря, сможет восстановить отдельные слова ранее введенные пользователем в форму. Вот так. Пишите со всяким грамматическими ошибками и тогда ни какие словари хакерам не помогут.

Чекбокс Enable Lazarus in Private Browsing Mode - разрешить Lazarus в режиме приватного просмотра. Авторы дополнения, в случае активации этого чекбокса, советуют не забыть установить пароль на восстановление содержимого форм.

Вкладка Database.

Окно настроек дополнения Firefox Lazarus. Вкладка Database

Кнопка Search Lazarus - если нажать появится уже знакомое окно поиска по базе данных Lazaru.

Кнопка Remove all saved forms - удалить все сохраненные формы и их содержимое.

Кнопка Delete The Database - удалить файл базы данных, браузер при этом перезагрузится.

Ну вот собственно и все.

P.S.

Название дополнения Lazarus - это имя библейского персонажа Лазаря, простого парня воскрешонного Исусом Христом, а иконка дополнения это Анх (Анкх) - египетский крест, в частности символизирующий бессмертие, предстоящую вечную жизнь.


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

21.08.2009

Пакет matplotlib. График с дополнительной осью ординат

Часто для различных научно-технических надобностей требуется график с двумя осями ординат (осями Y) и одной общей осью абсцисс (осью X). Вот python скрипт, который строит такой график.

 1 # -*- coding: UTF-8 -*-
 2 
 3 import matplotlib as mpl
 4 import matplotlib.pyplot as plt
 5 
 6 # Значения по оси X (Большая часть данных опущена)
 7 
 8 # Время, ч
 9 
10 X = [0.00, 0.08, 0.17, ... 3.42, 3.50]
11 
12 # Значения по осям Y (Большая часть данных опущена)
13 
14 # Степнь разложения
15 
16 Y_01 = [0.0000, 0.0000, 0.0000, ... 0.8180, 0.8482]
17 
18 # Температура, oC
19 
20 Y_02 = [ 21, 30, 70, ... 721, 724 ]
21 
22 # Задем размеры изображения диаграммы
23 
24 mpl.rcParams['figure.figsize'] = (8.0, 6.0)
25 
26 # Строим диаграмму
27 
28 # Получаем ссылку на объект типа matplotlib.axes.AxesSubplot, текущую диаграмму 
29 
30 ax_01 = plt.axes()
31 
32 # Задаем исходные данные для первой линии диаграммы (линии степени разложения), внешний вид линии и маркера.
33 # Функция plot() возвращает ссылку на объект класса matplotlib.lines.Line2D
34 
35 line_01, = ax_01.plot(X, Y_01, 'bh:')
36 
37 # Задаем интервалы значений по осям X и основной оси Y
38 
39 ax_01.axis([-0.04, 3.6, -0.01, 0.90])
40 
41 # Включаем сетку по оси X и основной оси Y. Задаем цвет сетки
42 
43 ax_01.grid(color = 'b')
44 
45 # Задаем подписи к осям X и основной оси Y
46 
47 ax_01.set_xlabel(u'Время, ч')
48 ax_01.set_ylabel(u'Степень разложения')
49 
50 # Задаем заголовок диаграммы
51 
52 ax_01.set_title(u'Термограмма разложения оксалата кальция')
53 
54 # Включаем дополнительную ось Y
55 
56 ax_02 = ax_01.twinx()
57 
58 # Задаем исходные данные для второй линии диаграммы (линии степени разложения), внешний вид линии и маркера.
59 # Функция plot() возвращает ссылку на объект класса matplotlib.lines.Line2D
60 
61 line_02 = ax_02.plot(X, Y_02, 'ro:')
62 
63 # Задаем интервалы значений по осям X и дополнительной оси Y
64 
65 ax_02.axis([-0.04, 3.6, 0.0, 800.0])
66 
67 # Задаем подпись к дополнительной оси Y
68 
69 ax_02.set_ylabel(u'Температура, \u00b0C')
70 
71 # Включаем сетку по дополнительной оси Y. Задаем цвет сетки
72 
73 ax_02.grid(color = 'r')
74 
75 # Задаем исходные данные для легенды и место ее размещение
76 
77 ax_02.legend((line_01, line_02), (u'Степень разложения', u'Температура'), loc = 'best')
78 
79 # Сохраняем построенную диаграмму в файл
80 # Задаем имя файла и его тип
81 
82 plt.savefig('termo.png', format = 'png')

В результате выполнения скрипта, в файле termo.png будет сохранено такое изображение:

Matplotlib. Пример графика с двумя осями ординат

Пояснения к скрипту.

В начале небольшое отступление. Matplotlib при работе со своими графическими объектами придерживается следующей идеологии: существуют текущая фигура (в документации figure) и текущая гм... диаграмма (в документации axes). Фигура это некое полотно на котором происходит построение чего либо. Диаграмма это объект принадлежащий фигуре (одной фигуре может принадлежать несколько диаграмм), к которому собственно и применяются команды pyplot. Диаграммы могут быть различных типов (в нашем случае прямоугольная 2D - обычный график). Тип диаграммы задается командой её построения (в нашем случае plot()) и определяет назначение диаграммы, внешний вид, свойства и возможные действия с ней.

В выражении ax_01 = plt.axes() мы получаем ссылку на объект типа matplotlib.axes.AxesSubplot - текущую диаграмму. Далее, при построении графика, мы пользуемся методами этого объекта, действие которых в целом аналогично действию рассмотренным в предыдущих постах функций модуля pyplot.

После построения первой линии диаграммы (зависимости степени разложения от времени) создаем новый объект класса matplotlib.axes.Axes и получаем ссылку на него: ax_02 = ax_01.twinx(). В результате на диаграмму ax_01 будет "наложена" вторая диаграмма ax_02, при этом, ось X будет общей для обеих диаграмм. Далее с помощью тех же методов, только уже принадлежащими объекту ax_02 строим и оформляем вторую линию (зависимость температуры от времени).

Вот и все, сохраняем получившееся творение.

Подробнее о фигурах и диаграммах поговорим позже.

Предыдущий пост по теме: Пакет matplotlib. Строим банальный график.

Следующий пост по теме: Пакет matplotlib. Наводим красивости.


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