Визуализация данных в Web с использованием Python

  Коллеги-экономисты, вас не тормозят привычные инструменты бизнес-аналитики? Может быть пора уже попробовать встать на правильный путь, изучить Python и заняться более глубоким анализом социально‑экономических процессов, так, как это делается во всём мире?

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

33 способа визуализации
Инфографика, которая стимулировала изучение инструментов визуализации на Python.

Тщательнее: Диаграмма, График функции, Блок‑схема, Карта памяти, Облако тегов (Облако слов), Дерево решений, Диаграмма Гантта, Гистограмма, Диаграмма Эйлера, Диаграмма Венна

Быстрый старт с Bokeh

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

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

Pycharm и Bokeh

С инструментарием для разработки мы уже определились и подробнее прочитать о нём можно в статье PyCharm — эффективная разработка на Python. Поэтому невзирая на то, что в оригинальной документации Bokeh предполагается использовать Jupiter Notebook, для своих упражнений будем использовать Pycharm. Для нас подойдёт любая версия от Education до Professional.

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

Создаём демо-проект
Создаём демо-проект
Начинаем настройку виртуального окружения
Начинаем настройку виртуального окружения
Назначаем базовый интерпретатор Python 3.8.6
Назначаем базовый интерпретатор Python 3.8.6
Подключаем требуемые для проекта пакеты Bokeh, Numpy, pandas. Ну, и связанные с ними
Подключаем требуемые для проекта пакеты bokeh, numpy, pandas. Ну, и связанные с ними, которые сами встанут благодаря pip

Теперь всё готово для начала наших экспериментов.

Создаём файл <code>bars.py</code> и копипастим первый скрипт с этой страницы в окно редактора Pycharm.
Создаём файл bars.py и копипастим первый скрипт с этой страницы в окно редактора Pycharm.

Запускаем скрипт bars.py из контекстного меню, но можно и любым другим доступным способом
Запускаем скрипт bars.py из контекстного меню, но можно и любым другим доступным способом

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

Окно браузера. Обратите внимание на адрес показываемого ресурса file:///D:/PHYTON/quickstart-bokeh/bars.html
Окно браузера. Обратите внимание на адрес показываемого ресурса file:///D:/PHYTON/quickstart-bokeh/bars.html

В папке вашего проекта появился новый файл bars.html, который после работы скрипта вы видите в окне навигатора проекта Pycharm. Его можно прочитать своим браузером и/или загрузить куда-нибудь в интернет на доступные вам ресурсы хостинга. Вот так передаются сообществам результаты своих исследований, просто файл .html и никакого «шаманства».

В результате работы скрипта появился новый файл bars.tml
В результате работы скрипта появился новый файл bars.html

Теперь файл bars.html можно опубликовать на любом сервере, что и сделано, и в чём вы можете убедиться, пройдя по ссылке Live Demo: Строим гистограмму.

