Содержание

Пример Python Pipe

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

Содержание

  1. Что такое pipe в Python?
  2. Почему я должен использовать pipe в Python?
  3. Пример использования pipe в Python
  4. Заключение

Что такое pipe в Python?

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

Почему я должен использовать pipe в Python?

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

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

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

Примечание. Spyder IDE можно использовать для реализации программы на Python с помощью Windows 10 или любого дистрибутива Linux; однако функция «os.fork ()», которая используется в следующем примере, поддерживается только Linux. Следовательно, вы не сможете реализовать следующий код в Windows 10.

Пример использования pipe в Python

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

В этом коде Python для реализации конвейера мы сначала импортировали модуль «os» Python, который облегчит эту реализацию. Затем мы создали канал с функцией «os.pipe ()» и назначили его двум файловым дескрипторам «r» и «w» для чтения и записи данных соответственно. После этого мы хотели создать дочерний процесс с идентификатором процесса, то есть pid, что можно сделать с помощью функции «os.fork ()». Затем у нас есть оператор «if», который работает с PID больше, чем «0», то есть, если PID является идентификатором родительского процесса, только тогда будет выполнен этот блок «if». В этом блоке «если» родительский процесс сначала блокирует «прочитанный» файловый дескриптор, т. Е. R, так что родительский процесс может легко писать в конвейер без каких-либо прерываний. Это делается с помощью функции «os.close ®».

После этого мы хотели уведомить пользователя через консоль о том, что родительский процесс теперь пишет в канал, для которого мы отобразили сообщение, с помощью команды «print». Затем у нас есть «текстовая» переменная, которой мы присвоили текст, который родительский процесс хочет записать в конвейер.

После этого мы вызвали функцию «os.write ()». Эта функция принимает два аргумента, то есть дескриптор файла записи и текст, который должен быть записан в конвейер. Когда эта функция вызывается, текст автоматически записывается в канал. После этого мы хотели отобразить текст, записанный в конвейер, на нашей консоли, что мы и сделаем с помощью функции «print», декодируя текстовую переменную.

Затем есть инструкция «else», которая будет работать, если PID не больше «0», т. Е. PID — это идентификатор дочернего процесса; только тогда будет выполнен этот блок «else». В этом блоке «else» дочерний процесс сначала блокирует дескриптор файла «запись», то есть w, чтобы легко прочитать текст, записанный в конвейер, без каких-либо изменений. Это делается с помощью функции «os.close (w)».

После этого мы хотели уведомить пользователя через консоль о том, что дочерний процесс теперь читает из канала, для которого мы отобразили сообщение, с помощью команды «print». Затем мы присвоили значение дескриптора открытого файла чтения «r» нашему первоначально объявленному дескриптору файла чтения. Наконец, мы хотели отобразить текст, прочитанный из канала нашим дочерним процессом, на нашей консоли с помощью функции «print». После написания этого кода Python в IDE Spyder мы просто сохранили его, а затем выполнили.

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

В этих выходных данных вы можете видеть, что первое сообщение, появившееся на консоли, было «Родительский процесс пишет:», что означает, что в настоящее время дескриптор файла чтения заблокирован, поскольку родительский процесс записывает в канал. Второе сообщение, появившееся на консоли, было «Письменный текст: добро пожаловать, дитя мое!» который представляет текст, записанный в конвейер родительским процессом. Затем третье сообщение, которое было отображено в выходных данных, было «Дочерний процесс читает:», что означает, что дескриптор файла записи заблокирован в настоящее время, поскольку дочерний процесс читает из канала. Наконец, четвертое сообщение, которое было отображено на консоли, было «Прочтите текст: добро пожаловать, мой ребенок!» который просто представляет текст, который был прочитан из канала дочерним процессом.

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

Заключение

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

Класс Pipe() модуля multiprocessing в Python.

Обмен данными между процессами при помощи канала Pipe.

Синтаксис:
import multiprocessing
pipe = multiprocessing.Pipe([duplex])
Параметры:
  • duplex
Возвращаемое значение:
  • кортеж (conn1, conn2), состоящий из объектов Connection.
Описание:

Класс Pipe() модуля multiprocessing возвращает парный кортеж (conn1, conn2), состоящий из объектов Connection, представляющих концы одного канала.

  • Если аргумент дуплекса duplex=True (по умолчанию), то тогда канал является двунаправленным.
  • Если аргумент дуплекса duplex=False, то тогда канал является однонаправленным:
    • conn1 может использоваться только для приема сообщений,
    • conn2 может использоваться только для отправки сообщений.

Объекты Connection позволяют отправлять и получать упакованные picklable объекты или текстовые или байтовые строки. Их можно рассматривать как подключенные сокеты, ориентированные на сообщения.

Методы объекта

Connection.
  • Connection.send() отправляет объект на другой конец соединения,
  • Connection.recv() возвращает объект, отправленный с другого конца соединения,
  • Connection. fileno() возвращает файловый дескриптор соединения,
  • Connection.close() закрывает соединение,
  • Connection.poll() возвращает, если есть какие-либо данные,
  • Connection.send_bytes() отправляет байтовые данные из байтового объекта,
  • Connection.recv_bytes() возвращает полное сообщение байтовых данных,
  • Connection.recv_bytes_into() читает в буфер полное сообщение байтовых данных.
  • Примеры создания канала и использования методов объекта Connection

Connection.send(obj):

Метод Connection.send() отправляет объект obj на другой конец соединения, который должен быть прочитан с помощью метода Connection.recv().

Объект должен быть упакован picklable. Очень большие объекты picklable (примерно 32 МБ+, хотя это зависит от операционной системы) могут вызвать исключение ValueError.

Connection.recv():

Метод Connection.recv() возвращает объект, отправленный с другого конца соединения с помощью функции Connection.send().

Блокируется до тех пор, пока есть что получить. Поднимает исключение EOFError, если больше нечего принимать, а другой конец был закрыт.

Connection.fileno():

Метод Connection.fileno() возвращает файловый дескриптор или дескриптор, используемый соединением.

Connection.close():

Метод Connection.close() закрывает соединение.

Метод вызывается автоматически при сборке мусора.

Connection.poll([timeout]):

Метод Connection.poll() возвращает, если есть какие-либо данные, доступные для чтения.

  • Если аргумент тайм-аута timeout не указан, то метод возвращает результат немедленно.
  • Если аргумент timeout — это число, то он указывает максимальное время блокировки в секундах.
  • Если timeout=None, то используется бесконечный тайм-аут. Другими словами, метод ждет до упора, пока не поступят данные.

Обратите внимание, что несколько объектов подключения могут быть опрошены одновременно с помощью multiprocessing.connection.wait().

Connection.send_bytes(buffer[, offset[, size]]):

Метод Connection.send_bytes() отправляет байтовые данные из байтового объекта в виде полного сообщения.

Если задано смещение offset, то данные считываются из этой позиции в буфере buffer.Если указан размер size, то переданное количество байт будет прочитано из буфера.

Очень большие буферы buffer (примерно 32 МБ +, хотя это зависит от ОС) могут вызвать исключение ValueError.

Connection.recv_bytes([maxlength]):

Метод Connection.recv_bytes() возвращает полное сообщение байтовых данных, отправленных с другого конца соединения в виде строки.

Блокируется до тех пор, пока есть что получить. Поднимает исключение EOFError, если больше нечего получить, а другой конец был закрыт.

Если задан аргумент maxlength и сообщение длиннее maxlength, то возникает ошибка OSError, а соединение больше не будет читаться.

Connection.recv_bytes_into(buffer[, offset]):

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

Блокируется до тех пор, пока есть что получить. Поднимает исключение EOFError, если больше нечего получить, а другой конец был закрыт.

Аргумент buffer должен быть записываемым байтовым объектом (array.array, bytearray или memoryview).

Если задано смещение offset, то сообщение будет записано в буфер с этой позиции. Смещение должно быть неотрицательным целым числом меньше длины буфера (в байтах).

Если буфер слишком короткий, то возникает исключение BufferTooShort, а полное сообщение будет доступно как e.args[0], где e это экземпляр исключения.


Примеры создания канала и использования методов объекта Connection.
>>> from multiprocessing import Pipe
>>> a, b = Pipe()
>>> a.send([1, 'hello', None])
>>> b.recv()
# [1, 'hello', None]
>>> b.send_bytes(b'thank you')
>>> a.recv_bytes()
# b'thank you'
>>> import array
>>> arr1 = array.array('i', range(5))
>>> arr2 = array.array('i', [0] * 10)
>>> a.send_bytes(arr1)
>>> count = b.recv_bytes_into(arr2)
>>> assert count == len(arr1) * arr1.itemsize
>>> arr2
# array('i', [0, 1, 2, 3, 4, 0, 0, 0, 0, 0])

Функциональное программирование на Python. Часть 2.

Абстракция и композиция. Функции

Если попытаться выделить наиболее фундаментальные концепции, которые используются в программировании, то это будут абстракция и композиция (Category: The Essence of Composition). Рассмотрим их через призму понятия функции с примерами на Python.

  • Число
  • Функция
    • Композиция функций
  • Рекурсия
  • Функции высшего порядка. Функции как аргументы
  • Функция как возвращаемое значение. Каррирование, замыкание, частичное применение 
  • Функции – объекты первого класса

Для начал обратимся к википедии за определениями указанных выше терминов: 

Абстракция (лат. abstractio — отвлечение) — теоретическое обобщение как результат абстрагирования. Абстрагирование отвлечение в процессе познания от несущественных сторон, свойств, связей объекта (предмета или явления) с целью выделения их существенных, закономерных признаков. Результат абстрагирования — абстрактные понятия, например: цвет, кривизна, красота и т.

д. 

Композиция (лат. compositio — составление, связывание, сложение, соединение) — составление целого из частей. 

Число

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

Начнем с базовой вещи – с понятия числа. То, как мы работаем с числами, это достаточно новое изобретение человечества. Для нас, когда мы говорим: пять яблок или пять стульев — это одни и те же пятерки. Число пять, в данном случае, это некоторая абстракция, которая позволяет не думать о содержании (стулья, яблоки и т.п.), а сосредоточиться на их количестве. Но понадобились тысячи лет эволюции, чтобы это произошло, чтобы мы (люди) могли отвлеченно использовать числа. Об этом интересно пишет Алексей Савватеев в книге “Математика для гуманитариев”, и приводит там такой пример: “… в русском языке до сих пор говорят “сорок” вместо “четырьдесят”, хотя раньше можно было сказать “сорок собольих шкурок”, но не “сорок деревьев”. То есть сорок означало не количество каких-либо предметов вообще, а только вполне определенных. Сейчас мы довольно свободно оперируем числами для счета предметов (и не только), а сами вычисления выполняем уже в отрыве от связи числа с сущностью. 

Функция

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

1+2=3 

4+7=11 

121+144=265 

… 

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

 

a + b = c 

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

>>> def add(a, b): 
        return a + b 
>>> add(1, 3) 
4 
>>> add(4, 7) 
11

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

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

  

