№7

From Fiery Butterfly, 1 Year ago, written in Plain Text, viewed 697 times.
URL http://codebin.org/view/8742de2d Embed
Download Paste or View Raw
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3.  
  4. import dash
  5. import dash_core_components as dcc
  6. import dash_html_components as html
  7. from dash.dependencies import Input, Output
  8.  
  9. import plotly.graph_objs as go
  10.  
  11. from datetime import datetime
  12.  
  13. import pandas as pd
  14.  
  15. # задаём данные для отрисовки
  16. from sqlalchemy import create_engine
  17.  
  18. # пример подключения к базе данных для Postresql
  19. #db_config = {'user': 'my_user',
  20. #             'pwd': 'my_user_password',
  21. #             'host': 'localhost',
  22. #             'port': 5432,
  23. #             'db': 'games'}
  24. #engine = create_engine('postgresql://{}:{}@{}:{}/{}'.format(db_config['user'],
  25. #                                                            db_config['pwd'],
  26. #                                                            db_config['host'],
  27. #                                                            db_config['port'],
  28. #                                                            db_config['db']))
  29. # пример подключения к базе данных для Sqlite
  30. engine = create_engine('sqlite:////db/games.db', echo=False)
  31.  
  32. # получаем сырые данные
  33. query = '''
  34.             SELECT * FROM agg_games_year_genre_platform
  35.         '''
  36. agg_games_year_genre_platform = pd.io.sql.read_sql(query, con = engine)
  37. agg_games_year_genre_platform['year_of_release'] = pd.to_datetime(agg_games_year_genre_platform['year_of_release'])
  38.  
  39. query = '''
  40.             SELECT * FROM agg_games_year_score
  41.         '''
  42. agg_games_year_score = pd.io.sql.read_sql(query, con = engine)
  43. agg_games_year_score['year_of_release'] = pd.to_datetime(agg_games_year_score['year_of_release'])
  44. # игнорируем записи без оценок
  45. agg_games_year_score = agg_games_year_score.query('avg_user_score > 0 and avg_critic_score > 0')
  46.  
  47. note = '''
  48.           Этот дашборд показывает историю игрового рынка (исключая мобильные устройства).
  49.           Используйте выбор интервала даты выпуска, жанра и платформы для управления дашбордом.
  50.           Используйте селектор выбора режима отображения для того, чтобы показать абсолютные
  51.           или относительные значения выпуска и продаж игр по годам.
  52.        '''
  53.  
  54. # задаём лейаут
  55. external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
  56. app = dash.Dash(__name__, external_stylesheets=external_stylesheets, compress=False)
  57. app.layout = html.Div(children=[  
  58.  
  59.     # формируем html
  60.     html.H1(children = 'История игрового рынка'),
  61.  
  62.     html.Br(),  
  63.  
  64.     html.Div([
  65.         html.Div([
  66.  
  67.             # график выпуска игр по годам и жанрам
  68.             html.Label('Выпуск игр по жанрам:'),    
  69.  
  70.             dcc.RadioItems(
  71.                 options = [
  72.                     {'label': 'Абсолютные значения', 'value': 'absolute_values'},
  73.                     {'label': '% от общего выпуска', 'value': 'relative_values'},
  74.                 ],
  75.                 value = 'absolute_values',
  76.                 id = 'mode_selector'
  77.             ),
  78.  
  79.  
  80.             dcc.Graph(
  81.                 id = 'launches_by_genre'
  82.             ),  
  83.         ], className = 'eight columns'),            
  84.  
  85.         html.Div([
  86.             # график выпуска игр по платформам
  87.              html.Label('Выпуск игр по платформам:'),
  88.             dcc.Graph(
  89.                 id = 'launches_by_platform'
  90.             ),    
  91.         ], className = 'four columns'),
  92.  
  93.     ], className = 'row'),
  94.  
  95.     html.Div([
  96.         html.Div([
  97.  
  98.             # график выпуска игр по годам и жанрам
  99.             html.Label('Продажи игр по жанрам:'),    
  100.  
  101.             dcc.Graph(
  102.                 id = 'sales_by_genre'
  103.             ),  
  104.         ], className = 'eight columns'),            
  105.  
  106.         html.Div([
  107.             # график средних оценок по жанрам
  108.             html.Label('Средние оценки по жанрам:'),    
  109.  
  110.             dcc.Graph(
  111.                 id = 'scores_by_genre'
  112.             ),  
  113.         ], className = 'four columns'),
  114.  
  115.     ], className = 'row'),  
  116.  
  117.  
  118.     # пояснения
  119.     html.Label(note),    
  120.  
  121.     html.Br(),    
  122.  
  123.     html.Div([  
  124.  
  125.         html.Div([
  126.             # выбор временного периода
  127.             html.Label('Года выпуска:'),
  128.             dcc.DatePickerRange(
  129.                 start_date = agg_games_year_genre_platform['year_of_release'].dt.date.min(),
  130.                 end_date = datetime(2016,1,1).strftime('%Y-%m-%d'),
  131.                 display_format = 'YYYY-MM-DD',
  132.                 id = 'dt_selector',      
  133.             ),
  134.         ], className = 'two columns'),
  135.  
  136.         html.Div([    
  137.             # выбор жанра
  138.             html.Label('Жанры:'),
  139.             dcc.Dropdown(
  140.                 options = [{'label': x, 'value': x} for x in agg_games_year_genre_platform['genre'].unique()],
  141.                 value = agg_games_year_genre_platform['genre'].unique().tolist(),
  142.                 multi = True,
  143.                 id = 'genre_selector'
  144.             ),                  
  145.         ], className = 'four columns'),    
  146.  
  147.         html.Div([        
  148.             # выбор платформы
  149.             html.Label('Платформы:'),
  150.             dcc.Dropdown(
  151.                 options = [{'label': x, 'value': x} for x in agg_games_year_genre_platform['platform'].unique()],
  152.                 value = agg_games_year_genre_platform['platform'].unique().tolist(),
  153.                 multi = True,
  154.                 id = 'platform_selector'
  155.             ),                
  156.         ], className = 'six columns'),
  157.  
  158.     ], className = 'row'),        
  159.  
  160. ])
  161.  
  162. # описываем логику дашборда
  163. @app.callback(
  164.     [Output('launches_by_genre', 'figure'),
  165.      Output('launches_by_platform', 'figure'),
  166.      Output('sales_by_genre', 'figure'),
  167.      Output('scores_by_genre', 'figure'),
  168.     ],
  169.     [Input('dt_selector', 'start_date'),
  170.      Input('dt_selector', 'end_date'),
  171.      Input('mode_selector', 'value'),
  172.      Input('genre_selector', 'value'),
  173.      Input('platform_selector', 'value'),
  174.     ])
  175. def update_figures(start_date, end_date, mode, selected_genres, selected_platforms):
  176.  
  177.     # применяем фильтрацию
  178.     filtered = agg_games_year_genre_platform.query('year_of_release >= @start_date and year_of_release <= @end_date')
  179.     filtered = filtered.query('genre in @selected_genres')
  180.     filtered = filtered.query('platform in @selected_platforms')
  181.  
  182.     filtered_score = agg_games_year_score.query('year_of_release >= @start_date and year_of_release <= @end_date')
  183.     filtered_score = filtered_score.query('genre in @selected_genres')
  184.     filtered_score = filtered_score.query('platform in @selected_platforms')
  185.  
  186.     games_by_genre = (filtered.groupby(['year_of_release', 'genre'])
  187.                       .agg({'games': 'sum', 'total_copies_sold': 'sum'})
  188.                       .reset_index()
  189.                      )
  190.  
  191.     games_by_platform = (filtered.groupby(['platform'])
  192.                          .agg({'games': 'sum'})
  193.                          .reset_index()
  194.                         )
  195.     # все платформы с малым количеством игр помещаем в одну категорию
  196.     games_by_platform['percent'] = games_by_platform['games'] / games_by_platform['games'].sum()
  197.     games_by_platform.loc[games_by_platform['percent'] < 0.05, 'platform'] = 'Другие'
  198.     # и ещё раз группируем
  199.     games_by_platform = (games_by_platform.groupby(['platform'])
  200.                          .agg({'games': 'sum'})
  201.                          .reset_index()
  202.                         )
  203.  
  204.     # трансформируем в соотв. с выбранным режимом отображения
  205.     y_label = 'Выпущенные игры'
  206.     y_label_sales = 'Продажи игр, млн копий'
  207.     if mode == 'relative_values':
  208.         y_label = '% выпущенных игр'
  209.         y_label_sales = '% продаж игр'
  210.         total = (games_by_genre.groupby('year_of_release')
  211.                  .agg({'games': 'sum', 'total_copies_sold': 'sum'})
  212.                  .rename(columns = {'games': 'total_launches',
  213.                                     'total_copies_sold': 'total_sales'})
  214.                 )
  215.         games_by_genre = (games_by_genre.set_index('year_of_release')
  216.                           .join(total)
  217.                           .reset_index())
  218.         games_by_genre['games'] = games_by_genre['games'] / games_by_genre['total_launches']
  219.         games_by_genre['total_copies_sold'] = games_by_genre['total_copies_sold'] / games_by_genre['total_sales']
  220.  
  221.     # графики выпуска и продаж игр по жанру
  222.     launches_by_genre = []
  223.     sales_by_genre = []
  224.     for genre in games_by_genre['genre'].unique():
  225.         launches_by_genre += [go.Scatter(x = games_by_genre.query('genre == @genre')['year_of_release'],
  226.                                     y = games_by_genre.query('genre == @genre')['games'],
  227.                                     mode = 'lines',
  228.                                     stackgroup = 'one',
  229.                                     name = genre)]
  230.         sales_by_genre += [go.Bar(x = games_by_genre.query('genre == @genre')['year_of_release'],
  231.                                   y = games_by_genre.query('genre == @genre')['total_copies_sold'],
  232.                                   name = genre)]
  233.  
  234.     # график выпуска игр по платформам    
  235.     launches_by_platform = [go.Pie(labels = games_by_platform['platform'],
  236.                                values = games_by_platform['games'],
  237.                                name = 'platfroms')]
  238.  
  239.     # точечная диаграмма оценок по жанрам и годам
  240.     scores_by_genre = []
  241.     for genre in filtered_score['genre'].unique():
  242.         scores_by_genre += [go.Scatter(x = filtered_score.query('genre == @genre')['avg_user_score'],
  243.                                        y = filtered_score.query('genre == @genre')['avg_critic_score'],
  244.                                        mode = 'markers',
  245.                                        name = genre)]
  246.  
  247.     # формируем результат для отображения
  248.     return (
  249.         {
  250.             'data': launches_by_genre, # напишите код
  251.             'layout': go.Layout(xaxis = {'title': 'Год'},
  252.                                 yaxis = {'title': y_label})
  253.         },
  254.         {
  255.             'data': launches_by_platform, # напишите код
  256.             'layout': go.Layout(xaxis = {'title': 'Год'},
  257.                                 yaxis = {'title': y_label_sales},
  258.                                 barmode = 'stack',
  259.                                )
  260.         },            
  261.         {
  262.             'data': sales_by_genre, # напишите код
  263.             'layout': go.Layout()
  264.         },
  265.         {
  266.             'data': scores_by_genre, # напишите код
  267.             'layout': go.Layout(xaxis = {'title': 'Средняя оценка пользователей'},
  268.                                 yaxis = {'title': 'Средняя оценка критиков'})
  269.         },            
  270.  
  271.     )  
  272.  
  273. if __name__ == '__main__':
  274.     app.run_server(host='0.0.0.0', port=3000)

Replies to №7 rss

Title Name Language When
Re: №4 Mungo Crane text 11 Months ago.

Reply to "№7"

Here you can reply to the paste above