Skip to content

Commit 4017286

Browse files
committed
transfer
0 parents  commit 4017286

File tree

989 files changed

+354709
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

989 files changed

+354709
-0
lines changed

.DS_Store

6 KB
Binary file not shown.

Procfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
web: gunicorn app:server --workers 2

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# 360-ftw
2+
BDC hackathon

app.py

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
import dash
2+
from datetime import datetime as dt
3+
from dash.dependencies import Input, Output
4+
import dash_core_components as dcc
5+
import dash_html_components as html
6+
import pandas as pd
7+
import plotly.graph_objs as go
8+
9+
from components import Column, Header, Row
10+
11+
import mysql.connector
12+
13+
14+
def get_dictionary():
15+
mydb = mysql.connector.connect(
16+
host="hackathon-db.bdc.n360.io",
17+
user="events",
18+
passwd="", # add api key
19+
database="hackathon"
20+
)
21+
22+
mycursor = mydb.cursor()
23+
dictionary = dict()
24+
mycursor.execute("""
25+
SELECT organization_unit_id, organization_unit_name
26+
FROM organization_unit
27+
""")
28+
res = mycursor.fetchall()
29+
for tuple in res:
30+
dictionary[tuple[0]] = tuple[1]
31+
32+
return dictionary
33+
34+
35+
name_map = get_dictionary()
36+
37+
38+
# Load data
39+
website_df = pd.read_csv('data/website_statistics.csv')
40+
segment_names = website_df.segment_name.value_counts().index.tolist()
41+
website_ids = website_df.website_id.value_counts().index.tolist()
42+
43+
lead_df = pd.read_csv('data/lead.csv')
44+
dealer_list = lead_df.organization_unit_id.tolist()
45+
46+
47+
stats = [
48+
'avg_session_duration',
49+
'avg_time_on_page',
50+
'bounce_rate',
51+
'bounces',
52+
'new_user_percentage',
53+
'new_users',
54+
'pageviews',
55+
'pageviews_per_session',
56+
'percent_new_sessions',
57+
'session_duration',
58+
'sessions',
59+
'time_on_page',
60+
'users'
61+
]
62+
63+
app = dash.Dash(__name__)
64+
server = app.server # Expose the server variable for deployments
65+
66+
# Standard Dash app code below
67+
app.layout = html.Div(className='container', children=[
68+
69+
Header('Interactive Dashboard'),
70+
71+
Row([
72+
Column(width=6, children=[
73+
dcc.Dropdown(
74+
id='dealer-dropdown',
75+
options=[
76+
{'label': f"{name_map[i]} ({i})", 'value': str(i)}
77+
for i in dealer_list
78+
],
79+
value=dealer_list[0]
80+
),
81+
dcc.DatePickerRange(
82+
id='date-picker-range',
83+
display_format='Y-M-D',
84+
min_date_allowed=dt(2017, 1, 1),
85+
max_date_allowed=dt(2020, 1, 1),
86+
start_date=dt(2017, 1, 1),
87+
end_date=dt(2020, 1, 1),
88+
),
89+
dcc.RadioItems(
90+
id='lead-radio-items',
91+
options=[
92+
{'label': i.replace('_', ' ').title(), 'value': i}
93+
for i in ['lead_type', 'lead_status']
94+
],
95+
labelStyle={'display': 'inline-block'},
96+
value='lead_type'
97+
),
98+
dcc.Graph(id='lead-graph')
99+
]),
100+
Column(width=6, children=[
101+
dcc.Dropdown(
102+
id='stats-dropdown',
103+
options=[
104+
{'label': i.replace('_', ' ').title(), 'value': i}
105+
for i in stats
106+
],
107+
value=stats[0]
108+
),
109+
dcc.Dropdown(
110+
id='website-id-dropdown',
111+
options=[
112+
{'label': f"Website #{i}", 'value': str(i)}
113+
for i in website_ids
114+
],
115+
value=str(website_ids[0])
116+
),
117+
dcc.Graph(id='website-stats-graph')
118+
])
119+
])
120+
])
121+
122+
123+
@app.callback(Output('lead-graph', 'figure'),
124+
[Input('lead-radio-items', 'value'),
125+
Input('dealer-dropdown', 'value'),
126+
Input('date-picker-range', 'start_date'),
127+
Input('date-picker-range', 'end_date')])
128+
def update_lead_graph(col_name, dealer, start_date, end_date):
129+
source_mask = lead_df['lead_source'] == 'Web'
130+
start_date_mask = lead_df['date_created'] > start_date
131+
end_date_mask = lead_df['date_created'] < end_date
132+
dealer_mask = lead_df['organization_unit_id'] == int(dealer)
133+
masked_df = lead_df[source_mask & start_date_mask & end_date_mask & dealer_mask]
134+
135+
pie_data = masked_df[col_name].value_counts()[:10]
136+
137+
trace1 = go.Pie(
138+
labels=pie_data.index,
139+
values=pie_data.values
140+
)
141+
layout = go.Layout(
142+
title=col_name.replace("_", " ").title()
143+
)
144+
fig = go.Figure([trace1], layout=layout)
145+
146+
return fig
147+
148+
149+
@app.callback(Output('website-stats-graph', 'figure'),
150+
[Input('stats-dropdown', 'value'),
151+
Input('website-id-dropdown', 'value'),
152+
Input('date-picker-range', 'start_date'),
153+
Input('date-picker-range', 'end_date')])
154+
def update_website_stats_graph(stat, website_id, start_date, end_date):
155+
y_name = stat.replace('_', ' ').title()
156+
website_id = int(website_id)
157+
158+
traces = []
159+
for segment_name in segment_names:
160+
segment_mask = website_df['segment_name'] == segment_name
161+
website_mask = website_df['website_id'] == website_id
162+
start_date_mask = website_df['date_start'] > start_date
163+
end_date_mask = website_df['date_start'] < end_date
164+
masked_df = website_df[segment_mask & website_mask & start_date_mask & end_date_mask]
165+
166+
trace = go.Scatter(
167+
x=masked_df.date_start.values,
168+
y=masked_df[stat].values,
169+
name=segment_name
170+
)
171+
172+
traces.append(trace)
173+
174+
layout = go.Layout(
175+
title=f"Monthly statistics for Website #{website_id}",
176+
xaxis=dict(title="Start Date"),
177+
yaxis=dict(title=y_name)
178+
)
179+
fig = go.Figure(traces, layout)
180+
181+
return fig
182+
183+
184+
if __name__ == '__main__':
185+
app.run_server(debug=True)