Введем понятие lambda-функции (в программировании): lambda-функция – это безымянная функция с произвольным числом аргументов, вычисляющая одно выражение. В Python она определяется так: вначале записывается ключевое слово lambda, потом перечисляются через запятую аргументы, с которыми будет проводиться работа, далее ставится двоеточие, а после него тело функции. Более подробно про нее можете прочитать в статье Python. Урок 10. Функции в

Python

Перейдем к решению задачи. Точку с координатами будем задавать как кортеж (см Python. Урок 8. Кортежи (tuple)). Напишем функцию, которая возводит в квадрат разность двух чисел: 

>>> sq_sub = lambda x1, x2: (x2 - x1)**2

Реализуем непосредственно саму функцию dist

>>> dist = lambda p1, p2: (sq_sub(p1[0], p2[0])+sq_sub(p1[1], p2[1]))**0.5

Проверим ее работу: 

>>> point1 = (1, 1) 
>>> point2 = (4, 5) 
>>> dist(point1, point2) 
5.
0

Композиция функций

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

Математически она записывается вот так:

h = g ∘ f

Результат последовательного применения ряда функций можно заменить на применение только одной функции.

Решим нашу задачу, задав все вычисления явно – через функции, для этого нам понадобятся: 

>>> sub = lambda a, b: a - b # функция вычитания 
>>> sq = lambda x: x**2      # функция возведения в квадрат 
>>> sm = lambda a, b: a + b  # функция сложения 
>>> sqrt = lambda x: x**0.5  # функция извлечения квадратного корня

Благодаря тому, что Python умеет распаковывать кортежи, мы может этим воспользоваться и реализовать dist следующим образом: 

>>> dist = lambda x1, y1, x2, y2: sqrt(sm(sq(sub(x1, x2)), sq(sub(y1, y2)))) 
>>> dist(*point1, *point2) 
5. 0

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

dist более предпочтителен, второй был приведен для иллюстрации принципа. 

Рекурсия

Используя приведенный выше подход создания функций и объединения их в композиции, можно решить довольно большое количество задач (и не только вычислительных): посчитать логарифм, вычислить синус или косинус заданного угла, определить квадрат числа и т.д. Все эти задачи объединяет то, что нам достаточно подставить какое-то число (или набор чисел), в качестве аргумента, в функцию, и мы получаем решение. Но бывают задачи, где этого недостаточно, например, определение факториала числа или элемента ряда Фибоначчи. Ключевое отличие этих задач заключается в том, что там присутствует некоторый вычислительный процесс, протекание которого определяется переданным аргументом. Другими словами, для того чтобы вычислить расстояния между точками по уже известной формуле, мы всегда будем делать одно и тоже количество операций: два вычитания, два возведения в степень, одно сложение и один раз извлечем корень. Количество умножений, которое придется выполнить, для того чтобы посчитать факториал, определяется числом, факториал которого мы хотим найти: для факториала пяти – пять умножений, для факториала десяти – десять.

