<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="http://wiki.linuxformat.ru/wiki/skins/common/feed.css?303"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://wiki.linuxformat.ru/wiki/index.php?action=history&amp;feed=atom&amp;title=LXF126%3APython</id>
		<title>LXF126:Python - История изменений</title>
		<link rel="self" type="application/atom+xml" href="http://wiki.linuxformat.ru/wiki/index.php?action=history&amp;feed=atom&amp;title=LXF126%3APython"/>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/index.php?title=LXF126:Python&amp;action=history"/>
		<updated>2026-05-13T15:39:13Z</updated>
		<subtitle>История изменений этой страницы в вики</subtitle>
		<generator>MediaWiki 1.19.20+dfsg-0+deb7u3</generator>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/index.php?title=LXF126:Python&amp;diff=11400&amp;oldid=prev</id>
		<title>Crazy Rebel: викификация, оформление, иллюстрация</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/index.php?title=LXF126:Python&amp;diff=11400&amp;oldid=prev"/>
				<updated>2011-02-15T08:02:35Z</updated>
		
		<summary type="html">&lt;p&gt;викификация, оформление, иллюстрация&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Новая страница&lt;/b&gt;&lt;/p&gt;&lt;div&gt;: '''''Python''''' Используйте сведения от Flickr для создания карт с геоданными&lt;br /&gt;