assets/dash.css

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
._dash-undo-redo {
2+
/* Change to 'display: none' if you want to remove
3+
* the undo/redo buttons */
4+
display: block;
5+
}
6+
7+
/* Plotly.js
8+
–––––––––––––––––––––––––––––––––––––––––––––––––– */
9+
/* plotly.js's modebar's z-index is outta the roof by default - lower it down */
10+
.js-plotly-plot .plotly .modebar {
11+
z-index: 1;
12+
}

assets/grid.css

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/* Grid
2+
–––––––––––––––––––––––––––––––––––––––––––––––––– */
3+
.container {
4+
position: relative;
5+
width: 90%;
6+
margin: 0 auto;
7+
padding: 0 20px;
8+
box-sizing: border-box; }
9+
.column,
10+
.columns {
11+
width: 100%;
12+
float: left;
13+
box-sizing: border-box; }
14+
.container {
15+
width: 90%; }
16+
.column,
17+
.columns {
18+
margin-left: 4%; }
19+
.column:first-child,
20+
.columns:first-child {
21+
margin-left: 0; }
22+
23+
.one.column,
24+
.one.columns { width: 4.66666666667%; }
25+
.two.columns { width: 13.3333333333%; }
26+
.three.columns { width: 22%; }
27+
.four.columns { width: 30.6666666667%; }
28+
.five.columns { width: 39.3333333333%; }
29+
.six.columns { width: 48%; }
30+
.seven.columns { width: 56.6666666667%; }
31+
.eight.columns { width: 65.3333333333%; }
32+
.nine.columns { width: 74.0%; }
33+
.ten.columns { width: 82.6666666667%; }
34+
.eleven.columns { width: 91.3333333333%; }
35+
.twelve.columns { width: 100%; margin-left: 0; }
36+
37+
.one-third.column { width: 30.6666666667%; }
38+
.two-thirds.column { width: 65.3333333333%; }
39+
40+
.one-half.column { width: 48%; }
41+
42+
/* Self Clearing Goodness */
43+
.container:after,
44+
.row:after,
45+
.u-cf {
46+
content: "";
47+
display: table;
48+
clear: both; }

