{"cells":[{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","collapsed":true,"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":false},"cell_type":"markdown","source":"### Being new to Google Analytics, I have decided to attempt to perform some analysis on the available Google Analytics Customer Revenue Prediction dataset here on Kaggle. Most of the work here are tutorials/bits that I have found on Kaggle or other sources, and the source will be attached respectively."},{"metadata":{},"cell_type":"markdown","source":"As per the source of the dataset, the objective of our prediction is the natural log of the sum of all transacations per user, where our resulting model will be applied onto the test set. The formula can be understood as:\n\n$$y_{user} = \\sum_{i=1}^{n} transaction_{user_i} $$\n$$target_{user} = \\ln({y_{user} + 1})$$"},{"metadata":{"trusted":true},"cell_type":"code","source":"import os \nimport pandas as pd\nimport numpy as np\nimport random\nimport json\nfrom pandas.io.json import json_normalize\n\nprint(os.listdir(\"../input\"))\nprint(os.listdir(\"../input/ga-customer-revenue-prediction/\"))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"There are 6 csvs in total, but from the looks of it, the main dataset that we will likely be using are the last two csvs."},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df = pd.read_csv(\"../input/ga-customer-revenue-prediction/train.csv\", low_memory = False)\ntrain_df.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"From the output above, we can tell that some columns that come in the form of dictionaries or more precisely JSON format. Now I am not a big fan when it comes to JSON format and have always struggled dealing with them. So here, I was able to find a function that flattens the columns. [source][1]\n\n[1]: https://www.kaggle.com/julian3833/1-quick-start-read-csv-and-flatten-json-fields/notebook\n\nAll hail the kaggle masters who share their code for free. =D"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Function that flattens the json format columns, namely device, geoNetwork, totals & trafficSource\ndef load_df(file_path, nrows=None):\n    JSON_COLUMNS = ['device', 'geoNetwork', 'totals', 'trafficSource']\n    \n    df = pd.read_csv(file_path, \n                     converters={column: json.loads for column in JSON_COLUMNS}, \n                     dtype={'fullVisitorId': 'str'}, # Important!!\n                     nrows=nrows)\n    \n    for column in JSON_COLUMNS:\n        column_as_df = json_normalize(df[column]) # Breaks down the json formats columns into seperate columns\n        column_as_df.columns = [f\"{column}.{subcolumn}\" for subcolumn in column_as_df.columns]\n        df = df.drop(column, axis=1).merge(column_as_df, right_index=True, left_index=True)\n    print(f\"Loaded {os.path.basename(file_path)}. Shape: {df.shape}\")\n    return df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df = load_df(file_path = \"../input/ga-customer-revenue-prediction/train.csv\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"pd.options.display.max_columns = 999","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### What do the columns tell:\n\n1. channelGrouping: The source that directed the user to the Store\n2. date: Date the user visited the store.\n3. fullvisitorId: Unique set of id for each user\n4. sessionId: Unique identifier for each visit per user to the store. The structure of the id is can be understood as: fullVisitorId + _ + visitID\n5. SocialEngagementType: Engagement Type, could be socially engaged or not socially engaged, but all of them are actually not socially engaged.\n6. visitID: unique visit identifier \n7. visitStartTime: Timestamp in Posix format\n8. geoNetwork: Geological location of visit\n9. trafficSource: Information about Traffic Source from the session originated."},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.describe()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.columns.tolist()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Check column data types. "},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.dtypes","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"Channel Grouping:\", train_df.channelGrouping.unique().tolist())\nprint(\"Social Engagement Type:\", train_df.socialEngagementType.unique().tolist())\nprint(\"Number of unique IDs:\",len(train_df.visitId.unique()))\nprint(\"Browser used:\", train_df[\"device.browser\"].unique())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Dropping constant values"},{"metadata":{"trusted":true},"cell_type":"code","source":"const_cols = [col for col in train_df.columns if train_df[col].nunique(dropna = False) == 1]\nconst_cols","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Exploratory Data Analysis"},{"metadata":{},"cell_type":"markdown","source":"### As we are attempting to predict the total revenue per user, it would be good to look into the distribution of the revenue per visitor we have in the training data."},{"metadata":{"trusted":true},"cell_type":"code","source":"import seaborn as sns\nimport matplotlib.pyplot as plt","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Turning the column of transaction Revenue into float instead of object. We want it to be numeric\ntrain_df[\"totals.transactionRevenue\"] = train_df[\"totals.transactionRevenue\"].astype(float)\n\n# Grouping the revenue by visitor ID\ngrouped_by_vis_id = train_df.groupby(\"fullVisitorId\")[\"totals.transactionRevenue\"].sum().reset_index()\n\ngrouped_by_vis_id.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"grouped_by_vis_id.shape[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize = (8, 6))\nsns.scatterplot(data = grouped_by_vis_id, x = range(grouped_by_vis_id.shape[0]), y = np.sort(np.log1p(grouped_by_vis_id[\"totals.transactionRevenue\"].values)))\nplt.title(\"Seaborn Way\")\nplt.ylabel(\"Transaction Revenue\", fontsize = 14)\n\nplt.figure(figsize = (8, 6))\nplt.scatter(x = range(grouped_by_vis_id.shape[0]), y = np.sort(np.log1p(grouped_by_vis_id[\"totals.transactionRevenue\"].values)))\nplt.title(\"Matplotlib way\")\nplt.ylabel(\"Transaction Revenue\", fontsize = 14)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The outputs above further supports the 80/20 rule that: only small percentage of customers produce most of the revenue, as per the overview from the data source."},{"metadata":{},"cell_type":"markdown","source":"### Obtaining the ratio/percentage numerically"},{"metadata":{"trusted":true},"cell_type":"code","source":"non_zero_cases = pd.notnull(train_df[\"totals.transactionRevenue\"]).sum()\nprint(\"Non zero transactions:\", non_zero_cases)\nprint(\"Percentage of non-zero transactions out of entire dataset:\", non_zero_cases / train_df.shape[0])\n\nrevenue_generating_customers = (grouped_by_vis_id[\"totals.transactionRevenue\"] > 0).sum()\nprint(\"Unique customers with non-zero transactions:\", revenue_generating_customers)\nprint(\"Percentage of UNIQUE revenue generating customers out of entire dataset:\", revenue_generating_customers / grouped_by_vis_id.shape[0]) #dvded by grouped_by_vis_id as we want the UNIQUE customers","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The following plots are basically a copy of SRK's version, which I find really well executed. Can be found [here][1]\n\n[1]: https://www.kaggle.com/sudalairajkumar/simple-exploration-baseline-ga-customer-revenue"},{"metadata":{},"cell_type":"markdown","source":"### Device Info"},{"metadata":{"trusted":true},"cell_type":"code","source":"import plotly.subplots\nfrom plotly import tools\nimport plotly.offline as py\npy.init_notebook_mode(connected = True)\nimport plotly.graph_objs as go","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Below, is a use of the plotly Python library, an interactive plotting library that allows us to create beautiful interactive web-based visualizations. This is the first time I have approached plotly, and as mentioned, the work is just a spin-off version of SRK's work (basically the same stuff to be honest). "},{"metadata":{"trusted":true},"cell_type":"code","source":"def horizontal_bar_chart(cnt_srs, color):\n    trace = go.Bar(\n        y = cnt_srs.index[::-1], #This will turn the sequence of index upside down, i.e. last becomes first and vice versa.\n        x = cnt_srs.values[::-1],\n        showlegend = False,\n        orientation = \"h\",\n        marker = dict(\n            color = color))\n    return trace","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Device Browser\ncnt_srs = train_df.groupby(\"device.browser\")[\"totals.transactionRevenue\"].agg([\"size\", \"count\", \"mean\"])\ncnt_srs.columns = [\"count\", \"count_of_non_zero_revenue\", \"mean\"]\ncnt_srs = cnt_srs.sort_values(by = \"count\", ascending = False)\n#cnt_srs.head()\n#cnt_srs.index[::-1]\ntrace1 = horizontal_bar_chart(cnt_srs[\"count\"].head(10), \"rgba(242, 160, 160, 1)\")\ntrace2 = horizontal_bar_chart(cnt_srs[\"count_of_non_zero_revenue\"].head(10), \"rgba(156, 240, 198, 1)\")\ntrace3 = horizontal_bar_chart(cnt_srs[\"mean\"].head(10), \"rgba(115, 228, 246, 1)\")\n\n\n# Device Category\ncnt_srs = train_df.groupby(\"device.deviceCategory\")[\"totals.transactionRevenue\"].agg([\"size\", \"count\", \"mean\"])\ncnt_srs.columns = [\"count\", \"count_of_non_zero_revenue\", \"mean\"]\ncnt_srs = cnt_srs.sort_values(by = \"count\", ascending = False)\ntrace4 = horizontal_bar_chart(cnt_srs[\"count\"].head(10), \"rgba(242, 160, 160, 1)\")\ntrace5 = horizontal_bar_chart(cnt_srs[\"count_of_non_zero_revenue\"].head(10), \"rgba(156, 240, 198, 1)\")\ntrace6 = horizontal_bar_chart(cnt_srs[\"mean\"].head(10), \"rgba(115, 228, 246, 1)\")\n\n# Device Operating System\ncnt_srs = train_df.groupby(\"device.operatingSystem\")[\"totals.transactionRevenue\"].agg([\"size\", \"count\", \"mean\"])\ncnt_srs.columns = [\"count\", \"count_of_non_zero_revenue\", \"mean\"]\ncnt_srs = cnt_srs.sort_values(by = \"count\", ascending = False)\ntrace7 = horizontal_bar_chart(cnt_srs[\"count\"].head(10), \"rgba(242, 160, 160, 1)\")\ntrace8 = horizontal_bar_chart(cnt_srs[\"count_of_non_zero_revenue\"].head(10), \"rgba(156, 240, 198, 1)\")\ntrace9 = horizontal_bar_chart(cnt_srs[\"mean\"].head(10), \"rgba(115, 228, 246, 1)\")\n\n\n\nfig = plotly.subplots.make_subplots(rows = 3, cols = 3, vertical_spacing = 0.04, subplot_titles = [\"Device Browser - Count\", \n                                                                                         \"Device Browser - Non-zero Revenue Count\", \n                                                                                         \"Device Browser - Mean Revenue\",\n                                                                                         \"Device Category - Count\", \n                                                                                         \"Device Category - Non-zero Revenue Count\", \n                                                                                         \"Device Category - Mean Revenue\", \n                                                                                         \"Device OS - Count\", \n                                                                                         \"Device OS - Non-zero Revenue Count\", \n                                                                                         \"Device OS - Mean Revenue\"])\n\nfig.append_trace(trace1, 1, 1)\nfig.append_trace(trace2, 1, 2)\nfig.append_trace(trace3, 1, 3)\nfig.append_trace(trace4, 2, 1)\nfig.append_trace(trace5, 2, 2)\nfig.append_trace(trace6, 2, 3)\nfig.append_trace(trace7, 3, 1)\nfig.append_trace(trace8, 3, 2)\nfig.append_trace(trace9, 3, 3)\n\nfig['layout'].update(height=1200, width=1200, paper_bgcolor='rgb(233, 233, 233)', title=\"Device Plots\")\npy.iplot(fig, filename='device-plots')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Timeline plotting: Date exploration"},{"metadata":{"trusted":true},"cell_type":"code","source":"import datetime","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def scatter_plot(cnt_srs, color):\n    trace = go.Scatter(\n        x = cnt_srs.index[::-1],\n        y = cnt_srs.values[::-1],\n        showlegend = False,\n        marker = dict(color = color))\n    return trace","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.head(2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df['date'] = train_df['date'].apply(lambda x: datetime.date(int(str(x)[:4]), int(str(x)[4:6]), int(str(x)[6:])))\ntrain_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"cnt_srs = train_df.groupby(\"date\")[\"totals.transactionRevenue\"].agg([\"size\", \"count\"])\ncnt_srs.columns = [\"count\", \"count_of_non_zero_revenue\"]\ncnt_srs = cnt_srs.sort_index()\ntrace1 = scatter_plot(cnt_srs[\"count\"], \"rgba(13, 81, 108, 1)\")\ntrace2 = scatter_plot(cnt_srs[\"count_of_non_zero_revenue\"], \"rgba(54, 13, 108, 1)\")\n\n\nfig = plotly.subplots.make_subplots(rows = 2, cols = 1, vertical_spacing = 0.08,\n                                   subplot_titles = [\"Date - Count\", \"Date - Non-zero Revenue Instances\"])\nfig.append_trace(trace1, 1, 1)\nfig.append_trace(trace2, 2, 1)\nfig[\"layout\"].update(height = 800, width = 800, paper_bgcolor = \"rgb(233, 233, 233)\", title = \"Timeline Plots\")\npy.iplot(fig, filename = \"date_plots\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df = load_df(file_path = \"../input/ga-customer-revenue-prediction/test.csv\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df[\"date\"] = test_df[\"date\"].apply(lambda x:datetime.date(int(str(x)[:4]), int(str(x)[4:6]), int(str(x)[6:])))\ncnt_srs = test_df.groupby(\"date\")[\"fullVisitorId\"].size()\ncnt_srs.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"trace = scatter_plot(cnt_srs, \"rgba(162, 11, 74, 11)\")\n\nlayout = go.Layout(\n    height = 400, \n    width = 800,\n    paper_bgcolor = \"rgb(233, 233, 233)\",\n    title = \"Test set timeline\")\n\ndata = [trace]\nfig = go.Figure(data = data, layout = layout)\npy.iplot(fig, filename = \"ActivationDate\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"cnt_srs = train_df.groupby(\"geoNetwork.continent\")[\"totals.transactionRevenue\"].agg([\"size\", \"count\", \"mean\"])\ncnt_srs.columns = [\"count\", \"count_of_non_zero_revenue\", \"mean\"]\ncnt_srs = cnt_srs.sort_values(by = \"count\", ascending = False)\ntrace1 = horizontal_bar_chart(cnt_srs[\"count\"].head(10), \"rgba(237, 139, 27, 1)\")\ntrace2 = horizontal_bar_chart(cnt_srs[\"count_of_non_zero_revenue\"].head(10), \"rgba(241, 200, 94, 1)\")\ntrace3 = horizontal_bar_chart(cnt_srs[\"mean\"].head(10), \"rgba(253, 220, 6, 1)\")\n\ncnt_srs = train_df.groupby(\"geoNetwork.subContinent\")[\"totals.transactionRevenue\"].agg([\"size\", \"count\", \"mean\"])\ncnt_srs.columns = [\"count\", \"count_of_non_zero_revenue\", \"mean\"]\ncnt_srs = cnt_srs.sort_values(by = \"count\", ascending = False)\ntrace4 = horizontal_bar_chart(cnt_srs[\"count\"], \"rgba(237, 139, 27, 1)\")\ntrace5 = horizontal_bar_chart(cnt_srs[\"count_of_non_zero_revenue\"], \"rgba(241, 200, 94, 1)\")\ntrace6 = horizontal_bar_chart(cnt_srs[\"mean\"], \"rgba(253, 220, 6, 1)\")\n\n\ncnt_srs = train_df.groupby(\"geoNetwork.networkDomain\")[\"totals.transactionRevenue\"].agg([\"size\", \"count\", \"mean\"])\ncnt_srs.columns = [\"count\", \"count_of_non_zero_revenue\", \"mean\"]\ncnt_srs = cnt_srs.sort_values(by = \"count\", ascending = False)\ntrace7 = horizontal_bar_chart(cnt_srs[\"count\"].head(10), \"rgba(237, 139, 27, 1)\")\ntrace8 = horizontal_bar_chart(cnt_srs[\"count_of_non_zero_revenue\"].head(10), \"rgba(241, 200, 94, 1)\")\ntrace9 = horizontal_bar_chart(cnt_srs[\"mean\"].head(10), \"rgba(253, 220, 6, 1)\")\n\nfig = plotly.subplots.make_subplots(rows = 3, cols = 3, vertical_spacing = 0.08, horizontal_spacing = 0.15,\n                                  subplot_titles = [\"Continent - Count\", \"Continent - Non-zero Revenue Count\", \"Continent - Mean Revenue\",\n                                          \"Sub Continent - Count\",  \"Sub Continent - Non-zero Revenue Count\", \"Sub Continent - Mean Revenue\",\n                                          \"Network Domain - Count\", \"Network Domain - Non-zero Revenue Count\", \"Network Domain - Mean Revenue\"])\n\nfig.append_trace(trace1, 1, 1)\nfig.append_trace(trace2, 1, 2)\nfig.append_trace(trace3, 1, 3)\nfig.append_trace(trace4, 2, 1)\nfig.append_trace(trace5, 2, 2)\nfig.append_trace(trace6, 2, 3)\nfig.append_trace(trace7, 3, 1)\nfig.append_trace(trace8, 3, 2)\nfig.append_trace(trace9, 3, 3)\n\nfig[\"layout\"].update(height = 1500, width = 1200, paper_bgcolor = \"rgb(233, 233, 233)\", \n                    title = \"Geographical Information\")\npy.iplot(fig, filename = \"geo_plots\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def create_cnt_srs(df, col1, col2):\n    cnt_srs = df.groupby(col1)[col2].agg([\"size\", \"count\", \"mean\"])\n    cnt_srs.columns = [\"count\", \"count_of_non_zero_revenue\", \"mean\"]\n    cnt_srs = cnt_srs.sort_values(by = \"count\", ascending = False)\n    \n    return cnt_srs","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"cnt_srs = create_cnt_srs(train_df, \"trafficSource.source\", \"totals.transactionRevenue\")\ntrace1 = horizontal_bar_chart(cnt_srs[\"count\"].head(10), \"rgba(113, 228, 228, 1)\")\ntrace2 = horizontal_bar_chart(cnt_srs[\"count_of_non_zero_revenue\"].head(10), \"rgba(30, 158, 158, 1)\")\ntrace3 = horizontal_bar_chart(cnt_srs[\"mean\"].head(10), \"rgba(21, 106, 106, 1)\")\n\ncnt_srs = create_cnt_srs(train_df, \"trafficSource.medium\", \"totals.transactionRevenue\")\ntrace4 = horizontal_bar_chart(cnt_srs[\"count\"].head(10), \"rgba(113, 228, 228, 1)\")\ntrace5 = horizontal_bar_chart(cnt_srs[\"count_of_non_zero_revenue\"].head(10), \"rgba(30, 158, 158, 1)\")\ntrace6 = horizontal_bar_chart(cnt_srs[\"mean\"].head(10), \"rgba(21, 106, 106, 1)\")\n\nfig = plotly.subplots.make_subplots(rows = 2, cols = 3, vertical_spacing = 0.08, horizontal_spacing = 0.15,\n                                   subplot_titles = [\"Traffic Source - Count\", \"Traffic Source - Non_zero_revenue_count\", \"Traffic Source - Mean\",\n                                                    \"Traffic Medium - Count\", \"Traffic Medium - Non_zero_revenue_count\", \"Traffic_medium - Mean\"])\n\nfig.append_trace(trace1, 1, 1)\nfig.append_trace(trace2, 1, 2)\nfig.append_trace(trace3, 1, 3)\nfig.append_trace(trace4, 2, 1)\nfig.append_trace(trace5, 2, 2)\nfig.append_trace(trace6, 2, 3)\n\nfig[\"layout\"].update(height = 1200, width = 1200, paper_bgcolor = \"rgb(233, 233, 233)\", \n                    title = \"Traffic Source\")\npy.iplot(fig, filename = \"traffic_info_plots\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"cnt_srs = create_cnt_srs(train_df, \"totals.pageviews\", \"totals.transactionRevenue\")\ntrace1 = horizontal_bar_chart(cnt_srs[\"count\"].head(60), \"rgba(171, 11, 11, 1)\")\ntrace2 = horizontal_bar_chart(cnt_srs[\"count_of_non_zero_revenue\"].head(60), \"rgba(238, 21, 21, 1)\")\ntrace3 = horizontal_bar_chart(cnt_srs[\"mean\"].head(60), \"rgba(246, 125, 125, 1)\")\n\ncnt_srs = create_cnt_srs(train_df, \"totals.hits\", \"totals.transactionRevenue\")\ntrace4 = horizontal_bar_chart(cnt_srs[\"count\"].head(60), \"rgba(8, 51, 144, 1)\")\ntrace5 = horizontal_bar_chart(cnt_srs[\"count_of_non_zero_revenue\"].head(60), \"rgba(13, 84, 236, 1)\")\ntrace6 = horizontal_bar_chart(cnt_srs[\"mean\"].head(60), \"rgba(97, 144, 244, 1)\")\n\nfig = plotly.subplots.make_subplots(rows = 2, cols = 3, vertical_spacing = 0.08, horizontal_spacing = 0.15,\n                                   subplot_titles = [\"Pageviews - Count\", \"Pageviews - Non_zero_revenue\", \"Pageviews - Mean\"\n                                                    \"Total hits - Count\", \"Total hits - Non_zero_revnue\", \"Total hits - Mean\"])\n\nfig.append_trace(trace1, 1, 1)\nfig.append_trace(trace2, 1, 2)\nfig.append_trace(trace3, 1, 3)\nfig.append_trace(trace4, 2, 1)\nfig.append_trace(trace5, 2, 2)\nfig.append_trace(trace6, 2, 3)\n\nfig[\"layout\"].update(height = 1200, width = 1200, paper_bgcolor = \"rgb(233, 233, 233)\", \n                    title = \"Page Visits\")\npy.iplot(fig, filename = \"page_view_visits_plot\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### So that concludes what Plotly is capable of. I find that it is really similar to R-studio's Shiny, something which I am much more familiar with. But there are certain aspects I find plotly better, mainly when it comes to the interactive-ness. Plus, the object-oriented programming style, is much more straightforward for me, which makes picking it up much easier than I thought."}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}