&lt;br /&gt;
==''Python'': Место на карте==&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Python}}&lt;br /&gt;
&lt;br /&gt;
: '''Ник Вейч''' вновь зачертил, но на сей раз идея хороша: найти самые фотогеничные участки вашей местности при помощи карт с геоданными…&lt;br /&gt;
&lt;br /&gt;
Верите вы или нет, но у меня есть подруга. Ей-Богу. Это реальный человек. Зовут ее Пэм, а живет она в Тампа, Флорида. В прошлом году она собиралась в Барселону и спросила, что там стоит фотографировать. А ведь это зависит от вкуса, верно? Кто-то хочет заснять обычные туристические объекты, как все, а иной предпочитает исследовать менее «затертые» части города. Вы можете прочесать сайты с фотографиями, но на самом деле вам нужна карта.&lt;br /&gt;
&lt;br /&gt;
Множество фотоаппаратов и мобильников с камерами теперь внедряют в свои изображения геотэги – указывая широту и долготу – наряду с добавлением других Exif-данных. Сайты с фотографиями, подобные Flickr, записывают эту информацию и делают ее доступной. Так нельзя ли создать карту типа «где в этом городе люди делают снимки»?&lt;br /&gt;
&lt;br /&gt;
===WOE — это я===&lt;br /&gt;
&lt;br /&gt;
В 2008 году Yahoo открыла для разработчиков свою службу геолокации. Одной из ключевых концепций была иерархия уникальных ID для мест или областей этой планеты. Например, один ID идентифицирует такую вещь, как Эйфелева башня. Он будет связан с другими ID, таким как квартал, район, город, область, страна и т. д. Эти числовые ID получили название ''Where On Earth [Где на Земле] ID'', или '''WOEID''', и теперь широко используются в других геолокационных службах, включая Flickr. Более подробно о WOEID можно прочитать на http://developer.yahoo.com/geo/geoplanet/guide/concepts.html, но сейчас вам важно знать, что каждый город имеет WOEID, а многие еще и разбиты на районы, также имеющие свои WOEID.&lt;br /&gt;
&lt;br /&gt;
Итак, как узнать WOEID какой-либо местности? Yahoo требует, чтобы вы зарегистрировались и получили ключ API, чтобы воспользоваться ее службами и найти ответ на данный вопрос. Однако, как мы говорили, Flickr также поддерживает WOEID, и, имея доступ к его «песочнице», мы сможем сделать тестовый запрос и получить WOEID интересующего нас города. Перейдите на http://www.flickr.com/services/api/explore/?method=flickr.places.find и введите ‘Barcelona’. Из полученных данных станет ясно, что WOEID для Барселоны – 753692.&lt;br /&gt;
&lt;br /&gt;
API Flickr также включают другой полезный метод с более длинным именем '''places.getChildrenWithPhotosPublic()'''. Он возвращает структурированный список данных, представляющий собой потомков той области, что вы указали. В случае города, потомками будут районы и/или, в некоторых случаях, почтовые индексы региона. Каждый из них снабжается долготой и широтой центра области и количеством общедоступных фотографий в ней.&lt;br /&gt;
&lt;br /&gt;
Чтобы использовать для запросов API Flickr, необходимо иметь учетную запись на Flickr и обратиться за ключом API – см. врезку. Кроме того, раздобудьте модуль API Flickr для ''Python'', что выливается просто в загрузку пакета для вашего дистрибутива или посещение http://stuvel.eu/projects/flickrapi.&lt;br /&gt;
&lt;br /&gt;
Заполучив эти компоненты, вы сможете увидеть, как работает ваш сборщик WOEID-изображений.&lt;br /&gt;
&lt;br /&gt;
  &amp;gt;&amp;gt;&amp;gt;import flickrapi&lt;br /&gt;
  &amp;gt;&amp;gt;&amp;gt;apikey=’bxxxxxxxxxx2’&lt;br /&gt;
  &amp;gt;&amp;gt;&amp;gt;woeid=753692&lt;br /&gt;
  &amp;gt;&amp;gt;&amp;gt;flickr = flickrapi.FlickrAPI(apikey)&lt;br /&gt;
  &amp;gt;&amp;gt;&amp;gt;request=flickr.places_getChildrenWithPhotosPublic(woe_id=woeid)&lt;br /&gt;
  &amp;gt;&amp;gt;&amp;gt;list=request[0].getchildren()&lt;br /&gt;
  &amp;gt;&amp;gt;&amp;gt;for item in list:&lt;br /&gt;
  ... if item.attrib[‘place_type_id’] == ‘22’:&lt;br /&gt;
  ... print item.attrib[‘latitude’], item.attrib[‘longitude’]&lt;br /&gt;
  ... print item.text&lt;br /&gt;
  ...&lt;br /&gt;
  41.380 2.176&lt;br /&gt;
  Ciutat Vella, Barcelona, Catalonia, ES, Spain&lt;br /&gt;
  41.393 2.161&lt;br /&gt;
  L’example, Barcelona, Catalonia, ES, Spain&lt;br /&gt;
  41.383 2.183&lt;br /&gt;
  Barceloneta, Barcelona, Catalonia, ES, Spain&lt;br /&gt;
  41.386 2.177&lt;br /&gt;
  Ribera, Barcelona, Catalonia, ES, Spain&lt;br /&gt;
  41.406 2.179&lt;br /&gt;
  La Dreta De L’eixample, Barcelona, Catalonia, ES, Spain&lt;br /&gt;
  41.379 2.167&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
