{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": { "papermill": { "duration": 1.178838, "end_time": "2019-08-20T23:09:03.949939", "exception": false, "start_time": "2019-08-20T23:09:02.771101", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "import seaborn as sns\n", "import pandas as pd\n", "import numpy as np\n", "import altair as alt\n", "from markdown import markdown\n", "from IPython.display import Markdown\n", "from ipywidgets.widgets import HTML, Tab\n", "from ipywidgets import widgets\n", "from datetime import timedelta\n", "from matplotlib import pyplot as plt\n", "from tqdm import tqdm\n", "import os.path as op\n", "\n", "from mod import load_data, alt_theme\n", "\n", "from warnings import simplefilter\n", "simplefilter('ignore')" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "papermill": { "duration": 0.020774, "end_time": "2019-08-20T23:09:03.983366", "exception": false, "start_time": "2019-08-20T23:09:03.962592", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "def author_url(author):\n", " return f\"https://github.com/{author}\"" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "papermill": { "duration": 0.021081, "end_time": "2019-08-20T23:09:04.015856", "exception": false, "start_time": "2019-08-20T23:09:03.994775", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "bot_names = pd.read_csv('./bot_names.csv')" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "papermill": { "duration": 0.019488, "end_time": "2019-08-20T23:09:04.046387", "exception": false, "start_time": "2019-08-20T23:09:04.026899", "status": "completed" }, "tags": [ "parameters", "hide_input" ] }, "outputs": [], "source": [ "fmt_date = \"{:%Y-%m-%d}\"\n", "\n", "start_date = None\n", "end_date = None\n", "\n", "renderer = \"jupyterlab\"\n", "github_orgs = [\"jupyterhub\", \"jupyter\", \"jupyterlab\", \"jupyter-widgets\", \"ipython\", \"binder-examples\", \"nteract\"]" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "papermill": { "duration": 0.017388, "end_time": "2019-08-20T23:09:04.074697", "exception": false, "start_time": "2019-08-20T23:09:04.057309", "status": "completed" }, "tags": [ "injected-parameters" ] }, "outputs": [], "source": [ "# Parameters\n", "renderer = \"kaggle\"\n", "github_orgs = [\"jupyterhub\", \"jupyter\", \"jupyterlab\", \"jupyter-widgets\", \"ipython\", \"binder-examples\"]\n" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "papermill": { "duration": 0.023179, "end_time": "2019-08-20T23:09:04.109759", "exception": false, "start_time": "2019-08-20T23:09:04.086580", "status": "completed" }, "tags": [] }, "outputs": [ { "data": { "text/plain": [ "ThemeRegistry.enable('my_theme')" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "alt.renderers.enable(renderer);\n", "alt.themes.register('my_theme', alt_theme)\n", "alt.themes.enable(\"my_theme\")" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "papermill": { "duration": 2.582334, "end_time": "2019-08-20T23:09:06.703108", "exception": false, "start_time": "2019-08-20T23:09:04.120774", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "comments, issues, prs = load_data('../data/', github_orgs=github_orgs)\n", "comments = comments.query('author not in @bot_names').drop_duplicates()\n", "issues = issues.query('author not in @bot_names').drop_duplicates()\n", "prs = prs.query('author not in @bot_names').drop_duplicates()" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "papermill": { "duration": 0.051011, "end_time": "2019-08-20T23:09:06.768496", "exception": false, "start_time": "2019-08-20T23:09:06.717485", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "if start_date is None:\n", " start_date = comments['updatedAt'].min()\n", " \n", "if end_date is None:\n", " end_date = comments['updatedAt'].max()" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "papermill": { "duration": 0.031334, "end_time": "2019-08-20T23:09:06.814377", "exception": false, "start_time": "2019-08-20T23:09:06.783043", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "# Information about out time window\n", "time_delta = pd.to_datetime(end_date) - pd.to_datetime(start_date)\n", "n_days = time_delta.days\n", "\n", "# Information about the data we loaded\n", "github_orgs = comments['org'].unique()" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "papermill": { "duration": 0.043985, "end_time": "2019-08-20T23:09:06.872612", "exception": false, "start_time": "2019-08-20T23:09:06.828627", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "def highlighted_line_plot(data, x, y, color, title, domain=[\"2019-05-01\", \"2019-08-01\"], legend=True):\n", " ch = alt.Chart(data=data, width=1000, title=title)\n", "\n", " highlight = alt.selection(type='single', on='mouseover',\n", " fields=[color], nearest=True)\n", "\n", " ln = ch.mark_line(clip=True).encode(\n", " x=alt.X(x, scale=alt.Scale(domain=domain)),\n", " y=y,\n", " color=alt.Color(color, legend=legend),\n", " opacity=alt.condition(~highlight, alt.value(.3), alt.value(1)),\n", " size=alt.condition(~highlight, alt.value(2), alt.value(5))\n", " )\n", "\n", " pt = ch.mark_point(clip=True).encode(\n", " x=alt.X(x, scale=alt.Scale(domain=domain)),\n", " y=y,\n", " color=alt.Color(color, legend=legend),\n", " tooltip=color,\n", " size=alt.value(300),\n", " opacity=alt.value(0)\n", " ).add_selection(highlight).interactive()\n", " return ln + pt" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "papermill": { "duration": 0.264555, "end_time": "2019-08-20T23:09:07.151241", "exception": false, "start_time": "2019-08-20T23:09:06.886686", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "date_fields = ['updatedAt', 'createdAt', 'closedAt']\n", "for field in date_fields:\n", " if field in comments.columns:\n", " comments[field] = pd.to_datetime(comments[field])\n", " if field in prs.columns:\n", " prs[field] = pd.to_datetime(prs[field])\n", " if field in issues.columns:\n", " issues[field] = pd.to_datetime(issues[field])" ] }, { "cell_type": "markdown", "metadata": { "papermill": { "duration": 0.011292, "end_time": "2019-08-20T23:09:07.174968", "exception": false, "start_time": "2019-08-20T23:09:07.163676", "status": "completed" }, "tags": [] }, "source": [ "## Comments over time by people" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "papermill": { "duration": 0.017849, "end_time": "2019-08-20T23:09:07.206930", "exception": false, "start_time": "2019-08-20T23:09:07.189081", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "time_bin = '2W'\n", "n_authors = 20\n", "rolling_mean_amt = 4" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "papermill": { "duration": 1.727669, "end_time": "2019-08-20T23:09:08.946324", "exception": false, "start_time": "2019-08-20T23:09:07.218655", "status": "completed" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "jupyterhub\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "jupyter-widgets\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "jupyter\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "jupyterlab\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "ipython\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "binder-examples\n" ] }, { "data": { "text/html": [ "\n", " \n", "
\n", " " ], "text/plain": [ "HConcatChart({\n", " hconcat: [LayerChart({\n", " data: author level_1 updatedAt id\n", " 0 Carreau 0 2015-03-08 00:00:00+00:00 NaN\n", " 1 Carreau 1 2015-03-22 00:00:00+00:00 NaN\n", " 2 Carreau 2 2015-04-05 00:00:00+00:00 NaN\n", " 3 Carreau 3 2015-04-19 00:00:00+00:00 2.25\n", " 4 Carreau 4 2015-05-03 00:00:00+00:00 1.25\n", " ... ... ... ... ...\n", " 1566 yuvipanda 1566 2019-05-26 00:00:00+00:00 53.75\n", " 1567 yuvipanda 1567 2019-06-09 00:00:00+00:00 62.75\n", " 1568 yuvipanda 1568 2019-06-23 00:00:00+00:00 65.00\n", " 1569 yuvipanda 1569 2019-07-07 00:00:00+00:00 59.00\n", " 1570 yuvipanda 1570 2019-07-21 00:00:00+00:00 26.00\n", " \n", " [1571 rows x 4 columns],\n", " layer: [Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'author',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: OpacityValue({\n", " condition: OpacityValue({\n", " selection: SelectionNot({\n", " not: 'selector001'\n", " }),\n", " value: 0.3\n", " }),\n", " value: 1\n", " }),\n", " size: SizeValue({\n", " condition: SizeValue({\n", " selection: SelectionNot({\n", " not: 'selector001'\n", " }),\n", " value: 2\n", " }),\n", " value: 5\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2014-08-24', '2019-09-01']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'line'\n", " }),\n", " title: 'Comments over time for jupyterhub',\n", " width: 1000\n", " }), Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'author',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 0\n", " }),\n", " size: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 300\n", " }),\n", " tooltip: Tooltip({\n", " field: 'author',\n", " type: 'nominal'\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2014-08-24', '2019-09-01']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'point'\n", " }),\n", " selection: {'selector001': SelectionDef({\n", " fields: ['author'],\n", " nearest: True,\n", " on: 'mouseover',\n", " type: 'single'\n", " }), 'selector002': SelectionDef({\n", " bind: 'scales',\n", " encodings: ['x', 'y'],\n", " type: 'interval'\n", " })},\n", " title: 'Comments over time for jupyterhub',\n", " width: 1000\n", " })]\n", " }), LayerChart({\n", " data: author level_1 updatedAt id\n", " 0 SylvainCorlay 0 2015-05-10 00:00:00+00:00 NaN\n", " 1 SylvainCorlay 1 2015-05-24 00:00:00+00:00 NaN\n", " 2 SylvainCorlay 2 2015-06-07 00:00:00+00:00 NaN\n", " 3 SylvainCorlay 3 2015-06-21 00:00:00+00:00 6.50\n", " 4 SylvainCorlay 4 2015-07-05 00:00:00+00:00 13.25\n", " ... ... ... ... ...\n", " 1467 willingc 1467 2017-03-12 00:00:00+00:00 0.00\n", " 1468 willingc 1468 2017-03-26 00:00:00+00:00 0.00\n", " 1469 willingc 1469 2017-04-09 00:00:00+00:00 0.00\n", " 1470 willingc 1470 2017-04-23 00:00:00+00:00 0.25\n", " 1471 willingc 1471 2017-05-07 00:00:00+00:00 0.50\n", " \n", " [1472 rows x 4 columns],\n", " layer: [Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'author',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: OpacityValue({\n", " condition: OpacityValue({\n", " selection: SelectionNot({\n", " not: 'selector003'\n", " }),\n", " value: 0.3\n", " }),\n", " value: 1\n", " }),\n", " size: SizeValue({\n", " condition: SizeValue({\n", " selection: SelectionNot({\n", " not: 'selector003'\n", " }),\n", " value: 2\n", " }),\n", " value: 5\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2014-05-25', '2019-09-01']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'line'\n", " }),\n", " title: 'Comments over time for jupyter-widgets',\n", " width: 1000\n", " }), Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'author',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 0\n", " }),\n", " size: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 300\n", " }),\n", " tooltip: Tooltip({\n", " field: 'author',\n", " type: 'nominal'\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2014-05-25', '2019-09-01']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'point'\n", " }),\n", " selection: {'selector003': SelectionDef({\n", " fields: ['author'],\n", " nearest: True,\n", " on: 'mouseover',\n", " type: 'single'\n", " }), 'selector004': SelectionDef({\n", " bind: 'scales',\n", " encodings: ['x', 'y'],\n", " type: 'interval'\n", " })},\n", " title: 'Comments over time for jupyter-widgets',\n", " width: 1000\n", " })]\n", " }), LayerChart({\n", " data: author level_1 updatedAt id\n", " 0 Carreau 0 2012-12-16 00:00:00+00:00 NaN\n", " 1 Carreau 1 2012-12-30 00:00:00+00:00 NaN\n", " 2 Carreau 2 2013-01-13 00:00:00+00:00 NaN\n", " 3 Carreau 3 2013-01-27 00:00:00+00:00 0.75\n", " 4 Carreau 4 2013-02-10 00:00:00+00:00 0.25\n", " ... ... ... ... ...\n", " 2440 yuvipanda 2440 2019-06-09 00:00:00+00:00 15.75\n", " 2441 yuvipanda 2441 2019-06-23 00:00:00+00:00 15.25\n", " 2442 yuvipanda 2442 2019-07-07 00:00:00+00:00 15.75\n", " 2443 yuvipanda 2443 2019-07-21 00:00:00+00:00 9.75\n", " 2444 yuvipanda 2444 2019-08-04 00:00:00+00:00 9.25\n", " \n", " [2445 rows x 4 columns],\n", " layer: [Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'author',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: OpacityValue({\n", " condition: OpacityValue({\n", " selection: SelectionNot({\n", " not: 'selector005'\n", " }),\n", " value: 0.3\n", " }),\n", " value: 1\n", " }),\n", " size: SizeValue({\n", " condition: SizeValue({\n", " selection: SelectionNot({\n", " not: 'selector005'\n", " }),\n", " value: 2\n", " }),\n", " value: 5\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2012-12-16', '2019-09-01']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'line'\n", " }),\n", " title: 'Comments over time for jupyter',\n", " width: 1000\n", " }), Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'author',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 0\n", " }),\n", " size: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 300\n", " }),\n", " tooltip: Tooltip({\n", " field: 'author',\n", " type: 'nominal'\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2012-12-16', '2019-09-01']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'point'\n", " }),\n", " selection: {'selector005': SelectionDef({\n", " fields: ['author'],\n", " nearest: True,\n", " on: 'mouseover',\n", " type: 'single'\n", " }), 'selector006': SelectionDef({\n", " bind: 'scales',\n", " encodings: ['x', 'y'],\n", " type: 'interval'\n", " })},\n", " title: 'Comments over time for jupyter',\n", " width: 1000\n", " })]\n", " }), LayerChart({\n", " data: author level_1 updatedAt id\n", " 0 BoPeng 0 2018-01-07 00:00:00+00:00 NaN\n", " 1 BoPeng 1 2018-01-21 00:00:00+00:00 NaN\n", " 2 BoPeng 2 2018-02-04 00:00:00+00:00 NaN\n", " 3 BoPeng 3 2018-02-18 00:00:00+00:00 0.50\n", " 4 BoPeng 4 2018-03-04 00:00:00+00:00 0.25\n", " ... ... ... ... ...\n", " 1297 vidartf 1297 2019-06-23 00:00:00+00:00 33.00\n", " 1298 vidartf 1298 2019-07-07 00:00:00+00:00 39.00\n", " 1299 vidartf 1299 2019-07-21 00:00:00+00:00 35.00\n", " 1300 vidartf 1300 2019-08-04 00:00:00+00:00 32.50\n", " 1301 vidartf 1301 2019-08-18 00:00:00+00:00 30.00\n", " \n", " [1302 rows x 4 columns],\n", " layer: [Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'author',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: OpacityValue({\n", " condition: OpacityValue({\n", " selection: SelectionNot({\n", " not: 'selector007'\n", " }),\n", " value: 0.3\n", " }),\n", " value: 1\n", " }),\n", " size: SizeValue({\n", " condition: SizeValue({\n", " selection: SelectionNot({\n", " not: 'selector007'\n", " }),\n", " value: 2\n", " }),\n", " value: 5\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2016-06-12', '2019-09-01']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'line'\n", " }),\n", " title: 'Comments over time for jupyterlab',\n", " width: 1000\n", " }), Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'author',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 0\n", " }),\n", " size: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 300\n", " }),\n", " tooltip: Tooltip({\n", " field: 'author',\n", " type: 'nominal'\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2016-06-12', '2019-09-01']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'point'\n", " }),\n", " selection: {'selector007': SelectionDef({\n", " fields: ['author'],\n", " nearest: True,\n", " on: 'mouseover',\n", " type: 'single'\n", " }), 'selector008': SelectionDef({\n", " bind: 'scales',\n", " encodings: ['x', 'y'],\n", " type: 'interval'\n", " })},\n", " title: 'Comments over time for jupyterlab',\n", " width: 1000\n", " })]\n", " }), LayerChart({\n", " data: author level_1 updatedAt id\n", " 0 Carreau 0 2011-12-04 00:00:00+00:00 NaN\n", " 1 Carreau 1 2011-12-18 00:00:00+00:00 NaN\n", " 2 Carreau 2 2012-01-01 00:00:00+00:00 NaN\n", " 3 Carreau 3 2012-01-15 00:00:00+00:00 1.25\n", " 4 Carreau 4 2012-01-29 00:00:00+00:00 1.00\n", " ... ... ... ... ...\n", " 2957 willingc 2957 2019-06-16 00:00:00+00:00 0.00\n", " 2958 willingc 2958 2019-06-30 00:00:00+00:00 0.00\n", " 2959 willingc 2959 2019-07-14 00:00:00+00:00 0.00\n", " 2960 willingc 2960 2019-07-28 00:00:00+00:00 0.00\n", " 2961 willingc 2961 2019-08-11 00:00:00+00:00 1.00\n", " \n", " [2962 rows x 4 columns],\n", " layer: [Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'author',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: OpacityValue({\n", " condition: OpacityValue({\n", " selection: SelectionNot({\n", " not: 'selector009'\n", " }),\n", " value: 0.3\n", " }),\n", " value: 1\n", " }),\n", " size: SizeValue({\n", " condition: SizeValue({\n", " selection: SelectionNot({\n", " not: 'selector009'\n", " }),\n", " value: 2\n", " }),\n", " value: 5\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2010-10-10', '2019-08-25']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'line'\n", " }),\n", " title: 'Comments over time for ipython',\n", " width: 1000\n", " }), Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'author',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 0\n", " }),\n", " size: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 300\n", " }),\n", " tooltip: Tooltip({\n", " field: 'author',\n", " type: 'nominal'\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2010-10-10', '2019-08-25']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'point'\n", " }),\n", " selection: {'selector009': SelectionDef({\n", " fields: ['author'],\n", " nearest: True,\n", " on: 'mouseover',\n", " type: 'single'\n", " }), 'selector010': SelectionDef({\n", " bind: 'scales',\n", " encodings: ['x', 'y'],\n", " type: 'interval'\n", " })},\n", " title: 'Comments over time for ipython',\n", " width: 1000\n", " })]\n", " }), LayerChart({\n", " data: author level_1 updatedAt id\n", " 0 MatsGustavsson 0 2018-01-14 00:00:00+00:00 NaN\n", " 1 RaoOfPhysics 1 2018-02-18 00:00:00+00:00 NaN\n", " 2 RaoOfPhysics 2 2018-03-04 00:00:00+00:00 NaN\n", " 3 RaoOfPhysics 3 2018-03-18 00:00:00+00:00 NaN\n", " 4 RaoOfPhysics 4 2018-04-01 00:00:00+00:00 0.75\n", " .. ... ... ... ...\n", " 316 yuvipanda 316 2019-01-13 00:00:00+00:00 0.00\n", " 317 yuvipanda 317 2019-01-27 00:00:00+00:00 0.00\n", " 318 yuvipanda 318 2019-02-10 00:00:00+00:00 0.00\n", " 319 yuvipanda 319 2019-02-24 00:00:00+00:00 0.00\n", " 320 yuvipanda 320 2019-03-10 00:00:00+00:00 0.75\n", " \n", " [321 rows x 4 columns],\n", " layer: [Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'author',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: OpacityValue({\n", " condition: OpacityValue({\n", " selection: SelectionNot({\n", " not: 'selector011'\n", " }),\n", " value: 0.3\n", " }),\n", " value: 1\n", " }),\n", " size: SizeValue({\n", " condition: SizeValue({\n", " selection: SelectionNot({\n", " not: 'selector011'\n", " }),\n", " value: 2\n", " }),\n", " value: 5\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2017-06-25', '2019-07-28']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'line'\n", " }),\n", " title: 'Comments over time for binder-examples',\n", " width: 1000\n", " }), Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'author',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 0\n", " }),\n", " size: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 300\n", " }),\n", " tooltip: Tooltip({\n", " field: 'author',\n", " type: 'nominal'\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2017-06-25', '2019-07-28']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'point'\n", " }),\n", " selection: {'selector011': SelectionDef({\n", " fields: ['author'],\n", " nearest: True,\n", " on: 'mouseover',\n", " type: 'single'\n", " }), 'selector012': SelectionDef({\n", " bind: 'scales',\n", " encodings: ['x', 'y'],\n", " type: 'interval'\n", " })},\n", " title: 'Comments over time for binder-examples',\n", " width: 1000\n", " })]\n", " })]\n", "})" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "charts = []\n", "for iorg in github_orgs:\n", " print(iorg)\n", " icomments = comments.query('org == @iorg')\n", " authors = icomments.groupby(['author', 'updatedAt']).agg({'id': 'count'}).reset_index()\n", "\n", " top_authors = authors.groupby('author').sum()['id'].sort_values(ascending=False).head(n_authors).index\n", " authors = authors.query('author in @top_authors')\n", " authors = authors.groupby('author').resample(time_bin, on='updatedAt').sum().reset_index()\n", " authors = authors.groupby('author').rolling(rolling_mean_amt, on='updatedAt').mean().reset_index()\n", " domain = [fmt_date.format(authors['updatedAt'].min()), fmt_date.format(authors['updatedAt'].max())]\n", " ch = highlighted_line_plot(authors, 'updatedAt', 'id', 'author', f\"Comments over time for {iorg}\",\n", " legend=None, domain=domain)\n", " charts.append(ch)\n", "alt.hconcat(*charts)" ] }, { "cell_type": "markdown", "metadata": { "papermill": { "duration": 0.02392, "end_time": "2019-08-20T23:09:08.994837", "exception": false, "start_time": "2019-08-20T23:09:08.970917", "status": "completed" }, "tags": [] }, "source": [ "## Comments over time by repo" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "papermill": { "duration": 0.030541, "end_time": "2019-08-20T23:09:09.053219", "exception": false, "start_time": "2019-08-20T23:09:09.022678", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "time_bin = '2W'\n", "n_repos = 30\n", "rolling_mean_amt = 2" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "papermill": { "duration": 1.877887, "end_time": "2019-08-20T23:09:10.956534", "exception": false, "start_time": "2019-08-20T23:09:09.078647", "status": "completed" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "jupyterhub\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "jupyter-widgets\n", "jupyter\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "jupyterlab\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "ipython\n", "binder-examples\n" ] }, { "data": { "text/html": [ "\n", " \n", "
\n", " " ], "text/plain": [ "HConcatChart({\n", " hconcat: [LayerChart({\n", " data: repo level_1 updatedAt id\n", " 0 alabaster-jupyterhub 0 2018-10-21 00:00:00+00:00 NaN\n", " 1 alabaster-jupyterhub 1 2018-11-04 00:00:00+00:00 4.0\n", " 2 alabaster-jupyterhub 2 2018-11-18 00:00:00+00:00 0.0\n", " 3 alabaster-jupyterhub 3 2018-12-02 00:00:00+00:00 0.0\n", " 4 alabaster-jupyterhub 4 2018-12-16 00:00:00+00:00 0.0\n", " ... ... ... ... ...\n", " 2010 zero-to-jupyterhub-k8s 2010 2019-07-07 00:00:00+00:00 35.5\n", " 2011 zero-to-jupyterhub-k8s 2011 2019-07-21 00:00:00+00:00 34.5\n", " 2012 zero-to-jupyterhub-k8s 2012 2019-08-04 00:00:00+00:00 36.0\n", " 2013 zero-to-jupyterhub-k8s 2013 2019-08-18 00:00:00+00:00 38.0\n", " 2014 zero-to-jupyterhub-k8s 2014 2019-09-01 00:00:00+00:00 23.5\n", " \n", " [2015 rows x 4 columns],\n", " layer: [Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'repo',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: OpacityValue({\n", " condition: OpacityValue({\n", " selection: SelectionNot({\n", " not: 'selector013'\n", " }),\n", " value: 0.3\n", " }),\n", " value: 1\n", " }),\n", " size: SizeValue({\n", " condition: SizeValue({\n", " selection: SelectionNot({\n", " not: 'selector013'\n", " }),\n", " value: 2\n", " }),\n", " value: 5\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2014-08-24', '2019-09-01']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'line'\n", " }),\n", " title: 'Comments over time for jupyterhub',\n", " width: 1000\n", " }), Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'repo',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 0\n", " }),\n", " size: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 300\n", " }),\n", " tooltip: Tooltip({\n", " field: 'repo',\n", " type: 'nominal'\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2014-08-24', '2019-09-01']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'point'\n", " }),\n", " selection: {'selector013': SelectionDef({\n", " fields: ['repo'],\n", " nearest: True,\n", " on: 'mouseover',\n", " type: 'single'\n", " }), 'selector014': SelectionDef({\n", " bind: 'scales',\n", " encodings: ['x', 'y'],\n", " type: 'interval'\n", " })},\n", " title: 'Comments over time for jupyterhub',\n", " width: 1000\n", " })]\n", " }), LayerChart({\n", " data: repo level_1 updatedAt id\n", " 0 ipyleaflet 0 2014-05-25 00:00:00+00:00 NaN\n", " 1 ipyleaflet 1 2014-06-08 00:00:00+00:00 0.5\n", " 2 ipyleaflet 2 2014-06-22 00:00:00+00:00 0.0\n", " 3 ipyleaflet 3 2014-07-06 00:00:00+00:00 0.0\n", " 4 ipyleaflet 4 2014-07-20 00:00:00+00:00 0.0\n", " .. ... ... ... ...\n", " 652 widget-ts-cookiecutter 652 2019-03-10 00:00:00+00:00 0.5\n", " 653 widget-ts-cookiecutter 653 2019-03-24 00:00:00+00:00 4.5\n", " 654 widget-ts-cookiecutter 654 2019-04-07 00:00:00+00:00 4.0\n", " 655 widget-ts-cookiecutter 655 2019-04-21 00:00:00+00:00 0.0\n", " 656 widget-ts-cookiecutter 656 2019-05-05 00:00:00+00:00 2.5\n", " \n", " [657 rows x 4 columns],\n", " layer: [Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'repo',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: OpacityValue({\n", " condition: OpacityValue({\n", " selection: SelectionNot({\n", " not: 'selector015'\n", " }),\n", " value: 0.3\n", " }),\n", " value: 1\n", " }),\n", " size: SizeValue({\n", " condition: SizeValue({\n", " selection: SelectionNot({\n", " not: 'selector015'\n", " }),\n", " value: 2\n", " }),\n", " value: 5\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2014-05-25', '2019-08-25']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'line'\n", " }),\n", " title: 'Comments over time for jupyter-widgets',\n", " width: 1000\n", " }), Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'repo',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 0\n", " }),\n", " size: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 300\n", " }),\n", " tooltip: Tooltip({\n", " field: 'repo',\n", " type: 'nominal'\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2014-05-25', '2019-08-25']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'point'\n", " }),\n", " selection: {'selector015': SelectionDef({\n", " fields: ['repo'],\n", " nearest: True,\n", " on: 'mouseover',\n", " type: 'single'\n", " }), 'selector016': SelectionDef({\n", " bind: 'scales',\n", " encodings: ['x', 'y'],\n", " type: 'interval'\n", " })},\n", " title: 'Comments over time for jupyter-widgets',\n", " width: 1000\n", " })]\n", " }), LayerChart({\n", " data: repo level_1 updatedAt id\n", " 0 atom-notebook 0 2015-08-02 00:00:00+00:00 NaN\n", " 1 atom-notebook 1 2015-08-16 00:00:00+00:00 6.0\n", " 2 atom-notebook 2 2015-08-30 00:00:00+00:00 1.0\n", " 3 atom-notebook 3 2015-09-13 00:00:00+00:00 0.0\n", " 4 atom-notebook 4 2015-09-27 00:00:00+00:00 0.0\n", " ... ... ... ... ...\n", " 2954 tmpnb 2954 2017-12-10 00:00:00+00:00 0.0\n", " 2955 tmpnb 2955 2017-12-24 00:00:00+00:00 0.5\n", " 2956 tmpnb 2956 2018-01-07 00:00:00+00:00 0.5\n", " 2957 tmpnb 2957 2018-01-21 00:00:00+00:00 5.0\n", " 2958 tmpnb 2958 2018-02-04 00:00:00+00:00 6.5\n", " \n", " [2959 rows x 4 columns],\n", " layer: [Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'repo',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: OpacityValue({\n", " condition: OpacityValue({\n", " selection: SelectionNot({\n", " not: 'selector017'\n", " }),\n", " value: 0.3\n", " }),\n", " value: 1\n", " }),\n", " size: SizeValue({\n", " condition: SizeValue({\n", " selection: SelectionNot({\n", " not: 'selector017'\n", " }),\n", " value: 2\n", " }),\n", " value: 5\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2012-12-16', '2019-09-01']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'line'\n", " }),\n", " title: 'Comments over time for jupyter',\n", " width: 1000\n", " }), Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'repo',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 0\n", " }),\n", " size: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 300\n", " }),\n", " tooltip: Tooltip({\n", " field: 'repo',\n", " type: 'nominal'\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2012-12-16', '2019-09-01']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'point'\n", " }),\n", " selection: {'selector017': SelectionDef({\n", " fields: ['repo'],\n", " nearest: True,\n", " on: 'mouseover',\n", " type: 'single'\n", " }), 'selector018': SelectionDef({\n", " bind: 'scales',\n", " encodings: ['x', 'y'],\n", " type: 'interval'\n", " })},\n", " title: 'Comments over time for jupyter',\n", " width: 1000\n", " })]\n", " }), LayerChart({\n", " data: repo level_1 updatedAt id\n", " 0 debugger 0 2019-08-11 00:00:00+00:00 NaN\n", " 1 debugger 1 2019-08-25 00:00:00+00:00 10.5\n", " 2 extension-cookiecutter-js 2 2016-09-25 00:00:00+00:00 NaN\n", " 3 extension-cookiecutter-js 3 2016-10-09 00:00:00+00:00 13.5\n", " 4 extension-cookiecutter-js 4 2016-10-23 00:00:00+00:00 6.5\n", " ... ... ... ... ...\n", " 1088 theme-cookiecutter 1088 2019-05-26 00:00:00+00:00 0.0\n", " 1089 theme-cookiecutter 1089 2019-06-09 00:00:00+00:00 0.0\n", " 1090 theme-cookiecutter 1090 2019-06-23 00:00:00+00:00 0.0\n", " 1091 theme-cookiecutter 1091 2019-07-07 00:00:00+00:00 0.0\n", " 1092 theme-cookiecutter 1092 2019-07-21 00:00:00+00:00 1.0\n", " \n", " [1093 rows x 4 columns],\n", " layer: [Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'repo',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: OpacityValue({\n", " condition: OpacityValue({\n", " selection: SelectionNot({\n", " not: 'selector019'\n", " }),\n", " value: 0.3\n", " }),\n", " value: 1\n", " }),\n", " size: SizeValue({\n", " condition: SizeValue({\n", " selection: SelectionNot({\n", " not: 'selector019'\n", " }),\n", " value: 2\n", " }),\n", " value: 5\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2016-06-12', '2019-09-01']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'line'\n", " }),\n", " title: 'Comments over time for jupyterlab',\n", " width: 1000\n", " }), Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'repo',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 0\n", " }),\n", " size: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 300\n", " }),\n", " tooltip: Tooltip({\n", " field: 'repo',\n", " type: 'nominal'\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2016-06-12', '2019-09-01']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'point'\n", " }),\n", " selection: {'selector019': SelectionDef({\n", " fields: ['repo'],\n", " nearest: True,\n", " on: 'mouseover',\n", " type: 'single'\n", " }), 'selector020': SelectionDef({\n", " bind: 'scales',\n", " encodings: ['x', 'y'],\n", " type: 'interval'\n", " })},\n", " title: 'Comments over time for jupyterlab',\n", " width: 1000\n", " })]\n", " }), LayerChart({\n", " data: repo level_1 updatedAt id\n", " 0 disp 0 2017-06-11 00:00:00+00:00 NaN\n", " 1 disp 1 2017-06-25 00:00:00+00:00 6.0\n", " 2 disp 2 2017-07-09 00:00:00+00:00 2.5\n", " 3 disp 3 2017-07-23 00:00:00+00:00 0.0\n", " 4 disp 4 2017-08-06 00:00:00+00:00 0.0\n", " ... ... ... ... ...\n", " 1291 xkcd-font 1291 2018-12-02 00:00:00+00:00 0.0\n", " 1292 xkcd-font 1292 2018-12-16 00:00:00+00:00 0.0\n", " 1293 xkcd-font 1293 2018-12-30 00:00:00+00:00 0.0\n", " 1294 xkcd-font 1294 2019-01-13 00:00:00+00:00 0.0\n", " 1295 xkcd-font 1295 2019-01-27 00:00:00+00:00 0.5\n", " \n", " [1296 rows x 4 columns],\n", " layer: [Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'repo',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: OpacityValue({\n", " condition: OpacityValue({\n", " selection: SelectionNot({\n", " not: 'selector021'\n", " }),\n", " value: 0.3\n", " }),\n", " value: 1\n", " }),\n", " size: SizeValue({\n", " condition: SizeValue({\n", " selection: SelectionNot({\n", " not: 'selector021'\n", " }),\n", " value: 2\n", " }),\n", " value: 5\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2010-05-16', '2019-08-25']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'line'\n", " }),\n", " title: 'Comments over time for ipython',\n", " width: 1000\n", " }), Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'repo',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 0\n", " }),\n", " size: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 300\n", " }),\n", " tooltip: Tooltip({\n", " field: 'repo',\n", " type: 'nominal'\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2010-05-16', '2019-08-25']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'point'\n", " }),\n", " selection: {'selector021': SelectionDef({\n", " fields: ['repo'],\n", " nearest: True,\n", " on: 'mouseover',\n", " type: 'single'\n", " }), 'selector022': SelectionDef({\n", " bind: 'scales',\n", " encodings: ['x', 'y'],\n", " type: 'interval'\n", " })},\n", " title: 'Comments over time for ipython',\n", " width: 1000\n", " })]\n", " }), LayerChart({\n", " data: repo level_1 updatedAt id\n", " 0 appmode 0 2017-12-17 00:00:00+00:00 NaN\n", " 1 appmode 1 2017-12-31 00:00:00+00:00 2.5\n", " 2 appmode 2 2018-01-14 00:00:00+00:00 11.5\n", " 3 apt_install 3 2019-03-10 00:00:00+00:00 NaN\n", " 4 bokeh 4 2019-06-23 00:00:00+00:00 NaN\n", " .. ... ... ... ...\n", " 350 setup.py 350 2018-11-11 00:00:00+00:00 0.0\n", " 351 setup.py 351 2018-11-25 00:00:00+00:00 0.0\n", " 352 setup.py 352 2018-12-09 00:00:00+00:00 0.0\n", " 353 setup.py 353 2018-12-23 00:00:00+00:00 0.5\n", " 354 stencila-r 354 2018-11-25 00:00:00+00:00 NaN\n", " \n", " [355 rows x 4 columns],\n", " layer: [Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'repo',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: OpacityValue({\n", " condition: OpacityValue({\n", " selection: SelectionNot({\n", " not: 'selector023'\n", " }),\n", " value: 0.3\n", " }),\n", " value: 1\n", " }),\n", " size: SizeValue({\n", " condition: SizeValue({\n", " selection: SelectionNot({\n", " not: 'selector023'\n", " }),\n", " value: 2\n", " }),\n", " value: 5\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2017-06-25', '2019-07-21']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'line'\n", " }),\n", " title: 'Comments over time for binder-examples',\n", " width: 1000\n", " }), Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'repo',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 0\n", " }),\n", " size: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 300\n", " }),\n", " tooltip: Tooltip({\n", " field: 'repo',\n", " type: 'nominal'\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2017-06-25', '2019-07-21']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'point'\n", " }),\n", " selection: {'selector023': SelectionDef({\n", " fields: ['repo'],\n", " nearest: True,\n", " on: 'mouseover',\n", " type: 'single'\n", " }), 'selector024': SelectionDef({\n", " bind: 'scales',\n", " encodings: ['x', 'y'],\n", " type: 'interval'\n", " })},\n", " title: 'Comments over time for binder-examples',\n", " width: 1000\n", " })]\n", " })]\n", "})" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "charts = []\n", "for iorg in github_orgs:\n", " print(iorg)\n", " icomments = comments.query('org == @iorg')\n", " repos = icomments.groupby(['repo', 'updatedAt']).agg({'id': 'count'}).reset_index()\n", "\n", " top_repos = repos.groupby('repo').sum()['id'].sort_values(ascending=False).head(n_repos).index\n", " repos = repos.query('repo in @top_repos')\n", " repos = repos.groupby('repo').resample(time_bin, on='updatedAt').sum().reset_index()\n", " repos = repos.groupby('repo').rolling(rolling_mean_amt, on='updatedAt').mean().reset_index()\n", " domain = [fmt_date.format(repos['updatedAt'].min()), fmt_date.format(repos['updatedAt'].max())]\n", " ch = highlighted_line_plot(repos, 'updatedAt', 'id', 'repo', f\"Comments over time for {iorg}\",\n", " legend=None, domain=domain)\n", " charts.append(ch)\n", "alt.hconcat(*charts)" ] }, { "cell_type": "markdown", "metadata": { "papermill": { "duration": 0.027687, "end_time": "2019-08-20T23:09:11.012019", "exception": false, "start_time": "2019-08-20T23:09:10.984332", "status": "completed" }, "tags": [] }, "source": [ "### Activity over time in each organization" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "papermill": { "duration": 1.237184, "end_time": "2019-08-20T23:09:12.276007", "exception": false, "start_time": "2019-08-20T23:09:11.038823", "status": "completed" }, "tags": [] }, "outputs": [ { "data": { "text/html": [ "\n", " \n", "
\n", " " ], "text/plain": [ "HConcatChart({\n", " hconcat: [LayerChart({\n", " data: org level_1 createdAt id\n", " 0 binder-examples 0 2017-06-25 00:00:00+00:00 NaN\n", " 1 binder-examples 1 2017-07-02 00:00:00+00:00 NaN\n", " 2 binder-examples 2 2017-07-09 00:00:00+00:00 NaN\n", " 3 binder-examples 3 2017-07-16 00:00:00+00:00 0.25\n", " 4 binder-examples 4 2017-07-23 00:00:00+00:00 0.00\n", " ... ... ... ... ...\n", " 1646 jupyterlab 1646 2019-07-28 00:00:00+00:00 48.75\n", " 1647 jupyterlab 1647 2019-08-04 00:00:00+00:00 43.75\n", " 1648 jupyterlab 1648 2019-08-11 00:00:00+00:00 43.00\n", " 1649 jupyterlab 1649 2019-08-18 00:00:00+00:00 43.75\n", " 1650 jupyterlab 1650 2019-08-25 00:00:00+00:00 33.00\n", " \n", " [1651 rows x 4 columns],\n", " layer: [Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'org',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: OpacityValue({\n", " condition: OpacityValue({\n", " selection: SelectionNot({\n", " not: 'selector025'\n", " }),\n", " value: 0.3\n", " }),\n", " value: 1\n", " }),\n", " size: SizeValue({\n", " condition: SizeValue({\n", " selection: SelectionNot({\n", " not: 'selector025'\n", " }),\n", " value: 2\n", " }),\n", " value: 5\n", " }),\n", " x: X({\n", " field: 'createdAt',\n", " scale: Scale({\n", " domain: ['2017-06-25', '2019-07-21']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'line'\n", " }),\n", " title: 'issues over time',\n", " width: 1000\n", " }), Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'org',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 0\n", " }),\n", " size: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 300\n", " }),\n", " tooltip: Tooltip({\n", " field: 'org',\n", " type: 'nominal'\n", " }),\n", " x: X({\n", " field: 'createdAt',\n", " scale: Scale({\n", " domain: ['2017-06-25', '2019-07-21']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'point'\n", " }),\n", " selection: {'selector025': SelectionDef({\n", " fields: ['org'],\n", " nearest: True,\n", " on: 'mouseover',\n", " type: 'single'\n", " }), 'selector026': SelectionDef({\n", " bind: 'scales',\n", " encodings: ['x', 'y'],\n", " type: 'interval'\n", " })},\n", " title: 'issues over time',\n", " width: 1000\n", " })]\n", " }), LayerChart({\n", " data: org level_1 createdAt id\n", " 0 binder-examples 0 2017-10-22 00:00:00+00:00 NaN\n", " 1 binder-examples 1 2017-10-29 00:00:00+00:00 NaN\n", " 2 binder-examples 2 2017-11-05 00:00:00+00:00 NaN\n", " 3 binder-examples 3 2017-11-12 00:00:00+00:00 1.00\n", " 4 binder-examples 4 2017-11-19 00:00:00+00:00 0.75\n", " ... ... ... ... ...\n", " 1208 jupyterlab 1208 2019-08-04 00:00:00+00:00 29.50\n", " 1209 jupyterlab 1209 2019-08-11 00:00:00+00:00 25.50\n", " 1210 jupyterlab 1210 2019-08-18 00:00:00+00:00 26.00\n", " 1211 jupyterlab 1211 2019-08-25 00:00:00+00:00 21.75\n", " 1212 nteract 1212 2019-08-04 00:00:00+00:00 NaN\n", " \n", " [1213 rows x 4 columns],\n", " layer: [Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'org',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: OpacityValue({\n", " condition: OpacityValue({\n", " selection: SelectionNot({\n", " not: 'selector027'\n", " }),\n", " value: 0.3\n", " }),\n", " value: 1\n", " }),\n", " size: SizeValue({\n", " condition: SizeValue({\n", " selection: SelectionNot({\n", " not: 'selector027'\n", " }),\n", " value: 2\n", " }),\n", " value: 5\n", " }),\n", " x: X({\n", " field: 'createdAt',\n", " scale: Scale({\n", " domain: ['2017-06-25', '2019-07-21']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'line'\n", " }),\n", " title: 'prs over time',\n", " width: 1000\n", " }), Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'org',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 0\n", " }),\n", " size: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 300\n", " }),\n", " tooltip: Tooltip({\n", " field: 'org',\n", " type: 'nominal'\n", " }),\n", " x: X({\n", " field: 'createdAt',\n", " scale: Scale({\n", " domain: ['2017-06-25', '2019-07-21']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'point'\n", " }),\n", " selection: {'selector027': SelectionDef({\n", " fields: ['org'],\n", " nearest: True,\n", " on: 'mouseover',\n", " type: 'single'\n", " }), 'selector028': SelectionDef({\n", " bind: 'scales',\n", " encodings: ['x', 'y'],\n", " type: 'interval'\n", " })},\n", " title: 'prs over time',\n", " width: 1000\n", " })]\n", " }), LayerChart({\n", " data: org level_1 createdAt id\n", " 0 binder-examples 0 2017-06-25 00:00:00+00:00 NaN\n", " 1 binder-examples 1 2017-07-02 00:00:00+00:00 NaN\n", " 2 binder-examples 2 2017-07-09 00:00:00+00:00 NaN\n", " 3 binder-examples 3 2017-07-16 00:00:00+00:00 0.50\n", " 4 binder-examples 4 2017-07-23 00:00:00+00:00 0.00\n", " ... ... ... ... ...\n", " 1644 jupyterlab 1644 2019-07-28 00:00:00+00:00 258.25\n", " 1645 jupyterlab 1645 2019-08-04 00:00:00+00:00 263.00\n", " 1646 jupyterlab 1646 2019-08-11 00:00:00+00:00 298.25\n", " 1647 jupyterlab 1647 2019-08-18 00:00:00+00:00 334.00\n", " 1648 jupyterlab 1648 2019-08-25 00:00:00+00:00 239.75\n", " \n", " [1649 rows x 4 columns],\n", " layer: [Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'org',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: OpacityValue({\n", " condition: OpacityValue({\n", " selection: SelectionNot({\n", " not: 'selector029'\n", " }),\n", " value: 0.3\n", " }),\n", " value: 1\n", " }),\n", " size: SizeValue({\n", " condition: SizeValue({\n", " selection: SelectionNot({\n", " not: 'selector029'\n", " }),\n", " value: 2\n", " }),\n", " value: 5\n", " }),\n", " x: X({\n", " field: 'createdAt',\n", " scale: Scale({\n", " domain: ['2017-06-25', '2019-07-21']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'line'\n", " }),\n", " title: 'comments over time',\n", " width: 1000\n", " }), Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'org',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 0\n", " }),\n", " size: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 300\n", " }),\n", " tooltip: Tooltip({\n", " field: 'org',\n", " type: 'nominal'\n", " }),\n", " x: X({\n", " field: 'createdAt',\n", " scale: Scale({\n", " domain: ['2017-06-25', '2019-07-21']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'id',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'point'\n", " }),\n", " selection: {'selector029': SelectionDef({\n", " fields: ['org'],\n", " nearest: True,\n", " on: 'mouseover',\n", " type: 'single'\n", " }), 'selector030': SelectionDef({\n", " bind: 'scales',\n", " encodings: ['x', 'y'],\n", " type: 'interval'\n", " })},\n", " title: 'comments over time',\n", " width: 1000\n", " })]\n", " })]\n", "})" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "charts = []\n", "\n", "for kind, idata in [('issues', issues), ('prs', prs), ('comments', comments)]:\n", " org_comments = idata.groupby('org').resample('W', on='createdAt').count()['id'].reset_index()\n", " org_comments = org_comments.groupby('org').rolling(4, on='createdAt').mean().reset_index()\n", "\n", " ch = highlighted_line_plot(org_comments, 'createdAt', 'id', 'org', f\"{kind} over time\", legend=None, domain=domain)\n", " charts.append(ch)\n", "alt.hconcat(*charts)" ] }, { "cell_type": "markdown", "metadata": { "papermill": { "duration": 0.035159, "end_time": "2019-08-20T23:09:12.340116", "exception": false, "start_time": "2019-08-20T23:09:12.304957", "status": "completed" }, "tags": [] }, "source": [ "## Time to first response of issues" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "papermill": { "duration": 0.079681, "end_time": "2019-08-20T23:09:12.453581", "exception": false, "start_time": "2019-08-20T23:09:12.373900", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "first_comments = (\n", " comments.groupby(['org', 'repo', 'issue_id'], as_index=False) \n", " .agg({'id': 'first', 'createdAt': 'first'})\n", " .rename(columns={'createdAt': 'firstResponse', 'issue_id': 'number'})\n", " .drop(columns='id')\n", ")" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "papermill": { "duration": 0.085153, "end_time": "2019-08-20T23:09:12.572126", "exception": false, "start_time": "2019-08-20T23:09:12.486973", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "issues_w_response = pd.merge(first_comments, issues, on=['org', 'repo', 'number'])\n", "issues_w_response[['createdAt', 'firstResponse']] = issues_w_response[['createdAt', 'firstResponse']].apply(pd.to_datetime)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "papermill": { "duration": 0.186074, "end_time": "2019-08-20T23:09:12.797072", "exception": false, "start_time": "2019-08-20T23:09:12.610998", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "issues_w_response['time_to_first_response'] = issues_w_response['firstResponse'] - issues_w_response['createdAt']\n", "issues_w_response['hours_to_first_response'] = issues_w_response['time_to_first_response'].map(lambda a: 24 * a.days + a.seconds / 60 / 60)" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "papermill": { "duration": 2.424111, "end_time": "2019-08-20T23:09:15.249268", "exception": false, "start_time": "2019-08-20T23:09:12.825157", "status": "completed" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "jupyterhub\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "jupyter-widgets\n", "jupyter\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "jupyterlab\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "ipython\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "binder-examples\n" ] }, { "data": { "text/html": [ "\n", " \n", "
\n", " " ], "text/plain": [ "HConcatChart({\n", " hconcat: [LayerChart({\n", " data: repo updatedAt \\\n", " 4 batchspawner 2016-07-10 00:00:00+00:00 \n", " 5 batchspawner 2016-07-24 00:00:00+00:00 \n", " 6 batchspawner 2016-08-07 00:00:00+00:00 \n", " 7 batchspawner 2016-08-21 00:00:00+00:00 \n", " 8 batchspawner 2016-09-04 00:00:00+00:00 \n", " ... ... ... \n", " 2048 zero-to-jupyterhub-k8s 2019-07-07 00:00:00+00:00 \n", " 2049 zero-to-jupyterhub-k8s 2019-07-21 00:00:00+00:00 \n", " 2050 zero-to-jupyterhub-k8s 2019-08-04 00:00:00+00:00 \n", " 2051 zero-to-jupyterhub-k8s 2019-08-18 00:00:00+00:00 \n", " 2052 zero-to-jupyterhub-k8s 2019-09-01 00:00:00+00:00 \n", " \n", " hours_to_first_response \n", " 4 NaN \n", " 5 NaN \n", " 6 NaN \n", " 7 NaN \n", " 8 22.398333 \n", " ... ... \n", " 2048 439.230917 \n", " 2049 486.551833 \n", " 2050 544.098639 \n", " 2051 529.202972 \n", " 2052 1147.504083 \n", " \n", " [1576 rows x 3 columns],\n", " layer: [Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'repo',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: OpacityValue({\n", " condition: OpacityValue({\n", " selection: SelectionNot({\n", " not: 'selector031'\n", " }),\n", " value: 0.3\n", " }),\n", " value: 1\n", " }),\n", " size: SizeValue({\n", " condition: SizeValue({\n", " selection: SelectionNot({\n", " not: 'selector031'\n", " }),\n", " value: 2\n", " }),\n", " value: 5\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2015-01-11', '2019-09-01']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'hours_to_first_response',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'line'\n", " }),\n", " title: 'Hours to first response for jupyterhub',\n", " width: 1000\n", " }), Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'repo',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 0\n", " }),\n", " size: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 300\n", " }),\n", " tooltip: Tooltip({\n", " field: 'repo',\n", " type: 'nominal'\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2015-01-11', '2019-09-01']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'hours_to_first_response',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'point'\n", " }),\n", " selection: {'selector031': SelectionDef({\n", " fields: ['repo'],\n", " nearest: True,\n", " on: 'mouseover',\n", " type: 'single'\n", " }), 'selector032': SelectionDef({\n", " bind: 'scales',\n", " encodings: ['x', 'y'],\n", " type: 'interval'\n", " })},\n", " title: 'Hours to first response for jupyterhub',\n", " width: 1000\n", " })]\n", " }), LayerChart({\n", " data: repo updatedAt hours_to_first_response\n", " 0 ipyleaflet 2018-04-08 00:00:00+00:00 NaN\n", " 1 ipyleaflet 2018-04-22 00:00:00+00:00 NaN\n", " 2 ipyleaflet 2018-05-06 00:00:00+00:00 NaN\n", " 3 ipyleaflet 2018-05-20 00:00:00+00:00 NaN\n", " 4 ipyleaflet 2018-06-03 00:00:00+00:00 1657.512167\n", " .. ... ... ...\n", " 416 widget-ts-cookiecutter 2019-03-10 00:00:00+00:00 12.720000\n", " 417 widget-ts-cookiecutter 2019-03-24 00:00:00+00:00 17.746722\n", " 418 widget-ts-cookiecutter 2019-04-07 00:00:00+00:00 15.587778\n", " 419 widget-ts-cookiecutter 2019-04-21 00:00:00+00:00 15.587778\n", " 420 widget-ts-cookiecutter 2019-05-05 00:00:00+00:00 33.306778\n", " \n", " [421 rows x 3 columns],\n", " layer: [Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'repo',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: OpacityValue({\n", " condition: OpacityValue({\n", " selection: SelectionNot({\n", " not: 'selector033'\n", " }),\n", " value: 0.3\n", " }),\n", " value: 1\n", " }),\n", " size: SizeValue({\n", " condition: SizeValue({\n", " selection: SelectionNot({\n", " not: 'selector033'\n", " }),\n", " value: 2\n", " }),\n", " value: 5\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2015-05-10', '2019-09-01']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'hours_to_first_response',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'line'\n", " }),\n", " title: 'Hours to first response for jupyter-widgets',\n", " width: 1000\n", " }), Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'repo',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 0\n", " }),\n", " size: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 300\n", " }),\n", " tooltip: Tooltip({\n", " field: 'repo',\n", " type: 'nominal'\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2015-05-10', '2019-09-01']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'hours_to_first_response',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'point'\n", " }),\n", " selection: {'selector033': SelectionDef({\n", " fields: ['repo'],\n", " nearest: True,\n", " on: 'mouseover',\n", " type: 'single'\n", " }), 'selector034': SelectionDef({\n", " bind: 'scales',\n", " encodings: ['x', 'y'],\n", " type: 'interval'\n", " })},\n", " title: 'Hours to first response for jupyter-widgets',\n", " width: 1000\n", " })]\n", " }), LayerChart({\n", " data: repo updatedAt hours_to_first_response\n", " 4 atom-notebook 2015-08-02 00:00:00+00:00 NaN\n", " 5 atom-notebook 2015-08-16 00:00:00+00:00 NaN\n", " 6 atom-notebook 2015-08-30 00:00:00+00:00 NaN\n", " 7 atom-notebook 2015-09-13 00:00:00+00:00 NaN\n", " 8 atom-notebook 2015-09-27 00:00:00+00:00 1.447583\n", " ... ... ... ...\n", " 3763 testpath 2019-05-12 00:00:00+00:00 0.000000\n", " 3764 testpath 2019-05-26 00:00:00+00:00 0.000000\n", " 3765 testpath 2019-06-09 00:00:00+00:00 0.000000\n", " 3766 testpath 2019-06-23 00:00:00+00:00 0.000000\n", " 3767 testpath 2019-07-07 00:00:00+00:00 8.398778\n", " \n", " [2182 rows x 3 columns],\n", " layer: [Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'repo',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: OpacityValue({\n", " condition: OpacityValue({\n", " selection: SelectionNot({\n", " not: 'selector035'\n", " }),\n", " value: 0.3\n", " }),\n", " value: 1\n", " }),\n", " size: SizeValue({\n", " condition: SizeValue({\n", " selection: SelectionNot({\n", " not: 'selector035'\n", " }),\n", " value: 2\n", " }),\n", " value: 5\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2015-01-11', '2019-09-01']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'hours_to_first_response',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'line'\n", " }),\n", " title: 'Hours to first response for jupyter',\n", " width: 1000\n", " }), Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'repo',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 0\n", " }),\n", " size: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 300\n", " }),\n", " tooltip: Tooltip({\n", " field: 'repo',\n", " type: 'nominal'\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2015-01-11', '2019-09-01']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'hours_to_first_response',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'point'\n", " }),\n", " selection: {'selector035': SelectionDef({\n", " fields: ['repo'],\n", " nearest: True,\n", " on: 'mouseover',\n", " type: 'single'\n", " }), 'selector036': SelectionDef({\n", " bind: 'scales',\n", " encodings: ['x', 'y'],\n", " type: 'interval'\n", " })},\n", " title: 'Hours to first response for jupyter',\n", " width: 1000\n", " })]\n", " }), LayerChart({\n", " data: repo updatedAt \\\n", " 1 extension-cookiecutter-js 2016-10-02 00:00:00+00:00 \n", " 2 extension-cookiecutter-js 2016-10-16 00:00:00+00:00 \n", " 3 extension-cookiecutter-js 2016-10-30 00:00:00+00:00 \n", " 4 extension-cookiecutter-js 2016-11-13 00:00:00+00:00 \n", " 5 extension-cookiecutter-js 2016-11-27 00:00:00+00:00 \n", " .. ... ... \n", " 956 scipy2018-jupyterlab-tutorial 2019-05-12 00:00:00+00:00 \n", " 957 scipy2018-jupyterlab-tutorial 2019-05-26 00:00:00+00:00 \n", " 958 scipy2018-jupyterlab-tutorial 2019-06-09 00:00:00+00:00 \n", " 959 scipy2018-jupyterlab-tutorial 2019-06-23 00:00:00+00:00 \n", " 960 scipy2018-jupyterlab-tutorial 2019-07-07 00:00:00+00:00 \n", " \n", " hours_to_first_response \n", " 1 NaN \n", " 2 NaN \n", " 3 NaN \n", " 4 NaN \n", " 5 0.250111 \n", " .. ... \n", " 956 0.000000 \n", " 957 0.000000 \n", " 958 0.000000 \n", " 959 0.000000 \n", " 960 181.427333 \n", " \n", " [926 rows x 3 columns],\n", " layer: [Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'repo',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: OpacityValue({\n", " condition: OpacityValue({\n", " selection: SelectionNot({\n", " not: 'selector037'\n", " }),\n", " value: 0.3\n", " }),\n", " value: 1\n", " }),\n", " size: SizeValue({\n", " condition: SizeValue({\n", " selection: SelectionNot({\n", " not: 'selector037'\n", " }),\n", " value: 2\n", " }),\n", " value: 5\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2016-06-12', '2019-09-01']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'hours_to_first_response',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'line'\n", " }),\n", " title: 'Hours to first response for jupyterlab',\n", " width: 1000\n", " }), Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'repo',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 0\n", " }),\n", " size: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 300\n", " }),\n", " tooltip: Tooltip({\n", " field: 'repo',\n", " type: 'nominal'\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2016-06-12', '2019-09-01']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'hours_to_first_response',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'point'\n", " }),\n", " selection: {'selector037': SelectionDef({\n", " fields: ['repo'],\n", " nearest: True,\n", " on: 'mouseover',\n", " type: 'single'\n", " }), 'selector038': SelectionDef({\n", " bind: 'scales',\n", " encodings: ['x', 'y'],\n", " type: 'interval'\n", " })},\n", " title: 'Hours to first response for jupyterlab',\n", " width: 1000\n", " })]\n", " }), LayerChart({\n", " data: repo updatedAt hours_to_first_response\n", " 0 disp 2017-06-11 00:00:00+00:00 NaN\n", " 1 disp 2017-06-25 00:00:00+00:00 NaN\n", " 2 disp 2017-07-09 00:00:00+00:00 NaN\n", " 3 disp 2017-07-23 00:00:00+00:00 NaN\n", " 4 disp 2017-08-06 00:00:00+00:00 2.490667\n", " .. ... ... ...\n", " 893 xkcd-font 2018-12-02 00:00:00+00:00 0.000000\n", " 894 xkcd-font 2018-12-16 00:00:00+00:00 0.000000\n", " 895 xkcd-font 2018-12-30 00:00:00+00:00 0.000000\n", " 896 xkcd-font 2019-01-13 00:00:00+00:00 0.000000\n", " 897 xkcd-font 2019-01-27 00:00:00+00:00 6665.689722\n", " \n", " [898 rows x 3 columns],\n", " layer: [Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'repo',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: OpacityValue({\n", " condition: OpacityValue({\n", " selection: SelectionNot({\n", " not: 'selector039'\n", " }),\n", " value: 0.3\n", " }),\n", " value: 1\n", " }),\n", " size: SizeValue({\n", " condition: SizeValue({\n", " selection: SelectionNot({\n", " not: 'selector039'\n", " }),\n", " value: 2\n", " }),\n", " value: 5\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2015-01-04', '2019-09-01']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'hours_to_first_response',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'line'\n", " }),\n", " title: 'Hours to first response for ipython',\n", " width: 1000\n", " }), Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'repo',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 0\n", " }),\n", " size: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 300\n", " }),\n", " tooltip: Tooltip({\n", " field: 'repo',\n", " type: 'nominal'\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2015-01-04', '2019-09-01']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'hours_to_first_response',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'point'\n", " }),\n", " selection: {'selector039': SelectionDef({\n", " fields: ['repo'],\n", " nearest: True,\n", " on: 'mouseover',\n", " type: 'single'\n", " }), 'selector040': SelectionDef({\n", " bind: 'scales',\n", " encodings: ['x', 'y'],\n", " type: 'interval'\n", " })},\n", " title: 'Hours to first response for ipython',\n", " width: 1000\n", " })]\n", " }), LayerChart({\n", " data: repo updatedAt hours_to_first_response\n", " 2 apt_install 2019-03-10 00:00:00+00:00 NaN\n", " 3 bokeh 2019-06-23 00:00:00+00:00 NaN\n", " 4 conda 2018-12-16 00:00:00+00:00 NaN\n", " 5 continuous-build 2018-07-22 00:00:00+00:00 NaN\n", " 6 continuous-build 2018-08-05 00:00:00+00:00 NaN\n", " .. ... ... ...\n", " 216 requirements 2019-03-17 00:00:00+00:00 0.000000\n", " 217 requirements 2019-03-31 00:00:00+00:00 0.000000\n", " 218 requirements 2019-04-14 00:00:00+00:00 0.000000\n", " 219 requirements 2019-04-28 00:00:00+00:00 1.530167\n", " 220 setup.py 2018-12-23 00:00:00+00:00 NaN\n", " \n", " [218 rows x 3 columns],\n", " layer: [Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'repo',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: OpacityValue({\n", " condition: OpacityValue({\n", " selection: SelectionNot({\n", " not: 'selector041'\n", " }),\n", " value: 0.3\n", " }),\n", " value: 1\n", " }),\n", " size: SizeValue({\n", " condition: SizeValue({\n", " selection: SelectionNot({\n", " not: 'selector041'\n", " }),\n", " value: 2\n", " }),\n", " value: 5\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2017-11-19', '2019-07-28']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'hours_to_first_response',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'line'\n", " }),\n", " title: 'Hours to first response for binder-examples',\n", " width: 1000\n", " }), Chart({\n", " encoding: FacetedEncoding({\n", " color: Color({\n", " field: 'repo',\n", " legend: None,\n", " type: 'nominal'\n", " }),\n", " opacity: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 0\n", " }),\n", " size: ValueDefWithOptionalConditionMarkPropFieldDefnumber({\n", " value: 300\n", " }),\n", " tooltip: Tooltip({\n", " field: 'repo',\n", " type: 'nominal'\n", " }),\n", " x: X({\n", " field: 'updatedAt',\n", " scale: Scale({\n", " domain: ['2017-11-19', '2019-07-28']\n", " }),\n", " type: 'temporal'\n", " }),\n", " y: Y({\n", " field: 'hours_to_first_response',\n", " type: 'quantitative'\n", " })\n", " }),\n", " mark: MarkDef({\n", " clip: True,\n", " type: 'point'\n", " }),\n", " selection: {'selector041': SelectionDef({\n", " fields: ['repo'],\n", " nearest: True,\n", " on: 'mouseover',\n", " type: 'single'\n", " }), 'selector042': SelectionDef({\n", " bind: 'scales',\n", " encodings: ['x', 'y'],\n", " type: 'interval'\n", " })},\n", " title: 'Hours to first response for binder-examples',\n", " width: 1000\n", " })]\n", " })]\n", "})" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "charts = []\n", "for iorg in github_orgs:\n", " print(iorg)\n", " i_issues = issues_w_response.query('org == @iorg')\n", " repo_comments = (\n", " i_issues.groupby('repo')\n", " .resample(time_bin, on='updatedAt').median()['hours_to_first_response']\n", " .reset_index()\n", " .replace(np.nan, 0)\n", " .groupby('repo').rolling(5, on='updatedAt').mean().reset_index('repo')\n", " )\n", "\n", " n_plot = 20\n", " top_repos = repo_comments.groupby('repo').count()['hours_to_first_response'].sort_values(ascending=False).head(n_plot).index.values\n", " repo_comments = repo_comments.query('repo in @top_repos')\n", " domain = [fmt_date.format(repo_comments['updatedAt'].min()), fmt_date.format(repo_comments['updatedAt'].max())]\n", " ch = highlighted_line_plot(repo_comments, 'updatedAt', 'hours_to_first_response', 'repo', f\"Hours to first response for {iorg}\",\n", " legend=None, domain=domain)\n", " charts.append(ch)\n", "alt.hconcat(*charts)" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "papermill": { "duration": 0.061551, "end_time": "2019-08-20T23:09:15.348647", "exception": false, "start_time": "2019-08-20T23:09:15.287096", "status": "completed" }, "tags": [] }, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%%html\n", "" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "papermill": { "duration": 0.047356, "end_time": "2019-08-20T23:09:15.437163", "exception": false, "start_time": "2019-08-20T23:09:15.389807", "status": "completed" }, "tags": [] }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.3" }, "papermill": { "duration": 14.268804, "end_time": "2019-08-20T23:09:15.888733", "environment_variables": {}, "exception": null, "input_path": "./time.ipynb", "output_path": "../reports/summaries/time.ipynb", "parameters": { "github_orgs": [ "jupyterhub", "jupyter", "jupyterlab", "jupyter-widgets", "ipython", "binder-examples" ], "renderer": "kaggle" }, "start_time": "2019-08-20T23:09:01.619929", "version": "1.0.1" }, "widgets": { "application/vnd.jupyter.widget-state+json": { "state": {}, "version_major": 2, "version_minor": 0 } } }, "nbformat": 4, "nbformat_minor": 4 }