assets/inputs.css

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/* Buttons
2+
–––––––––––––––––––––––––––––––––––––––––––––––––– */
3+
.button,
4+
button,
5+
input[type="submit"],
6+
input[type="reset"],
7+
input[type="button"] {
8+
display: inline-block;
9+
height: 38px;
10+
padding: 0 30px;
11+
color: #555;
12+
text-align: center;
13+
font-size: 11px;
14+
font-weight: 600;
15+
line-height: 38px;
16+
letter-spacing: .1rem;
17+
text-transform: uppercase;
18+
text-decoration: none;
19+
white-space: nowrap;
20+
background-color: transparent;
21+
border-radius: 0px;
22+
border: 1px solid #bbb;
23+
cursor: pointer;
24+
box-sizing: border-box; }
25+
.button:hover,
26+
button:hover,
27+
input[type="submit"]:hover,
28+
input[type="reset"]:hover,
29+
input[type="button"]:hover,
30+
.button:focus,
31+
button:focus,
32+
input[type="submit"]:focus,
33+
input[type="reset"]:focus,
34+
input[type="button"]:focus {
35+
color: #333;
36+
border-color: #888;
37+
outline: 0; }
38+
.button.button-primary,
39+
button.button-primary,
40+
input[type="submit"].button-primary,
41+
input[type="reset"].button-primary,
42+
input[type="button"].button-primary {
43+
color: #FFF;
44+
background-color: #33C3F0;
45+
border-color: #33C3F0; }
46+
.button.button-primary:hover,
47+
button.button-primary:hover,
48+
input[type="submit"].button-primary:hover,
49+
input[type="reset"].button-primary:hover,
50+
input[type="button"].button-primary:hover,
51+
.button.button-primary:focus,
52+
button.button-primary:focus,
53+
input[type="submit"].button-primary:focus,
54+
input[type="reset"].button-primary:focus,
55+
input[type="button"].button-primary:focus {
56+
color: #FFF;
57+
background-color: #1EAEDB;
58+
border-color: #1EAEDB; }
59+
60+
61+
/* Forms
62+
–––––––––––––––––––––––––––––––––––––––––––––––––– */
63+
input:not([type]),
64+
input[type="email"],
65+
input[type="number"],
66+
input[type="search"],
67+
input[type="text"],
68+
input[type="tel"],
69+
input[type="url"],
70+
input[type="password"],
71+
textarea,
72+
select {
73+
width: 200px;
74+
height: 38px;
75+
padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */
76+
background-color: #fff;
77+
border: none;
78+
border-bottom: 1px solid lightgrey;
79+
border-radius: 0px;
80+
box-shadow: none;
81+
box-sizing: border-box;
82+
font-family: inherit;
83+
font-size: inherit; /*https://stackoverflow.com/questions/6080413/why-doesnt-input-inherit-the-font-from-body*/}
84+
/* Removes awkward default styles on some inputs for iOS */
85+
86+
input[type="email"],
87+
input[type="number"],
88+
input[type="search"],
89+
input[type="text"],
90+
input[type="tel"],
91+
input[type="url"],
92+
input[type="password"],
93+
textarea {
94+
-webkit-appearance: none;
95+
-moz-appearance: none;
96+
appearance: none; }
97+
textarea {
98+
min-height: 65px;
99+
padding-top: 6px;
100+
padding-bottom: 6px; }
101+
input[type="email"]:focus,
102+
input[type="number"]:focus,
103+
input[type="search"]:focus,
104+
input[type="text"]:focus,
105+
input[type="tel"]:focus,
106+
input[type="url"]:focus,
107+
input[type="password"]:focus,
108+
textarea:focus,
109+
select:focus {
110+
border: none;
111+
border-bottom: 1px solid #33C3F0;
112+
outline: 0; }
113+
label,
114+
legend {
115+
display: block;
116+
margin-bottom: 0px; }
117+
fieldset {
118+
padding: 0;
119+
border-width: 0; }
120+
input[type="checkbox"],
121+
input[type="radio"] {
122+
display: inline; }
123+
label > .label-body {
124+
display: inline-block;
125+
margin-left: .5rem;
126+
font-weight: normal; }

0 commit comments

Comments
 (0)