Мы вызвали метод '''getChildrenWithPublicPhotos''', который вернул результат. При тестировании его на сайте Flickr мы видели, что он возвращает объект с одним элементом, по имени '''places''', содержащим список мест, соответствующих запросу. Чтобы получить сам список, раскроем объект при помощи метода '''.getChildren''' и проверим, пройдя по списку, что в полученных данных '''place_type''' означает соседство, тип '''22'''. Причина тут в том, что некоторые области имеют перекрывающиеся объекты – например, области с почтовым кодом или районы, и некоторые снимки могут быть посчитаны дважды, исказив результат.&lt;br /&gt;
&lt;br /&gt;
Метод '''.attrib()''' возвращает именованные значения (по ключу) из объектов отдельных мест и текст-описание, хранящийся в свойстве '''.text'''. Среди других значений – '''photo_count''' и WOEID района. Если у нас имеются значения известных точек, можно отобразить их на диаграмме и показать наиболее фотографируемые области, не так ли? Теперь осталось приискать способ создания привлекательной графики из имеющихся данных.&lt;br /&gt;
&lt;br /&gt;
===Строим диаграмму===&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF126_77_1.jpg|300px]] OpenStreetMap – лучший источник юридически чистых картографических сведений, которые можно отображать и публиковать.|Ширина=300px}}}}&lt;br /&gt;
&lt;br /&gt;
Если нужно построить контуры, гистограмму или график по точкам, каждый уважающий себя питонист первым делом обращается к модулю ''Mathplotlib''. Как и его проприетарный кузен ''Matlab'', ''Mathplotlib'' – это библиотека функций для преобразования данных в нечто приятное глазу. И опять-таки этот модуль ''Python'' обычно имеется в вашем дистрибутиве. Можно также установить модуль ''Numpy'': он добавляет в ''Python'' несколько удобных возможностей и функций для визуализации данных, включая многомерные массивы.&lt;br /&gt;
&lt;br /&gt;
''Matplotlib'' содержит полезную функцию с именем '''contourf''', которая просто берет список значений '''x, y''' и '''z''' и строит на их базе контурные цветные области вокруг точек с максимальным значением – по сути, это карта температур. Но прежде чем передать данные, следует устранить проблему: функция '''contourf''' работает только с данными в виде равномерной сетки, а наши точки и значения распределены случайным образом. Решение – создать пустую сетку данных, а затем наложить на нее наши значения при помощи какого-либо метода интерполяции. Вот почему модуль ''Numpy'' вам очень пригодится.&lt;br /&gt;
&lt;br /&gt;
Метод '''numpy.linspace()''' возвращает список, заполненный набором числовых значений из заданного диапазона – а это нам и нужно для создания сетки '''x–y'''. Затем мы сможем воспользоваться функцией '''griddata''' из ''Matplotlib'' для интерполяции наших точек в нормальную сетку. Тогда наш код будет выглядеть так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=Python&amp;gt;&lt;br /&gt;
 for item in list:&lt;br /&gt;
   if item.attrib[‘place_type_id’] == ‘22’:&lt;br /&gt;
      y.append(float(item.attrib[‘latitude’]))&lt;br /&gt;
      x.append(float(item.attrib[‘longitude’]))&lt;br /&gt;
      z.append(int(item.attrib[‘photo_count’]))&lt;br /&gt;
 xmin=min(x)&lt;br /&gt;
 xmax=max(x)&lt;br /&gt;
 ymin=min(y)&lt;br /&gt;
 ymax=max(y)&lt;br /&gt;
 x += xmin, xmin, xmax, xmax&lt;br /&gt;
 y += ymin, ymax, ymin, ymax&lt;br /&gt;
 z += 0, 0, 0, 0&lt;br /&gt;
 yrange=ymax­ymin&lt;br /&gt;
 xrange=xmax­xmin&lt;br /&gt;
 maxrange=max(xrange, yrange)&lt;br /&gt;
 stepsize=maxrange/500&lt;br /&gt;
 # создаем пустую сетку&lt;br /&gt;
 xi = numpy.linspace(xmin,xmax,int(xrange/stepsize))&lt;br /&gt;
 yi = numpy.linspace(ymin,ymax,int(yrange/stepsize))&lt;br /&gt;
 # вносим данные в сетку&lt;br /&gt;
 zi = griddata(x,y,z,xi,yi)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь мы позаботились и о других двух моментах. Получение максимальных и минимальных значений для '''x''' и '''y''' дает нам границы прямоугольной области. Мы можем добавить эти точки (и нулевые значения) в наш массив данных, чтобы убедиться, что построенные контуры доходят до края карты. Кроме того, мы можем использовать эти данные для расчета шага нашей сетки. Не все города квадратные, поэтому мы изменяем размер шага в соответствии с занимаемой ими площадью.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Осталось только воспользоваться функцией '''contourf''' для построения градиента вокруг областей и отобразить их (и сохранить в виде файла):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
 CS = plt.contour(xi,yi,zi,15,linewidths=0.5,colors=’k’)&lt;br /&gt;
 CS = plt.contourf(xi,yi,zi,15,cmap=plt.cm.jet)&lt;br /&gt;
 plt.colorbar() # рисуем цвет ную полоску&lt;br /&gt;
 # отображаем точки данных&lt;br /&gt;
 plt.scatter(x,y,marker=’o’,c=’b’,s=5)&lt;br /&gt;
 plt.xlim(xmin,xmax)&lt;br /&gt;
 plt.ylim(ymin,ymax)&lt;br /&gt;
 plt.title(‘Barcelona’)&lt;br /&gt;
 plt.savefig(‘barcac.svg’)&lt;br /&gt;
 plt.show()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь мы сперва построили контурную черную '''(’k’)''' линию толщиной 0,5, затем применили метод цветной заливки контуров. Параметр '''cmap''' – одна из предопределенных цветовых карт ''Matplotlib'', дающая хороший диапазон от голубого через желтый до красного.&lt;br /&gt;
