Введение в pygal для диаграмм Python

искусственный интеллект Python GitHub SVG
Введение в pygal для диаграмм Python

Простое использование pygal

Пример взят из этой книги: «Программирование на Python от вступления до реального боя» [США] Эрик Маттес.

pygal — это библиотека диаграмм SVG. _SVG_ — это формат векторной графики. Полное название Scalable Vector Graphics — масштабируемая векторная графика.

Откройте svg в браузере, вы можете легко с ним взаимодействовать.

Следующий код запускается в Jupyter Notebook.

Имитация броска костей

Давайте рассмотрим простой пример. Он имитирует бросание игральных костей.

import random

class Die:
    """
    一个骰子类
    """
    def __init__(self, num_sides=6):
        self.num_sides = num_sides

    def roll(self):
        return random.randint(1, self.num_sides)

Моделируйте броски костей и визуализируйте

import pygal

die = Die()
result_list = []
# 掷1000次
for roll_num in range(1000):
    result = die.roll()
    result_list.append(result)

frequencies = []
# 范围1~6,统计每个数字出现的次数
for value in range(1, die.num_sides + 1):
    frequency = result_list.count(value)
    frequencies.append(frequency)

# 条形图
hist = pygal.Bar()
hist.title = 'Results of rolling one D6 1000 times'
# x轴坐标
hist.x_labels = [1, 2, 3, 4, 5, 6]
# x、y轴的描述
hist.x_title = 'Result'
hist.y_title = 'Frequency of Result'
# 添加数据, 第一个参数是数据的标题
hist.add('D6', frequencies)
# 保存到本地,格式必须是svg
hist.render_to_file('die_visual.svg')

Откройте этот файл в браузере, наведите указатель мыши на данные, вы увидите, что отображается заголовок «D6», координаты по оси X и координаты по оси Y.

Можно обнаружить, что частота шести чисел одинакова (теоретическая вероятность равна 1/6, с увеличением количества экспериментов тенденция становится все более очевидной).

Бросьте два кубика одновременно

Просто немного измените код, а затем создайте экземпляр кости.

die_1 = Die()
die_2 = Die()

result_list = []
for roll_num in range(5000):
    # 两个骰子的点数和
    result = die_1.roll() + die_2.roll()
    result_list.append(result)

frequencies = []
# 能掷出的最大数
max_result = die_1.num_sides + die_2.num_sides

for value in range(2, max_result + 1):
    frequency = result_list.count(value)
    frequencies.append(frequency)

# 可视化
hist = pygal.Bar()
hist.title = 'Results of rolling two D6 dice 5000 times'
hist.x_labels = [x for x in range(2, max_result + 1)]
hist.x_title = 'Result'
hist.y_title = 'Frequency of Result'
# 添加数据
hist.add('two D6', frequencies)
# 格式必须是svg
hist.render_to_file('2_die_visual.svg')

Как видно из рисунка, сумма двух игральных костей равна 7 больше всего раз, а сумма 2 меньше всего. Потому что есть только один случай, когда можно выбросить 2 -> (1, 1), а случаи, когда можно выбросить 7, это (1, 6), (2, 5), (3, 4), (4). , 3), ( 5, 2), (6, 1) имеют в общей сложности 6 случаев, а остальные числа не так много, как 7, поэтому выпадение 7 имеет наибольшую вероятность.

Обработка данных json — карта населения мира

Требуются данные о населении.

нажмите сюда для того, чтобы скачатьpopulation.json, данные взяты изokfn.orgэтот сайт

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

