Какой рейтинг вас больше интересует?
|
Главная /
Каталог блоговCтраница блогера Жизнь на свободе/Записи в блоге |
Жизнь на свободе
Голосов: 1 Адрес блога: http://sovety.blogspot.com/ Добавлен: 2008-02-19 12:40:29 блограйдером Lurk |
|
unplot.py: извлекаем табличные данные из графиков
2010-11-26 02:28:00 (читать в оригинале)Недавно разгребал резервные копии, и обнаружил скрипт, который, пожалуй, может кому-нибудь пригодиться. Программа делает действие обратное построение графику: по изображению графика восстанавливает таблицу с числовыми данными. Поэтому она и называется unplot.
Скачать: unplot.py.
Исходники лежат на bitbucket. Исправляйте и улучшайте.
Перед запуском программы нужно вначале определить координаты (в пикселях) той части графика, которую надо обработать. Это можно сделать в Gimp или в Geeqie.
Если на графике несколько линий, то нужную из них нужно покрасить отдельным цветом, отличным от всех других. Это тоже можно сделать в Gimp. Нужно записать HTML-код её цвета.
В общем, исходный график должен выглядеть примерно так:
После этого можно запустить и сам скрипт:
./unplot.py "#00ff00" 0 151 0 475 5.0 824 0.09 85 /путь/к/plot.png > /путь/к/data.txt
Первый параметр — это код цвета линии. Вторые два числа это значение и координата X левого нижнего угла. Потом ещё два числа, значение и координата Y того же угла. Потом ещё четыре числа — соответственно для правого верхнего угла. И в конце имя файла с графиком. Результаты (текстовую таблицу с данными) перенаправляем в файл. Можно ещё задавать «чувствительность» к цвету (параметр
-s
).После применения скрипта полезно построить ещё раз график по полученным точкам и убедиться, что выбран правильный участок графика, указан правильный цвет и разумные числовые значения точек. Например, в этом случае я захватил слишком много справа, и зелёные буквы тоже были учтены как точки графика.
Обновление 20101203: теперь скрипт умеет обрабатывать графики с линией толще 1 пикселя; также в репозитории появился и небольшой скрипт для тестирования unplot.py на вменяемость.
По-английски: Unplot.py: from plots to tabular data.
unplot.py: извлекаем табличные данные из графиков
2010-11-26 02:28:00 (читать в оригинале)Недавно разгребал резервные копии, и обнаружил скрипт, который, пожалуй, может кому-нибудь пригодиться. Программа делает действие обратное построение графику: по изображению графика восстанавливает таблицу с числовыми данными. Поэтому она и называется unplot.
Скачать: unplot.py.
Исходники лежат на bitbucket. Исправляйте и улучшайте.
Перед запуском программы нужно вначале определить координаты (в пикселях) той части графика, которую надо обработать. Это можно сделать в Gimp или в Geeqie.
Если на графике несколько линий, то нужную из них нужно покрасить отдельным цветом, отличным от всех других. Это тоже можно сделать в Gimp. Нужно записать HTML-код её цвета.
В общем, исходный график должен выглядеть примерно так:
После этого можно запустить и сам скрипт:
./unplot.py "#00ff00" 0 151 0 475 5.0 824 0.09 85 /путь/к/plot.png > /путь/к/data.txt
Первый параметр — это код цвета линии. Вторые два числа это значение и координата X левого нижнего угла. Потом ещё два числа, значение и координата Y того же угла. Потом ещё четыре числа — соответственно для правого верхнего угла. И в конце имя файла с графиком. Результаты (текстовую таблицу с данными) перенаправляем в файл. Можно ещё задавать «чувствительность» к цвету (параметр
-s
).После применения скрипта полезно построить ещё раз график по полученным точкам и убедиться, что выбран правильный участок графика, указан правильный цвет и разумные числовые значения точек. Например, в этом случае я захватил слишком много справа, и зелёные буквы тоже были учтены как точки графика.
Обновление 20101203: теперь скрипт умеет обрабатывать графики с линией толще 1 пикселя; также в репозитории появился и небольшой скрипт для тестирования unplot.py на вменяемость.
По-английски: Unplot.py: from plots to tabular data.
Безболезненный upload с помощью Wondershaper
2010-10-12 01:38:00 (читать в оригинале)Наверное, многие замечали, особенно на домашнем интернете, что во время интенсивной закачивания данных в сеть (во время upload), соединение начинает «тормозить». Страницы сайтов подолгу не открываются, скачивание и медиапотоки подвисают на месте... Это легко измерить: у меня дома, например, пинг до гугла вырастает с 50 мс до порядка 1000 мс, при этом около 8% пакетов вообще теряются.
Причина этого явления (чаще всего) — загрузка в сеть занимает весь доступный исходящий канал, а соединения по протоколу TCP/IP требуют двухсторонней связи. Даже если мы пытаемся что-то просто скачать, машина должна посылать обратно пакеты подтверждения приёма (т.н. ACK). Если же исходящий канал весь занят, то и пакеты подтверждения, какими бы маленькими они не были, надолго задерживаются, и, соответственно, перестают приходить и входящие пакеты, даже если ширина входящего канала достаточна.
Решить эту проблему можно с помощью скрипта
wondershaper
(есть в составе большинства дистрибутивов). Он позволяет установить ограничения на скорость загрузки из сети и в сеть. Хитрость в том, чтобы вначале узнать свою реальную скорость соединения, а потом установить ограничения чуть-чуть ниже реальной доступной скорости. В этом случае будет всегда оставаться «запас» для своевременной передачи служебных пакетов, и задержки станут гораздо меньше.Например, я хочу выложить кучу фотографий на яндекс-фотки. Иду на internet.yandex.ru и измеряю скорость соединения с Яндексом, сегодня вечером у меня получилось так:
Можно пойти на testspeed.net или другую измерительную страничку. Можно измерить вручную. Главное, получить реальные значения скорости в килобитах в секунду.
После этого надо включить
wondershaper
на используемом сетевом интерфейсе и указать ему значения немного меньше измеренных. Сетевой интерфейс — это обычно wlan0
в случае соединения по WiFi, или eth0
в случае соединения по локальной сети. Чтобы уточнить, можно выполнить команду route -n
в терминале, имя используемого интерфейса искать в строке с флагами UG
.$ sudo wondershaper wlan0 3900 450
Готово. Запускаем загрузку в сеть (выкладываем фото, видео, раздаём торренты, и т.д.), измеряем время пинга. Чудесным образом, даже во время загрузки, пинг у меня упал до 61 мс, что не сильно больше его минимального значения при свободном канале, а веб-страницы стали скачиваться вполне шустро. Если не помогло с первого раза, можно попробовать ограничить скорость закачивания в сеть ещё сильнее.
Чтобы отключить
wondershaper
, выполнить:$ sudo wondershaper clear интерфейс
Безболезненный upload с помощью Wondershaper
2010-10-12 01:38:00 (читать в оригинале)Наверное, многие замечали, особенно на домашнем интернете, что во время интенсивной закачивания данных в сеть (во время upload), соединение начинает «тормозить». Страницы сайтов подолгу не открываются, скачивание и медиапотоки подвисают на месте... Это легко измерить: у меня дома, например, пинг до гугла вырастает с 50 мс до порядка 1000 мс, при этом около 8% пакетов вообще теряются.
Причина этого явления (чаще всего) — загрузка в сеть занимает весь доступный исходящий канал, а соединения по протоколу TCP/IP требуют двухсторонней связи. Даже если мы пытаемся что-то просто скачать, машина должна посылать обратно пакеты подтверждения приёма (т.н. ACK). Если же исходящий канал весь занят, то и пакеты подтверждения, какими бы маленькими они не были, надолго задерживаются, и, соответственно, перестают приходить и входящие пакеты, даже если ширина входящего канала достаточна.
Решить эту проблему можно с помощью скрипта
wondershaper
(есть в составе большинства дистрибутивов). Он позволяет установить ограничения на скорость загрузки из сети и в сеть. Хитрость в том, чтобы вначале узнать свою реальную скорость соединения, а потом установить ограничения чуть-чуть ниже реальной доступной скорости. В этом случае будет всегда оставаться «запас» для своевременной передачи служебных пакетов, и задержки станут гораздо меньше.Например, я хочу выложить кучу фотографий на яндекс-фотки. Иду на internet.yandex.ru и измеряю скорость соединения с Яндексом, сегодня вечером у меня получилось так:
Можно пойти на testspeed.net или другую измерительную страничку. Можно измерить вручную. Главное, получить реальные значения скорости в килобитах в секунду.
После этого надо включить
wondershaper
на используемом сетевом интерфейсе и указать ему значения немного меньше измеренных. Сетевой интерфейс — это обычно wlan0
в случае соединения по WiFi, или eth0
в случае соединения по локальной сети. Чтобы уточнить, можно выполнить команду route -n
в терминале, имя используемого интерфейса искать в строке с флагами UG
.$ sudo wondershaper wlan0 3900 450
Готово. Запускаем загрузку в сеть (выкладываем фото, видео, раздаём торренты, и т.д.), измеряем время пинга. Чудесным образом, даже во время загрузки, пинг у меня упал до 61 мс, что не сильно больше его минимального значения при свободном канале, а веб-страницы стали скачиваться вполне шустро. Если не помогло с первого раза, можно попробовать ограничить скорость закачивания в сеть ещё сильнее.
Чтобы отключить
wondershaper
, выполнить:$ sudo wondershaper clear интерфейс
Как аппликативные функторы с if-ами боролись
2010-10-01 16:26:00 (читать в оригинале)Maybe А и Maybe Б сидели на трубе,
А упало, Б пропало, что осталось на трубе?
А упало, Б пропало, что осталось на трубе?
На днях заметил, как полезны могут быть аппликативные функторы для избавления от леса вложенных условных конструкций (
if
-ов и case
-ов). А именно, как удобно, что тип Maybe
можно использовать как аппликативный функтор.О функторах, пирогах и яблоках
Речь пойдёт о языке Хаскель, но постараюсь рассказать так, чтобы пользователям других языков было тоже понятно. Кто Хаскель знает, этот раздел может пропустить и сразу перейти к следующему.
Итак, для представления такого результата, которого может и не быть, в Хаскеле используется тип
Maybe a
, где a
— любой тип. У Maybe a
бывают значения двух видов: Just a
(«просто а», если значение есть) и Nothing
(«ничего», если значения нет). Maybe
является функтором, то есть из любой функции из a
в b
(тип :: a -> b
) можно сделать функцию из Maybe a
в Maybe b
(тип :: Maybe a -> Maybe b
). В общем, функтором является любой тип f
, для которого определена*:fmap :: (a -> b) -> (f a -> f b)
* определениеfmap
должно удовлетворять при этом двум условиям: 1)fmap id = id
, гдеid
— функция, возвращаюая свой аргумент, 2)fmap
должна быть дистрибутивна слева относительно композиции функций... [ссылка]
Например, пусть у нас есть типы
Яблоко
и Пирог
и функция испечь :: Яблоко -> Пирог
, превращающая одно в другое. Тогда мы легко можем взять яблоко, которого может и не быть, и испечь из него пирог, , которого может и не быть. То есть если будет просто яблоко, то выйдет просто пирог, а если ничего не было, то ничего и не выйдет. Делается это проще простого: fmap испечь
.data Яблоко = Яблоко deriving Show
data Пирог = Пирог deriving Show
испечь :: Яблоко -> Пирог
испечь Яблоко = Пирог
испечьЕслиЕсть :: (Maybe Яблоко) -> (Maybe Пирог)
испечьЕслиЕсть = fmap испечь
После этого мы можем печь пироги, которых может и не быть:
ghci> испечьЕслиЕсть (Just Яблоко)
Just Пирог
ghci> испечьЕслиЕсть Nothing
Nothing
А что делать, если самой функции из
a
в b
может и не быть? Как применить Maybe (a -> b)
к Maybe a
? Такая операция определена для аппликативных функторов, Maybe
— один из них. В Хаскеле для этого подключают модуль Control.Applicative
, саму же операцию последовательного применения называют звучным словом (<*>)
.Поясняю на яблоках. Что делать случае на входе у нас
Maybe (Яблоко -> Пирог)
— рецепт, которого может и не оказаться? Естественно, что пирог у нас получится тогда и только тогда, когда есть и яблоко, и сам рецепт. Если хоть что-то отсутствует, то и пирога не будет, будет Nothing
. Итак, дано:безРецепта = Nothing
сРецептом = Just испечь
Проверяем, как работает с такими «рецептами» аппликативный функтор
Maybe
:ghci> :m + Control.Applicative
ghci> сРецептом <*> Just Яблоко
Just Пирог
ghci> сРецептом <*> Nothing
Nothing
ghci> безРецепта <*> Just Яблоко
Nothing
ghci> безРецепта <*> Nothing
Nothing
Это всё, что нам сейчас потребуется из «теории». И ещё пара замечаний: 1) с аппликативными функторами часто применяется ещё операция
(<$>)
, которая является для них синонимом fmap
и в инфиксной записи выглядит короче; 2) любая монада является также аппликативным функтором (обратное неверное), и для неё ap
и (<*>)
совпадают (об этом полезно знать, хотя нам сейчас и не потребуется).Избавление от условных конструкций
Перехожу к практическим вопросам. На днях писал небольшой парсер для файлов формата Matrix Market. Это несложный формат, состоящий из заголовка в котором указывается, как хранится структура матрицы (покоординатно или сплошным массивом) и тип значений её элементов (целые, действительные или комплексные). Возможны разные комбинации.
Логику разбора такого формата на императивном псевдокоде можно описать так:
if (структура == координатная) {
if (тип == целые) {
читатьЦелыеПоКоординатам;
} else if (тип == действительные) {
читатьДействительныеПоКоординатам;
} else if (тип == комплексные) {
читатьКомплексныеПоКоординатам;
} else {
ошибка;
}
} else if (структура == массив) {
if (тип == целые) {
читатьМассивЦелых;
} else if (тип == действительные) {
читатьМассивДействительных;
} else if (тип == комплексные) {
читатьМассивКомплексных;
} else {
ошибка;
}
} else {
ошибка;
}
Естественно, что такого развесистого дерева выбора можно избежать, потому что выбор типа элементов и выбор структуры матрицы независимы друг от друга. В функциональном стиле можно просто составить «словарь» поддерживаемых функций для разбора структуры и отдельный «словарь» функций для чтения значений разных типов, выбирать подходящие, и потом передавать вторые в качестве параметра первым. Так я и сделал.
Опять псевдокод для пояснения этой идеи:
let читатьСтруктуру = lookup структура словарьФункцийРазбора
читатьЧисло = lookup тип словарьФункцийРазбораЧисла
in читатьСтруктуру читатьЧисло исходныеДанные
На практике дело обстоит немного сложнее. Операция поиска в словаре может ничего не найти. Как легко догадаться,
lookup
в Хаскеле возвращает Maybe a
. Итак, у нас есть Maybe функция
, Maybe аргумент
, а мы хотим получить Maybe результат
. Ничего не напоминает? Да-да, тут самое время применить (<*>)
.Однако представим на минуту, как эта задача решается без операции последовательного применения
Maybe a
. И для функции, и для её аргумента нужно проверять являются ли они чем-то (Just a
) или ничем (Nothing
), и в результате получается тот же лес проверок, что и в императивном псевдокоде, только в этот раз с проверкой на результат поиска. Можно, правда, все проверки объединить в одной единственной условной конструкции на каждое применение функции, но все проверки надо всё равно записывать явно. То есть без (<*>)
получается что-то такое:let читатьСтруктуру = lookup структура словарьФункцийРазбора
читатьЧисло = lookup тип словарьФункцийРазбораЧисла
in case (читатьСтруктуру, читатьЧисло) of
(Just f, Just g) -> Just (f g исходныеДанные)
_ -> Nothing
Код склонен паталогически ветвиться, если таких
Maybe
-аргументов у функции больше одного, или если полученный Maybe
-результат нужно использовать в качестве аргумента ещё одной функции (тут не обойтись без вложенных проверок).К счастью, все эти проверки тривиальны, и код можно записать гораздо короче:
let читатьСтруктуру = lookup структура словарьФункцийРазбора
читатьЧисло = lookup тип словарьФункцийРазбораЧисла
in читатьСтруктуру <*> читатьЧисло <*> (Just исходныеДанные)
Здесь нет ни одной явной условной конструкции, но код, тем не менее, делает все необходимые проверки, и вернёт
Just результат
только если нашлись обе функции.У меня получилось немного длиннее, но суть та же:
let p = lookup fmt parsers :: Maybe FormatReader
nr = lookup fieldq readers :: Maybe (Int, ValueReader)
sy = lookup symq symmetries :: Maybe Symmetry
p' = uncurry <$> p <*> nr :: Maybe ([String] -> Maybe MatrixData)
d = join $ p' <*> (Just toks) :: Maybe MatrixData
m = MM <$> d <*> sy :: Maybe Matrix
in ...
Что тут можно заметить. Во-первых,
(<$>)
практически так же часто используется, как и (<*>)
. Эта операция позволяет применять обычные функции к Maybe
-значениям. Вместо (<$>)
можно поднимать значения в функтор с помощью pure
(для любых аппликативных функторов) или Just
(конкретно для Maybe
) и использовать только (<*>)
.Во-вторых, если у нас кругом функции, возвращающие
Maybe
, и они сами оказываются внутри Maybe
(см. p'
в моём примере), то рано или поздно появляются «вложенные» значения типа Maybe (Maybe a)
. Тут помогает монадный join
, превращающий их в просто Maybe a
. join
определён в Control.Monad
. И кстати, это тоже помогает избавиться от вложенных тривиальных проверок (join (Just Nothing)
даёт Nothing
).В-третьих, при таком подходе мы, естественно, теряем информацию о том, какое именно вычисление не дало результата (дало
Nothing
). Для передачи «исключения» по цепочке можно использовать другие типы, например Either e
, определив для них Applicative
.Заключение
Мне такой способ комбинировать вычисления очень понравился. По-моему, случай, когда все условные проверки сводятся к «если в порядке, то считать дальше, а если нет, то прервать» — довольно распространённый. Тип
Maybe
с операцией последовательного применения (<*>)
позволяет такие проверки, любой степени вложенности, не писать вообще.
Категория «Новости»
Взлеты Топ 5
+903 |
934 |
Блог о подарках и праздниках |
+883 |
955 |
Kitten |
+876 |
942 |
And_So_On |
+846 |
1007 |
Уголок народного трейдера |
+814 |
958 |
ank |
Падения Топ 5
-1 |
255 |
Главная |
-1 |
4 |
Equillibrium |
-2 |
15 |
Elephant_Talk |
-6 |
771 |
Сибдепо / Блоги |
-6 |
5 |
lqp |
Популярные за сутки
Загрузка...
BlogRider.ru не имеет отношения к публикуемым в записях блогов материалам. Все записи
взяты из открытых общедоступных источников и являются собственностью их авторов.
взяты из открытых общедоступных источников и являются собственностью их авторов.