&lt;br /&gt;
Остается наложить созданное изображение на карту. Можно бы зайти на Google Maps, но их карты, естественно, не ваша, а их собственность, поэтому лучше взять картографические данные от OpenStreetMap.&lt;br /&gt;
&lt;br /&gt;
Простого метода изъятия PNG из указанного места нет, но вы можете загрузить его вручную, перейдя на вкладку '''Export''' на главной странице карты и введя широту и долготу местности, карту которой желаете загрузить. Выберите отрисовку '''OSM''' при наибольшем приближении.&lt;br /&gt;
&lt;br /&gt;
Изображение-карта и созданная карта температур могут быть совмещены в ''GIMP, Scribus'' или ''Inkscape''. По-моему, в ''Inkscape'' это проще всего, потому что можно загрузить SVG-версию контурной карты, установить прозрачность 50 % и растянуть ее над картой улиц. Соотношение сторон не будет таким же, поскольку в нашей контурной карте предполагается, что шаг по x и y одинаков, а на сферической поверхности Земли это не так, но для малых областей искажения минимальны.&lt;br /&gt;
&lt;br /&gt;
Тем не менее, чтобы получить информацию, соответствующую реальности, необходимо растянуть контур до размера карты.&lt;br /&gt;
&lt;br /&gt;
===Подождите, это еще не все===&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF126_78_1.jpg|300px]] По этому рисунку с наложением точно видно, где люди делают снимки в Бате — хороший индикатор достопримечательностей.|Ширина=300px}}}}&lt;br /&gt;
&lt;br /&gt;
Этот подход работает только для большой местности, имеющей достаточно данных о соседях, чтобы в результате получить значимую информацию. Чтобы получить более точный вид или отрисовать области с малым числом соседей или вообще без них, необходимо действовать по-другому. Лобовой метод – загрузить информацию обо всех снимках, сделанных в требуемом районе. Для большого города это неподъемно, но, например, для городка Бат [курортное место, где находятся Башни LXF] вполне в пределах досягаемости.&lt;br /&gt;
&lt;br /&gt;
Основной метод Flickr '''photos.search()''' предоставляет механизм для извлечения данных только из некоторых WOEID. Затем информация об изображениях возвращается в виде постраничного списка, и по запросу в эти данные будут включены сведения о географическом положении.&lt;br /&gt;
&lt;br /&gt;
Поскольку Flickr-сервера ворочаются со скрипом, лучше вытащить информацию для последующей обработки в файл – тогда нам не надо будет загружать данные о городе более одного раза. Их предварительный просмотр также даст нам возможность отсеять снимки с неверными геолокационными тэгами (иногда изображения помечаются как обладающие геоданными, но содержат нулевые широту и долготу) или с невысокой точностью.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
 import flickrapi&lt;br /&gt;
 apikey=’bxxxxxxxx52’ #your key here&lt;br /&gt;
 out=open(“bath.csv”,”w”)&lt;br /&gt;
 woeid=12056&lt;br /&gt;
 geolist=[]&lt;br /&gt;
 flickr = flickrapi.FlickrAPI(apikey)&lt;br /&gt;
 #request=flickr.interestingness_getList(extras=’geo’,&lt;br /&gt;
 per_page=500)&lt;br /&gt;
 request = flickr.photos_search(woe_id=woeid, per_page=250)&lt;br /&gt;
 foo=request.getchildren()&lt;br /&gt;
 pages=int(foo[0].items()[3][1])&lt;br /&gt;
 print pages&lt;br /&gt;
 for i in range(1, pages+1):&lt;br /&gt;
    try:&lt;br /&gt;
      request = flickr.photos_search(woe_id=woeid, extras=’geo’,per_page=250, page=i)&lt;br /&gt;
      foo=request.getchildren()&lt;br /&gt;
      bar=foo[0].getchildren()&lt;br /&gt;
      #bar теперь список фотоэлемен тов&lt;br /&gt;
      print ‘attempt ‘+str(i)&lt;br /&gt;
      for pic in bar:&lt;br /&gt;
         if (pic.attrib[‘accuracy’])&amp;gt;14:&lt;br /&gt;
            lat=(float(pic.attrib[‘latitude’]))&lt;br /&gt;
            lon=(float(pic.attrib[‘longitude’]))&lt;br /&gt;
            if (lat, lon)!=(0.0, 0.0):&lt;br /&gt;
               out.writelines(str(lat)+’, ‘+str(lon) +’\n’)&lt;br /&gt;
      except:&lt;br /&gt;
         print ‘skipped ‘ + str(i)&lt;br /&gt;
 out.close&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Этот скрипт пробегает все страницы результатов поиска данных и сохраняет широту и долготу в простом формате '''CSV'''. Мы можем воспользоваться этим файлом для создания более точной карты. Но нужно все-таки сгенерировать сетку данных; наш случай отличается отсутствием оси '''z'''. У нас просто есть точки, а значения в них одинаковы. Поэтому, воспользовавшись тем же подходом, что и раньше, мы получим плоское изображение. Для количественной оценки данных их следует сгруппировать. &lt;br /&gt;