[ 
{
 "Country Name":"Arab World",
 "Country Code":"ARB",
 "Year":"1960",
 "Value":"92496099"
 },
...

Ключей всего четыре, из нихCountry CodeОтносится к коду страны, который здесь состоит из 3 цифр.ValueЭто население.

import json

filename = r'F:\Jupyter Notebook\matplotlib_pygal_csv_json\population.json'
with open(filename) as f:
    # json.load()可以将json文件转为Python能处理的形式,这里位列表,列表里是字典
    pop_data = json.load(f)

cc_populations = {}
for pop_dict in pop_data:
    if pop_dict['Year'] == '2015':
        country_name = pop_dict['Country Name']
        # 有些值是小数,先转为float再转为int
        population = int(float(pop_dict['Value']))
        print(country_name + ': ' + population)

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

Arab World: 392168030
Caribbean small states: 7116360
Central Europe and the Baltics: 103256779
Early-demographic dividend: 3122757473.68203
East Asia & Pacific: 2279146555
...

Обратите внимание, что некоторые значения в данных о населении указаны в десятичных дробях (невероятно). Тип данных населения — это строка str, если вы преобразуете ее непосредственно в int, например'35435.12432'Такую строку нельзя сильно преобразовать в int, ее нужно сначала преобразовать в float, а затем преобразовать в int после потери точности.

Получите двухбуквенный код страны

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

pip install pygal_maps_worldпросто хорошо

код страны вi18nмодуль

from pygal_maps_world.i18n import COUNTRIESЭто импортировано, COUNTRIES — это словарь, ключ — это двузначный код страны, а значение — конкретное название страны.

key -> value
af Afghanistan
af Afghanistan
al Albania
al Albania
dz Algeria
dz Algeria
ad Andorra
ad Andorra
ao Angola

Напишите функцию для возврата двух кодов стран, предоставленных pygal, в соответствии с конкретным названием страны.

def get_country_code(country_name):
    """
    根据国家名返回两位国别码
    """
    for code, name in COUNTRIES.items():
        if name == country_name:
            return code
    return None

карта населения мира

Сначала дайте весь код, вам нужно использоватьWorldсвоего рода

import json

from pygal_maps_world.i18n import COUNTRIES
from pygal_maps_world.maps import World
# 颜色相关
from pygal.style import RotateStyle
from pygal.style import LightColorizedStyle

def get_country_code(country_name):
    """
    根据国家名返回两位国别码
    """
    for code, name in COUNTRIES.items():
        if name == country_name:
            return code
    return None

filename = r'F:\Jupyter Notebook\matplotlib_pygal_csv_json\population.json'
with open(filename) as f:
    pop_data = json.load(f)

cc_populations = {}
for pop_dict in pop_data:
    if pop_dict['Year'] == '2015':
        country_name = pop_dict['Country Name']

        # 有些值是小数,先转为float再转为int
        population = int(float(pop_dict['Value']))
        code = get_country_code(country_name)
        if code:
            cc_populations[code] = population

# 为了使颜色分层更加明显
cc_populations_1,cc_populations_2, cc_populations_3 = {}, {}, {}
for cc, population in cc_populations.items():
    if population < 10000000:
        cc_populations_1[cc] = population
    elif population < 1000000000:
        cc_populations_2[cc] = population
    else:
        cc_populations_3[cc] = population

wm_style = RotateStyle('#336699', base_style=LightColorizedStyle)
world = World(style=wm_style)
world.title = 'World Populations in 2015, By Country'
world.add('0-10m', cc_populations_1)
world.add('10m-1bn', cc_populations_2)
world.add('>1bn', cc_populations_3)
world.render_to_file('world_population_2015.svg')

Несколько переменных важнее

  • cc_populationsЭто dict, в котором хранятся две пары ключ-значение: код страны и население.
  • cc_populations_1,cc_populations_2, cc_populations_3Это 3 словаря, популяция разбита на ступени по количеству, а те, у которых популяция менее 10 миллионов, хранятся вcc_populations_1, от десяти миллионов до одного миллиарда уровней хранятся вcc_populations_2, более одного миллиарда хранится вcc_populations_3, ** Это сделано для того, чтобы сделать цветовую стратификацию более очевидной и чтобы легче было найти самую густонаселенную страну в каждой лестнице. **Поскольку он разделен на три уровня, при добавлении данных он также добавляется три раза, и три словаря передаются отдельно.
  • world = World(style=wm_style)Это класс карты, метод импортаfrom pygal_maps_world.maps import World
  • wm_style = RotateStyle('#336699', base_style=LightColorizedStyle)Здесь изменяется цвет темы pygal по умолчанию. Первый параметр — это цвет RGB в ** шестнадцатеричном формате. Первые две цифры представляют R, две средние представляют G, а последние две представляют B. Чем выше число, тем темнее цвет. **Второй параметр задает в качестве базового стиля яркую цветовую тему, pygal по умолчанию использует более темную цветовую тему, и этот метод может изменить стиль по умолчанию.

Босс Китая, №1

Как видно из рисунка, три цветовых уровня делятся на . Фиолетовый — больше миллиарда, синий — от десяти миллионов до миллиарда, зеленый — меньше десяти миллионов. Самый темный из трех цветов соответствует самой густонаселенной стране на трех лестницах.

<div class="image-package">
</div>

Если присмотреться, некоторые картинки пустые. Дело не в том, что в этих местах нет людей, а в том, что названия некоторых стран в наших данных json не соответствуют названиям стран модуля COUNTIES в pygal. Жаль, но это можно изменитьget_country_codeФункция не возвращает None при обнаружении неподходящего названия страны. Для этих стран проверьте код СТРАНЫ, узнайте соответствующий код страны, верните его, и все должно быть в порядке. например следующее

# 传入的参数country_name是json数据中的,可能与COUNTRIES里面的国家名不一致,按照上面的代码直接就返回None,导致绘图时这个国家的人口数据空白
if country_name == 'Yemen, Rep':
    return 'ye'

Но мне лень пробовать 233

Анализ данных с помощью веб-API

На примере GitHub я хочу увидеть самые популярные библиотеки Python. Сортировать по звездам.

доступэтот URLсмотреть. Данные выглядят так

{
  "total_count": 1767997,
  "incomplete_results": false,
  "items": [{
     {
       "id": 21289110,
      "name": "awesome-python",
      "full_name": "vinta/awesome-python",
      "owner": {
        "login": "vinta",
        ...
          },
       ...    
       "html_url": "https://github.com/vinta/awesome-python",
        ...
          "stargazers_count": 35234,
        ...

  }, {...}
      ...]
}

Третьи данные,items. Внутри топ-30 с наибольшим количеством звезд.nameто есть имя библиотеки,ownerвнизloginЯвляется владельцем библиотеки, html_url — это URL-адрес библиотеки (обратите внимание, что у владельца также есть html_url. Но это URL-адрес GitHub пользователя, мы хотим найти конкретную библиотеку пользователя, поэтому не используйте html_url под хозяином)stargazers_countВажно, количество полученных звезд.

Кстати, первый ключtotal_count, представляющий общее количество репозиториев на языке Python; второй ключ,incomplete_results, указывающее, что значение ответа является неполным, как правило, ложное, указывающее, что данные ответа являются полными.

import requests

url = 'https://api.github.com/search/repositories?q=language:python&sort=stars'
response = requests.get(url)
# 200为响应成功
print(response.status_code, '响应成功!')
response_dict = response.json()

total_repo = response_dict['total_count']
repo_list = response_dict['items']
print('总仓库数: ', total_repo)
print('top', len(repo_list))
for repo_dict in repo_list:
    print('\nName: ', repo_dict['name'])
    print('Owner: ', repo_dict['owner']['login'])
    print('Stars: ', repo_dict['stargazers_count'])
    print('Repo: ', repo_dict['html_url'])
    print('Description: ', repo_dict['description'])

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

200 响应成功!
总仓库数:  1768021
top 30

Name:  awesome-python
Owner:  vinta
Stars:  35236
Repo:  https://github.com/vinta/awesome-python
Description:  A curated list of awesome Python frameworks, libraries, software and resources

Name:  httpie
Owner:  jakubroztocil
Stars:  30149
Repo:  https://github.com/jakubroztocil/httpie
Description:  Modern command line HTTP client – user-friendly curl alternative with intuitive UI, JSON support, syntax highlighting, wget-like downloads, extensions, etc.  https://httpie.org

Name:  thefuck
Owner:  nvbn
Stars:  28535
Repo:  https://github.com/nvbn/thefuck
Description:  Magnificent app which corrects your previous console command.
...

Визуализация, конечно, была бы более интуитивной.

pygal визуализировать данные

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

import requests

import pygal
from pygal.style import LightColorizedStyle, LightenStyle

url = 'https://api.github.com/search/repositories?q=language:python&sort=stars'
response = requests.get(url)
# 200为响应成功
print(response.status_code, '响应成功!')
response_dict = response.json()

total_repo = response_dict['total_count']
repo_list = response_dict['items']
print('总仓库数: ', total_repo)
print('top', len(repo_list))

names, plot_dicts = [], []
for repo_dict in repo_list:
    names.append(repo_dict['name'])
    # 加上str强转,因为我遇到了'NoneType' object is not subscriptable (: 说明里面有个没有此项, 是NoneType
    plot_dict = {
        'value' : repo_dict['stargazers_count'],
        # 有些描述很长很长,选最前一部分
        'label' : str(repo_dict['description'])[:200]+'...',
        'xlink' : repo_dict['html_url']
    }
    plot_dicts.append(plot_dict)

# 改变默认主题颜色,偏蓝色
my_style = LightenStyle('#333366', base_style=LightColorizedStyle)
# 配置
my_config = pygal.Config()
# x轴的文字旋转45度
my_config.x_label_rotation = -45
# 隐藏左上角的图例
my_config.show_legend = False
# 标题字体大小
my_config.title_font_size = 30
# 副标签,包括x轴和y轴大部分
my_config.label_font_size = 20
# 主标签是y轴某数倍数,相当于一个特殊的刻度,让关键数据点更醒目
my_config.major_label_font_size = 24
# 限制字符为15个,超出的以...显示
my_config.truncate_label = 15
# 不显示y参考虚线
my_config.show_y_guides = False
# 图表宽度
my_config.width = 1000

# 第一个参数可以传配置
chart = pygal.Bar(my_config, style=my_style)
chart.title = 'Most-Starred Python Projects on GitHub'
# x轴的数据
chart.x_labels = names
# 加入y轴的数据,无需title设置为空,注意这里传入的字典,
# 其中的键--value也就是y轴的坐标值了
chart.add('', plot_dicts)
chart.render_to_file('most_stars_python_repo.svg')

Посмотрите на картинку ниже, эффект отображается в браузере хром. Я всегда чувствую, что некоторые настройки в конфиге не действуют, а метки осей x и y все еще такие маленькие или ... ноplot_dictОтображаются три данных внутри, нажмите, чтобы перейти.

Ну и накинем столько, эта библиотека не особо популярна...


исходный адрес