- #!/usr/bin/python
- # -*- coding: utf-8 -*-
- import dash
- import dash_core_components as dcc
- import dash_html_components as html
- from dash.dependencies import Input, Output
- import plotly.graph_objs as go
- from datetime import datetime
- import pandas as pd
- # задаём данные для отрисовки
- from sqlalchemy import create_engine
- # пример подключения к базе данных для Postresql
- #db_config = {'user': 'my_user',
- # 'pwd': 'my_user_password',
- # 'host': 'localhost',
- # 'port': 5432,
- # 'db': 'games'}
- #engine = create_engine('postgresql://{}:{}@{}:{}/{}'.format(db_config['user'],
- # db_config['pwd'],
- # db_config['host'],
- # db_config['port'],
- # db_config['db']))
- # пример подключения к базе данных для Sqlite
- engine = create_engine('sqlite:////db/games.db', echo=False)
- # получаем сырые данные
- query = '''
- SELECT * FROM agg_games_year_genre_platform
- '''
- agg_games_year_genre_platform = pd.io.sql.read_sql(query, con = engine)
- agg_games_year_genre_platform['year_of_release'] = pd.to_datetime(agg_games_year_genre_platform['year_of_release'])
- query = '''
- SELECT * FROM agg_games_year_score
- '''
- agg_games_year_score = pd.io.sql.read_sql(query, con = engine)
- agg_games_year_score['year_of_release'] = pd.to_datetime(agg_games_year_score['year_of_release'])
- # игнорируем записи без оценок
- agg_games_year_score = agg_games_year_score.query('avg_user_score > 0 and avg_critic_score > 0')
- note = '''
- Этот дашборд показывает историю игрового рынка (исключая мобильные устройства).
- Используйте выбор интервала даты выпуска, жанра и платформы для управления дашбордом.
- Используйте селектор выбора режима отображения для того, чтобы показать абсолютные
- или относительные значения выпуска и продаж игр по годам.
- '''
- # задаём лейаут
- external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
- app = dash.Dash(__name__, external_stylesheets=external_stylesheets, compress=False)
- app.layout = html.Div(children=[
- # формируем html
- html.H1(children = 'История игрового рынка'),
- html.Br(),
- html.Div([
- html.Div([
- # график выпуска игр по годам и жанрам
- html.Label('Выпуск игр по жанрам:'),
- dcc.RadioItems(
- options = [
- {'label': 'Абсолютные значения', 'value': 'absolute_values'},
- {'label': '% от общего выпуска', 'value': 'relative_values'},
- ],
- value = 'absolute_values',
- id = 'mode_selector'
- ),
- dcc.Graph(
- id = 'launches_by_genre'
- ),
- ], className = 'eight columns'),
- html.Div([
- # график выпуска игр по платформам
- html.Label('Выпуск игр по платформам:'),
- dcc.Graph(
- id = 'launches_by_platform'
- ),
- ], className = 'four columns'),
- ], className = 'row'),
- html.Div([
- html.Div([
- # график выпуска игр по годам и жанрам
- html.Label('Продажи игр по жанрам:'),
- dcc.Graph(
- id = 'sales_by_genre'
- ),
- ], className = 'eight columns'),
- html.Div([
- # график средних оценок по жанрам
- html.Label('Средние оценки по жанрам:'),
- dcc.Graph(
- id = 'scores_by_genre'
- ),
- ], className = 'four columns'),
- ], className = 'row'),
- # пояснения
- html.Label(note),
- html.Br(),
- html.Div([
- html.Div([
- # выбор временного периода
- html.Label('Года выпуска:'),
- dcc.DatePickerRange(
- start_date = agg_games_year_genre_platform['year_of_release'].dt.date.min(),
- end_date = datetime(2016,1,1).strftime('%Y-%m-%d'),
- display_format = 'YYYY-MM-DD',
- id = 'dt_selector',
- ),
- ], className = 'two columns'),
- html.Div([
- # выбор жанра
- html.Label('Жанры:'),
- dcc.Dropdown(
- options = [{'label': x, 'value': x} for x in agg_games_year_genre_platform['genre'].unique()],
- value = agg_games_year_genre_platform['genre'].unique().tolist(),
- multi = True,
- id = 'genre_selector'
- ),
- ], className = 'four columns'),
- html.Div([
- # выбор платформы
- html.Label('Платформы:'),
- dcc.Dropdown(
- options = [{'label': x, 'value': x} for x in agg_games_year_genre_platform['platform'].unique()],
- value = agg_games_year_genre_platform['platform'].unique().tolist(),
- multi = True,
- id = 'platform_selector'
- ),
- ], className = 'six columns'),
- ], className = 'row'),
- ])
- # описываем логику дашборда
- @app.callback(
- [Output('launches_by_genre', 'figure'),
- Output('launches_by_platform', 'figure'),
- Output('sales_by_genre', 'figure'),
- Output('scores_by_genre', 'figure'),
- ],
- [Input('dt_selector', 'start_date'),
- Input('dt_selector', 'end_date'),
- Input('mode_selector', 'value'),
- Input('genre_selector', 'value'),
- Input('platform_selector', 'value'),
- ])
- def update_figures(start_date, end_date, mode, selected_genres, selected_platforms):
- # применяем фильтрацию
- filtered = agg_games_year_genre_platform.query('year_of_release >= @start_date and year_of_release <= @end_date')
- filtered = filtered.query('genre in @selected_genres')
- filtered = filtered.query('platform in @selected_platforms')
- filtered_score = agg_games_year_score.query('year_of_release >= @start_date and year_of_release <= @end_date')
- filtered_score = filtered_score.query('genre in @selected_genres')
- filtered_score = filtered_score.query('platform in @selected_platforms')
- games_by_genre = (filtered.groupby(['year_of_release', 'genre'])
- .agg({'games': 'sum', 'total_copies_sold': 'sum'})
- .reset_index()
- )
- games_by_platform = (filtered.groupby(['platform'])
- .agg({'games': 'sum'})
- .reset_index()
- )
- # все платформы с малым количеством игр помещаем в одну категорию
- games_by_platform['percent'] = games_by_platform['games'] / games_by_platform['games'].sum()
- games_by_platform.loc[games_by_platform['percent'] < 0.05, 'platform'] = 'Другие'
- # и ещё раз группируем
- games_by_platform = (games_by_platform.groupby(['platform'])
- .agg({'games': 'sum'})
- .reset_index()
- )
- # трансформируем в соотв. с выбранным режимом отображения
- y_label = 'Выпущенные игры'
- y_label_sales = 'Продажи игр, млн копий'
- if mode == 'relative_values':
- y_label = '% выпущенных игр'
- y_label_sales = '% продаж игр'
- total = (games_by_genre.groupby('year_of_release')
- .agg({'games': 'sum', 'total_copies_sold': 'sum'})
- .rename(columns = {'games': 'total_launches',
- 'total_copies_sold': 'total_sales'})
- )
- games_by_genre = (games_by_genre.set_index('year_of_release')
- .join(total)
- .reset_index())
- games_by_genre['games'] = games_by_genre['games'] / games_by_genre['total_launches']
- games_by_genre['total_copies_sold'] = games_by_genre['total_copies_sold'] / games_by_genre['total_sales']
- # графики выпуска и продаж игр по жанру
- launches_by_genre = []
- sales_by_genre = []
- for genre in games_by_genre['genre'].unique():
- launches_by_genre += [go.Scatter(x = games_by_genre.query('genre == @genre')['year_of_release'],
- y = games_by_genre.query('genre == @genre')['games'],
- mode = 'lines',
- stackgroup = 'one',
- name = genre)]
- sales_by_genre += [go.Bar(x = games_by_genre.query('genre == @genre')['year_of_release'],
- y = games_by_genre.query('genre == @genre')['total_copies_sold'],
- name = genre)]
- # график выпуска игр по платформам
- launches_by_platform = [go.Pie(labels = games_by_platform['platform'],
- values = games_by_platform['games'],
- name = 'platfroms')]
- # точечная диаграмма оценок по жанрам и годам
- scores_by_genre = []
- for genre in filtered_score['genre'].unique():
- scores_by_genre += [go.Scatter(x = filtered_score.query('genre == @genre')['avg_user_score'],
- y = filtered_score.query('genre == @genre')['avg_critic_score'],
- mode = 'markers',
- name = genre)]
- # формируем результат для отображения
- return (
- {
- 'data': launches_by_genre, # напишите код
- 'layout': go.Layout(xaxis = {'title': 'Год'},
- yaxis = {'title': y_label})
- },
- {
- 'data': launches_by_platform, # напишите код
- 'layout': go.Layout(xaxis = {'title': 'Год'},
- yaxis = {'title': y_label_sales},
- barmode = 'stack',
- )
- },
- {
- 'data': sales_by_genre, # напишите код
- 'layout': go.Layout()
- },
- {
- 'data': scores_by_genre, # напишите код
- 'layout': go.Layout(xaxis = {'title': 'Средняя оценка пользователей'},
- yaxis = {'title': 'Средняя оценка критиков'})
- },
- )
- if __name__ == '__main__':
- app.run_server(host='0.0.0.0', port=3000)
№7
From Fiery Butterfly, 2 Months ago, written in Plain Text, viewed 92 times.
URL http://codebin.org/view/8742de2d
Embed
Download Paste or View Raw
— Expand Paste to full width of browser