&lt;br /&gt;
Мы можем сделать это, создав, как и ранее, пустую сетку, а затем пройти повсем точкам и определить, к какому «квадрату» новой сетки они относятся. Увеличение каждого отдельного значения массива '''z''' в случае принадлежности точки квадрату даст нам заполненность каждого из них, а на базе этого можно строить диаграмму.&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Заголовок=Скорая помощь|Содержание=Команда '''matplotlibplt.show()''' открывает окно и останавливает выполнение скрипта, пока отображается картинка – вызывайте ее в самом конце вашего приложения.|Ширина=200px}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
 import matplotlib.pyplot as plt&lt;br /&gt;
 import numpy as np&lt;br /&gt;
 import matplotlib.cm as cm&lt;br /&gt;
 ####читаем данные&lt;br /&gt;
 lats=[]&lt;br /&gt;
 lons=[]&lt;br /&gt;
 a = open(‘bath.csv’, ‘r’)&lt;br /&gt;
 for line in a.readlines():&lt;br /&gt;
   lats.append(float(line.split(‘,’)[0]))&lt;br /&gt;
   lons.append(float(line.split(‘,’)[1]))&lt;br /&gt;
 print ‘Data points: ‘, len(lats)&lt;br /&gt;
 xmin=min(lons)&lt;br /&gt;
 xmax=max(lons)&lt;br /&gt;
 ymin=min(lats)&lt;br /&gt;
 ymax=max(lats)&lt;br /&gt;
 yrange=ymax­ymin&lt;br /&gt;
 xrange=xmax­xmin&lt;br /&gt;
 maxrange=max(xrange, yrange)&lt;br /&gt;
 stepsize=maxrange/100&lt;br /&gt;
 limit =int(len(lats)/20)&lt;br /&gt;
 print ‘area mapped:’&lt;br /&gt;
 print xmin, xmax&lt;br /&gt;
 print ymin, ymax&lt;br /&gt;
 #define a new grid&lt;br /&gt;
 xi = np.linspace(xmin,xmax,int(xrange/stepsize))&lt;br /&gt;
 yi = np.linspace(ymin,ymax,int(yrange/stepsize))&lt;br /&gt;
 zi = np.ones((len(yi), len(xi)))&lt;br /&gt;
 print ‘xi dimension ‘ +str(len(xi))&lt;br /&gt;
 print ‘yi dimension ‘ +str(len(yi))&lt;br /&gt;
 print ‘zi dimension ‘+ str(zi.shape)&lt;br /&gt;
 for yindex in range(len(lats)):&lt;br /&gt;
   #find which box it goes into&lt;br /&gt;
   xx=lons[yindex]­xmin&lt;br /&gt;
   xx=int(xx/stepsize)­1&lt;br /&gt;
   yy=lats[yindex]­ymin&lt;br /&gt;
   yy=int(yy/stepsize)­1&lt;br /&gt;
   if zi[yy, xx] &amp;lt; limit:&lt;br /&gt;
      zi[yy, xx]+=1&lt;br /&gt;
 Plot = plt.contourf(xi,yi,zi,15,cmap=plt.cm.jet)&lt;br /&gt;
 plt.savefig(‘bath.svg’)&lt;br /&gt;
 plt.show()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Окончательная доработка===&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF126_79_1.jpg|300px]] Метод подсчета соседей дает гладкие контуры и хорошее представление о том, где люди делают снимки, но его трудно применить к конкретному месту.|Ширина=300px}}}}&lt;br /&gt;
&lt;br /&gt;
Есть еще кое-что, требующее доработки. Переменная '''limit''' была введена в связи с тем, что, скорее всего, немало изображений будут иметь одинаковые координаты. Даже в логарифмической шкале их количество «задавит» остальные части карты. В нашем скрипте '''limit''' вычисляется как процент от общего количества изображений в области – если результат не вдохновляет, поиграйте с этим значением, но '''20 %''' вроде бы хорошо работает для большинства мест.&lt;br /&gt;
&lt;br /&gt;
Еще один варьируемый параметр – количество квадратов нашей сетки. За него отвечает строка:&lt;br /&gt;
&lt;br /&gt;
 stepsize=maxrange/100&lt;br /&gt;
&lt;br /&gt;
Фактически мы получаем 100 интервалов вдоль более длинной стороны. Другая сторона вычисляется в соответствии с этим значением. Вы можете счесть, что 100 – слишком мало. Увеличение шага сетки повышает гранулярность результата, но также и «шум» изображения, и в конце концов вы получите на экране практически двоичные данные.&lt;br /&gt;
&lt;br /&gt;
===Еще о чтении карт===&lt;br /&gt;
&lt;br /&gt;
Посмотрите ''Basemap'' (http://matplotlib.sourceforge.net/basemap/doc/html/), облегчающую отрисовку элементов в различных проекциях на реальной карте мира.&lt;br /&gt;
&lt;br /&gt;
Документация Flickr API (http://www.flickr.com/services/api) не только информативна, но и предоставляет удобную функцию пробных вызовов API на web-странице.&lt;br /&gt;
&lt;br /&gt;
О WOEID и других полезных сервисах читайте на Yahoo GeoPlanet (http://developer.yahoo.com/geo/geoplanet/guide/).&lt;br /&gt;
&lt;br /&gt;
''Matplotlib'', http://matplotlib.sourceforge.net, – это модуль ''Python'' для построения различных диаграмм.&lt;br /&gt;
&lt;br /&gt;
И, наконец, посетите http://stuvel.eu/projects/flickrapi для лучшего интерфейса Python–Flickr.&lt;/div&gt;</summary>
		<author><name>Crazy Rebel</name></author>	</entry>

	</feed>