С дальнейшими примера поступаем точно так-же.

  1. Строим Гистограмму:
    from bokeh.io import show, output_file
    from bokeh.plotting import figure
    
    output_file("bars.html")
    
    fruits = ['Яблоки', 'Груши', 'Нектарин', 'Сливы', 'Виноград', 'Клубника']
    counts = [5, 3, 4, 2, 4, 6]
    
    p = figure(x_range=fruits, plot_height=250, title="Фрукты (количество)",
               toolbar_location=None, tools="")
    
    p.vbar(x=fruits, top=counts, width=0.9)
    
    p.xgrid.grid_line_color = None
    p.y_range.start = 0
    
    show(p)
    

    Live Demo: Строим гистограмму

  2. Строим Отсортированную гистограмму:
    from bokeh.io import show, output_file
    from bokeh.plotting import figure
    
    output_file("bar_sorted.html")
    
    fruits = ['Яблоки', 'Груши', 'Нектарин', 'Сливы', 'Виноград', 'Клубника']
    counts = [5, 3, 4, 2, 4, 6]
    
    # sorting the bars means sorting the range factors
    sorted_fruits = sorted(fruits, key=lambda x: counts[fruits.index(x)])
    
    p = figure(x_range=sorted_fruits, plot_height=350, title="Фрукты (количество)",
               toolbar_location=None, tools="")
    
    p.vbar(x=fruits, top=counts, width=0.9)
    
    p.xgrid.grid_line_color = None
    p.y_range.start = 0
    
    show(p)
    

    Live Demo: Строим отсортированную гистограмму

  3. Строим Цветную гистограмму:
    from bokeh.io import show, output_file
    from bokeh.models import ColumnDataSource
    from bokeh.palettes import Spectral6
    from bokeh.plotting import figure
    
    output_file("color_bars.html")
    
    fruits = ['Яблоки', 'Груши', 'Нектарин', 'Сливы', 'Виноград', 'Клубника']
    counts = [5, 3, 4, 2, 4, 6]
    
    source = ColumnDataSource(data=dict(fruits=fruits, counts=counts, color=Spectral6))
    
    p = figure(x_range=fruits, y_range=(0,9), plot_height=250, title="Количество фруктов",
               toolbar_location=None, tools="")
    
    p.vbar(x='fruits', top='counts', width=0.9, color='color', legend_field="fruits", source=source)
    
    p.xgrid.grid_line_color = None
    p.legend.orientation = "horizontal"
    p.legend.location = "top_center"
    
    show(p)
    

    Live Demo: Строим цветную гистограмму

  4. Скрип Пример простой линии:
    from bokeh.plotting import figure, output_file, show
    
    # prepare some data
    x = [1, 2, 3, 4, 5]
    y = [6, 7, 2, 4, 5]
    
    # output to static HTML file
    output_file("lines.html")
    
    # create a new plot with a title and axis labels
    p = figure(title="Пример простой линии", x_axis_label='x', y_axis_label='y')
    
    # add a line renderer with legend and line thickness
    p.line(x, y, legend="Обозначение", line_width=2)
    
    # show the results
    show(p)
    

    Live Demo: Пример простой линии

  5. Скрипт Цветные графики с логарифмической шкалой:
    from bokeh.plotting import figure, output_file, show
    
    # prepare some data
    x = [0.1, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0]
    y0 = [i**2 for i in x]
    y1 = [10**i for i in x]
    y2 = [10**(i**2) for i in x]
    
    # output to static HTML file
    output_file("log_lines.html")
    
    # create a new plot
    p = figure(
       tools="pan,box_zoom,reset,save",
       y_axis_type="log", y_range=[0.001, 10**11], title="Пример графиков с логарифмической шкалой",
       x_axis_label='область определения', y_axis_label='значение функций'
    )
    
    # add some renderers
    p.line(x, x, legend="y=x")
    p.circle(x, x, legend="y=x", fill_color="white", size=8)
    p.line(x, y0, legend="y=x^2", line_width=3)
    p.line(x, y1, legend="y=10^x", line_color="red")
    p.circle(x, y1, legend="y=10^x", fill_color="red", line_color="red", size=6)
    p.line(x, y2, legend="y=10^x^2", line_color="orange", line_dash="4 4")
    
    # show the results
    show(p)
    

    Live Demo: Цветные графики с логарифмической шкалой

  6. Аналитика Импорт/Экспорт фруктов по годам:
    from bokeh.io import output_file, show
    from bokeh.models import ColumnDataSource
    from bokeh.palettes import GnBu3, OrRd3
    from bokeh.plotting import figure
    
    output_file("stacked_split.html")
    
    fruits = ['Яблоки', 'Груши', 'Нектарин', 'Сливы', 'Виноград', 'Клубника']
    years = ["2015", "2016", "2017"]
    
    exports = {'fruits' : fruits,
               '2015'   : [2, 1, 4, 3, 2, 4],
               '2016'   : [5, 3, 4, 2, 4, 6],
               '2017'   : [3, 2, 4, 4, 5, 3]}
    imports = {'fruits' : fruits,
               '2015'   : [-1, 0, -1, -3, -2, -1],
               '2016'   : [-2, -1, -3, -1, -2, -2],
               '2017'   : [-1, -2, -1, 0, -2, -2]}
    
    p = figure(y_range=fruits, plot_height=250, x_range=(-16, 16), title="Импорт/Экспорт фруктов по годам",
               toolbar_location=None)
    
    p.hbar_stack(years, y='fruits', height=0.9, color=GnBu3, source=ColumnDataSource(exports),
                 legend_label=["%s экспорт" % x for x in years])
    
    p.hbar_stack(years, y='fruits', height=0.9, color=OrRd3, source=ColumnDataSource(imports),
                 legend_label=["%s импорт" % x for x in years])
    
    p.y_range.range_padding = 0.1
    p.ygrid.grid_line_color = None
    p.legend.location = "top_left"
    p.axis.minor_tick_line_color = None
    p.outline_line_color = None
    
    show(p)
    

    Live Demo: Импорт/Экспорт фруктов по годам

  7. Комментарии к объектам на рисунках:
    from bokeh.io import output_file, show
    from bokeh.models import GeoJSONDataSource
    from bokeh.plotting import figure
    from bokeh.sampledata.sample_geojson import geojson
    import json
    
    output_file("geojson.html")
    
    data = json.loads(geojson)
    for i in range(len(data['features'])):
        data['features'][i]['properties']['Color'] = ['blue', 'red'][i%2]
    
    geo_source = GeoJSONDataSource(geojson=json.dumps(data))
    
    TOOLTIPS = [
        ('Организация', '@OrganisationName')
    ]
    
    p = figure(background_fill_color="lightgrey", tooltips=TOOLTIPS)
    p.circle(x='x', y='y', size=15, color='Color', alpha=0.7, source=geo_source)
    
    show(p)
    

    Live Demo: Комментарии к объектам на рисунках

  8. Посмотрим на карту Google:
    from bokeh.io import output_file, show
    from bokeh.models import ColumnDataSource, GMapOptions
    from bokeh.plotting import gmap
    
    output_file("gmap.html")
    
    map_options = GMapOptions(lat=30.2861, lng=-97.7394, map_type="roadmap", zoom=11)
    
    # For GMaps to function, Google requires you obtain and enable an API key:
    #
    #     https://developers.google.com/maps/documentation/javascript/get-api-key
    #
    # Replace the value below with your personal API key:
    p = gmap("GOOGLE_API_KEY", map_options, title="Austin")
    
    source = ColumnDataSource(
        data=dict(lat=[ 30.29,  30.20,  30.29],
                  lon=[-97.70, -97.74, -97.78])
    )
    
    p.circle(x="lon", y="lat", size=15, fill_color="blue", fill_alpha=0.8, source=source)
    
    show(p)
    

    Live Demo: Посмотрим на карту Google

    Примечание: карта Google работает коряво, не прописал ключ API. Заведите свой GOOGLE_API_KEY и наслаждайтесь.

  9. Посмотрим как изменяются координаты «мышки»:
    import numpy as np
    from bokeh.io import show, output_file
    from bokeh.plotting import figure
    from bokeh import events
    from bokeh.models import CustomJS, Div, Button
    from bokeh.layouts import column, row
    
    def display_event(div, attributes=[], style = 'float:left;clear:left;font_size=10pt'):
        "Build a suitable CustomJS to display the current event in the div model."
        return CustomJS(args=dict(div=div), code="""
            var attrs = %s; var args = [];
            for (var i = 0; i
    

    Live Demo: Посмотрим как изменяются координаты «мышки»

  10. Интерактивность — Подвигаем полозок и поменяем график:
     
    from bokeh.layouts import column
    from bokeh.models import CustomJS, ColumnDataSource, Slider
    from bokeh.plotting import Figure, output_file, show
    
    output_file("js_on_change.html")
    
    x = [x*0.005 for x in range(0, 200)]
    y = x
    
    source = ColumnDataSource(data=dict(x=x, y=y))
    
    plot = Figure(plot_width=400, plot_height=400)
    plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6)
    
    callback = CustomJS(args=dict(source=source), code="""
        var data = source.data;
        var f = cb_obj.value
        var x = data['x']
        var y = data['y']
        for (var i = 0; i < x.length; i++) {
            y[i] = Math.pow(x[i], f)
        }
        source.change.emit();
    """)
    
    slider = Slider(start=0.1, end=4, value=1, step=.1, title="Двигаем этот полозок")
    slider.js_on_change('value', callback)
    
    layout = column(slider, plot)
    
    show(layout)
    

    Live Demo: Подвигаем полозок и поменяем график

  11. Интерактивность — Просто карта:
    from bokeh.plotting import figure, show, output_file
    from bokeh.tile_providers import get_provider, Vendors
    
    output_file("tile.html")
    
    tile_provider = get_provider(Vendors.CARTODBPOSITRON)
    
    # range bounds supplied in web mercator coordinates
    p = figure(x_range=(-2000000, 6000000), y_range=(-1000000, 7000000),
               x_axis_type="mercator", y_axis_type="mercator")
    p.add_tile(tile_provider)
    
    show(p)
    

    Live Demo: Просто карта

Для ленивых, но любопытных все коды лежат на Github, так что идите туда.

Наслаждайтесь и наращивайте свои компетенции в Python ... Счастливого и удачного PY-тонинга!

CC BY-NC 4.0 Визуализация данных в Web с использованием Python, опубликовано К ВВ, лицензия — Creative Commons Attribution-NonCommercial 4.0 International.


Респект и уважуха

Добавить комментарий