Skip to content

Instantly share code, notes, and snippets.

@oshikiri
Last active June 12, 2018 14:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oshikiri/5bd0bc8bd6d49090ec0b8396513fc787 to your computer and use it in GitHub Desktop.
Save oshikiri/5bd0bc8bd6d49090ec0b8396513fc787 to your computer and use it in GitHub Desktop.
Plot the GitHub punch card of d3/d3 repository using d3.js
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"ExecuteTime": {
"end_time": "2018-06-12T13:58:11.249726Z",
"start_time": "2018-06-12T13:58:10.950752Z"
}
},
"outputs": [],
"source": [
"import pandas as pd\n",
"from IPython.display import IFrame, HTML"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Fetch and preprocess json"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"ExecuteTime": {
"end_time": "2018-06-12T13:58:11.956593Z",
"start_time": "2018-06-12T13:58:11.251083Z"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style>\n",
" .dataframe thead tr:only-child th {\n",
" text-align: right;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: left;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>dow</th>\n",
" <th>hour</th>\n",
" <th>contributions</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>7</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>0</td>\n",
" <td>2</td>\n",
" <td>1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>0</td>\n",
" <td>3</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>0</td>\n",
" <td>4</td>\n",
" <td>0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" dow hour contributions\n",
"0 0 0 7\n",
"1 0 1 0\n",
"2 0 2 1\n",
"3 0 3 0\n",
"4 0 4 0"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"user, repository = 'd3', 'd3'\n",
"\n",
"data = pd.read_json(f'https://api.github.com/repos/{user}/{repository}/stats/punch_card')\n",
"data.columns = ['dow', 'hour', 'contributions']\n",
"data.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Save to local"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"ExecuteTime": {
"end_time": "2018-06-12T13:58:11.961669Z",
"start_time": "2018-06-12T13:58:11.958479Z"
}
},
"outputs": [],
"source": [
"data.to_json('contributions.json', orient='records')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Plot using d3.js"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"ExecuteTime": {
"end_time": "2018-06-12T13:58:12.077996Z",
"start_time": "2018-06-12T13:58:11.964149Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<!DOCTYPE html>\r\n",
"<meta charset=\"utf-8\">\r\n",
"<body>\r\n",
"<style>\r\n",
" div.tooltip {\r\n",
" position: absolute;\r\n",
" text-align: center;\r\n",
" width: 60px;\r\n",
" height: 28px;\r\n",
" padding: 2px;\r\n",
" font: 12px sans-serif;\r\n",
" background: rgb(255, 255, 255);\r\n",
" border: 0px;\r\n",
" border-radius: 8px;\r\n",
" pointer-events: none;\r\n",
" }\r\n",
"</style>\r\n",
"<script src=\"https://d3js.org/d3.v5.min.js\"></script>\r\n",
"<script>\r\n",
" const margin = {top: 20, right: 20, bottom: 50, left: 50};\r\n",
" const width = 600 - margin.left - margin.right;\r\n",
" const height = 200 - margin.top - margin.bottom;\r\n",
"\r\n",
" const xScale = d3.scaleLinear().range([0, width]);\r\n",
" const yScale = d3.scaleLinear().rangeRound([0, height]);\r\n",
" const rScale = d3.scaleSqrt().range([0, 10]);\r\n",
"\r\n",
" const dayOfWeek = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thr\", \"Fri\", \"Sat\"];\r\n",
"\r\n",
" const svg = d3.select(\"body\")\r\n",
" .append(\"svg\")\r\n",
" .attr(\"width\", width + margin.left + margin.right)\r\n",
" .attr(\"height\", height + margin.top + margin.bottom)\r\n",
" .append(\"g\")\r\n",
" .attr(\"transform\", `translate(${margin.left}, ${margin.top})`);\r\n",
"\r\n",
" d3.json(\"/files/contributions.json\").then(data => {\r\n",
" xScale.domain([-0.5, 23.5]);\r\n",
" yScale.domain([-0.5, 6.5]);\r\n",
" rScale.domain([0, d3.max(data, d => d.contributions)]);\r\n",
"\r\n",
" const div = d3.select(\"body\").append(\"div\")\r\n",
" .attr(\"class\", \"tooltip\")\r\n",
" .style(\"opacity\", 0);\r\n",
"\r\n",
" svg.selectAll(\"dot\")\r\n",
" .data(data)\r\n",
" .enter().append(\"circle\")\r\n",
" .attr(\"r\", d => rScale(d.contributions))\r\n",
" .attr(\"cx\", d => xScale(d.hour))\r\n",
" .attr(\"cy\", d => yScale(d.dow))\r\n",
" .on('mouseover', d => {\r\n",
" div.transition()\r\n",
" .duration(200)\r\n",
" .style(\"opacity\", .9);\r\n",
" div.html(`${dayOfWeek[d.dow]}, ${d.hour}<br />${d.contributions}`)\r\n",
" .style(\"left\", (d3.event.pageX) + \"px\")\r\n",
" .style(\"top\", (d3.event.pageY - 28) + \"px\");\r\n",
" })\r\n",
" .on(\"mouseout\", d => {\r\n",
" div.transition()\r\n",
" .duration(500)\r\n",
" .style(\"opacity\", 0);\r\n",
" });\r\n",
"\r\n",
" svg.append(\"g\")\r\n",
" .attr(\"transform\", `translate(0, ${height})`)\r\n",
" .call(d3.axisBottom(xScale).ticks(24));\r\n",
"\r\n",
" svg.append(\"g\")\r\n",
" .call(\r\n",
" d3.axisLeft(yScale)\r\n",
" .ticks(7)\r\n",
" .tickFormat((d, i) => dayOfWeek[d])\r\n",
" );\r\n",
"\r\n",
" svg.append(\"text\")\r\n",
" .attr(\"transform\", `translate(${width / 2}, ${(height + margin.top + 15)})`)\r\n",
" .style(\"text-anchor\", \"middle\")\r\n",
" .style(\"font-size\", \"12px\")\r\n",
" .text(\"hour\");\r\n",
"\r\n",
" svg.append(\"text\")\r\n",
" .attr(\"transform\", \"rotate(-90)\")\r\n",
" .attr(\"y\", 0 - margin.left)\r\n",
" .attr(\"x\", 0 - (height / 2))\r\n",
" .attr(\"dy\", \"1em\")\r\n",
" .style(\"text-anchor\", \"middle\")\r\n",
" .style(\"font-size\", \"12px\")\r\n",
" .text(\"day of week\"); \r\n",
" });\r\n",
"</script>\r\n",
"</body>\r\n"
]
}
],
"source": [
"!cat punchcard.html"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"ExecuteTime": {
"end_time": "2018-06-12T13:58:12.082965Z",
"start_time": "2018-06-12T13:58:12.079402Z"
}
},
"outputs": [
{
"data": {
"text/html": [
"\n",
" <iframe\n",
" width=\"650\"\n",
" height=\"250\"\n",
" src=\"punchcard.html\"\n",
" frameborder=\"0\"\n",
" allowfullscreen\n",
" ></iframe>\n",
" "
],
"text/plain": [
"<IPython.lib.display.IFrame at 0x7f932f8d1198>"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"IFrame(src=\"punchcard.html\", width=650, height=250)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"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.6.3"
},
"toc": {
"nav_menu": {},
"number_sections": true,
"sideBar": true,
"skip_h1_title": false,
"toc_cell": false,
"toc_position": {},
"toc_section_display": "block",
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 2
}
@oshikiri
Copy link
Author

screenshot

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment