Главная страница
Навигация по странице:

  • Рис. 16.9.

  • Книга Изучаем Python


    Скачать 4.68 Mb.
    НазваниеКнига Изучаем Python
    Дата10.12.2022
    Размер4.68 Mb.
    Формат файлаpdf
    Имя файлаErik_Metiz_Izuchaem_Python_Programmirovanie_igr_vizualizatsia_da.pdf
    ТипКнига
    #837531
    страница39 из 53
    1   ...   35   36   37   38   39   40   41   42   ...   53
    УПРАЖНЕНИЯ
    16-1 . Сан-Франциско: к какому месту ближе температура в Сан-Франциско: к Ситке или
    Долине Смерти? Постройте температурную диаграмму для Сан-Франциско и сравните .
    (Погодные данные практически для любого места можно загрузить по адресу http://www .
    wunderground .com/history/ . Введите название места и диапазон дат, прокрутите страницу и найдите ссылку Comma-Delimited File . Щелкните правой кнопкой мыши на ссылке и со- храните данные в файле CSV .)
    16-2 . Сравнение Ситки с Долиной Смерти: разные масштабы температур отражают разные диапазоны данных . Чтобы точно сравнить температурный диапазон в Ситке с температурным диапазоном Долины Смерти, необходимо установить одинаковый масштаб по оси y . Изме- ните параметры оси y для одной или обеих диаграмм на рис . 16 .5 и 16 .6 и проведите пря- мое сравнение температурных диапазонов в этих двух местах (или любых других, которые вас интересуют) . Также можно попробовать нанести два набора данных на одну диаграмму .
    16-3 . Осадки: выберите любое место и постройте диаграмму с уровнем осадков . Для начала ограничьтесь данными за один месяц, а когда ваш код заработает, выполните программу для данных за полный год .
    16-4 . Исследования: постройте еще несколько визуализаций, отражающих любые другие аспекты погоды для интересующих вас мест .
    Формат JSON
    В этом разделе мы загрузим данные о странах в формате JSON и будем работать с ними при помощи модуля json
    . Используя удобные средства Pygal для работы с географическими данными, мы построим визуализации, отражающие распреде- ление населения по странам.
    Загрузка демографических данных
    Скопируйте файл population_data .json
    , содержащий данные о численности населения большинства стран мира с 1960 по 2010 год, в каталог с программами этой главы.

    Формат JSON 349
    Информация взята из многочисленных наборов данных, бесплатно публикуемых фондом Open Knowledge Foundation (http://data.okfn.org/).
    Извлечение необходимых данных
    Взглянем на файл population_data .json и попробуем понять, как взяться за обработку данных файла:
    population_data.json
    [
    {
    "Country Name": "Arab World",
    "Country Code": "ARB",
    "Year": "1960",
    "Value": "96388069"
    },
    {
    "Country Name": "Arab World",
    "Country Code": "ARB",
    "Year": "1961",
    "Value": "98882541.4"
    },
    ]
    Фактически перед нами один длинный список Python. Каждый элемент списка представляет собой словарь с четырьмя ключами: название страны (
    Country
    Name
    ), код страны (
    Country
    Code
    ), год (
    Year
    ) и значение (
    Value
    ), представляющее числен- ность населения. В нашей программе будут использоваться названия стран и чис- ленность населения только за 2010 год, поэтому для начала напишем программу, которая выводит только эту информацию:
    world_population.py
    import json
    # Список заполняется данными.
    filename = 'population_data.json'
    with open(filename) as f:
     pop_data = json.load(f)
    # Вывод населения каждой страны за 2010 год.
     for pop_dict in pop_data:
     if pop_dict['Year'] == '2010':
     country_name = pop_dict['Country Name']
    population = pop_dict['Value']
    print(country_name + ": " + population)
    Сначала программа импортирует модуль json
    , чтобы иметь возможность загружать данные из файла. Загруженные данные сохраняются в списке pop_data
    . Функ- ция json.load()
    преобразует данные в формат, с которым может работать Python: в данном случае это список. В точке  создается цикл, перебирающий все элементы

    350 Глава 16 • Загрузка данных pop_data
    . Каждый элемент представляет собой словарь с четырьмя парами «ключ—
    значение», который сохраняется в переменной pop_dict
    В точке  ключ 'Year'
    каждого словаря проверяется на значение 2010. (Так как все значения population_data .json заключены в кавычки, выполняется сравнение строк.)
    Если словарь относится к 2010 году, то значение, связанное с ключом 'Country
    Name'
    , сохраняется в переменной country_name
    , а значение, связанное с ключом 'Value'
    , сохраняется в переменной population
    . Затем программа выводит на- звание каждой страны и ее население.
    Программа выводит последовательность названий стран и численности их на- селения:
    Arab World: 357868000
    Caribbean small states: 6880000
    East Asia & Pacific (all income levels): 2201536674
    Zimbabwe: 12571000
    Не все данные включают точные названия стран, но это неплохое начало для даль- нейшей работы. Теперь данные необходимо преобразовать в формат, с которым может работать Pygal.
    Преобразование строк в числовые значения
    Все ключи и значения в population_data .json хранятся в строковом формате. Чтобы работать с данными численности населения, необходимо преобразовать строковые значения в числа. Для этого в программе используется функция int()
    :
    world_population.py
    for pop_dict in pop_data:
    if pop_dict['Year'] == '2010':
    country_name = pop_dict['Country Name']
     population = int(pop_dict['Value'])
     print(country_name + ": " + str(population))
    После преобразования  все данные численности населения хранятся в число- вом формате. При выводе численность населения должна быть преобразована в строку . Впрочем, для некоторых значений это изменение приводит к ошибке:
    Arab World: 357868000
    Caribbean small states: 6880000
    East Asia & Pacific (all income levels): 2201536674
    Traceback (most recent call last):
    File "print_populations.py", line 12, in population = int(pop_dict['Value'])

    ValueError: invalid literal for int() with base 10:
    '1127437398.85751'
    Необработанные данные часто форматируются непоследовательно, поэтому ошибки в них встречаются достаточно часто. В данном случае ошибка происхо-

    Формат JSON 351
    дит из-за того, что Python не может преобразовать строку с дробным значением '1127437398.85751'
    в целое число . (Вероятно, дробное значение было получено в результате интерполяции в те годы, в которые перепись населения не производи- лась.) Чтобы решить эту проблему, мы сначала преобразуем строку в вещественное число, а затем преобразуем вещественное число в целое:
    world_population.py
    for pop_dict in pop_data:
    if pop_dict['Year'] == '2010':
    country = pop_dict['Country Name']
    population = int(float(pop_dict['Value']))
    print(country + ": " + str(population))
    Функция float()
    преобразует строку в целое число, а функция int()
    отсекает дробную часть и возвращает целое число. Теперь можно вывести полный набор данных численности населения за 2010 год без ошибок:
    Arab World: 357868000
    Caribbean small states: 6880000
    East Asia & Pacific (all income levels): 2201536674
    Zimbabwe: 12571000
    Каждая строка успешно преобразуется сначала в вещественное, а затем в целое число. Обратите внимание: данные хранятся в числовом формате, чтобы их можно было использовать для построения карты распределения населения.
    Получение кодов стран
    Прежде чем переходить к построению карты, необходимо разобраться еще с одним аспектом данных. Инструментарий Pygal для работы с географическими картами ожидает получить данные в четко определенном формате: страны должны задавать- ся кодами стран, а численность населения — значениями. Существует несколько стандартных наборов кодов стран, часто применяемых при работе с геополитиче- скими данными; коды, включенные в population_data .json
    , состоят из трех букв, но
    Pygal использует систему с двухбуквенными кодами. Нужно найти способ полу- чения двухбуквенных кодов стран по их названиям.
    Коды стран Pygal хранятся в модуле i18n
    (сокращение от «internationalization»).
    В словаре
    COUNTRIES
    двухбуквенные коды стран являются ключами, а названия стран — значениями. Чтобы просмотреть коды, импортируйте словарь из модуля i18n и выведите его ключи и значения:
    countries.py
    from pygal.i18n import COUNTRIES
     for country_code in sorted(COUNTRIES.keys()):
    print(country_code, COUNTRIES[country_code])
    В цикле for ключи сортируются в алфавитном порядке . Затем программа выво- дит каждый код страны и страну, с которой этот код связан:

    352 Глава 16 • Загрузка данных ad Andorra ae United Arab Emirates af Afghanistan zw Zimbabwe
    Напишем функцию, которая перебирает
    COUNTRIES
    и возвращает коды стран.
    Функция будет размещаться в отдельном модуле с именем country_codes
    , чтобы ее можно было позднее импортировать в программу визуализации:
    country_codes.py
    from pygal.i18n import COUNTRIES
     def get_country_code(country_name):
    """Возвращает для заданной страны ее код Pygal, состоящий из 2 букв."""
     for code, name in COUNTRIES.items():
     if name == country_name:
    return code
    # Если страна не найдена, вернуть None.
     return None print(get_country_code('Andorra'))
    print(get_country_code('United Arab Emirates'))
    print(get_country_code('Afghanistan'))
    Название страны передается функции get_country_code()
    и сохраняется в па- раметре country_name
    . Затем программа перебирает пары «код—название» в
    COUNTRIES
    . Если название страны будет найдено, функция возвращает код страны , а если нет — после цикла добавляется строка, возвращающая
    None
    .
    Наконец, программа передает названия трех стран для проверки функции. Как и ожидалось, программа выводит три двухбуквенных кода:
    ad ae af
    Прежде чем переходить к использованию функции, удалите три команды print из country_codes .py
    Затем функция get_country_code()
    импортируется в world_population .py
    :
    world_population.py
    import json from country_codes import get_country_code
    # Вывод населения каждой страны за 2010 год.
    for pop_dict in pop_data:
    if pop_dict['Year'] == '2010':
    country_name = pop_dict['Country Name']
    population = int(float(pop_dict['Value']))
     code = get_country_code(country_name)
    if code:
     print(code + ": "+ str(population))

    Формат JSON 353
     else:
    print('ERROR - ' + country_name)
    После извлечения названия и населения в code сохраняется код страны — или
    None
    , если код недоступен . Если код получен, то код и население страны выводятся ко- мандой print . Если код недоступен, выводится сообщение об ошибке с названием страны, для которого не удалось найти код . Запустите программу, и вы увидите коды стран с населением и несколько сообщений об ошибках:
    ERROR - Arab World
    ERROR - Caribbean small states
    ERROR - East Asia & Pacific (all income levels)
    af: 34385000
    al: 3205000
    dz: 35468000
    ERROR - Yemen, Rep.
    zm: 12927000
    zw: 12571000
    Ошибки происходят по двум причинам. Во-первых, классификация в наборе дан- ных не всегда осуществляется по странам; часть статистики относится к регионам или экономическим группам. Во-вторых, в части статистики используется другая запись полных названий стран (
    Yemen,
    Rep.
    вместо
    Yemen
    ). Пока опустим данные стран, вызывающие ошибки, и посмотрим, как будет выглядеть карта с успешно прочитанными данными.
    Построение карты мира
    С имеющимися кодами стран карта мира строится легко и просто. В Pygal под- держивается тип диаграммы
    Worldmap
    , упрощающий работу с географическими наборами данных. В качестве примера использования
    Worldmap мы создадим про- стую карту с данными по Северной, Центральной и Южной Америке:
    americas.py
    import pygal
     wm = pygal.Worldmap()
    wm.title = 'North, Central, and South America'
     wm.add('North America', ['ca', 'mx', 'us'])
    wm.add('Central America', ['bz', 'cr', 'gt', 'hn', 'ni', 'pa', 'sv'])
    wm.add('South America', ['ar', 'bo', 'br', 'cl', 'co', 'ec', 'gf',
    'gy', 'pe', 'py', 'sr', 'uy', 've'])
     wm.render_to_file('americas.svg')
    В точке  мы создаем экземпляр класса
    Worldmap и задаем атрибут title объекта карты. В точке  используется метод add()
    , который получает метку и список кодов стран, на которых вы хотите сосредоточиться. Каждый вызов add()
    создает новый цвет для набора стран и добавляет этот цвет в список условных обозначений

    354 Глава 16 • Загрузка данных в левой части диаграммы с заданным текстом. Весь регион Северной Америки будет представлен одним цветом, поэтому мы включаем коды 'ca'
    ,
    'mx'
    и 'us'
    в список, передаваемый первому вызову add()
    , для единого представления на карте Канады,
    Мексики и Соединенных Штатов. Затем то же самое делается для стран Централь- ной и Южной Америки.
    Метод render_to_file()
    в точке  создает файл
    .svg с диаграммой; вы можете от- крыть этот файл в своем браузере. На полученной карте Северная, Центральная и Южная Америка выделены другими цветами (рис. 16.7).
    Рис. 16.7. Простой экземпляр диаграммы Worldmap
    Теперь вы знаете, как создать карту с цветными областями, условные обозна- чения и аккуратные метки. Добавим на карту данные для вывода информации о стране.
    Нанесение числовых данных на карту мира
    Чтобы потренироваться с нанесением числовых данных на карту, создайте карту с населением трех стран Северной Америки:
    na_populations.py
    import pygal wm = pygal.Worldmap()
    wm.title = 'Populations of Countries in North America'

    wm.add('North America', {'ca': 34126000, 'us': 309349000, 'mx':
    113423000})
    wm.render_to_file('na_populations.svg')

    Формат JSON 355
    Рис. 16.8. Численность населения стран Северной Америки
    Сначала мы создаем экземпляр
    Worldmap и назначаем заголовок. Далее снова следу- ет вызов add()
    , но на этот раз во втором аргументе передается словарь вместо спи- ска . Словарь содержит двухбуквенные коды стран Pygal (ключи) и численность населения (значения). Pygal автоматически использует числа для окраски стран от светлых (менее населенные) до темных (наиболее населенные). На рис. 16.8 показана полученная карта.
    Эта карта интерактивна: если вы наведете указатель мыши на каждую страну, то увидите ее население. Добавим на карту побольше данных.
    Построение полной карты населения
    Чтобы нанести на карту данные численности населения для других стран, об- работанные ранее данные необходимо преобразовать в формат словаря Pygal: с двухбуквенными кодами стран и численностью населения, образующими пары
    «ключ—значение». Добавьте следующий код в world_population .py
    :
    world_population.py
    import json import pygal from country_codes import get_country_code
    # Список заполняется данными.
    # Построение словаря с данными численности населения.

    356 Глава 16 • Загрузка данных

    cc_populations = {}
    for pop_dict in pop_data:
    if pop_dict['Year'] == '2010':
    country = pop_dict['Country Name']
    population = int(float(pop_dict['Value']))
    code = get_country_code(country)
    if code:
     cc_populations[code] = population
     wm = pygal.Worldmap()
    wm.title = 'World Population in 2010, by Country'
     wm.add('2010', cc_populations)
    wm.render_to_file('world_population.svg')
    Сначала импортируется модуль pygal
    . В точке  создается пустой словарь для хранения кодов стран и численности населения в формате, принятом Pygal. В точ- ке  для полученных кодов строится очередной элемент словаря cc_populations
    ; ключом пары становится код страны, а значением — численность населения. Также из программы удаляются все команды print
    Мы создаем экземпляр
    Worldmap и задаем его атрибут title
    . При вызове add()
    передается словарь с кодами стран и значениями численности населения .
    На рис. 16.9 изображена полученная карта.
    Несколько стран, для которых данные отсутствуют, окрашены в черный цвет, но большинство стран раскрашено в соответствии с размером населения. Проблемой отсутствующих данных мы займемся позднее в этой главе, а сначала приведем тон закраски в соответствие с населением стран. В настоящее время на карте слишком
    Рис. 16.9. Численность мирового населения в 2010 году

    Формат JSON 357
    много стран окрашено в светлые тона, а стран с темной окраской всего две. Кон- траст между большинством стран попросту недостаточен для того, чтобы зритель мог понять, в какой стране больше или меньше население. Чтобы решить эту про- блему, мы сгруппируем страны по уровням населения и окрасим каждую группу по отдельности.
    Группировка стран по населению
    Китай и Индия по численности населения опережают все остальные страны, по- этому нашей карте не хватает контраста. И в Китае, и в Индии проживает свыше миллиарда человек, тогда как в следующей по численности населения стране —
    Соединенных Штатах — население составляет около 300 миллионов. Вместо того чтобы наносить на диаграмму все страны в одной группе, разделим страны на три уровня населения: менее 10 миллионов, от 10 миллионов до 1 миллиарда и более
    1 миллиарда:
    world_population.py
    # Построение словаря с данными численности населения.
    cc_populations = {}
    for pop_dict in pop_data:
    if pop_dict['Year'] == '2010':
    --snip-- if code:
    cc_populations[code] = population
    # Группировка стран по 3 уровням населения.
     cc_pops_1, cc_pops_2, cc_pops_3 = {}, {}, {}
     for cc, pop in cc_populations.items():
    if pop < 10000000:
    cc_pops_1[cc] = pop elif pop < 1000000000:
    cc_pops_2[cc] = pop else:
    cc_pops_3[cc] = pop
    # Проверка количества стран на каждом уровне.
     print(len(cc_pops_1), len(cc_pops_2), len(cc_pops_3))
    wm = pygal.Worldmap()
    wm.title = 'World Population in 2010, by Country'
    x wm.add('0-10m', cc_pops_1)
    wm.add('10m-1bn', cc_pops_2)
    wm.add('>1bn', cc_pops_3)
    wm.render_to_file('world_population.svg')
    Чтобы сгруппировать страны, мы создаем пустой словарь для каждой категории .
    Затем программа перебирает cc_populations и проверяет население каждой стра- ны . Блок if
    - elif
    - else добавляет элемент в соответствующий словарь (
    cc_pops_1
    , cc_pops_2
    или cc_pops_3
    ) для каждой пары «код страны—население».

    358 Глава 16 • Загрузка данных
    Рис. 16.10. Численность мирового населения в 2010 году
    В точке  выводится длина каждого словаря для определения размеров групп.
    При нанесении данных на диаграмму  все три группы добавляются на диаграмму
    Worldmap
    . При запуске программы сначала выводятся размеры всех групп:
    85 69 2
    Вывод показывает, что существуют 85 стран с населением менее 10 миллионов,
    69 стран с населением от 10 миллионов до 1 миллиарда и две особые страны с населением свыше 1 миллиарда. Разбиение получается достаточно равномерным для получения содержательной карты. Полученная карта изображена на рис. 16.10.
    Три разных цвета помогают подчеркнуть различия между уровнями населения.
    В каждом из трех уровней страны окрашиваются от светлого к темному оттенку в соответствии с ростом численности населения.
    Оформление карты мира в Pygal
    Группировка стран на карте работает эффективно, но цвета по умолчанию вы- бираются довольно странно: например, в нашем примере Pygal выбирает схему с ярко-розовым и зеленым цветом. Директивы оформления Pygal помогут решить проблему с цветами.
    В новой версии мы снова прикажем Pygal использовать один базовый цвет, но на этот раз выберем цвет и применим более выразительные оттенки для трех групп численности населения:
    world_population.py
    import json

    Формат JSON
    1   ...   35   36   37   38   39   40   41   42   ...   53


    написать администратору сайта