-
Notifications
You must be signed in to change notification settings - Fork 0
/
index-1.html
332 lines (297 loc) · 29 KB
/
index-1.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
<!DOCTYPE html>
<html prefix="og: http://ogp.me/ns# " lang="en">
<head>
<meta charset="utf-8">
<meta name="description" content="Mike Jarrett's Blog">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Mike Jarrett (old posts, page 1) | Mike Jarrett</title>
<link href="assets/css/all-nocdn.css" rel="stylesheet" type="text/css">
<link href="assets/css/ipython.min.css" rel="stylesheet" type="text/css">
<link href="assets/css/nikola_ipython.css" rel="stylesheet" type="text/css">
<meta name="theme-color" content="#5670d4">
<meta name="generator" content="Nikola (getnikola.com)">
<link rel="alternate" type="application/rss+xml" title="RSS" hreflang="en" href="rss.xml">
<link rel="canonical" href="https://notes.mikejarrett.ca/index-1.html">
<link rel="icon" href="images/favicon.ico" sizes="16x16">
<link rel="apple-touch-icon" href="images/apple-icon-57x57.png" sizes="57x57">
<link rel="apple-touch-icon" href="images/apple-icon-60x60.png" sizes="60x60">
<link rel="apple-touch-icon" href="images/apple-icon-72x72.png" sizes="72x72">
<link rel="apple-touch-icon" href="images/apple-icon-76x76.png" sizes="76x76">
<link rel="apple-touch-icon" href="images/apple-icon-114x114.png" sizes="114x114">
<link rel="apple-touch-icon" href="images/apple-icon-120x120.png" sizes="120x120">
<link rel="apple-touch-icon" href="images/apple-icon-144x144.png" sizes="144x144">
<link rel="apple-touch-icon" href="images/apple-icon-152x152.png" sizes="152x152">
<link rel="apple-touch-icon" href="images/apple-icon-180x180.png" sizes="180x180">
<link rel="icon" href="images/android-icon-192x192.png" sizes="192x192">
<link rel="icon" href="images/favicon-32x32.png" sizes="32x32">
<link rel="icon" href="images/favicon-96x96.png" sizes="96x96">
<link rel="icon" href="images/favicon-16x16.png" sizes="16x16">
<link rel="prev" href="." type="text/html">
<!--[if lt IE 9]><script src="assets/js/html5.js"></script><![endif]--><meta property="og:image" content="/images/logo_large.png">
<!-- Global site tag (gtag.js) - Google Analytics --><script async src="https://www.googletagmanager.com/gtag/js?id=UA-132843241-1"></script><script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-132843241-1');
</script><script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
<body>
<a href="#content" class="sr-only sr-only-focusable">Skip to main content</a>
<!-- Menubar -->
<nav class="navbar navbar-inverse navbar-static-top"><div class="container">
<!-- This keeps the margins nice -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-navbar" aria-controls="bs-navbar" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="https://notes.mikejarrett.ca/">
<img src="images/logo.png" alt="Mike Jarrett" id="logo"><span id="blog-title">Mike Jarrett</span>
</a>
</div>
<!-- /.navbar-header -->
<div class="collapse navbar-collapse" id="bs-navbar" aria-expanded="false">
<ul class="nav navbar-nav">
<li>
<a href="archive.html">Archive</a>
</li>
<li>
<a href="categories/">Tags</a>
</li>
<li>
<a href="about-me/">About</a>
</li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Projects <b class="caret"></b></a>
<ul class="dropdown-menu">
<li>
<a href="https://twitter.com/vanbikesharebot">@VanBikeShareBot</a>
</li>
<li>
<a href="https://twitter.com/tobikesharebot">@TOBikeShareBot</a>
</li>
<li>
<a href="https://bikedata.mikejarrett.ca">BikeData Vancouver</a>
</li>
</ul>
</li>
</ul>
<ul class="nav navbar-nav navbar-right"></ul>
</div>
<!-- /.navbar-collapse -->
</div>
<!-- /.container -->
</nav><!-- End of Menubar --><div class="container" id="content" role="main">
<div class="body-content">
<!--Body content-->
<div class="row">
<div class="postindex">
<article class="h-entry post-text" itemscope="itemscope" itemtype="http://schema.org/Article"><header><h1 class="p-name entry-title"><a href="mobi-station-activity/" class="u-url">Mobi station activity</a></h1>
<div class="metadata">
<p class="byline author vcard"><span class="byline-name fn" itemprop="author">
Mike Jarrett
</span></p>
<p class="dateline">
<a href="mobi-station-activity/" rel="bookmark">
<time class="published dt-published" datetime="2017-11-04T22:36:22-07:00" itemprop="datePublished" title="2017-11-04 22:36">2017-11-04 22:36</time></a>
</p>
<p class="commentline">
<a href="mobi-station-activity/#disqus_thread" data-disqus-identifier="cache/posts/mobi-station-activity.html">Comments</a>
</p>
</div>
</header><div class="p-summary entry-summary">
<div>
<p></p>
<p>I finally got around to learning how to map data on to maps with Cartopy, so here's some quick maps of Mobi bikeshare station activity.</p>
<p>First, an animation of station activity during a random summer day. The red-blue spectrum represents whether more bikes were taken or returned at a given station, and the brightness represents total station activity during each hour. I could take the time resolution lower than an hour, but I doubt the data is very meaningful at that level.</p>
<p>[video width="704" height="528" mp4="http://mikejarrett.ca/blog/wp-content/uploads/movie_2017-08-18.mp4"][/video]</p>
<!--more-->
<p>There's actually less pattern to this than I expected. I thought that in the morning you'd see more bikes being taken from the west end and south False Creek and returned downtown, and vice versa in the afternoon. But I can't really make out that pattern visually.</p>
<p>I've also pulled out total station activity during the time I've been collecting this data, June through October 2017. I've separated it by total bikes taken and total bikes returned. A couple things to note about these images: many of these stations were not active for the whole time period, and some stations have been moved around. I've made no effort to account for this; this is simply the raw usage at each location, so the downtown</p>
<p><img class="alignnone size-full wp-image-210" style="font-size: 1rem;" src="http://mikejarrett.ca/blog/wp-content/uploads/Total-Bikes-Taken-June-Oct-2017-1.png" alt="" width="640" height="480"><img class="alignnone size-full wp-image-209" style="font-size: 1rem;" src="http://mikejarrett.ca/blog/wp-content/uploads/Total-Bikes-Returned-June-Oct-2017-1.png" alt="" width="640" height="480"></p>
<p>The similarity in these maps is striking. Checking the raw data, I'm seeing incredibly similar numbers of bikes being taken and returned at each station. This either means that on aggregate people use Mobis for two way trips much more often than I expected; one way trips are cancelling each other out; or Mobi is rebalancing the stations to a degree that any unevenness is being masked out*. I hope to look more into whether I can spot artificial station balancing from my data soon, but we may have to wait for official data from Mobi to get around this.</p>
<p><em>*There's also the possibility that my data is bad, but let's ignore that for now</em></p>
<p>Instead of just looking at activity, I tried to quantify whether there are different activity patterns at different stations. Like <a href="http://mikejarrett.ca/blog/2017/10/machine-learning-with-vancouver-bike-share-data/">last week</a>, I performed a primary component analysis (PCA) but with bike activity each hour in the columns, and each station as a row. I then plot the top two components which most explain the variance in the data.<img class="alignnone size-full wp-image-213" src="http://mikejarrett.ca/blog/wp-content/uploads/PCA_stations.png" alt="" width="640" height="480"></p>
<p>Like last week, much of the difference in station activity is explained by the total number of trips at each station, here represented on the X axis. There is a single main group of stations with a negative slope, but some outliers that are worth looking at. There are a few stations with higher Y values than expected.</p>
<p><img class="alignnone size-full wp-image-214" src="http://mikejarrett.ca/blog/wp-content/uploads/PCA_stations_labeled1.png" alt="" width="640" height="480"></p>
<p>These 5 stations are all Stanley Park stations. There's another four stations that might be slight outliers.</p>
<p><img class="alignnone size-full wp-image-215" src="http://mikejarrett.ca/blog/wp-content/uploads/PCA_stations_labeled2.png" alt="" width="640" height="480"></p>
<p>These are Anderson & 2nd (Granville Island); Aquatic Centre; Coal Harbour Community Centre; and Davie & Beach. All seawall stations at major destinations. So all the outlier stations are stations that we wouldn't expect to show regular commuter patterns, but more tourist-style activity.</p>
<p>I was hoping to see different clusters to represent residential area stations vs employment area stations, but these don't show up. Not terribly surprising since the Mobi stations cover an area of the city where there is fairly dense residential development almost everywhere. This fits with our maps of station activity, where we saw that there were no major difference between bikes taken and bikes returned at each station.</p>
<p><em>All the source code used for data acquisition and analysis in this post is available on my <a href="https://github.com/mjarrett/mobi">github page</a>.</em></p>
<p><em>To see more posts like this, follow me on twitter <a href="https://twitter.com/mikejarrett_">@mikejarrett_</a>.</em></p>
</div>
</div>
</article><article class="h-entry post-text" itemscope="itemscope" itemtype="http://schema.org/Article"><header><h1 class="p-name entry-title"><a href="machine-learning-with-vancouver-bike-share-data/" class="u-url">Machine learning with Vancouver bike share data</a></h1>
<div class="metadata">
<p class="byline author vcard"><span class="byline-name fn" itemprop="author">
Mike Jarrett
</span></p>
<p class="dateline">
<a href="machine-learning-with-vancouver-bike-share-data/" rel="bookmark">
<time class="published dt-published" datetime="2017-10-23T05:00:19-07:00" itemprop="datePublished" title="2017-10-23 05:00">2017-10-23 05:00</time></a>
</p>
<p class="commentline">
<a href="machine-learning-with-vancouver-bike-share-data/#disqus_thread" data-disqus-identifier="cache/posts/machine-learning-with-vancouver-bike-share-data.html">Comments</a>
</p>
</div>
</header><div class="p-summary entry-summary">
<div>
<p></p>
<p>Six months ago I came across Jake VanderPlas' blog post <a href="https://jakevdp.github.io/blog/2015/07/23/learning-seattles-work-habits-from-bicycle-counts/">examining Seattle bike commuting habits through bike trip data</a>. I wanted to try to recreate it for Vancouver, but the city doesn't publish detailed bike trip data, just monthly numbers. For plan B, I looked into Mobi bike share data. But still no published data! Luckily, Mobi does publish an API with the number of bike at each station. It doesn't give trip information, but it's a start.</p>
<!--more-->
<p><em>All the code needed to recreate this post is available on <a href="https://github.com/mjarrett/mobi">my github page</a>.</em>
</p>
<h3>Data Acquisition</h3>
The first problem was to read the API and take a guess at station activity. To do this, I query the API every minute. Whenever the bike count at a station changes, this is counted as bikes being taken out or returned. I don't know exactly how often Mobi updates this API, but I'm certainly undercounting activity -- whenever two people return a bike and take a bike within a minute or so of each other I'll miss the activity. But it's good enough for my purposes, and I'm more interested in trends than total numbers anyway.
<p>I had two main problems querying the API: First, I'd starting by running the query script on my home machine. This meant that any computer downtime meant missing data. There's a few days missing while I updated my computer. Eventually I migrated to a google cloud server, so downtime is no longer an issue, but this introduced the second problem: time zones. I hadn't set a time zone for my new server, so all the times were recorded as UTC, while earlier data had been recorded in local Vancouver time. It took a long time of staring at the data wondering why it didn't make sense for me to realize what had happened, but luckily an easy fix in Pandas.
</p>
<h3>Analysis</h3>
<img class="aligncenter wp-image-168 size-full" src="http://mikejarrett.ca/blog/wp-content/uploads/hourly_usage_may-sep.png" alt="" width="640" height="480"><p>Our long stretch of good weather this summer is visible in the data. Usage was pretty consistent over July and August, and began to fall off near the end of September when the weather turned. I'll be looking more into the relationship between weather and bike usage once I have more off-season data, but for now I'm more interested in zooming in and looking at daily usage patterns. Looking at a typical week in mid summer, we see weekdays showing a typical commuter pattern with morning and evening peaks and a midday lull. One thing that jumps out is the afternoon peak being consistently larger than the morning peak. With bike share, people have the option to take the bus to work in the morning and then pick up a bike afterwork if they're in the mood. Weekends lose that bimodal distribution and show a single normal distribution centered in the afternoon. On most weekend days and some weekdays, there is a shoulder or very minor peak visible in the late evening, presumably people heading home from a night out.</p>
<p><img class="aligncenter wp-image-166 size-full" src="http://mikejarrett.ca/blog/wp-content/uploads/weekdata-2017-07-31-2017-08-06.png" alt="" width="640" height="480"></p>
<p>Looking at the next week, Monday immediately jumps out as showing a weekend pattern instead of a weekday. That Monday, of course, is the Monday of the August long weekend.</p>
<p><img class="aligncenter wp-image-167 size-full" src="http://mikejarrett.ca/blog/wp-content/uploads/weekdata-2017-08-07-2017-08-13.png" alt="" width="640" height="480"></p>
<p>So, by eye we can fairly easily distinguish weekday and weekend travel patterns. How can we train a computer to do the same?</p>
<p>First, I pivoted my data such that each row is a day, and each column is the hourly bike activity at each station (# columns = # stations * 24). I decided to keep the station information instead of summing across stations, but both give about the same result. This was provided as input to the <a href="http://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html">primary component analysis (PCA) class of the Scikit-Learn Python package</a>. PCA attempts to reduce the dimensionality of a data set (in our case, columns) while preserving the variance. For visualization, we can plot our data based on the the two components which most explain the variance in the data. Each point is a single day, colour labelled by total number of trips that day.</p>
<p><img class="wp-image-192 size-full" style="font-size: 1rem;" src="http://mikejarrett.ca/blog/wp-content/uploads/PCA_numtrips-2.png" alt="" width="640" height="480"> PCA coloured by number of daily trips</p>
<p>It's apparent that the first component (along the X axis) corresponds roughly (but not exactly) to total number of trips. But what does the Y axis represent? To investigate further, we label the data points by day of week.</p>
<p><img class="wp-image-191 size-full" style="font-size: 1rem;" src="http://mikejarrett.ca/blog/wp-content/uploads/PCA_dayofweek-2.png" alt="" width="640" height="480"> PCA coloured by day of week</p>
<p>The pattern is immediately clear. Weekdays are clustered at the bottom of our plot, and weekends are clustered at the top. A few outliers jump out. There are 3 Mondays clustered in with the weekend group. These turn out to be the Canada Day, BC Day and Labour Day stat holidays.</p>
<p><img class="wp-image-190 size-full" style="font-size: 1rem;" src="http://mikejarrett.ca/blog/wp-content/uploads/PCA_dayofweek_mondays-2.png" alt="" width="640" height="480"> PCA with noteable Mondays labelled</p>
<p>Finally, I wanted to try unsupervised clustering to see if weekday and weekend clusters are separated enough to be distinguished automatically. For this, I used the <a href="http://scikit-learn.org/stable/modules/mixture.html">GaussianMixture class from Scikit-learn</a>. Here, we try to automatically split our data into a given number of groups, in this case two.</p>
<p><img class="wp-image-193 size-full" src="http://mikejarrett.ca/blog/wp-content/uploads/PCA_clustering-2.png" alt="" width="640" height="480"> PCA and unsupervised clustering of June-September bike share usage</p>
<p>Not quite. There is a group of low-volume weekend days in the top right cornerthat can't be automatically distinguished from weekdays. All these days are in June and September. Maybe with more non-summer data this will resolve itself.</p>
<p>Out of curiosity, I re-ran the PCA and unsupervised clustering with only peak season data (July and August). Here, with more a more homogenous dataset, clustering works much better. In fact, only the first component (plotted along the X axis) is needed to distinguish between usage patterns.</p>
<p><img class="wp-image-194 size-full" src="http://mikejarrett.ca/blog/wp-content/uploads/PCA_clustering-3.png" alt="" width="640" height="480"> PCA and unsupervised clustering of July and August bike share usage</p>
<p>Bike share usage will obviously decline during Vancouver's wet season, but I'm very interested to see how usage patterns will differ during the lower volume months.</p>
<p><em>All the source code used for data acquisition and analysis in this post is available on my <a href="https://github.com/mjarrett/mobi">github page</a>.</em></p>
<p><em>To see more posts like this, follow me on twitter <a href="https://twitter.com/MikeJarrett_">@MikeJarrett_</a>.</em></p>
</div>
</div>
</article><article class="h-entry post-text" itemscope="itemscope" itemtype="http://schema.org/Article"><header><h1 class="p-name entry-title"><a href="140/" class="u-url">Datetime axis formatting with Pandas and matplotlib</a></h1>
<div class="metadata">
<p class="byline author vcard"><span class="byline-name fn" itemprop="author">
Mike Jarrett
</span></p>
<p class="dateline">
<a href="140/" rel="bookmark">
<time class="published dt-published" datetime="2017-05-26T22:08:36-07:00" itemprop="datePublished" title="2017-05-26 22:08">2017-05-26 22:08</time></a>
</p>
<p class="commentline">
<a href="140/#disqus_thread" data-disqus-identifier="cache/posts/140.html">Comments</a>
</p>
</div>
</header><div class="p-summary entry-summary">
<div>
<p></p>
<p>Panda's Dataframe.plot() function is handy, but sometimes I run up against edge cases and spend too much time trying to fix them.</p>
<p>On one case recently, I wanted to overlay a line plot on top of a bar plot. Easy, right? Not when your dataframe has a datetime axis. The bar plot and and line plot functions format the x-axis date labels differently, and cause chaos when you try to use them on the same axes. None of the usual tick label formatting methods got me back anything useable.</p>
<!--more-->
<p>The solution was to take a step back and use the basic matplotlib functions to plot instead of the pandas wrappers. Calling ax.plot() and ax.bar() give sensible outputs where df.plot() didn't.</p>
<p>See the below notebook for an example of the problem and solution.</p>
<script src="https://gist.github.com/mjarrett/72ac77d80e50f32f020ca1abee5bdc49.js"></script><p></p>
</div>
</div>
</article><article class="h-entry post-text" itemscope="itemscope" itemtype="http://schema.org/Article"><header><h1 class="p-name entry-title"><a href="matplotlib-on-the-web/" class="u-url">Matplotlib on the web</a></h1>
<div class="metadata">
<p class="byline author vcard"><span class="byline-name fn" itemprop="author">
Mike Jarrett
</span></p>
<p class="dateline">
<a href="matplotlib-on-the-web/" rel="bookmark">
<time class="published dt-published" datetime="2017-04-14T19:08:55-07:00" itemprop="datePublished" title="2017-04-14 19:08">2017-04-14 19:08</time></a>
</p>
<p class="commentline">
<a href="matplotlib-on-the-web/#disqus_thread" data-disqus-identifier="cache/posts/matplotlib-on-the-web.html">Comments</a>
</p>
</div>
</header><div class="p-summary entry-summary">
<div>
<p></p>
<p>I've been learning a lot of Matplotlib recently at work and through a course I took on data visualization. I've especially had fun with making interactive plots, and I was curious about whether MPL code could be converted into HTML5 and/or javascript for presentation on the web. I'm a researcher, not a developer, so my main goal was to use the datavis library I already know without having to learn a bunch of javascript.</p>
<p>In my googling, I've found a few solutions to this issue. None are perfect for what I was hoping to do (have Django and MPL work together to produce a nice interactive figure) but I did come across some interesting tools.</p>
<!--more-->
<p></p>
<h4></h4>
<h4>The 'webagg' backend for matplotlib</h4>
This was the solution I was expecting to work. When you specify the webagg backend after importing matplotlib, running f.show() starts up a mini web server and opens the plot in your default browser. As far as I can tell, the plot has the full functionality you'd get with any of the traditional backends.
<p>The magic of having full interactivity in the browser relies on the figure staying connected to the python kernel, which is non-trivial to set up on a live website. I haven't found any instructions that a non-expert can follow to set this up on a personal website.</p>
<p></p>
<h4>MPLD3</h4>
<a href="http://mpld3.github.io/index.html">mpld3</a> is a python package that converts your matplotlib code into d3.js code. It's great! Instead of <code>f.show()</code>, you can run <code>mpld3.save_html(f, 'test.html')</code> and you have a html snippet that can be inserted into a webpage. The plot below is just vanilla matplotlib saved with mpld3.save_html.
<p>%CODE3%</p>
<p>The plots look great and you get the default panning/zooming functions you expect in MPL. However widgets don't work so you don't get the full interactive experience. mpld3 does have some plugins, so for example you can get tooltips when hovering over plot elements. This is great, but requires some non-MPL code. Below I've added a hover tooltip which displays the label of a line plot when you hover over it. Very neat, but still not quite matplotlib's picker.</p>
<p>%CODE4%</p>
<p>The mpld3 website has a tutorial on writing your own plugins, and it looks like there's very little stopping you from recreated any feature you want as long as you know d3.js. I really appreciate all the work that's gone into mpld3, but it's still missing some pretty important features. For example, you might have noticed the years in the x-axis tick labels have a comma in them, which would be easily fixable in vanilla MPL with <code>ax.xaxis.set_ticklabels()</code>. But mpld3 doesn't (yet?) have support for setting ticklabels, so you're stuck with whatever shows up. A small price to pay for the ease of use, but still noticeable.
</p>
<h4>Bokeh</h4>
<a href="http://bokeh.pydata.org">Bokeh</a> is a python visualization library that targets web browsers. It looks like it's further along in development than mpld3, however it's not trivially convertible from matplotlib. There is a bokeh.mpl module, but it is no longer maintained and is considered deprecated. I haven't tried Bokeh myself yet, but if I was going make web visuals a major focus and wanted to stick with python, this is probably where I'd end up.
<h4>plot.ly</h4>
<a href="http://plot.ly">plot.ly</a> seems to be the enterprise solution for interactive web plots in python (and other languages), and it funnels users towards hosting plots on its own server and has a subscription model. But they've released their code as open source, and it's possible to use the plotly library to convert your code to javascript to add to your own site. It's certainly more fully featured, but it's also substantially heavier than mpld3 -- for the same plot, the html snippet is 20,000 character for plot.ly but 2,000 characters for mpld3. To make the plot below, I took the same code as above and just added
<code>
import plotly.plotly as py
import plotly.tools as tls
import plotly.offline as plo</code>
<p>plotly_fig = tls.mpl_to_plotly( f )
plo.plot(plotly_fig, filename='housing_plotly')</p>
<p>%CODE5%</p>
<p>The tooltips happen without any extra code. I haven't spend much time learning the ins and outs of plotly so I'm not sure how customizable it is. I like that it works out of the box and looks professional, but the default tooltips and toolbar do feel a little busy. Hard to argue with free and easy though!</p>
<p>For me, the likely answer seems to be that I'll use mpld3 when I want simple and clean web visualizations, and I'll use plot.ly when I want to have a bit more interactivity. If I end up spending more of my time doing this I'll just learn Bokeh instead, but I'd rather not learn a new library if I don't have to. And I'll keep my fingers crossed that smarter people than me make it easy to host fully interactive MPL plots which stay connected to the python kernel on any django website.</p>
<p><strong>Update:</strong> Jake VanderPlas gave a great talk at Pycon that covers all this that I wish I'd found while researching all this.</p>
<p>https://www.youtube.com/watch?v=FytuB8nFHPQ</p>
</div>
</div>
</article><article class="h-entry post-text" itemscope="itemscope" itemtype="http://schema.org/Article"><header><h1 class="p-name entry-title"><a href="a-jupyter-friendly-nikola-theme/" class="u-url">A Jupyter Friendly Nikola Theme</a></h1>
<div class="metadata">
<p class="byline author vcard"><span class="byline-name fn" itemprop="author">
Mike Jarrett
</span></p>
<p class="dateline">
<a href="a-jupyter-friendly-nikola-theme/" rel="bookmark">
<time class="published dt-published" datetime="2017-01-19T17:54:45-08:00" itemprop="datePublished" title="2017-01-19 17:54">2017-01-19 17:54</time></a>
</p>
<p class="commentline">
<a href="a-jupyter-friendly-nikola-theme/#disqus_thread" data-disqus-identifier="cache/posts/a-jupyter-friendly-nikola-theme.html">Comments</a>
</p>
</div>
</header><div class="p-summary entry-summary">
<div class="cell border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<p>This post is outdated. <a href="https://notes.mikejarrett.ca/optimizing-your-nikola-blog-for-jupyter-notebooks/">See this more recent post</a> on optimizing Nikola for Jupyter blogs for my latest work on this.</p>
</div>
</div>
</div>
</div>
</article>
</div>
<nav class="postindexpager"><ul class="pager">
<li class="previous">
<a href="." rel="prev">Newer posts</a>
</li>
</ul></nav><script>var disqus_shortname="mikejarrett";(function(){var a=document.createElement("script");a.async=true;a.src="https://"+disqus_shortname+".disqus.com/count.js";(document.getElementsByTagName("head")[0]||document.getElementsByTagName("body")[0]).appendChild(a)}());</script><script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML" integrity="sha256-SDRP1VVYu+tgAGKhddBSl5+ezofHKZeI+OzxakbIe/Y=" crossorigin="anonymous"></script><script type="text/x-mathjax-config">
MathJax.Hub.Config({tex2jax: {inlineMath: [['$latex ','$'], ['\\(','\\)']]}});
</script>
</div>
<!--End of body content-->
<footer id="footer">
Contents © 2020 <a href="mailto:mike@mikejarrett.ca">Mike Jarrett</a> - Powered by <a href="https://getnikola.com" rel="nofollow">Nikola</a>
</footer>
</div>
</div>
<script src="assets/js/all-nocdn.js"></script><!-- fancy dates --><script>
moment.locale("en");
fancydates(0, "YYYY-MM-DD HH:mm");
</script><!-- end fancy dates --><script>
baguetteBox.run('div#content', {
ignoreClass: 'islink',
captions: function(element) {
return element.getElementsByTagName('img')[0].alt;
}});
</script>
</body>
</html>