Для построения такого типа (и не только) вычислительных процессов используется рекурсия. Суть рекурсии заключается в том, что функция вызывается из нее же самой. О рекурсии уже было достаточно много сказано на devpractice (https://devpractice.ru/fp-python-part1-general/#p32, https://devpractice.ru/about-rec-and-iter/), поэтому мы не будем на ней подробно останавливаться. 

Функции высшего порядка. Функции как аргументы

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

2+3=5, 7+8=15 и т.п. к самой операции сложения: мы абстрагировались от чисел, с которыми работали и сосредоточились на выполняемой операции. Так и здесь, мы можем абстрагироваться от частности: возведения всех элементов в квадрат или взятие абсолютного значения, и сосредоточиться на сути процесса: применение заданной функции к каждому элементу набора данных для построения нового набора. 

Так, мы приходим к идее, что нам нужны функции, которые могут использовать другие функции, переданные им в качестве аргументов.

Такие конструкции носят название: функции высшего порядка (higher-order function). Так как функции, которые передаются в качестве аргументов, как правило, небольшие по размеру, то для удобства, их конструируют в виде lambd’ы прямо в месте вызова. Приведем несколько полезных свойств lambda-функций: 

Их можно вызвать в месте объявления: 

>>> (lambda x: x*2)(3)

Lambd’у можно сохранить в переменную и использовать ее в дальнейшем: 

>>> mul2 = lambda x: x*2 
>>> mul2(3) 
6

Функция, реализующая процесс модификации заданного набора данных, называется map. В качестве первого аргумента (если говорить про Python), ей передается функция, вторым – набор данных. Продемонстрируем работу с ней на примере: возведем все элементы заданного списка в квадрат: 

>>> list(map(lambda x: x**2, [1, 2, 3, 4, 5])) 
[1, 4, 9, 16, 25]

Функция list нужна для построения списка из результата работы map.

 

Функции высшего порядка — это мощный инструмент, если научиться им пользоваться. Представим, что мы храним конфигурации различных программных модулей в словарях, получив такую структуру, перед тем как начать с ней работать, необходимо убедиться, что она является корректной. Наша задача заключается в том, чтобы написать универсальный интерфейс, через который можно проверять корректность любой конфигурации. Одни из вариантов решения может выглядеть так: модуль проверки конфигурации принимает структуру данных и тип конфигурации, в теле этого модуля, в зависимости от типа, производится необходимая проверка. Это решение имеет ряд недостатков: во-первых, необходимо где-то держать единый реестр конфигураций, во-вторых, когда будет появляться новая конфигурация, нужно будет добавлять код валидации в нашу функцию, в-третьих: такое решение фактически не позволяет, кому угодно создавать свои конфигурации для собственных нужд, если они не могут добавить код в нашу функцию валидации. То есть мы получаем решение, которое тяжело масштабировать. Более простое решение выглядит так: наша функция принимает валидатор и конфигурацию, проверяет с его помощью корректность и выдает результат. Единственное ограничение — это требование на возвращаемое значение валидатором, оно должно быть у всех одинаковое. Вот код такой функции: 

>>> def is_config_valid(validator, data_struct): 
        return validator(data_struct)

Создадим новую конфигурацию: 

>>> tmp_conf = {"test1": 123}

Для нее подготовим валидатор: 

>>> is_tmp_valid = lambda x: True if "test1" in x else False

Проверим корректность конфигурации: 

>>> is_config_valid(is_tmp_valid, tmp_conf) 
True

В случае, если конфигурация имеет ошибки: 

>>> tmp2_conf = {"test2": 456}

Валидатор нам об этом сообщит: 

>>> is_config_valid(is_tmp_valid, tmp2_conf) 
False

Функция как возвращаемое значение. Каррирование, замыкание, частичное применение

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

Замыкание— функция, в теле которой присутствуют ссылки на переменные, объявленные вне тела этой функции в окружающем коде и не являющиеся её параметрами. Поясним эту идею на примере: построим конструктор линейных функции вида y = k*x + b с заранее заданными коэффициентами: 

>>> def linear_builder(k, b): 
        def helper(x): 
            return k * x + b 
    return helper

Создадим линейную функцию со следующими параметрами 3 * x + 9 

>>> linf = linear_builder(3, 9) 
>>> linf(5) 
24

Если вас заинтересовала тема замыкания, рекомендуем вам обратиться к статье Замыкания в Python.  

 Каррирование — преобразование функции от многих аргументов в набор функций, каждая из которых является функцией от одного аргумента. Суть в том, чтобы перейти от вида f(x, y, z) к виду f(x)(y)(z). Каррирование позволяет строить частично примененные функции. 

Создадим функцию, которая складывает три числа: 

>>> def faddr(x, y, z): 
        return x + y + z 
>>> faddr(1, 2, 3) 
6

Каррированный вариант этой функции будет выглядеть так: 

>>> def curr_faddr(x): 
    def tmp_a(y): 
        def tmp_b(z): 
            return x+y+z 
        return tmp_b 
    return tmp_a 
>>> curr_faddr(1)(2)(3) 
6

На базе нее можно строить частично примененные функции: 

>>> p_c_faddr = curr_faddr(1)(2) 
>>> p_c_faddr(3) 
6

В этом примере p_c_faddr делает следующее 1+2+x, неизвестное значение x принимает в качестве аргумента.  

Функции – объекты первого класса 

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

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

Сущность, удовлетворяющая перечисленным выше требованиям, называется объектом первого класса (или объектом первого порядка). Как было отмечено в первой части, наличие таких свойств, является отличительной чертой функциональных языков программирования. В Python функции являются объектами первого класса, что позволяет придерживаться функционального стиля, когда это необходимо, но при этом создатель языка Гвидо ван Россум отмечает: “… хотя сделал функции полноправными объектами, никогда не рассматривал Python как язык функционального программирования”.  

P.S.

Вводные уроки по “Линейной алгебре на Python” вы можете найти соответствующей странице нашего сайта. Все уроки по этой теме собраны в книге “Линейная алгебра на Python”.

Если вам интересна тема анализа данных, то мы рекомендуем ознакомиться с библиотекой Pandas.  Для начала вы можете познакомиться с вводными уроками. Все уроки по библиотеке Pandas собраны в книге “Pandas. Работа с данными”.

Пишите чистый код Python с использованием конвейеров | by Khuyen Tran

Короткий и чистый подход к обработке итерируемых объектов

map и filter — два эффективных метода Python для работы с итерируемыми объектами. Однако код может выглядеть беспорядочно, если вы одновременно используете карту и фильтр .

Изображение автора

Было бы неплохо, если бы вы могли использовать трубы | для применения нескольких методов к итерации, как показано ниже?

Изображение автора

Библиотека Pipe позволяет сделать именно это.

Pipe — это библиотека Python, которая позволяет использовать каналы в Python. Канал ( | ) передает результаты одного метода другому методу.

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

Для установки трубы введите:

 pip install pipe 

Подобно SQL, метод Pipe , где , также может использоваться для фильтрации элементов в итерируемом объекте.

Image by Author

Метод select аналогичен методу map . select применяет метод к каждому элементу итерации.

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

Изображение автора

Теперь вы можете задаться вопросом: зачем нам нужны методы , где и выберите , если они имеют те же функции, что и map и filter ?

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

Image by Author

chain — Цепочка последовательностей итерируемых объектов

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

Изображение автора

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

traverse — рекурсивное развертывание итерируемых объектов

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

Image by Author

Давайте интегрируем этот метод с методом select , чтобы получить значения словаря и сгладить список.

Изображение автора

Круто!

Иногда бывает полезно сгруппировать элементы в списке с помощью определенной функции. Это можно легко сделать с помощью метода groupby .

Чтобы увидеть, как работает этот метод, давайте превратим список чисел в словарь, который группирует числа в зависимости от того, четные они или нечетные.

Image by Author

В приведенном выше коде мы используем groupby для группировки чисел в группу Even и группу Odd . Результат после применения этого метода выглядит следующим образом:

 [('Even', ), 
('Odd', )]

Затем мы используем select , чтобы превратить список кортежей в список словарей, ключи которых являются первыми элементами кортежей, а значения — вторыми элементами кортежей.

 [{'Чет': [2, 4, 6, 8]}, {'Нечет': [1, 3, 5, 7, 9]}] 

Круто! Чтобы получить только значения больше 2, мы можем добавить метод , где внутри select method:

Image by Author

Обратите внимание, что в выходных данных больше нет 2 и 1 .

Метод дедупликации удаляет дубликаты в списке.

Image by Author

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

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

Изображение автора

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

Image by Author

В приведенном выше коде мы:

  • удаляем элементы с одинаковыми именами
  • получаем значения count
  • выбираем только целые числа.

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

Поздравляем! Вы только что узнали, как использовать конвейер, чтобы ваш код был чистым и коротким. Я надеюсь, что эта статья даст вам знания, как превратить сложные операции с итерируемым объектом в одну простую строку кода.

Не стесняйтесь играть и разветвлять исходный код этой статьи здесь:

Data-science/pipe.ipynb на master · khuyentran1401/Data-science

Коллекция полезных тем по науке о данных вместе с кодом и статьями — Data- science/pipe.ipynb на мастере ·…

github.com

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

Пометьте этот репозиторий звездочкой, если хотите проверить коды всех статей, которые я написал. Следуйте за мной на Medium, чтобы быть в курсе моих последних статей по науке о данных, таких как:

Чистый код Python: 6 лучших практик, чтобы сделать ваши функции Python более удобочитаемыми0161

в направлении datascience. com

4 плагина pre-commit для автоматизации просмотра и форматирования кода в Python Сборник отсутствующих утилит Python

Функциональное выполнение Python

в направлении datascience.com

3 хитрости Python для автоматического чтения, создания и запуска нескольких файлов

Автоматизируйте скучные задачи с помощью Python и Bash For Loop

в направлении datascience.com

Используйте конвейерные операции в Python для более удобного и быстрого кодирования

Python уже стал элегантным языком для программирования. Но это не значит, что нет места для улучшения.

Pipe — это красивый пакет, который выводит возможности Python по обработке данных на новый уровень. Для управления элементами в коллекции используется декларативный подход, подобный SQL. Он может фильтровать, преобразовывать, сортировать, удалять дубликаты, выполнять группировку по операциям и многое другое без необходимости писать миллионы строк кода.

В этом небольшом посте давайте обсудим упрощение нашего кода Python с помощью Pipe. Самое главное, мы создадим пользовательские многоразовые операции с каналами для повторного использования в нашем проекте.

Начнем с

  • вдохновляющего примера;
  • некоторые полезные готовые операции с трубами и;
  • строить наши собственные операции по производству труб.

Если вам интересно, как вы его настроили, вы можете легко установить Pipe с PyPI. Вот что вам нужно сделать.

 pip install pipe 

Начните использовать каналы в Python.

Вот пример использования Pipe. Предположим, у нас есть список чисел, и мы хотим

  • удалить все дубликаты;
  • фильтр только для нечетных чисел;
  • квадрат каждого элемента в списке, и;
  • отсортировать значения по возрастанию;

вот что мы обычно делаем в простом Python.

 num_list_with_duplicates = [1, 4, 2, 27,
                            6, 8, 10, 7, 13, 19, 21, 20, 7, 18, 27]
# Удалить дубликаты из списка
num_list = список (dict.fromkeys (num_list_with_duplicates))
# Фильтр по нечетным числам
od_list = [число для числа в num_list, если число% 2 == 1]
# Возвести числа в квадрат
нечетный_квадрат = список (карта (лямбда x: x ** 2, нечетный_список))
# Сортировать значения в порядке возрастания
нечетный_квадрат.sort ()
печать (нечетный_квадрат)
>> [1, 49, 169, 361, 441, 729] 

Приведенный выше код довольно читабелен. Но вот лучший способ использования Pipe.

 из дедупликации импорта трубы, где выбрать, отсортировать
num_list_with_duplicates = [1, 4, 2, 27,
                            6, 8, 10, 7, 13, 19, 21, 20, 7, 18, 27]
# выполняем операции с трубами
результаты = список (num_list_with_duplicates
                | дедупликация
                | где (лямбда х: х% 2 == 1)
                | выберите (лямбда х: х ** 2)
                | Сортировать
            )
печать (результаты)
>> [1, 49, 169, 361, 441, 729] 

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

Так Pipe помогает нам упростить наши коды. Мы можем связать операции над коллекцией без написания отдельных строк кода.

Связанный: Форматирование кода Python упрощается с помощью Git Pre-commit Hooks

Но в Pipe доступны более интересные операции, подобные тем, которые мы использовали в приведенном выше примере. Кроме того, мы можем создать его, если нам нужно что-то очень уникальное. Давайте сначала рассмотрим некоторые предварительно созданные операции.

Самые полезные операции с трубами

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

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

Group By

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

 дедупликация импорта из канала, группировка, где, выбрать, отсортировать
число_список = [1, 4, 2, 27,
            6, 8, 10, 7, 13, 19, 21, 20, 7, 18, 27]
результаты = список (num_list
               | groupby(лямбда x: «Нечетный», если x % 2 == 1, иначе «Четный»)
               )
print(results) 

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

 [
    ("Четный", <объект itertools._grouper по адресу 0x7fdc05ed0310>),
    ("Нечетный", объект ),
] 

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

 дедупликация импорта из канала, группировка, где, выбрать, отсортировать
число_список = [1, 4, 2, 27,
            6, 8, 10, 7, 13, 19, 21, 20, 7, 18, 27]
результаты = список (num_list
               | groupby(лямбда x: «Нечетный», если x % 2 == 1, иначе «Четный»)
               | выберите (лямбда x: {x[0]: [y**2 для y в x[1]]})
               )
печать (результаты) 
 [
    {'Четные': [16, 4, 36, 64, 100, 400, 324]},
    {'Нечетный': [1, 729, 49, 169, 361, 441, 49, 729]},
] 

Цепь и перемещение

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

Вот как работает цепочка.

 из цепи импорта труб
вложенный_список = [[1, 2, 3], [4, 5, 6], [7, [8, 9]]]
развернутый_список = список (вложенный_список
                     | цепь
                     )
печать (развернутый_список)
>> [1, 2, 3, 4, 5, 6, 7, [8, 9]] 

Как мы видим, chain развернула самый внешний уровень списка. 8 и 9 остаются внутри вложенного списка, поскольку они уже были вложены на один уровень ниже.

Вот результаты использования хода вместо этого.

 от траверсы импорта трубы
вложенный_список = [[1, 2, 3], [4, 5, 6], [7, [8, 9]]]
развернутый_список = список (вложенный_список
                 | траверс
                 )
печать (развернутый_список)
>> [1, 2, 3, 4, 5, 6, 7, 8, 9] 

Траверс развернул все, что мог.

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

 вложенный_список = [[1, 2, 3], [4, 5, 6], [7, [8, 9]]]
unfolded_list = [число для элемента в вложенном_списке для числа в элементе]
print(unfolded_list) 

Take_while и Skip_while

Эти две операции работают так же, как операция «где», которую мы использовали ранее. Критическое отличие состоит в том, что take_while и skip_while перестают искать дополнительные элементы в коллекции, если выполняются определенные условия. Хотя, с другой стороны, оценивает каждый элемент в списке.

Вот как и take_while, и where работают для простой задачи фильтрации значений меньше 5.

 from pipe import as_list, take_while, где
результат = [3, 4, 5, 3] | take_while (лямбда x: x < 5) | as_list
print(f"take_while: {результат}")
результат2 = [3, 4, 5, 3] | где (лямбда х: х < 5) | as_list
print(f"where: {result2}") 

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

 take_while: [5, 3]
где: [3, 4, 3] 

Обратите внимание, что операция take_while пропустила последнюю цифру «3», в то время как операция «где» включает ее.

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

 из канала импорта as_list, skip_while
результат = [3, 4, 5, 3] | skip_while (лямбда x: x < 5) | as_list
печать (результат)
>> [5, 3] 

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

Создание новой операции с трубой

Создать новую операцию с трубой относительно просто. Все, что нам нужно, это аннотировать функцию с помощью класса Pipe.

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

 из импортной трубы Труба
@Трубка
def sqr (n: int = 1):
    вернуть п**2
результат = 10 | кв
print(result) 

Поскольку мы аннотировали функцию классом @Pipe , она становится операцией конвейера. В строке 9 мы использовали его для возведения в квадрат одного числа.

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

Дополнительные аргументы могут быть даже функцией.

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

 при вводе списка импорта
from pipe import Pipe, as_list, выберите
def fib(n: int = 1):
    """Рекурсивно создать число Фибоначчи"""
    вернуть n, если n < 2, иначе fib(n-1)+fib(n-2)
@Трубка
def apply_fun (числа: список [int], удовольствие):
    """Применить любую функцию к элементам списка и создать новый список"""
    вернуть числа | выбрать(весело) | as_list
результат = [5, 10, 15] | apply_fun (фиб)
печать(результат) 

Связанный: Как создать интерактивный интерфейс командной строки в Python?

Заключительные мысли

Впечатляет то, как Python может быть улучшен.

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

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

Спасибо за прочтение, друг. Кажется, у нас с тобой много общих интересов. Передайте привет мне на LinkedIn , Twitter и Medium . Я растоплю для тебя лед.
Еще не являетесь пользователем Medium? Пожалуйста, используйте эту ссылку, чтобы стать участником , потому что я получаю комиссию за рекомендацию без каких-либо дополнительных затрат для вас.

Коллапс волновой функции в Python

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

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

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

Вот простой пример структуры, созданной WFC, с одной плиткой и ограничением, что трубы должны соединяться с трубами:

Процесс WFC является итеративным: мы по очереди решаем, что разместить в каждом месте, основываясь на том, что находится вокруг него.

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

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

Подготовительные работы

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

Давайте начнем с импорта:

 случайный импорт
импорт io
импортировать base64
из коллекций импортировать namedtuple
импортировать numpy как np
из изображения импорта PIL
из отображения импорта IPython
 

Следующие три функции помогают отображать частичное и конечное состояния сгенерированного шаблона. Что именно они делают, скоро будет объяснено; на самом деле это просто стандартные манипуляции с PIL и numpy.

 определение blend_many(ims):
    """
    Смешивает последовательность изображений.
    """
    текущий, *имс = имс
    для i, im в перечислении (ims):
        текущий = Image. blend (текущий, im, 1/(i+2))
    обратный ток
 
 def blend_tiles (выборы, плитки):
    """
    Учитывая список состояний (True, если исключено, False, если нет) для каждой плитки,
    и список плиток, вернуть смесь всех плиток, которые не были
    исключено.
    """
    to_blend = [tiles[i].bitmap для i в диапазоне(len(choices)) if selections[i]]
    вернуть blend_many(to_blend)
 
 def show_state (потенциал, плитки):
    """
    Учитывая список состояний для каждой плитки для каждой позиции изображения, верните
    изображение, представляющее состояние глобального изображения.
    """
    строки = []
    для строки в потенциале:
        rows.append([np.asarray(blend_tiles(t,tiles)) для t в строке])
    строки = np.массив (строки)
    n_rows, n_cols, tile_height, tile_width, _ = rows.shape
    изображения = np.swapaxes (строки, 1, 2)
    вернуть Image.fromarray(images.reshape(n_rows*tile_height, n_cols*tile_width, 4))
 

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

 по определению find_true (массив):
    """
    Как np.nonzero, за исключением того, что это имеет смысл.
    """
    transform = int, если len(np.asarray(array).shape) == 1 else tuple
    список возврата (карта (преобразование, np.transpose (np.nonzero (массив))))
 

Я назвал его find_true , потому что мы собираемся использовать его только для поиска индексов ячеек, равных 9.0007 True в логических массивах.

Тайлы и потенциал

Первое, что нам нужно, это тайлы, из которых мы собираем наше изображение. Для этого урока я создал пять изображений размером 10x10 пикселей: прямая линия, изгиб, крест, тройник и пустой фон. Вы также можете использовать свои собственные! В противном случае давайте загрузим растровые изображения (они все очень маленькие, поэтому я просто загружаю их как строки в кодировке base64):

 Straight_image = Image. open(io.BytesIO(base64.b64decode('iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAMklEQVQYlWNQVrT9r6xo+988UfN/0yqN/4evOP0/fMXpf9Mqjf/miZr/YfIMowrpqxAAjKLGXfWE8ZAAAAAASUVORK5CYII=')))
Bend_image = Image.open(io.BytesIO(base64.b64decode('iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAANklEQVQYlWNQVrT9TwxmIFmheaImXoyisGmVBk6MofDwFSesmHKFRFvdtEoDv2fQFWINHNwKAQHceAACl)))
пустое_изображение = Image.open(io.BytesIO(base64.b64decode('iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAFEelEQVQYlWNQVrT9TwxmGFVIX4UAoDOWARI9hF0AAAAAASUVORK5CYII=')))
cross_image = Image.open(io.BytesIO(base64.b64decode('iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAU0lEQVQYlWNQVrT9r6xo+988UfN/0yqN/4evOP0/fMXpf9Mqjf/miZr/YfIMRCs0T9T8D8PYFMIwQ9Mqjf/IGFkhMmaASRDCxCsk2mqiPUP1cAQAKI/idfPNuccAAAAAASUVORK5CYII=')))
t_image = Image.open(io.BytesIO(base64.b64decode('iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAWUlEQVQYlWNQVrT9r6xo+988UfN/0yqN/4evOP0/fMXpf9Mqjf/miZr/YfIMRCs0T9T8D8PYFMIwQ9Mqjf/IGFkhMmaASRDCxCtEtwIXRvEMPgwPHkKYaIUAow/UaQFDAc4AAAAASUVORK5CYII=')))
 

Для справки, вот как выглядят изображения:

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

… не слишком убедительно, правда?

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

дает нам [Истина, Ложь, Ложь, Правда] . Просто начните справа (труба), затем вверх (без трубы), влево (без трубы) и вниз (труба). Кроме того, мы дадим каждой плитке имя (просто для легкой идентификации) и вес, из которого мы получим вероятность появления в выходном изображении.

В качестве примечания: вы можете заменить этот вариант True / False любым перечислением для описания более сложных ограничений. Этот код должен справиться с этим без изменений.

 Плитка = namedtuple('Плитка', ('имя', 'растровое изображение', 'стороны', 'вес'))
 

Мы превратим 5 плиток, которые у нас есть, в 12, сгенерировав все повороты вручную. Эталонная реализация WFC генерирует повороты автоматически; это не очень сложно сделать, но этот урок и так достаточно длинный.

 тайлов = [
    Плитка('прямой_уд', прямое_изображение,
         [Ложь, Верно, Ложь, Верно], 1/2),
    Плитка('straight_lr', Straight_image.transpose(Image.ROTATE_90),
         [Верно, Ложь, Верно, Ложь], 1/2),
    Плитка('bend_br', Bend_Image,
         [Верно, Ложь, Ложь, Верно], 1/4),
    Плитка('bend_tr', Bend_image.transpose(Image.ROTATE_90),
         [Верно, Верно, Ложь, Ложь], 1/4),
    Плитка('bend_tl', Bend_image.transpose(Image.ROTATE_180),
         [Ложно, Верно, Верно, Ложно], 1/4),
    Плитка('bend_bl', Bend_image.transpose(Image.ROTATE_270),
         [Ложь, Ложь, Правда, Правда], 1/4),
    Плитка('t_u', t_image,
         [Верно, Верно, Верно, Ложно], 1/4),
    Плитка('t_l', t_image. transpose(Image.ROTATE_90),
         [Ложь, Верно, Верно, Верно], 1/4),
    Плитка ('t_d', t_image.transpose (Image.ROTATE_180),
         [Верно, Ложь, Верно, Верно], 1/4),
    Плитка ('t_r', t_image.transpose (Image.ROTATE_270),
         [Верно, Верно, Ложно, Верно], 1/4),
    Плитка('пусто', пустое_изображение,
         [Ложь, Ложь, Ложь, Ложь], 1),
    Плитка('крест', cross_image,
         [Правда, Правда, Правда, Правда], 1)
]
 

Мы также создаем специальный массив с весами тайлов. Это облегчит быстрое определение веса данной плитки позже.

 весов = np.asarray([t.weight для t в тайлах])
 

После всей этой настройки мы готовы перейти к самому WFC. Для этого примера мы создадим изображение 30 на 30 элементов.

Первоначально мы создаем изображение в виде сетки, где каждый элемент представляет собой суперпозицию всех возможных тайлов. Таким образом, состояние представлено массивом из 30×30×12 (поскольку у нас 12 плиток) логических элементов. Я называю этот массив потенциальным . Например, значение , потенциал[12][2][5] истинно тогда и только тогда, когда элемент с координатами (12, 5) все еще может быть тайлом номер 5, в нашем случае 'bend_bl' .

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

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

 потенциал = np.full((30, 30, len(плитки)), True)
display.display (show_state (потенциал, плитки))
 

Алгоритм коллапса волновой функции

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

Вот как это выглядит:

  1. Если все места определены, мы закончили.
  2. Если в какой-либо локации не осталось выбора, мы потерпели неудачу. О том, как справиться с этим, я расскажу ниже.
  3. В противном случае найти неопределившееся место с наименьшим оставшимся выбором.
  4. ( Свернуть шаг ) Выберите наугад плитку среди тех, что еще можно найти для этой локации. Отметьте эту плитку как единственную оставшуюся возможность для этой локации.
  5. (шаг распространения ) Этот выбор, вероятно, исключит некоторые возможные плитки в соседних местах, которые, в свою очередь, могут исключить возможности в своих соседях. Нам нужно обновить наш потенциал, чтобы отразить это.
  6. ➰ Петля ➰.

Следующий метод реализует одну итерацию этого алгоритма. Я отметил шаги выше в коде, чтобы было легче следовать.

 по определению run_iteration (старый_потенциал):
    потенциал = старый_потенциал. копия()
    to_collapse = location_with_feest_choices(потенциальный) #3
    если to_collapse равно None: #1
        поднять StopIteration()
    elif не np.any(потенциал[to_collapse]): #2
        поднять исключение (f «Нет вариантов в {to_collapse}»)
    иначе: #4 ↓
        ненулевое значение = find_true (потенциал [to_collapse])
        tile_probs = веса [отличные от нуля]/сумма (веса [отличные от нуля])
        selected_tile = np.random.choice (ненулевой, p = tile_probs)
        потенциал[to_collapse] = Ложь
        потенциал[to_collapse][selected_tile] = Истина
        распространять (потенциал, to_collapse) # 5
    возвратный потенциал
 

Давайте теперь посмотрим на составляющие функции. Самый простой — location_with_fewest_choices , который делает то, что написано на жестяной банке, и возвращает неопределенный элемент с наименьшим оставшимся выбором или возвращает None , если все элементы определены. (Эталонная реализация WFC вычисляет правильную энтропию на основе весов плиток вместо подсчета возможностей. Я обнаружил, что это не имеет большого значения для алгоритма, основанного на плитках.)

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

 по определению location_with_fewest_choices (потенциал):
    num_choices = np.sum (потенциал, ось = 2, dtype = 'float32')
    num_choices[num_choices == 1] = np.inf
    кандидат_местоположения = найти_истина (количество_выборов == число_выборов.мин())
    location = random.choice(candidate_locations)
    если num_choices[местоположение] == np.inf:
        возврат Нет
    место возвращения
 

Распространение ограничений

Осталось реализовать только распространение , которое будет распространять вновь созданные константы. Нам понадобится несколько помощников, чтобы облегчить переваривание. Во-первых, Класс Direction , который знает, как обратить себя вспять. Обратите внимание, как значения перечисления соответствуют порядку, в котором мы определили ограничения ранее (так что tile. sides[Direction.LEFT.value] возвращает ограничение на левой стороне плитки).

 из enum import Enum, авто
Направление класса (перечисление):
    ВПРАВО = 0; ВВЕРХ = 1; ВЛЕВО = 2; ВНИЗ = 3
    
    деф реверс (сам):
        return {Направление.ВПРАВО: Направление.ВЛЕВО,
                Направление.ВЛЕВО: Направление.ВПРАВО,
                Направление.ВВЕРХ: Направление.ВНИЗ,
                Направление.ВНИЗ: Направление.ВВЕРХ}[я]
 

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

 соседей по определению (расположение, высота, ширина):
    разрешение = []
    х, у = местоположение
    если х != 0:
        res.append((Направление.ВВЕРХ, x-1, y))
    если у != 0:
        res.append((Направление.ВЛЕВО, x, y-1))
    если х < высота - 1:
        res.append((Направление. ВНИЗ, x+1, y))
    если у < ширина - 1:
        res.append((Направление.ВПРАВО, x, y+1))
    вернуть разрешение
 

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

Более формально мы:

  1. Пометить ячейку, которую мы только что свернули, как требующую обновления.
  2. Для каждой ячейки, которая нуждается в обновлении U ,
    1. Для каждого из соседей этой ячейки N ,
      1. Удалите любую плитку, которая больше не совместима с возможными плитками U .
      2. Если мы удалили какие-либо плитки, нам нужно распространить все новые ограничения, поэтому отметьте N как требующие обновления на следующей итерации.
  3. Если какие-либо ячейки все еще нуждаются в обновлении, вернитесь к шагу 2. В противном случае все готово.

Упражнение для ностальгирующих по курсам CS: докажите, что этот алгоритм завершается 🙃

 распространение по умолчанию (потенциал, начальное_местоположение):
    высота, ширина = потенциал.форма[:2]
    need_update = np.full((высота, ширина), False)
    need_update[start_location] = Истина
    в то время как np.any(needs_update):
        need_update_next = np.full((высота, ширина), False)
        местоположения = find_true (needs_update)
        для размещения в локациях:
            возможных_плиток = [плитки [n] для n в find_true (потенциал [местоположение])]
            для соседа в соседях (расположение, высота, ширина):
                сосед_направление, сосед_х, сосед_у = сосед
                сосед_местоположение = (сосед_х, сосед_у)
                was_updated = add_constraint (потенциал, сосед_местоположение,
                                             сосед_направление, возможные_плитки)
                need_update_next[местоположение] |= was_updated
        need_update = need_update_next
 

Вы, наверное, заметили, что я снова пошалил и спрятал некоторые детали под пока еще не определенной функцией add_constraint . add_constraint строит набор сторон (труба или не труба, т. е. True или False ), которые все еще возможны в исходном местоположении, и исключает все плитки, которые все еще были возможны в целевом местоположении.

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

 def add_constraint (потенциал, местоположение, входящее_направление, возможные_плитки):
    Neighbor_constraint = {t.sides[incoming_direction.value] для t в возможных_плитках}
    исходящее_направление = входящее_направление.реверс()
    изменено = Ложь
    для i_p, p в перечислении (потенциал [местоположение]):
        если не п:
            Продолжать
        если плитки[i_p].sides[outgoing_direction.value] не находятся в Neighbor_constraint:
            потенциал[местоположение][i_p] = Ложь
            изменено = верно
    если не np. any (потенциал [местоположение]):
        поднять исключение (f «Нет шаблонов в {местоположении}»)
    возврат изменен
 

Зацикливание

Теперь, когда у нас есть все биты, мы можем просто вызвать нашу функцию run_iteration в цикле и получить классные результаты!

 р = потенциал
изображения = [show_state (p, плитки)]
пока верно:
    пытаться:
        p = run_iteration (p)
        images.append(show_state(p,tiles)) # Переместить меня для скорости
    кроме StopIteration как e:
        ломать
    кроме Исключения как e:
        печать (е)
        ломать
        
выход = io.BytesIO()
images[0].save(out, format='gif', save_all=True, append_images=images[1:],
               продолжительность = 50, цикл = 0)
изображения[-1]
 

(Если вы запускаете эту записную книжку, как и мы, вы можете заметить, что ячейка выше запускается некоторое время [обычно около минуты]. Может ли WFC быть медленным 😮? Ну, эта реализация не молниеносна, но он может сделать эту сетку 30 × 30 менее чем за секунду. Большую часть времени на самом деле занимает мой плохо написанный метод show_state . Если вы переместите вызов show_state за пределы цикла, вы потеряй крутую гифку, но она будет работать быстрее.)

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

 импорт base64
из отображения импорта IPython
display.HTML(''
             .format(base64.b64encode(out.getvalue()).decode('utf8')))
 

Идем дальше

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

Возврат

WFC почти всегда работает с набором тайлов, который я здесь привел. Однако, если вы немного повозитесь с набором плиток, вы поймете, что это не всегда так. Например, сохранение только четырех плиток с буквой «Т» приводит к гораздо более низкому уровню успеха, поскольку WFC сталкивается с противоречиями и уходит. (Вы все равно сможете что-то получить, если запустите WFC примерно 10 раз).

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

Создание из изображений

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

Ссылки

Вы можете скачать блокнот. Используемые версии ПО:

 Питон 3.7.1
юпитер == 1.0.0
число == 1.15.4
Подушка == 5.3.0
 
  • WFC Страница GitHub
  • Wave Function Collapse, 3D-генератор городов на основе WFC, который вдохновил на создание этого поста
  • Карт, Исаак и Адам М. Смит. «WaveFunctionCollapse — это устранение ограничений в дикой природе». Материалы 12-й Международной конференции по основам цифровых игр . АКМ, 2017.

Пожалуйста, оставляйте комментарии или отзывы ниже!

Объединение моделей — Astropy v5.1

Названия моделей

В приведенных выше двух примерах еще одна примечательная особенность созданного соединения классы моделей заключается в том, что имя класса, отображаемое при печати класса в в командной строке не «TwoGaussians», «FourGaussians» и т. д. Вместо этого это сгенерированное имя, состоящее из «CompoundModel», за которым следует по существу произвольное целое число, выбранное просто так, чтобы каждая составная модель имела уникальное имя по умолчанию. В настоящее время это ограничение, связанное с ограничением что это вообще невозможно в Python, когда объект создается выражение, чтобы он «знал» имя переменной, которой он будет присвоен, если Любые. Можно напрямую присвоить имя экземпляру составной модели. с помощью Model.name attribute:

 >>> two_gaussians.name = "TwoGaussians"
>>> print(two_gaussians)
Модель: CompoundModel...
Имя: Два Гаусса
Входы: ('х',)
Выходы: ('y',)
Размер набора моделей: 1
Выражение: [0] + [1]
Составные части:
    [0]: 
    [1]: 
Параметры:
    амплитуда_0 среднее_0 стандартное отклонение_0 амплитуда_1 среднее_1 стандартное отклонение_1
    ----------- ------ -------- ----------- ------ --------
            1,1 0,1 0,2 2,5 0,5 0,1
 

Индексирование и нарезка

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

 >>> из astropy.modeling.models импортировать Const1D
>>> A = Const1D(1.1, имя='A')
>>> B = Const1D(2.1, имя='B')
>>> C = Const1D(3.1, имя='C')
>>> М = А + В * С
>>> печать(М)
Модель: CompoundModel...
Входы: ('х',)
Выходы: ('y',)
Размер набора моделей: 1
Выражение: [0] + [1] * [2]
Составные части:
    [0]: 
    [1]: 
    [2]: 
Параметры:
    амплитуда_0 амплитуда_1 амплитуда_2
    ----------- ----------- -----------
            1,1 2,1 3,1
 

В этом примере вычисляется выражение (B * C) + A , т. е. умножение оценивается перед сложением по обычным арифметическим правилам. Однако компоненты этой модели просто считываются слева направо от выражение A + B * C , где A -> 0 , B -> 1 , C -> 2 . Если мы вместо этого было определено M = C * B + A , тогда индексы были бы обратными (хотя выражение математически эквивалентно). Эта конвенция выбран для простоты – учитывая список компонентов нет необходимости прыгать, мысленно сопоставляя их с выражением.

Мы можем вытащить каждый отдельный компонент составной модели M с помощью индексация обозначений на нем. Следуя приведенному выше примеру, M[1] должно вернуть модель B :

 >>> M[1]

 

Мы также можем взять срез составной модели. Это возвращает новое соединение модель, которая оценивает подвыражение , включающее модели, выбранные ломтик. Это следует той же семантике, что и нарезка список или массив в Python. Начальная точка включает, а конечная точка исключает. Таким образом, кусок, как M[1:3] (или просто M[1:] ) выбирает модели B и C (и все операторов между ними). Таким образом, результирующая модель оценивает только подвыражение B * C :

 >>> print(M[1:])
Модель: CompoundModel
Входы: ('х',)
Выходы: ('y',)
Размер набора моделей: 1
Выражение: [0] * [1]
Составные части:
    [0]: 
    [1]: 
Параметры:
    амплитуда_0 амплитуда_1
    ----------- -----------
            2.1 3.1
 

Примечание

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

Примечание

Начиная с версии 4.0 поведение нарезки более ограничено, чем ранее. Например, если:

 м = м1 * м2 + м3
 

и один нарезанный используя m[1:3] ранее, это вернет модель: m2 + m3 хотя такой подмодели m никогда не было. Начиная с 4.0 срез должен соответствовать подмодели (чему-то, что соответствует к промежуточному результату вычислительной цепочки оценки составная модель). Итак:

 м1*м2
 

— это подмодель (т. е. ``m[:2]``), но м[1:3] нет. В настоящее время это также означает, что в более простых выражениях например:

 м = м1 + м2 + м3 + м4
 

, где любой фрагмент должен быть действительным в принципе, только фрагменты, которые включают m1, являются частью все подмодули (поскольку порядок оценки:

 ((m1 + m2) + m3) + m4
 

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

 м = м1 + (м2 + м3) + м4.  В этом случае ``m[1:3]`` будет работать.
 

Новая составная модель для подвыражения может быть оценена как и любой другой:

 >>> M[1:](0)
6,51
 

Хотя модель M полностью состояла из моделей Const1D в этом Например, было полезно дать каждому компоненту уникальное имя ( A , B , C ), чтобы различать их. Это также можно использовать для индексация и нарезка:

 >>> print(M['B'])
Модель: Конст1Д
Имя: Б
Входы: ('х',)
Выходы: ('y',)
Размер набора моделей: 1
Параметры:
    амплитуда
    ---------
          2.1
 

В этом случае M['B'] эквивалентно M[1] . Но, используя имя, мы делаем не нужно беспокоиться о том, в каком индексе находится этот компонент (это становится особенно полезно при объединении нескольких составных моделей). ток ограничение, однако, состоит в том, что каждый компонент составной модели должен иметь уникальное имя — если некоторые компоненты имеют повторяющиеся имена, они могут быть доступ по их целочисленному индексу.

Нарезка также работает с именами. При использовании имен начальная и конечная точки оба включительно :

 >>> print(M['B':'C'])
Модель: CompoundModel...
Входы: ('х',)
Выходы: ('y',)
Размер набора моделей: 1
Выражение: [0] * [1]
Составные части:
    [0]: 
    [1]: 
Параметры:
    амплитуда_0 амплитуда_1
    ----------- -----------
            2.1 3.1
 

Итак, в данном случае M['B':'C'] эквивалентно M[1:3] .

Параметры

Вопрос, который часто возникает при первом знакомстве с составными моделями: как именно обрабатываются все параметры. К настоящему времени мы видели несколько примеры, которые дают некоторые подсказки, но необходимо более подробное объяснение. Это также одна из самых больших областей для возможных улучшений. поведение должно быть практичным, но не идеальным. (Некоторые возможные улучшения включают возможность переименовывать параметры и предоставление средств сужение количества параметров в составной модели. )

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

Простая схема, используемая в настоящее время для именования параметров в составной модели: это: param_names из каждой модели компонента объединяются с каждым другие в порядке слева направо, как описано в разделе Индексация и нарезка. Однако к каждому имени параметра добавляется _<#> , где <#> — индекс модели компонента, этот параметр принадлежит. Например:

 >>> Gaussian1D.param_names
(«амплитуда», «среднее», «стандартное отклонение»)
>>> (Gaussian1D() + Gaussian1D()).Имена_параметров
('амплитуда_0', 'среднее_0', 'стандартное отклонение_0', 'амплитуда_1', 'среднее_1', 'стандартное отклонение_1')
 

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

 >>> from astropy. modeling.models import RedshiftScaleFactor
>>> (RedshiftScaleFactor() | (Gaussian1D() + Gaussian1D())).param_names
('z_0', 'амплитуда_1', 'среднее_1', 'стандартное отклонение_1', 'амплитуда_2', 'среднее_2',
'stddev_2')
 

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

 >>> a = Gaussian1D(1, 0, 0.2, name='A')
>>> b = Gaussian1D(2.5, 0.5, 0.1, имя='B')
>>> м = а + б
>>> м.амплитуда_0
Параметр('амплитуда', значение=1.0)
 

эквивалентно:

 >>> m['A'].амплитуда
Параметр('амплитуда', значение=1.0)
 

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

 >>> m.amplitude_0 = 42
>>> m['A'].амплитуда
Параметр('амплитуда', значение=42.0)
>>> m['A'].амплитуда = 99
>>> м.амплитуда_0
Параметр('амплитуда', значение=99.0)
 

Обратите внимание, однако, что оригинал Gaussian1D экземпляр был обновлено:

 >>> a.амплитуда
Параметр('амплитуда', значение=99.0)
 

Это отличается от поведения в версиях до 4.0. Теперь составная модель параметры используют тот же экземпляр Parameter, что и исходная модель.

Дополнительные сопоставления

В некоторых предыдущих примерах мы видели, как модели могут быть объединены в цепочку для сформировать «конвейер» преобразований, используя модельную композицию и конкатенацию. Для облегчения создания более сложных цепочек преобразования (например, для преобразования WCS) новый класс 9Предусмотрено отображение 0007 дюймовых моделей.

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

В настоящее время существует только две модели отображения: Личность и (несколько общее название) Отображение .

Сопоставление Identity просто передает один или несколько входы через, без изменений. Он должен быть создан с указанием целого числа количество входов/выходов, которые он принимает. Это может быть использовано для тривиального расширения «размерность» модели с точки зрения количества входных данных, которые она принимает. В разделе о конкатенации мы видели например:

 >>> m = (Масштаб(1.2) & Масштаб(3.4)) | Вращение2D(90)
 

, где два входа координат масштабируются по отдельности, а затем поворачиваются в каждый Другой. Однако, скажем, мы хотели масштабировать только одну из этих координат. Это было бы хорошо просто использовать Scale(1) для одного из них или любую другую модель, которая фактически не работает. Но это также добавляет ненужные вычислительные затраты, поэтому мы могли бы просто указать, что эта координата не должна масштабироваться или трансформируется как-то. Это хороший пример использования Идентификатор :

 >>> из astropy.modeling.models import Identity
>>> m = Масштаб (1.2) и Идентичность (1)
>>> м(1, 2)
(1.2, 2.0)
 

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

 >>> m = Масштаб (1.2) и Идентичность (2)
>>> м(1, 2, 3)
(1.2, 2.0, 3.0)
 

(Естественно последний пример можно было бы выписать и Масштаб(1.2) и Identity(1) & Identity(1) . )

Модель Mapping аналогична тем, что не изменить любой из его входов. Однако он более общий, поскольку позволяет вводить дублироваться, переупорядочиваться или даже удаляться сразу. Он создается с помощью один аргумент: кортеж , количество элементов которого соответствует количество выходных данных, которые должен произвести Mapping . А 1-кортеж означает, что любые входные данные поступают в Mapping , будет выведено только одно. И так далее для 2-кортежа или выше (хотя длина кортежа не может быть больше длины количество входных данных — он не будет брать значения из воздуха). Элементы это отображение представляет собой целые числа, соответствующие индексам входных данных. За например, отображение Mapping((0,)) эквивалентно Identity(1) –it просто берет первый (0-й) ввод и возвращает его:

 >>> from astropy.modeling.models import Mapping
>>> m = отображение ((0,))
>>> м(1,0)
1,0
 

Аналогично Mapping((0, 1)) эквивалентно Identity(2) и так далее. Однако Mapping также позволяет произвольно переупорядочен:

 >>> m = Mapping((1, 0))
>>> м(1,0, 2,0)
(2.0, 1.0)
 
 >>> m = отображение ((1, 0, 2))
>>> м(1,0, 2,0, 3,0)
(2,0, 1,0, 3,0)
 

Выходы также могут быть удалены:

 >>> m = Mapping((1,))
>>> м(1,0, 2,0)
2.0
 
 >>> m = отображение ((0, 2))
>>> м(1,0, 2,0, 3,0)
(1.0, 3.0)
 

Или продублировано:

 >>> m = Mapping((0, 0))
>>> м(1,0)
(1.0, 1.0)
 
 >>> m = отображение ((0, 1, 1, 2))
>>> м(1,0, 2,0, 3,0)
(1,0, 2,0, 2,0, 3,0)
 

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

 >>> from astropy.modeling.models импортировать Polynomial1D как Poly1D
>>> из astropy.modeling.models импортировать Polynomial2D как Poly2D
>>> m = ((Poly1D(3, c0=1, c3=1) & Identity(1) & Poly1D(2, c2=1)) |
... Отображение((0, 2, 1)) |
...  (Poly2D(4, c0_0=1, c1_1=1, c2_2=2) и Gaussian1D(1, 0, 4)))
...
>>> м(2, 3, 4)
(41617.0, 0.7548392 + xz + 1\), одновременно вычисляя гауссиану на
\(у\). Конечным результатом является сокращение до двух координат. Вы можете
подтвердите для себя, что результат правильный. 

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

Уменьшение модели

Во избежание дублирования при построении сложных моделей рекомендуется можно определить одну сложную модель, охватывающую все случаи, когда переменные, которые отличают модели, становятся частью входных данных модели. переменные. Функция fix_inputs позволяет определять модели, полученные из более сложный, установив один или несколько входов на константу ценность. Примеры такого рода ситуаций возникают при отработке преобразования пикселя детектора в RA, Dec и лямбда для спектрографы, когда расположение щелей может быть перемещено (например, подача волокна или управляемые щелевые маски), или могут быть выбраны другие порядки (например, Eschelle). В случае заказа может быть функция пикселя x , y , спектральный_порядок это сопоставляется с RA , Dec и lambda . Без указания speckral_order , это неоднозначно, что RA , Dec и Lambda соответствует местоположению пикселя. Это обычно можно определить функцию всех трех входов. Предполагая эта модель general_transform , тогда fix_inputs может использоваться для определения преобразование для определенного порядка следующим образом:

::
 >>> order1_transform = fix_inputs(general_transform, {'order': 1})
 

создает новую составную модель, которая принимает только положение пикселя и генерирует RA , Dec и лямбда . Функцию fix_inputs можно использовать для установки значения по позиции (0 — первый) или по имени входной переменной и т. д. чем один может быть установлен в прилагаемом словаре.

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

Замена подмоделей

replace_submodel() создает новую модель путем замена подмодели с совпадающим именем на другую подмодель. Количество входы и выходы старой и новой подмоделей должны совпадать.

 >>> из моделей импорта astropy.modeling
>>> shift = модели.Shift(-1) и модели.Shift(-1)
>>> масштаб = модели.Масштаб(2) и модели.Масштаб(3)
>>> scale.name = "Масштаб"
>>> модель = сдвиг | шкала
>>> модель(2, 1)
(2,0, 0,0)
>>> new_model = model.replace_submodel('Масштаб', models.Rotation2D(90, имя='Вращение'))
>>> новая_модель (2, 1)
(6.12e-17, 1.0)
 

5. Трубы в Python | Приложения

Автор Бернд Кляйн . Последнее изменение: 01 февраля 2022 г.

На этой странице ➤

Труба

Unix или Linux без конвейеров немыслимы, или, по крайней мере, конвейеры являются очень важной частью приложений Unix и Linux. Мелкие элементы соединяются с помощью труб. Процессы объединены в цепочку своими стандартными потоками, т. е. выходные данные одного процесса используются в качестве входных данных другого процесса. Для цепочки таких процессов используются так называемые анонимные каналы.

Концепция каналов и конвейеров была введена Дугласом Макилроем, одним из авторов ранних командных оболочек, после того, как он заметил, что большую часть времени они обрабатывали выходные данные одной программы как входные данные для другой. Кен Томпсон добавил концепцию конвейеров в операционную систему UNIX в 1973 году. Позже конвейеры были перенесены и на другие операционные системы, такие как DOS, OS/2 и Microsoft Windows.

Обычно существует два вида труб:

  • безымянные трубы
    и
  • именованные трубы

Анонимные каналы существуют исключительно внутри процессов и обычно используются в сочетании с вилками.

Живое обучение Python

Нравится эта страница? Мы предлагаем интерактивных обучающих курса Python , охватывающих содержание этого сайта.

См.: Обзор курсов Live Python

Зарегистрироваться здесь

Пивная трубка на питоне

«99 Bottles of Beer» — традиционная песня в США и Канаде. Песня происходит от английского «Ten Green Bottles». Песня состоит из 100 куплетов, которые очень похожи. Просто количество бутылок разное. Только один, т.е. сотый куплет немного отличается. Эту песню часто поют в дальних поездках, потому что ее легко запомнить, особенно в пьяном виде, и петь ее можно долго.

Вот текст этой песни:

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

Следующий куплет такой же, начиная с 98 бутылок пива. Итак, общее правило таково: с каждым стихом на одну бутылку меньше, пока не останется ни одной. На этом песня обычно заканчивается. Но мы хотим реализовать Aleph-Null (т.е. бесконечную) версию этой песни с дополнительным куплетом:

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

Эта песня была реализована на всех мыслимых компьютерных языках, таких как "Whitespace" или "Brainfuck". Вы можете найти коллекцию на http://99-bottles-of-beer.net

.

Программируем Алеф-Нулевой вариант песни с вилкой и трубкой:

 импорт ОС

дочерний элемент (конвейер):
  бутылки = 99
  пока верно:
    боб = "бутылки пива"
    otw = "на стене"
    take1 = "Сними один и раздай всем"
    store = "Иди в магазин и купи еще"

    если бутылки > 0:
      значения = (бутылки, боб, otw, бутылки, боб, take1, бутылки - 1, боб, otw)
      стих = "%2d %s %s,\n%2d %s.\n%s,\n%2d %s %s." % ценности
      os.write(конвейер, стих)
      бутылки -= 1
    еще:
      бутылки = 99
      значения = (боб, otw, боб, магазин, бутылки, боб, otw)
      стих = "Хватит %s %s,\nбольше %s.\n%s,\n%2d %s %s." % ценности
      os.write(конвейер, стих)
      
деф родитель():
    канал, канал = os.pipe ()
    если os. fork() == 0:
        ребенок (трубопровод)
    еще:
        счетчик = 1
        пока верно:
            если счетчик % 100:
                стих = os.read (pipein, 117)
            еще:
                стих = os.read (конвейер, 128)
            напечатать 'стих %d\n%s\n' % (счетчик, стих)
            счетчик += 1

родитель()
 

Проблема в приведенном выше коде заключается в том, что мы или, лучше, родительский процесс должны точно знать, сколько байт каждый раз будет отправлять дочерний процесс. Для первых 99 стихов это будет 117 байт ( стих = os.read(pipein, 117) ), а для стиха Алеф-Нулл это будет 128 байт ( стих = os.read(pipein, 128)

Мы исправили это в следующей реализации, в которой мы читаем полные строки:

 импорт ОС

дочерний элемент (конвейер):
  бутылки = 99
  пока верно:
    боб = "бутылки пива"
    otw = "на стене"
    take1 = "Сними один и раздай всем"
    store = "Иди в магазин и купи еще"

    если бутылки > 0:
      значения = (бутылки, боб, otw, бутылки, боб, take1, бутылки - 1, боб, otw)
      стих = "%2d %s %s,\n%2d %s. \n%s,\n%2d %s %s.\n" % значений
      os.write(конвейер, стих)
      бутылки -= 1
    еще:
      бутылки = 99
      значения = (боб, otw, боб, магазин, бутылки, боб, otw)
      verse = "Нет больше %s %s,\nбольше нет %s.\n%s,\n%2d %s %s.\n" % значений
      os.write(конвейер, стих)
деф родитель():
    канал, канал = os.pipe ()
    если os.fork() == 0:
        os.close (конвейер)
        ребенок (трубопровод)
    еще:
        os.close (конвейер)
        счетчик = 1
        канал = os.fdopen (конвейер)
        пока верно:
            напечатать 'стих %d' % (счетчик)
            для я в диапазоне (4):
                стих = pipein.readline()[:-1]
                напечатать '%s' % (стих)
            счетчик += 1
            Распечатать

родитель()
 

Двунаправленные трубы

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

Изобретатель, тот, кто изобретает число, должен представить число в диапазоне от 1 до n. Угадывающий вводит свою догадку. Разработчик информирует игрока, если это число больше, меньше или равно секретному числу, т.е. числу, случайно созданному разработчиком. И разработчик, и угадывающий записывают свои результаты в лог-файлы, т. е. deviser.log и угадывающий.log соответственно.

Это полная реализация:

 импорт os, sys, случайный

Разработчик защиты (макс.):
    fh = открыть ("deviser.log", "w")
    to_be_guessed = int(max * random.random()) + 1
    
    предположение = 0
    в то время как угадать != to_be_guessed:
        предположение = int(raw_input())
        fh.write(str(догадка) + "")
        если предположение > 0:
            если угадать > to_be_guessed:
                распечатать 1
            Элиф догадаться < to_be_guessed:
                распечатать -1
            еще:
                распечатать 0
            sys. stdout.flush()
        еще:
            ломать
    fh.close()

угадывающий (макс.):
    fh = открыть("угадай.журнал","ш")
    низ = 0
    верх = макс.
    нечеткий = 10
    разрешение = 1
    в то время как разрешение != 0:
        предположение = (низ + верх) / 2
        распечатать предположение
        sys.stdout.flush()
        fh.write(str(догадка) + "")
        разрешение = интервал (raw_input())
        if res == -1: # число выше
            дно = предположение
        Элиф рез == 1:
            верх = угадать
        Элиф рез == 0:
            message = "Разыскивается номер %d" % предположение
            fh.write(сообщение)
        else: # этого случая быть не должно
            печатать "ввод неверный"
            fh.write("Что-то не так")
   

п = 100
stdin = sys.stdin.fileno() # обычно 0
stdout = sys.stdout.fileno() # обычно 1

parentStdin, childStdout = os.pipe()
childStdin, parentStdout = os.pipe()
pid = os.fork()
если пид:
    # родительский процесс
    os. close(childStdout)
    os.close(childStdin)
    os.dup2 (родительский стандарт, стандартный ввод)
    os.dup2 (родительский стандартный вывод, стандартный вывод)
    изобретатель (сущ.)
еще:
    # дочерний процесс
    os.close(родительскийStdin)
    os.close(родительскийStdout)
    os.dup2(childStdin, стандартный ввод)
    os.dup2(childStdout, стандартный вывод)
    угадывающий (сущ.)

 

Живое обучение Python

Нравится эта страница? Мы предлагаем интерактивных обучающих курса Python , охватывающих содержание этого сайта.

См.: Обзор курсов Live Python

Зарегистрироваться здесь

Именованные каналы, Fifos

Под Unix, так же как и под Linux, можно создавать каналы, которые реализованы в виде файлов.

Эти каналы называются «именованными каналами» или иногда Fifos (First In First Out).

Процесс читает и записывает в такой канал, как если бы это был обычный файл. Иногда несколько процессов пишут в такой канал, но только один процесс читает из него.

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

 импорт ОС, время, система
имя_трубы = 'тест_трубы'

деф дочерний( ):
    pipeout = os.open (имя_канала, os.O_WRONLY)
    счетчик = 0
    пока верно:
        время сна(1)
        os.write(pipeout, 'Number %03d\n' % counter)
        счетчик = (счетчик+1) % 5

деф родитель():
    pipein = открыть (имя_канала, 'r')
    пока верно:
        строка = pipein.readline()[:-1]
        print 'Родительский элемент %d получил "%s" в %s' % (os.getpid(), line, time.time())

если не os.path.exists (имя канала):
    os.mkfifo (имя канала)
pid = os.fork()
если pid != 0:
    родитель()
еще:
    ребенок()
 

Живое обучение Python

Нравится эта страница? Мы предлагаем интерактивных обучающих курса Python , охватывающих содержание этого сайта.

См.: Обзор курсов Live Python

Зарегистрируйтесь здесь

UCSF Chimera Feature Highlights

Различные конформации и даже разные белки можно сравнивать с помощью переходя из одной структуры в другую. Пользователи могут указать метод координатная интерполяция и сколько промежуточных структур должно быть сгенерировано. Результат отображается в средстве просмотра траектории Химеры, Фильм МД. Затем морф может быть сохранен в форме координат или записано как анимация. См. также: Галерея анимации

(Больше возможностей...)


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

На рисунке показаны четыре самых больших по объему кармана, идентифицированных CASTp для записи PDB 1ovh (полостной мутант лизоцима T4), показанный на желтый, оранжевый, розовый и пурпурный в порядке убывания объема. Самый большой - активный сайт лизоцима с двумя отверстиями. Второй по величине является инженерная полость. Мутированные позиции показаны красным. Зеленые шарики - Cl ионов.

(Больше возможностей...)


Пользователи могут легко импортировать данные, связанные со структурой, в Chimera. в виде атрибутов или значения, связанные с атомами, остатками или моделями. Данные можно импортировать с помощью Определить атрибут а потом представлены визуально с цветовыми диапазонами, атомными радиусами, или "червячная" толщина. Такие данные также могут быть манипулируют программно в Химере, а на самом деле Химере был разработан с учетом расширяемости и программируемости. Он в основном реализован в Python с некоторыми функциями закодирован в C++ для эффективности. Python — это простой в освоении интерпретируемый язык с объектно-ориентированными функциями. Все Химеры функциональность доступна через Python, и пользователи могут реализовать свои собственные алгоритмы и расширения без каких-либо изменений кода Chimera, поэтому любые такие пользовательские расширения будут продолжать работать через Химера выпускает. Много примеры программирования предназначены для помощи авторам расширений.

(Больше возможностей...)


Инструмент PDB/UniProt Info извлекает аннотации последовательности и структуры для Записи банка данных белков (PDB) с использованием веб-службы, предоставляемой РЦСБ ПДБ. Последовательности отображаются в Multalign Viewer и аннотации функций из ЮниПрот отображаются на последовательности как области или цветные прямоугольники. в обозреватель регионов (рисунок справа):

  • создание региона Активный выбирает любые соответствующие структурные остатки для дальнейших операций; одновременно может быть активен только один регион
  • создание области Показано отображает ее в окне последовательности
  • квадратные лунки для цветов показывать (и разрешать изменять) цвета интерьера и границ региона

ЮниПрот аннотации также могут быть извлечены вместе с последовательностью или сопоставляется с последовательностью, уже Multalign Viewer независимо от того, является ли последовательность ассоциируется со структурой.

(Больше возможностей...)


Space Navigator — недорогое (60 долларов) USB-устройство ввода от 3Dсоединение для движущихся и вращающихся моделей в 3-х измерениях. Этот анимация (8 Мб) показывает стыковку фагового фермента (ПДБ 1v0e) на карту электронной микроскопии (EMDB 1333) с помощью навигатора и мыши. Работает с версиями Windows и Mac Chimera (Детали).

(Больше возможностей...)


РУБ Карты расстояний создает карту расстояний , обобщение карта контактов белка в котором расстояния между остатками показаны с цветовыми градациями. Карта может показать расстояния Cα-Cα в пределах отдельного белка. цепочка или средние значения и стандартные отклонения для нескольких связанных цепочек (как на рисунке). Простая бинарная раскраска, такая как стандартная карта контактов, также может быть полученный.

(Больше возможностей. ..)


Несколько выравнивание последовательностей структурных цепочек в Chimera или перестройка последовательностей в существующем выравнивании может быть выполнено с помощью веб-сервисов, размещенных на UCSF РБВИ. Предусмотрены следующие программы:

  • Кластальная Омега
  • МЫШЦЫ

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

(Больше возможностей...)


Chimera предоставляет графический интерфейс для запуска программы. Модельер, либо локально, либо через веб-службу, размещенную на UCSF РБВИ. Доступны два типа расчетов:

  • Сравнительное (гомологическое) моделирование . Созданы теоретические модели белка мишени используя хотя бы одну известную родственную структуру шаблона и выравнивание последовательности мишень-шаблон. Есть несколько путей для создания этих входных данных в Chimera. См. также Сравнительное моделирование руководство.
  • Построение части белка без использования шаблона. Недостающие сегменты могут быть построены de novo или существующие сегменты уточняется путем создания дополнительных возможных конформаций.

Модельер разработан Лаборатория Сали.

(Больше возможностей...)


Одно использование Многодоменный Ассемблер должен настроить сравнительное моделирование и объединение существующих структур для создания полноразмерной модели мультидоменного белка. Однако даже без построения модели побочный продукт тоже полезен: визуальная сводка структур, доступных для последовательности запроса, опционально фильтруется по таким критериям, как оценка BLAST и % идентичности, расположены горизонтально в приблизительном порядке N→C относительно запроса. Перекрывающиеся хиты укладываются вертикально, сегменты без структурного покрытия обозначены сферами. По умолчанию множественное выравнивание последовательностей обращений к запросу также отображается.

На рисунке показаны результаты команды:
     mda p08648 ~/Desktop/MDA предел 4 процента 50
с несовпадениями последовательностей, выделенными красным, и молекулами, отличными от хита цепи синего цвета. Текст и указатели были добавлены с помощью 2D Этикетки .

Multidomain Assembler описан в бумага.

(Больше возможностей...)


В Chimera есть несколько способов наложения структур:
• MatchMaker выполняет подгонку после автоматического определения какие остатки должны быть спарены. Спаривание использует как последовательность, так и вторичную структуру, позволяет накладывать похожие структуры даже тогда, когда сходство их последовательностей от низкого до неопределяемого.
На рисунке показаны пять отдаленно родственных белков. (попарные тождества последовательностей надсемейства SCOP WD40 до и после Суперпозиция MatchMaker с параметрами по умолчанию.
• Структуры могут быть согласованы с использованием уже существующего выравнивания последовательностей.
• Точные атомы для пары могут быть указаны с помощью команда соответствия. Это работает на любом типе структуры, в то время как предыдущие методы относятся только к пептидным и нуклеотидным цепям.
• Структуры можно накладывать вручную с помощью активировать/деактивировать их для движения и с помощью мыши.

(Больше возможностей...)


Учитывая две или более наложенных друг на друга структур, Match→Align создает соответствующее выравнивание последовательности. Пользователь указывает допустимое расстояние отсечки остатков. в том же столбце выходного выравнивания. В белках расстояния измеряются между α-углеродами. Метод не зависит от типов остатков и от того, как структуры накладывались друг на друга.
На рисунке показана суперпозиция из MatchMaker из пяти белков из SCOP WD40 суперсемейство и соответствующее выравнивание последовательностей из Match→Align, автоматически отображается в Средство просмотра мультивыравнивания. В выравнивании последовательности, светло-зеленые и желтые прямоугольники обозначают нити и спирали, а заголовки RMSD и Сохранение показывают пространственное и последовательное консервации соответственно.

(Больше возможностей...)


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

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

(Больше возможностей...)


Сервер ConSurf дает результаты как Химера веб-данные; после браузер конфигурация, один клик отображает структуру запроса с цветовой кодировкой и множественное выравнивание последовательностей с филогенетическим деревом и пользовательскими заголовками в локально установленной копии Химера (детали).

Особая благодарность Элане Эрез и группам Бен-Тал и Пупко на Тель-Авивский университет и Фабиан Глейзер из Техниона.

(Больше возможностей. ..)


Структура может быть цветной чтобы показать атрибуты, такие как сохранение остатков. Открытие последовательности выравнивание в Chimera показывает это в Средство просмотра множественного выравнивания и автоматически связывает последовательности со структурами по мере необходимости. Остатки структур, связанных с выравниванием, имеют природоохранную ценность; доступные меры включают энтропию, изменчивость и сумму пар. Фигура была создана с использованием выравнивания семян PFAM Carb_anhydrase PF00194_seed.slx (см. изображение) и включает 2D этикетки и цветной ключ. Смотрите также: сохранение последовательности отображения

(Больше возможностей...)


Муха команда может оживить полет через молекулярные структуры. Щелкните изображение примера, чтобы пролететь вдоль копируемой РНК. РНК-полимераза ротавируса (ПДБ 2р7р), фермент, реплицирующий 11 сегментов вирусной РНК. См видео показывая, как была сделана эта анимация.

(Больше возможностей...)


Инструмент Blast Protein выполняет blast или psiblast поиск пдб или для аналогичных последовательностей на запрос, используя веб-службу, размещенную UCSF РБВИ. Запрос может быть:

  • цепочка из строения открытого в Химере
  • последовательность, вставленная как обычный текст
  • последовательность из выравнивания в Средство просмотра множественного выравнивания

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

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

(Больше возможностей. ..)


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

Например, на рисунке показаны рецептор допамина D3 и связанный ингибитор (запись PDB 3pbl), смоделированная в мембрану в База данных ОПМ. Плоскости внутренней и внешней границ мембраны показаны в виде прозрачных синих и красных дисков соответственно. Белковая лента имеет радужную окраску от синего на N-конце до красного. на С-конце, а ось каждой спирали показана в виде цилиндра подходящего цвета. Ось красной спирали образует с мембраной угол 15,1°. и находится в пределах 3,5 Å от внутренней границы. Желтая и оранжевая спирали почти антипараллельны. (угол пересечения 5,9°). Среднее (минимальное, максимальное) расстояние атомов ингибитора от внешней границы составляет 7,9 (5,1, 11,7) Å.

(Больше возможностей...)


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

  • при наведении курсора мыши на остаток в последовательности показывает номер его структурного остатка
  • выбор в последовательности выбирает остатки в структуре(ах) и наоборот
  • структуры могут быть наложены друг на друга с использованием выравнивания последовательностей

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

(Больше возможностей...)


Интерактивные тени (тени, которые перемещаются при перемещении структур) можно включить в Диалог эффектов или с командой установить тени. Щелкните изображение, чтобы показать маленькую молекулу, вращающуюся над прямоугольной плоскостью. Эта простая анимация была сделана с помощью командного скрипта Chimera. тамбл.com. Интерактивные тени также работают с лентами, поверхностями и другими объектами. представления.

(Больше возможностей...)


Траектория ленты по умолчанию — гладкая bspline (полупрозрачный загар на рисунке), которые могут расходиться с истинным положением атомов основной цепи (α-углероды показаны серыми шариками). Кардинальный сплайн позволяет более точно отслеживать магистраль. Без сглаживания (голубой) он точно следует за α-углеродами, или его можно комбинировать с некоторыми «компромиссное» сглаживание пряди и/или мотка. Параметры сплайна ленты можно настроить с помощью команда реберной линии или в молекуле атрибуты модели.

(Больше возможностей...)


Углы белкового остова можно изобразить на Рамачандран График вместе с контурами вероятности (зеленые линии) из эталонного набора хорошо определенных структур. Каждый аминокислотный остаток показан точкой на графике зависимости φ от ψ, более известный как график Рамачандрана или карта Рамачандрана. Остатки отображаются синими точками или когда выбранный, как красные точки. В примере были выбраны все остатки спирали . И наоборот, если щелкнуть точку на графике, выбрать соответствующий остаток в структуре. Когда график находится в фокусе мыши, положение курсора (x = φ, y = ψ) указывается под графиком.

(Больше возможностей...)


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

Градиенты могут содержать любое количество цветов и могут отображаться как дискретные полосы или интерполированные в цветовом пространстве RBG или HLS; их можно создавать, просматривать и называть с помощью Редактор палитры. Фоновые изображения могут быть обрезаны, растянуты, центрированы или размещены в виде мозаики. Форматы изображений включают PNG, TIFF и JPEG.

(Больше возможностей...)


Простой внешний вид, похожий на рисунок, можно получить, комбинируя черные края силуэта с плоским фоновым освещением. Изображение слева небольшой молекулы в виде шара и стержня можно получить с помощью нескольких Команда Химеры. Те же визуальные эффекты можно применить к лентам и другим представлениям. как показано в Цветы нейраминидазы и другие записи Галереи изображений.

(Больше возможностей...)


Карты электронной плотности можно считывать из локальных файлов или взяты из баз данных. Химеры Volume Viewer позволяет интерактивно настраивать уровни контуров, отображение нескольких изоповерхностей для данной карты и ограничение отображения зону вокруг выбранных атомов. На рисунке показана запись PDB 2fma и ее карта электронной плотности. Настройки аналогичны описанным в Плотность Показать учебник. Смотрите также: Объем химеры показать руководство

(Больше возможностей...)


трубы и доски инструмент показывает белковые спирали в виде «труб» (цилиндров) и пряди в виде «досок» (прямоугольных коробок), с соединителями для промежуточной катушки. Регулируемые настройки включают радиус трубы, планку ширина, цвета и необходимость включения стрелок для отображения цепочки N→C направленность (см. изображение с инструкциями).

(Больше возможностей...)


Структура может быть цветной для отображения значений атрибута, такого как атомарный B-фактор. Изображение включает в себя молекулярную поверхность, которая была обрезанный а также закрытый, 2D этикетки и цветной ключ. Цвет Зона использовалась для окрашивания плоского сечения поверхности (см. изображение как сделать).

(Больше возможностей...)


Текст, символы и стрелки разных цветов и размеров могут быть добавлены к дисплею Chimera с помощью 2D Инструмент «Ярлыки» или команда 2dlabels. Эти аннотации рисуются «в плоскости экрана». перед любыми отображаемыми объектами и не двигаться, когда объекты перемещаются. 2D-метки и стрелки включаются в сохраненные изображения и видеоролики, и их можно появляется или исчезает в течение определенного количества кадров.

(Больше возможностей.. .)


Многомасштабные модели расширение позволяет Chimera отображать большие комплексы, такие как вирусные капсиды, рибосомы и хроматин. Он отображает четверичную структуру моделей PDB и позволяет субъединицы должны быть выбраны и показаны в атомарных деталях. Матрицы считываются из файлов PDB, в которых указана биологическая единица. Также может быть показана кристаллографическая упаковка.

(Больше возможностей...)


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

(Больше возможностей. ..)


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

(Больше возможностей...)


Химеры Отображает Volume Viewer данные трехмерного электронного и светового микроскопа , Карты рентгеновской плотности, электростатического потенциала и др. объемные данные. Контурные поверхности, сетки и объемные Предоставляются стили отображения, а пороговые значения можно изменять в интерактивном режиме. Карты могут быть цветные, нарезанные, сегментированные, и изменения могут быть сохранены. Маркеры могут быть размещены и структуры могут быть прослежены. На прилагаемом изображении показана карта плотности Вирус мухи водорослей из электронной микроскопии окрашен радиально и с вырезанным октантом.

(Больше возможностей...)


Объемные данные может быть показана одна плоскость (или плита) одновременно с Самолеты особенность в Просмотрщик томов. Отображение плоскости можно настроить так, чтобы оно колебалось вдоль оси данных X, Y или Z или местоположение плоскости могут быть указаны в интерактивном режиме со слайдером.

(Больше возможностей...)


Ценности в плоскости объемные данные можно изобразить как высоты по нормали к плоскости (топографической карте). Когда не замужем плоскость отображается с Volume Viewer, команда топография будет отображать значения как высоты на поверхности.

(Больше возможностей...)


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

(Больше возможностей...)


Поверхность может быть цветной по плотности или др. объемные данные. На фото поверхность обрезанный а также закрытый, и только колпачок окрашен плотностью. Могут быть применены различные схемы окраски.

(Больше возможностей...)


Боковые цепи аминокислот принимают различные конформационные состояния, или ротамеры . Ротамеры из магистрально-зависимой библиотеки Dunbrack или "предпоследнюю" библиотеку Ричардсона можно просмотреть, оценить, и включены в конструкции с Инструмент ротамеры. Остаток может быть преобразован в другую конформацию того же типа. аминокислоты или мутировал в другой тип. Углы кручения ротамера и значения вероятностей библиотеки перечислены в диалоговом окне, наряду с (необязательно) водородными связями, столкновениями и согласием с данные электронной плотности. Отображаются только ротамеры, выбранные в списке. Когда выбран один ротамер, он может быть включен в структуру. Изображение включает в себя 2D этикетки.

(Больше возможностей...)


Специальные представления ДНК и РНК могут быть отображены с помощью нуклеотиды инструмент или команда нуклеотиды. Доступны различные уровни абстракции. На рисунке показана лента основа в сочетании со следующими вариантами боковой цепи (сахар/основа):

  • перекладины лестницы
  • представления атомов в виде заполненных колец
  • "леденцы", в которых основания показаны эллипсоидами, а сахара - трубочками

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

(Больше возможностей. ..)


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

(Больше возможностей...)


Инструмент Metal Geometry облегчает анализ металлической связи. места. В нем перечислены потенциальные атомы, координирующие металл. (рядом с нуклеофильными гетероатомами) и предполагает вероятную координационную геометрию. Идеализированную геометрию можно изобразить сплошными стрелками, как показано на рисунке для октаэдрической координации Mn ++ шестью атомами, а координационные псевдосвязи в структуре могут быть обновлены в соответствии с выбранной геометрией.