WEBVTT

00:00:00.001 --> 00:00:04.580
Do you have data you want to visualize and share? It's easy enough to make a static graph of it,

00:00:04.580 --> 00:00:09.180
but what if you want to zoom in and highlight different sections? What if you need to rerun

00:00:09.180 --> 00:00:13.680
your machine learning model on the selected data? Then you might want to consider working with Bokeh.

00:00:13.680 --> 00:00:18.420
It does this and much more. Join me on this episode where you'll meet Brian Vandeven,

00:00:18.420 --> 00:00:25.720
who heads up the Bokeh project. This is Talk Python To Me, episode 222, recorded July 24th, 2019.

00:00:25.720 --> 00:00:43.420
Welcome to Talk Python To Me, a weekly podcast on Python, the language, the libraries,

00:00:43.420 --> 00:00:48.220
the ecosystem, and the personalities. This is your host, Michael Kennedy. Follow me on Twitter,

00:00:48.220 --> 00:00:52.900
where I'm @mkennedy. Keep up with the show and listen to past episodes at talkpython.fm,

00:00:52.900 --> 00:00:55.340
and follow the show on Twitter via at Talk Python.

00:00:55.780 --> 00:00:59.660
This episode is brought to you by Ting and Linode. Please check out what they're offering

00:00:59.660 --> 00:01:03.280
during their segments. It really helps support the show. Brian, welcome to Talk Python.

00:01:03.280 --> 00:01:04.440
Hi, thanks for having me.

00:01:04.440 --> 00:01:09.420
Yeah, it's great to have you here. You know, I've often thought about ways in which I could

00:01:09.420 --> 00:01:14.140
use some of these cool Python visualization libraries, and I haven't recently had some

00:01:14.140 --> 00:01:18.020
great excuses to use them, so I haven't really covered them enough on the show, but I'm really

00:01:18.020 --> 00:01:19.600
excited to talk about Bokeh with you this week.

00:01:19.600 --> 00:01:24.480
Oh, I'm super excited to be here. I think Bokeh has really developed a lot over the last year or so

00:01:24.480 --> 00:01:26.100
in particular, and so this is a great opportunity.

00:01:26.100 --> 00:01:29.600
Yeah, absolutely. Before we get to it, though, let's start with your story. How'd you get into

00:01:29.600 --> 00:01:30.440
programming in Python?

00:01:30.440 --> 00:01:34.620
In Python? So I think the first version of Python I ever used was Python 1.4, actually way,

00:01:34.620 --> 00:01:39.900
way back in the day, and I was doing some system administration kind of job, so there was a lot

00:01:39.900 --> 00:01:44.780
of Perl, but I happened to get into using Python for a few things, and it was a lot of fun. Put it

00:01:44.780 --> 00:01:47.880
down for a while, picked it up here and there, but I've been using it pretty extensively

00:01:47.880 --> 00:01:51.120
probably since about 2005 or 2006.

00:01:51.120 --> 00:01:56.740
Okay, yeah, those are pretty early days, Python 1, right? We don't have that debate about 1 versus

00:01:56.740 --> 00:01:58.840
2 anymore. It's moved on to 2 versus 3.

00:01:58.840 --> 00:02:03.260
Yeah, I don't think there was ever really much debate. Everyone was ready for Python 2 for sure.

00:02:03.260 --> 00:02:05.600
Yeah, absolutely. So how'd you get into programming in the first place?

00:02:05.720 --> 00:02:10.360
Let's see. The first thing I ever did was on a TRS-80 that was actually checked out from our

00:02:10.360 --> 00:02:15.460
local library. They had a program to check out TRS-80s for two weeks, and there was a logo cartridge

00:02:15.460 --> 00:02:19.600
that came with it, so we could do logo programming. A little bit later, we had some Commodore computers,

00:02:19.600 --> 00:02:23.780
and so I did, you know, basic, and I think at one point I even got into like 6502 assembly,

00:02:23.780 --> 00:02:28.840
you know, when I was getting to be a teenager or something, but yeah, you know, just 8-bit

00:02:28.840 --> 00:02:30.380
programming way back in the day.

00:02:30.380 --> 00:02:34.680
Yeah, how interesting. Yeah, that's funny with assembly language, like that's not a super

00:02:34.680 --> 00:02:38.880
easy compare it. Like you've got basic on one side and assembly language on the other. Not

00:02:38.880 --> 00:02:39.840
a whole lot in between, huh?

00:02:39.840 --> 00:02:44.080
Well, there's not a lot of different ways to program on a Commodore 64.

00:02:44.080 --> 00:02:48.900
You had to earn your programming stripes back in the early days, that's for sure.

00:02:48.900 --> 00:02:54.980
Nice. Okay, so Boca is a very visual thing. For a long time, you were at Anaconda Inc.

00:02:55.520 --> 00:03:01.760
So, is there a science background as well that got you sort of in that path, or how do you get

00:03:01.760 --> 00:03:05.720
interested in all of these things? Yeah, I've had a pretty tortured academic path. I went to school

00:03:05.720 --> 00:03:09.120
for computer science, then left for a while, and I worked in some research labs, and I realized,

00:03:09.120 --> 00:03:12.920
hey, I want to go back to school, and so I actually ended up in graduate school for physics eventually,

00:03:12.920 --> 00:03:16.260
and so I have a pretty strong, you know, mathematics, physics background, but ultimately,

00:03:16.260 --> 00:03:20.900
I did decide to sort of go back into computer science, software engineering. I really like working

00:03:20.900 --> 00:03:24.960
on software, though, that's in the service of analytical endeavors or science and that sort of thing,

00:03:24.960 --> 00:03:28.960
and so this is why, you know, being able to work at Anaconda on all these tools has been really

00:03:28.960 --> 00:03:34.700
fantastic. Yeah, it's got to be super rewarding to have so much impact on the science side. Are you

00:03:34.700 --> 00:03:38.740
still at Anaconda? What are you doing these days? Like, what's a, what kind of programming and work

00:03:38.740 --> 00:03:42.400
do you do day to day now? Yeah, no, I actually just recently left earlier in the year, so I was at

00:03:42.400 --> 00:03:46.600
Anaconda from the beginning. I think I was the last original employee to leave, in fact, except for

00:03:46.600 --> 00:03:51.420
Peter Wang, of course, who's still there, but, you know, eight years is a long time, and so it's just time for

00:03:51.420 --> 00:03:54.400
me to go look for something different, and I actually went to go work at Microsoft, and that was really on the

00:03:54.400 --> 00:03:59.960
strength of some interactions I'd had with folks at DevDiv and Microsoft around Python, around open

00:03:59.960 --> 00:04:03.920
source. Everyone there has been really terrific and really supportive of Python and open source, and so I

00:04:03.920 --> 00:04:08.240
think it's a very different company than when I, you know, thought about it 15 years ago, where I

00:04:08.240 --> 00:04:12.560
probably would have used M dollar sign very sincerely on an angry forum post or something, but, you know,

00:04:12.560 --> 00:04:16.220
everyone there has been really terrific. It's been a good experience, and day-to-day, I work on Azure SDK

00:04:16.220 --> 00:04:21.840
for Python these days, which is, you know, a lot of PR reviewing, writing some code, and

00:04:21.840 --> 00:04:23.540
helping move the direction there.

00:04:23.540 --> 00:04:27.260
Oh, that's really interesting. You probably feel like you're bringing a little bit of the outside

00:04:27.260 --> 00:04:33.020
to Microsoft, right? Like, it is a very different company. They're more open to external stuff, but,

00:04:33.020 --> 00:04:37.400
you know, historically, it hasn't always been that way, so it's probably like, let me tell you about the

00:04:37.400 --> 00:04:40.000
Python scientific stack, folks, things like that, yeah?

00:04:40.000 --> 00:04:43.200
It's definitely interesting, and there's a lot of give and take. So I've actually learned,

00:04:43.280 --> 00:04:47.640
I haven't been in an organization this large in a very long time, and so it's been a lot of personal growth

00:04:47.640 --> 00:04:51.340
and learning for me, just to be in that kind of environment where, you know, people have to interact

00:04:51.340 --> 00:04:55.340
in different ways, and that's been very gratifying and helpful for me, but definitely, I think I have a

00:04:55.340 --> 00:04:59.280
pretty useful perspective to bring as well, especially in terms of, yeah, data science applications

00:04:59.280 --> 00:05:01.000
in Python and that sort of thing.

00:05:01.000 --> 00:05:06.140
Yeah, yeah, super cool. It sounds like a fun job. So let's start off this conversation talking about

00:05:06.140 --> 00:05:13.140
Bokeh by kind of getting the, like, a big picture of, you know, making pictures with Python, right?

00:05:13.200 --> 00:05:18.560
So if I have a graph, I want to do a map, if I want to do some kind of bar chart or some

00:05:18.560 --> 00:05:23.080
visualization of data, what are my options nowadays?

00:05:23.080 --> 00:05:29.280
There are a lot. So if people want to Google, there's actually a chart made by Jake VanderPlas,

00:05:29.280 --> 00:05:34.060
who, you know, is very active in sort of the PyData, SciPy community. He tried to draw a map,

00:05:34.060 --> 00:05:38.720
basically, of all the Python visualization landscape, and there are a lot of tools available. And some

00:05:38.720 --> 00:05:42.020
people think this is really great, and there's a lot of choice, and then some people think that

00:05:42.020 --> 00:05:45.060
there's just, you know, too many things, and they don't know what to deal with. But there are a lot

00:05:45.060 --> 00:05:49.440
of tools. So obviously, you know, MapPlotlib is the very big tool that's been around for a very long

00:05:49.440 --> 00:05:52.740
time. It's a really fantastic tool, and all the devs there, you know, they work really hard. And

00:05:52.740 --> 00:05:57.560
it's been great to see the sort of the strides that it's made in the last few years. In terms of,

00:05:57.560 --> 00:06:02.400
like, web visualization, there's, you know, Bokeh, of course. Plotly is another offering that's out

00:06:02.400 --> 00:06:07.640
there by the company Plotly. Altair is another tool that's been fairly recently added. Actually,

00:06:07.640 --> 00:06:12.120
Jake VanderPlas and Brian Granger from Jupyter put that together. And so it's inspired by

00:06:12.120 --> 00:06:16.960
the Vega plotting sort of toolkit that's available in browsers. And it's sort of a Python wrapper for

00:06:16.960 --> 00:06:17.180
that.

00:06:17.180 --> 00:06:21.640
Yeah, that's cool. I've heard a lot of good stuff about Altair, and that it's really quite nice as

00:06:21.640 --> 00:06:21.820
well.

00:06:21.820 --> 00:06:24.560
Yeah, I don't have a lot of experience with it. I mean, it's definitely intended for

00:06:24.560 --> 00:06:29.600
very high level sort of exploratory data analysis. It's very, you know, useful, especially in notebooks

00:06:29.600 --> 00:06:33.900
in particular. And so it looks very attractive from the things that I've seen. I just am so,

00:06:34.100 --> 00:06:38.340
you know, I'm very involved in Bokeh. And it takes up so much of my time that I almost don't

00:06:38.340 --> 00:06:41.840
have time to look at too many other things very often. But, you know, Jake's a fantastic guy.

00:06:41.840 --> 00:06:46.760
Brian Granger, of course, is great and has made just amazing things for the PyData and SciPy

00:06:46.760 --> 00:06:49.100
communities. So that's a great tool that they put together.

00:06:49.100 --> 00:06:54.360
Cool. And, you know, there's always things like the JavaScript libraries, like D3 and stuff like

00:06:54.360 --> 00:06:58.900
that. Is that really relevant? Or are we kind of got a handle with things like Bokeh and Plotly and so on?

00:06:58.900 --> 00:07:02.900
You know, so people ask that a lot. Like, what's the difference between Python and D3? Or why would you use

00:07:02.900 --> 00:07:07.420
one versus the other? And I think if you have people that are, you know, already using JavaScript

00:07:07.420 --> 00:07:12.860
and they want to work on things with D3, D3 is an amazing tool and it can make incredible, you know,

00:07:12.860 --> 00:07:17.380
output and really fantastic graphics. And there's probably things that are doable in D3 that maybe

00:07:17.380 --> 00:07:21.480
would be more difficult in, you know, Bokeh, for instance. But where I think the sweet spot for Bokeh

00:07:21.480 --> 00:07:25.800
is we've really tried to make it so that people who are already very productive in Python, they're doing,

00:07:25.800 --> 00:07:30.420
you know, work in data science or science, who are using all these tools that are in the PyData stack,

00:07:30.520 --> 00:07:34.760
you know, NumPy and SciPy and Pandas and scikit-learn and, you know, Dask and Numba and all

00:07:34.760 --> 00:07:38.720
these tools that are really productive with these in Python. We won't let them have access to very

00:07:38.720 --> 00:07:42.440
interactive, powerful visualizations in the browser without having to reach for that JavaScript

00:07:42.440 --> 00:07:46.320
and web tech and sort of be distracted from the actual work that they want to do. And so

00:07:46.320 --> 00:07:50.720
in terms of productivity, I think if you're already working in Python, I think Bokeh is a great

00:07:50.720 --> 00:07:51.800
choice, to put it that way.

00:07:51.800 --> 00:07:56.900
Yeah. Well, Bokeh to me feels like I get a lot of the benefits of the rich JavaScript stuff,

00:07:56.900 --> 00:07:59.020
but that I don't actually have to make it.

00:07:59.020 --> 00:08:00.420
That's a very, yeah.

00:08:00.420 --> 00:08:02.220
Yeah. A very succinct way to put it. Yeah.

00:08:02.220 --> 00:08:06.600
Okay. Interesting. And then maybe we could talk really quickly about Plotly just as a compare and

00:08:06.600 --> 00:08:12.420
contrast. So Plotly, like I don't fully understand Plotly. When I go to work with it, I feel like,

00:08:12.420 --> 00:08:17.040
okay, I'm working with a library, but then it seems like it has like a backend that they provide that

00:08:17.040 --> 00:08:21.260
I have to deal with. And then there's also a commercial version. Like what is Plotly? I don't really

00:08:21.260 --> 00:08:26.180
know where it fits. So in terms of their business, I actually don't know a lot. To be honest, I don't,

00:08:26.180 --> 00:08:29.200
I don't really follow that very closely. And so I think they've actually changed some of their

00:08:29.200 --> 00:08:32.700
offerings from, from what they used to be. I think they used to, you know, sell Plotly and I think

00:08:32.700 --> 00:08:36.800
they're not in that business anymore, but I can't really speak to that very carefully. But the main

00:08:36.800 --> 00:08:41.500
similarities are it's a Python API that generates a declarative, you know, specification,

00:08:41.500 --> 00:08:46.620
typically some kind of JSON that can be rendered by a front end library. Now, you know, Plotly is an

00:08:46.620 --> 00:08:50.360
entire company centered around this. And so they have had some really nice resources for, I think,

00:08:50.360 --> 00:08:53.600
developing both, you know, some things in ways that Bokeh hasn't had. Like I think, you know,

00:08:53.600 --> 00:08:56.960
their front end is a little more polished and some of the, you know, design stuff is definitely

00:08:56.960 --> 00:09:00.160
polished. And I'd love to get some help on the Bokeh side to sort of bring that up to speed.

00:09:00.160 --> 00:09:03.580
But, you know, relatively speaking, I think we've done a pretty good job at, you know,

00:09:03.580 --> 00:09:07.920
having the same set of features. They're very contemporaneous. They started at almost the same time,

00:09:07.920 --> 00:09:11.560
you know, way back in sort of 2012 kind of era. They have a lot of similarities,

00:09:11.560 --> 00:09:15.220
but definitely there's a little bit of difference. You know, my background comes from a lot of science

00:09:15.220 --> 00:09:18.820
stuff. So I'm really familiar with folks that have use cases, for instance, around like dense

00:09:18.820 --> 00:09:22.480
arrays, like, you know, big images. And so we've really focused on some things like having an

00:09:22.480 --> 00:09:27.140
efficient array protocol for the Bokeh server that can transmit large arrays, you know, very efficiently.

00:09:27.140 --> 00:09:29.860
And whereas I don't think they've sort of gone down that route, you know, again,

00:09:29.860 --> 00:09:34.720
they've worked on some other features that are more around slick dashboarding and, you know,

00:09:34.720 --> 00:09:35.360
that sort of thing.

00:09:35.360 --> 00:09:40.120
Okay. Yeah. Interesting. You know, let's talk about the history of Bokeh. Like you're saying it that way,

00:09:40.120 --> 00:09:45.280
and I guess I'm as well, I'm trying to anyway, the way the proper pronunciation is.

00:09:45.280 --> 00:09:50.940
I usually say Bokeh, but Bokeh, I think is also fine. Amusingly, long ago when we were funded through

00:09:50.940 --> 00:09:55.900
this DARPA X-Data initiative, there was some video that someone made, you know, unrelated to all the

00:09:55.900 --> 00:09:59.940
actual projects, but they made about the projects. And I remember in that they were describing all the

00:09:59.940 --> 00:10:03.840
projects that was under the X-Data initiative. And they mentioned the visual database Boke,

00:10:04.040 --> 00:10:05.580
I think. That's the only wrong pronunciation.

00:10:05.580 --> 00:10:07.440
Bokeh is not Bokeh. All right.

00:10:07.440 --> 00:10:08.640
Okay. It's fine. Yeah.

00:10:08.640 --> 00:10:14.800
All right. Excellent. And so where did it get started? It started out of research grants and

00:10:14.800 --> 00:10:16.620
this DARPA funding. Is that where it came from?

00:10:16.620 --> 00:10:20.480
No, the research grants really helped, but it started before then. So going back a little bit

00:10:20.480 --> 00:10:24.020
further. So I've been interested in visualization for a long time. Actually, the first, one of the

00:10:24.020 --> 00:10:28.300
first things I use in Python and Python 1.4 was a plotting plugin for Apache. And it was just,

00:10:28.300 --> 00:10:32.320
it amazed me that you could like take data and have a website just make a plot. It was incredible.

00:10:33.120 --> 00:10:37.140
I worked a little bit on VTK here and there years ago. A few, my first open source contributions

00:10:37.140 --> 00:10:43.300
were to VTK. But in the middle aughts, I guess, I went to work for a company with Peter Wang,

00:10:43.300 --> 00:10:49.000
who eventually founded Anaconda. And I worked with him on a library called Chaco, which was a rich client

00:10:49.000 --> 00:10:52.700
library for interactive visualization. So instead of in the browser, you would write like a Python

00:10:52.700 --> 00:10:58.960
application that was using like, you know, QT or, you know, the GTK, you know, kind of real

00:10:58.960 --> 00:11:03.020
application. And it was also contemporaneous with Plotlib.

00:11:03.020 --> 00:11:07.660
But ultimately, Matt Plotlib won sort of that battle. And the reason was pretty clear. It was

00:11:07.660 --> 00:11:11.360
because, you know, while Chaco had all this really rich capability for an activity, it was a very sort

00:11:11.360 --> 00:11:19.040
of fiddly API, very detailed, kind of verbose. And so later on, when Peter was getting Anaconda

00:11:19.040 --> 00:11:23.620
started, and I was on board to help with that, we had talked about wanting to update this idea of

00:11:23.620 --> 00:11:27.960
Chaco and create a new library that supported interactive visualizations and in browsers,

00:11:28.080 --> 00:11:30.700
because right, browsers is the right place for it to be in 2012, right?

00:11:30.700 --> 00:11:31.100
Of course.

00:11:31.100 --> 00:11:35.100
And so we had this idea, we started it. But getting the, you know, the funding through the

00:11:35.100 --> 00:11:39.080
DARPA X8 initiative in the early years of Anaconda, is then called Continuum Analytics,

00:11:39.080 --> 00:11:42.760
really helped, you know, mitigate business risk for us to put more resources into it. So it really

00:11:42.760 --> 00:11:46.480
accelerated the development, I would say. But we have certainly, you know, we started talking about

00:11:46.480 --> 00:11:49.500
the ideas behind Bokeh in sort of middle 2011, probably.

00:11:49.720 --> 00:11:53.160
Okay. Yeah, that's, that's pretty interesting. It's been around for a while. I guess that's,

00:11:53.160 --> 00:11:58.080
at that point, Ajax and interactive browser stuff's pretty well established, right? So it's pretty

00:11:58.080 --> 00:11:59.040
clear that was the right place.

00:11:59.040 --> 00:12:03.380
Yeah, I mean, we just knew that, like, the future of presentation and the future of getting, you know,

00:12:03.380 --> 00:12:06.960
this content in front of people was going to be in browsers. So writing another rich client library

00:12:06.960 --> 00:12:11.600
was not something that was really interesting to us. And so we definitely wanted to do the browser.

00:12:11.600 --> 00:12:15.040
And then we definitely wanted to make it architected in a way that it was very flexible,

00:12:15.040 --> 00:12:18.540
that it had this declarative specification that described what you wanted to visualize.

00:12:19.060 --> 00:12:21.820
Because, you know, that affords a lot of possibilities. So we've talked about the Python

00:12:21.820 --> 00:12:25.780
side of Bokeh, but you can actually have other languages drive Bokeh plots in the browser,

00:12:25.780 --> 00:12:30.480
you know, there's an R Bokeh binding, there is a Scala Bokeh binding that hasn't been updated in a while.

00:12:30.480 --> 00:12:35.140
I'm interested in actually reviving a Julia Bokeh binding. But that's all because there's this

00:12:35.140 --> 00:12:39.420
JSON specification. And any language that can, you know, dump out the right JSON can create these

00:12:39.420 --> 00:12:42.820
Bokeh plots in the browser. Now, we've spent a lot of effort investing in the Python bindings,

00:12:42.820 --> 00:12:46.780
because, you know, Anaconda is a big Python shop. But certainly the possibility is there for other

00:12:46.780 --> 00:12:47.400
languages as well.

00:12:47.400 --> 00:12:51.260
Okay, so maybe it's worth just touching on the architecture a little bit, and we can dive

00:12:51.260 --> 00:12:55.840
into the details more later. So there's a, I guess there's a couple ways we can use this,

00:12:55.840 --> 00:13:00.020
right? Like, there's a, probably the most straightforward way is we have a Bokeh server.

00:13:00.760 --> 00:13:06.000
And then there's some front end stuff that is the rendering point, right? Like I want to put a,

00:13:06.000 --> 00:13:12.240
some kind of graph in a browser, and the server handles all the data, and maybe it only prevents,

00:13:12.240 --> 00:13:18.100
presents like a slice into that world of the data and things like that, right? Can you tell us about

00:13:18.100 --> 00:13:18.200
that?

00:13:18.260 --> 00:13:21.160
That's absolutely a great use case for the server. But I will say the server is,

00:13:21.160 --> 00:13:25.120
in fact, optional. I would say most usage of Bokeh probably doesn't involve the server. So Bokeh can

00:13:25.120 --> 00:13:30.140
generate this JSON, and it can send it to a web page that can be embedded in like a Flask app or a Django

00:13:30.140 --> 00:13:34.740
app. It can be embedded in, you know, Jupyter notebook output cells. And it doesn't have to be

00:13:34.740 --> 00:13:39.240
connected to the Bokeh server. Bokeh.js will take that JSON and render it. And you've got an interactive

00:13:39.240 --> 00:13:43.340
plot that has panning and zooming. You can even have linked behaviors between plots. You can have custom JS

00:13:43.340 --> 00:13:47.500
callbacks that, you know, do work whenever you make a selection or click a button. None of that

00:13:47.500 --> 00:13:51.580
requires the Bokeh server. What the Bokeh server is really great for is when you want to connect all

00:13:51.580 --> 00:13:55.540
those interactive features to real running Python code. Like you want to click a button and have a,

00:13:55.540 --> 00:13:59.700
you know, a scikit-learn regression or a scikit-learn model run, or you want to, you know,

00:13:59.700 --> 00:14:03.520
make a selection on a plot and compute a linear regression line through those selected points

00:14:03.520 --> 00:14:07.780
with real Python code. That's what the Bokeh server is really great for, making that sort of two-way

00:14:07.780 --> 00:14:12.540
connection between this front end and real running Python code. But you can use Bokeh very effectively

00:14:12.540 --> 00:14:16.680
without the Bokeh server. And in fact, I guess, I think most usage is probably, we call it standalone

00:14:16.680 --> 00:14:21.680
usage, where it's just generating this pile of JSON that is used to drive a Bokeh plot in a webpage

00:14:21.680 --> 00:14:27.800
somewhere. This portion of Talk Python To Me is brought to you by Ting. Let me tell you about Ting,

00:14:27.800 --> 00:14:33.180
a new mobile service available in the US that's targeted developers and other technically savvy folks.

00:14:33.180 --> 00:14:38.100
First of all, their average customer only pays $23 a month, but they're no discount provider.

00:14:38.100 --> 00:14:41.940
Their service runs over T-Mobile's and Sprint's fast nationwide network.

00:14:42.240 --> 00:14:45.960
If you don't use that much data because you're usually on Wi-Fi, like many of you are,

00:14:45.960 --> 00:14:50.520
then Ting will save you a ton of cash. But don't worry, you can still use as much data as you like

00:14:50.520 --> 00:14:55.240
for just $10 per gig. One mobile feature I use all the time is tethering. And with Ting,

00:14:55.240 --> 00:15:00.560
you get unlimited tethering at the same data rate with your account. $6 a month for a phone line,

00:15:00.560 --> 00:15:06.100
$10 a gig, $3 a month for text if you usually chat over iMessage or WhatsApp. Think about it,

00:15:06.100 --> 00:15:14.380
no contracts and super clear and fair billing. Visit python.ting.com. That's python.ting.com and check

00:15:14.380 --> 00:15:19.420
out their savings calculator. Enter your usage and see exactly what you'd pay. Use that link and you'll

00:15:19.420 --> 00:15:25.200
get a $25 credit to try them as well. That's python.ting.com or just click the link in the show notes.

00:15:26.300 --> 00:15:32.680
The server is mostly about the interactive bits if you want to add smarts to your plots.

00:15:32.680 --> 00:15:37.900
Yeah, absolutely. If you want to connect all those PyData tools, NumPy, SciPy, Pandas, Dask,

00:15:37.900 --> 00:15:42.560
Numba, OpenCV, any of those tools. If you want to connect those things directly to

00:15:42.560 --> 00:15:47.100
these interactive visualizations with a minimal amount of fuss, that is what the Bokeh server is for.

00:15:47.100 --> 00:15:47.400
Exactly.

00:15:47.600 --> 00:15:52.920
Okay, cool. Before we move off the history and Anaconda Inc. and all that, when you created it,

00:15:52.920 --> 00:15:58.360
it sounds like you tried to create it as a standalone project with its own fundraising and its own

00:15:58.360 --> 00:16:02.580
outreach. What was the thinking there rather than just making it part of Anaconda?

00:16:02.580 --> 00:16:06.500
Well, I mean, in the very early days, it was definitely a project that was started at Anaconda.

00:16:06.500 --> 00:16:11.460
And the DARPA thing came along somewhat serendipitously. Not something we counted on or

00:16:11.460 --> 00:16:15.780
knew about when the company started. And that was a big sort of funding for a long time. After that ran

00:16:15.780 --> 00:16:20.740
out, because that was a fixed number of years sort of support, Anaconda very generously supported the

00:16:20.740 --> 00:16:25.920
development of Bokeh. But ultimately, it was always the goal to try to create these tools as sort of

00:16:25.920 --> 00:16:30.280
self-sufficient, self-governing, push them out in the open kind of projects. And so it took a long time

00:16:30.280 --> 00:16:34.180
to get to that point. The first step in that was for Bokeh to become a NumFocus fiscally sponsored

00:16:34.180 --> 00:16:39.160
project. But of late, we've really ramped up the self-governance and the self-sufficiency. So pretty

00:16:39.160 --> 00:16:43.280
much at this point, I think the cord's been cut and Bokeh is really out there. It's managing its own CDN

00:16:43.280 --> 00:16:45.760
resources. We're doing a lot of outreach and fundraising on

00:16:45.760 --> 00:16:50.980
our own right now that wasn't happening even six months ago. We just had or still having actually

00:16:50.980 --> 00:16:55.280
a July fundraiser going on to try to help pay for some of our infrastructure costs. But we're also

00:16:55.280 --> 00:16:58.820
ramping up some corporate engagements and trying to talk to corporations and see if they want to offer

00:16:58.820 --> 00:17:03.580
support. But that all is pretty new. For a long time, Anaconda was the primary beneficiary or

00:17:03.580 --> 00:17:04.900
benefactor, I should say, of Bokeh.

00:17:04.900 --> 00:17:11.760
Sure. And it just makes Python and data science stronger, which is really the heart of Anaconda Inc.

00:17:11.760 --> 00:17:15.740
anyway. So it seems pretty reasonable. You said that the project was a NumFocus

00:17:15.740 --> 00:17:22.240
project. And we spoke a little bit earlier about NumFocus a bit. And I guess my understanding is a

00:17:22.240 --> 00:17:30.020
little bit off. I saw NumFocus as a thing that kind of provides funding to these projects. And

00:17:30.020 --> 00:17:33.540
that's not quite exactly right, is it? What is NumFocus and what did it do for you all?

00:17:33.540 --> 00:17:38.000
Yeah, it's sort of yes and no. So NumFocus was started by Travis Alphont, who was one of the other

00:17:38.000 --> 00:17:43.460
co-founders of Anaconda. Of course, he's the original or he's the author of NumPy, building on previous work.

00:17:43.460 --> 00:17:51.200
But NumFocus is this nonprofit, 501c3. And its main role is to be an umbrella organization for

00:17:51.200 --> 00:17:55.040
open source projects, right? So open source projects often are not legal entities. And so that actually

00:17:55.040 --> 00:17:58.760
makes it quite difficult for them to accept money, right? It sort of gets very complicated with taxes.

00:17:58.760 --> 00:18:04.540
And so they're this legal entity that can accept donations on behalf of projects and then handle all

00:18:04.540 --> 00:18:10.120
the tax stuff. They also do a lot of outreach. They hold, you know, they support the PyData meetups and

00:18:10.120 --> 00:18:13.760
PyData conferences around the world. So they're this organization that sort of helps and supports

00:18:13.760 --> 00:18:17.560
open source. And they do fund these projects in the sense that, you know, they help the donations that

00:18:17.560 --> 00:18:21.440
come in get back to the projects. And also sometimes they spread some of those funds around. They get

00:18:21.440 --> 00:18:24.760
bigger donations that they can also use to give to projects that, you know, don't necessarily raise

00:18:24.760 --> 00:18:28.600
their own money. But yeah, that's their main role. Just to be this umbrella organization, they help out

00:18:28.600 --> 00:18:32.360
with the bureaucracy and take away that load from these open source projects.

00:18:32.580 --> 00:18:35.700
Yeah, that's really interesting. I guess it took me a long time to realize that it's

00:18:35.700 --> 00:18:39.100
actually hard for companies to give money.

00:18:39.100 --> 00:18:40.140
It's really hard.

00:18:40.140 --> 00:18:44.040
To these projects, right? Like it's not just a matter of put aside the point whether they should

00:18:44.040 --> 00:18:49.540
put aside the point whether they fiscally could. Of course, they most of them can and they should,

00:18:49.540 --> 00:18:58.260
right? But just the way that they're set up is they buy things. They exchange money for a service or a

00:18:58.260 --> 00:19:03.720
good. Even given to a charity like NumFocus probably is a little bit odd and hard for them to do.

00:19:03.720 --> 00:19:07.660
That is exactly right. There is just an impedance mismatch. I mean, the sums of money that would help

00:19:07.660 --> 00:19:11.600
a lot of open source projects, I think, are relatively small compared to the budgets of the

00:19:11.600 --> 00:19:16.060
companies we're talking about that are using these projects. But yeah, there's just an impedance

00:19:16.060 --> 00:19:21.800
mismatch for how do you actually it's not a purchase, right? And so it's not hiring someone. So what

00:19:21.800 --> 00:19:25.240
exactly is it? And companies just, you know, right now don't know how to handle that and don't know how to

00:19:25.240 --> 00:19:28.780
deal with it. And so there's some other efforts to make that easier. People are trying different

00:19:28.780 --> 00:19:32.720
things. There's, you know, Travis's company, Quonsight, is trying out some models for, you know,

00:19:32.720 --> 00:19:37.040
getting support for open source projects by engaging with companies in various ways. Tidelift as well

00:19:37.040 --> 00:19:41.480
is also trying that. GitHub is, you know, trying their new sponsorship sorts of things. So people are

00:19:41.480 --> 00:19:44.760
trying to find novel ways to attack this problem. And I hope we get there, but it's definitely

00:19:44.760 --> 00:19:46.000
something that will take some time.

00:19:46.000 --> 00:19:49.560
Yeah, I hope so as well, because it would make a huge difference and it would be

00:19:49.560 --> 00:19:52.420
a blip for these companies to make that contribution, right?

00:19:52.420 --> 00:19:56.100
Yeah. I mean, as an example, our goal for the July fundraiser was to raise a thousand dollars,

00:19:56.100 --> 00:19:57.320
right? And we have, you know...

00:19:57.320 --> 00:19:58.100
That's very modest, right?

00:19:58.100 --> 00:20:02.720
I think several hundred thousand users and we did, you know, I'm really happy to report that we did,

00:20:02.720 --> 00:20:06.120
but, you know, I had to tweet out a lot every day to make it happen. It was, you know, sort of

00:20:06.120 --> 00:20:10.620
knocking on doors and, but yeah, I'd love to be able to go to companies and try to be more effective

00:20:10.620 --> 00:20:12.740
and efficient at fundraising, if that makes sense.

00:20:12.740 --> 00:20:15.640
Sure. Well, while we're on the subject, let's talk about your fundraiser real quick.

00:20:15.640 --> 00:20:19.660
If you're going to raise a thousand dollars, that's probably not money to pay developers,

00:20:19.880 --> 00:20:21.720
right? It's something else.

00:20:21.720 --> 00:20:26.660
Yeah. I mean, I actually raised this exact issue around the sustainability conference that NumFocus

00:20:26.660 --> 00:20:29.600
is going to have later in the year. I think there's sort of two different buckets where things go into

00:20:29.600 --> 00:20:33.620
there's, you know, paying people. And I hope someday we can figure that out really well. And we can

00:20:33.620 --> 00:20:37.300
support, you know, people to be maintainers of open source software by actually paying them to do

00:20:37.300 --> 00:20:43.420
that work directly as a sort of a job or a living. But there's also just the matter of a lot of open

00:20:43.420 --> 00:20:48.020
source projects, I think, could use a fairly small amount of money just to cover expenses or help

00:20:48.020 --> 00:20:52.000
take some strain and stress off the maintainers. Like in the case of Bokeh, we have to run this,

00:20:52.000 --> 00:20:57.580
you know, CDN to deploy Bokeh.js. So all the users around the world can get Bokeh.js to display their

00:20:57.580 --> 00:21:02.560
plots. That is run on, you know, AWS CloudFront. And so we have to pay for that. Someone has to pay for

00:21:02.560 --> 00:21:06.160
that. Right. And so that's what this fundraiser was for. And so in the sense that it, you know,

00:21:06.160 --> 00:21:10.440
sort of reduces my stress because it helps me know that this is sort of taken care of for the next year.

00:21:10.800 --> 00:21:13.380
That's what that level of sort of funding is for. And there's other stuff too. There's,

00:21:13.380 --> 00:21:16.780
you know, it's good to get developers face to face sometimes. And so this could help with that

00:21:16.780 --> 00:21:18.460
as well as other infrastructure costs.

00:21:18.460 --> 00:21:23.300
Right. Some having some like yearly meet up with the core developers. It's odd. There's a lot of

00:21:23.300 --> 00:21:25.520
projects where the core developers have never actually met.

00:21:25.520 --> 00:21:30.420
Definitely. For sure. I think I've met everyone at least once, but there's some folks that are pretty

00:21:30.420 --> 00:21:33.620
scattered for Bokeh. But for sure, I have no doubt that's the case.

00:21:33.720 --> 00:21:39.940
Yeah, for sure. So you said that Bokeh works with this JSON output and it can just basically render

00:21:39.940 --> 00:21:44.660
anything that can generate the JSON. It can go out and render that. You know, I think when I think of

00:21:44.660 --> 00:21:50.500
graphs, I mostly think of notebooks and Jupyter and things like that. But also we can just plug this

00:21:50.500 --> 00:21:55.560
into whatever. Is that right? I can plug it into just a Flask site. Can I plug it into even like a,

00:21:55.560 --> 00:21:58.100
some kind of command line app and like somehow pop it up?

00:21:58.100 --> 00:22:01.700
Yeah, I don't see why not. I mean, anything that can run JavaScript basically, right? Anything that can

00:22:01.700 --> 00:22:06.440
load Bokeh.js. So if that's like an Electron app, I think that would be feasible, certainly in the,

00:22:06.440 --> 00:22:10.000
you know, in the Jupyter notebook. But, you know, there's a variety of ways. We have a whole Bokeh.embed,

00:22:10.000 --> 00:22:13.860
you know, API. And so there's a variety of different ways to embed Bokeh content. But if you're running a

00:22:13.860 --> 00:22:18.620
Flask site, you can use one of those ways to pop up Bokeh content in the middle of your site and in

00:22:18.620 --> 00:22:20.500
your template and sort of wherever you want to put it.

00:22:20.500 --> 00:22:27.640
When I think about the data science space, there's some libraries and data structures that are just used

00:22:27.640 --> 00:22:31.460
over and over and over. You mentioned Travis before. So there's NumPy. There's,

00:22:31.580 --> 00:22:36.560
of course, Pandas. There's a bunch of other stuff built on top of that. Is there special

00:22:36.560 --> 00:22:42.180
integration for those types of libraries? Like if I already have some NumPy array or I've got some

00:22:42.180 --> 00:22:45.160
Panda data frame, is there a way to just like plug it into Bokeh?

00:22:45.160 --> 00:22:49.260
Yeah. So Bokeh works really well with all those things. NumPy is an actual requirement,

00:22:49.260 --> 00:22:53.420
runtime requirement for Bokeh. We tried to avoid that. Even in the beginning, we wanted to make Bokeh as

00:22:53.420 --> 00:22:57.560
minimal and as accessible as possible. But NumPy is a requirement now. Pandas is not a hard

00:22:57.560 --> 00:23:00.820
requirement, but Bokeh works really well with Pandas. If you have Pandas data frames,

00:23:00.820 --> 00:23:05.220
you can basically plug them in anywhere a Bokeh column data source would go. I can automatically

00:23:05.220 --> 00:23:09.880
sort of convert them or use them in a way that's useful, either data frames or group by objects.

00:23:09.880 --> 00:23:13.660
And so we've tried to make it very easy to integrate with Pandas, but also make Pandas

00:23:13.660 --> 00:23:17.520
not required. And so that's sort of the state where things are at. Anything that can sort of behave

00:23:17.520 --> 00:23:21.360
like a list or an array or a Pandas series works pretty much out of the box with Bokeh.

00:23:21.480 --> 00:23:25.240
Okay. Are there other major libraries that I don't know to ask about?

00:23:25.240 --> 00:23:29.520
I think Bokeh works really well with Dask, I assume, because Dask has a data frame-like API.

00:23:29.520 --> 00:23:34.460
Matt Rockland actually used Bokeh to develop the interactive dashboard that's sort of the cluster

00:23:34.460 --> 00:23:35.540
monitor for Dask.

00:23:35.540 --> 00:23:39.920
I think it's great as well. And I did have Matthew Rockland on before to talk about Dask,

00:23:39.920 --> 00:23:45.500
but I don't know if everyone's listened to that one. And also if they've seen the actual

00:23:45.500 --> 00:23:49.980
visualization of that. So could you maybe describe that real quickly, what Dask is and then that

00:23:49.980 --> 00:23:53.020
dashboard? Because when I saw that, that just like blew me away.

00:23:53.200 --> 00:23:57.300
Yeah. Dask is a tool for basically parallel distributed programming. And it's trying to

00:23:57.300 --> 00:24:02.480
do so in a way that is a very sort of Pythonic, very Pandas-like API, right? So there's other

00:24:02.480 --> 00:24:06.660
tools that do this sort of thing, but they come from other languages originally. And so their APIs are

00:24:06.660 --> 00:24:11.120
maybe not very Pythonic and they kind of don't fit in well with Python tools. But Dask is meant to be

00:24:11.120 --> 00:24:16.520
a very Pythonic tool for this distributed computing task. And so to that end, it has this dashboard

00:24:16.520 --> 00:24:20.460
that Matt Rockland developed using Bokeh that can visualize everything that's going on around a

00:24:20.460 --> 00:24:23.180
cluster that's doing computation all at once, right? So it can show you what

00:24:23.180 --> 00:24:27.600
nodes are computing or waiting or they're transferring data in real time. And so that's

00:24:27.600 --> 00:24:32.160
really helpful for diagnosing problems with parallel distributed computations. And so Matt has always

00:24:32.160 --> 00:24:36.200
been very clear that Bokeh was great for him because he didn't have to write all this JavaScript to have

00:24:36.200 --> 00:24:40.480
this really interactive dashboard. He could just write it in Python and connect it directly to his

00:24:40.480 --> 00:24:43.780
telemetry that he was getting back from clusters and visualize it very quickly. And so I think it's

00:24:43.780 --> 00:24:47.420
been a great tool for his users. I shouldn't say his users. It's a big project now. Dask has actually

00:24:47.420 --> 00:24:52.300
grown up quite a bit. So I should say the Dask project's users. But we're happy to see that kind of thing happen.

00:24:52.520 --> 00:24:54.340
You know, love to see Bokeh used in those kind of use cases.

00:24:54.340 --> 00:25:01.640
Yeah. And it just looks so good and professional and, you know, live updating. It's really a nice

00:25:01.640 --> 00:25:05.620
use case for Bokeh. And I think it's also a good testament to what you guys have built.

00:25:05.620 --> 00:25:09.780
Well, it's also good to get feedback from real use cases like that. Nothing sharpens your tools

00:25:09.780 --> 00:25:13.200
better than sort of having them honed against real problems, right? And so we love when people do

00:25:13.200 --> 00:25:16.780
awesome things with Bokeh and tell us, you know, hey, this was great, but also this could be a little

00:25:16.780 --> 00:25:20.520
bit better or easier. You know, this is how you could make my life, you know, simpler or here's some pain

00:25:20.520 --> 00:25:23.840
points I had. That kind of feedback is really helpful from users.

00:25:23.840 --> 00:25:29.580
Yeah. It's great to design something, but once it actually meets real users and real use cases,

00:25:29.580 --> 00:25:35.680
like that's where it gets real. So you talked about Dask. Let's just touch on some of the other

00:25:35.680 --> 00:25:41.460
things that is built upon Bokeh because Bokeh has been around since 2011, 2012, like you said,

00:25:41.460 --> 00:25:43.960
and it's pretty stable for the most part.

00:25:43.960 --> 00:25:45.500
It's a lot more stable recently. Yeah.

00:25:45.580 --> 00:25:49.800
Yeah, that's great. So things are starting to build on top of it like Dask and just using it.

00:25:49.800 --> 00:25:50.880
So what else is out there like that?

00:25:50.880 --> 00:25:53.680
Well, there's a couple of different things in different classes of things, right? So first of

00:25:53.680 --> 00:25:57.680
all, there's other libraries now that are starting to build on top of Bokeh. So there is Chartify,

00:25:57.680 --> 00:26:02.040
which was created by the data labs at Spotify. And so it's their sort of high, very high level

00:26:02.040 --> 00:26:06.780
sort of data science, opinionated data science API on top of Bokeh. There's a project called Pandas

00:26:06.780 --> 00:26:10.700
Bokeh that just came out recently. That's sort of very tight integration with Pandas and using Bokeh to

00:26:10.700 --> 00:26:14.580
generate interactive plots. There's also a set of tools created by some folks who are still at Anaconda

00:26:14.580 --> 00:26:18.920
called sort of the efforts called PyViz. And so there's a tool called HoloViews, which is a very

00:26:18.920 --> 00:26:24.040
data centric API, and it can generate interactive visualizations using Bokeh and other tools as well.

00:26:24.040 --> 00:26:30.000
But there's also, you know, some tools like Data Shader, which are for, you know, very large data,

00:26:30.000 --> 00:26:34.600
you can finally control how they're rendered. And so you can combine Data Shader with Bokeh, you know,

00:26:34.600 --> 00:26:37.520
using HoloViews. So it can drive things at a very high level. So I'd love to see this effort where

00:26:37.520 --> 00:26:41.400
people are building these things on top of Bokeh. And I'm also glad that now, you know, Bokeh was

00:26:41.400 --> 00:26:45.540
a moving target for quite a while. And I very much appreciate the patience of all of our users who

00:26:45.540 --> 00:26:49.920
sort of, you know, kept with us as we were figuring things out. But I would like, you know, we're trying

00:26:49.920 --> 00:26:53.300
to be much more stable now. I think we've done a very good job since 1.0 was released at being,

00:26:53.300 --> 00:26:58.200
you know, much more stable. That's very good. The other kind of things that get built on top of

00:26:58.200 --> 00:27:04.100
Bokeh are more like applications or, you know, other projects. So there's a project called Microscopium

00:27:04.100 --> 00:27:09.960
that is for, you know, sort of biosciences research. There's a tool called Light Curve that a bunch of

00:27:09.960 --> 00:27:13.700
astronomers put together, which uses Bokeh to let you drill down. So you can see like an image of,

00:27:13.700 --> 00:27:17.020
you know, some star or something and hover over a single pixel and really drill down into something

00:27:17.020 --> 00:27:21.660
about, you know, that image using, you know, all the tools that are in Bokeh. You know, there's

00:27:21.660 --> 00:27:25.960
actually quite a, Dask, of course, is a great example. And then there's actually a bunch of other

00:27:25.960 --> 00:27:29.660
ones on GitHub. And I'm sorry, I don't have a list at the top of my head, but there are a lot of

00:27:29.660 --> 00:27:34.820
exo-bioscience projects that are built on top of Bokeh. And, you know, financial trading is another

00:27:34.820 --> 00:27:39.780
thing that comes up. People have done drug discovery type work on Bokeh. It's interesting where things are

00:27:39.780 --> 00:27:43.960
popping up, especially, you know, now, and now things are more stable. I think it's really a great time for

00:27:43.960 --> 00:27:44.440
that to happen.

00:27:44.440 --> 00:27:50.780
Yeah, that's super cool. The Light Curve project looks amazing. I mean, to explore like data from the

00:27:50.780 --> 00:27:57.160
the Kepler and TESS telescopes, that's pretty cool for exoplanet discovery. I mean, that's,

00:27:57.160 --> 00:27:58.600
it's really exciting.

00:27:58.600 --> 00:28:03.280
Like the project that you worked on is helping scientists like actually look for exoplanets.

00:28:03.280 --> 00:28:04.320
Like, that's incredible.

00:28:04.320 --> 00:28:07.500
That is a, no, it's really gratifying. Like, that's exactly the sort of thing that, you know,

00:28:07.500 --> 00:28:11.680
I'd say we wanted to be able to enable and, and, and help, help make happen. So it's really

00:28:11.680 --> 00:28:14.940
gratifying when people are able to use Bokeh for those kinds of situations.

00:28:14.940 --> 00:28:23.320
Yeah, absolutely. Do you see Bokeh being useful or appropriate for like real-time dashboard type

00:28:23.320 --> 00:28:28.140
of scenarios? I mean, obviously it draws great graphs. And then, you know, we talked about Dask

00:28:28.140 --> 00:28:33.780
and the real view of that. So like, let's imagine I'm like building software for software, for

00:28:33.780 --> 00:28:39.300
stock trading company or something like this. And I want to show in real time what the market's doing.

00:28:39.300 --> 00:28:43.420
All the data the traders need. Would that be appropriate? Is it too low late or too high

00:28:43.420 --> 00:28:46.860
latency or what's the story? I think it could be there's real time. And then there's quote,

00:28:46.860 --> 00:28:50.020
unquote, real time. Right. So it's always depends on what exactly people mean when they say real time.

00:28:50.020 --> 00:28:54.860
When I hear the word real time, I have images of like, you know, very low level, a certain kind

00:28:54.860 --> 00:29:00.580
of system that's implemented that has very specific guarantees about its performance. And for that kind

00:29:00.580 --> 00:29:03.880
of work, Bokeh is probably not suitable. Right. But if you're talking about real time, just in terms

00:29:03.880 --> 00:29:09.380
of like streaming data coming in from a financial system or, you know, from, IOT type devices

00:29:09.380 --> 00:29:13.140
or, you know, that sort of thing. And I think Bokeh can, has been useful. There's certainly

00:29:13.140 --> 00:29:16.980
people who have come looking for support on our discourse or on our other support forums,

00:29:16.980 --> 00:29:21.160
talking about using Bokeh, connecting it to real time sensors, for instance. Right. So they're in a

00:29:21.160 --> 00:29:24.620
factory or a warehouse and they've got data coming in. I want to visualize something. So people do do

00:29:24.620 --> 00:29:28.980
that. So if you mean, you know, quote unquote, real time, and just in the sense that I've got data

00:29:28.980 --> 00:29:32.840
coming in and I want to visualize it in a best ever kind of way, then I think Bokeh is definitely a

00:29:32.840 --> 00:29:33.300
good choice.

00:29:33.300 --> 00:29:37.740
Yeah. And that's mostly what I meant. I mean, obviously not like we need seven millisecond response time or else

00:29:37.740 --> 00:29:42.060
the plane crashes, something like that. Nothing like that. Right. But like, like when you're

00:29:42.060 --> 00:29:46.900
thinking of graphs, right, like a human has to see the graph and interpret the graph. Right. So that's,

00:29:46.900 --> 00:29:51.420
you know, how long is that? It can't be quicker than a hundred milliseconds. Right. Like the human

00:29:51.420 --> 00:29:52.660
can't understand graphs that quick.

00:29:52.660 --> 00:29:56.160
Well, and so real time is not even necessarily about quickness. It's really about predictability. It's

00:29:56.160 --> 00:30:00.380
about specific kinds of guarantees. But, but yeah, so I should mention, yeah, Bokeh does have some APIs

00:30:00.380 --> 00:30:04.560
for streaming specifically. Right. So, you know, if you've got data coming in or you want to update,

00:30:04.700 --> 00:30:08.580
you know, just the newest point, you've got a, you know, a time series with a hundred thousand points,

00:30:08.580 --> 00:30:13.060
you know, plotted and you've got new points coming in at the end. Bokeh can very efficiently just send

00:30:13.060 --> 00:30:16.860
the new data, right. Without sending, you know, the entire data set. So it is very useful for that sort

00:30:16.860 --> 00:30:21.060
of thing. Yeah. So then you load up the historical data and then you just take, you know, the update

00:30:21.060 --> 00:30:25.060
every half a second or something. That sounds pretty doable. Yeah, absolutely. Okay. Even more often.

00:30:25.060 --> 00:30:30.980
Yeah, yeah, yeah. Sure. That sounds, that sounds super interesting. One of the capabilities kind of

00:30:30.980 --> 00:30:36.140
around that, that you talked about is being able to work with like quite large data, maybe having some

00:30:36.140 --> 00:30:41.580
on the server or something like that. And then either interpreting that or running a machine learning

00:30:41.580 --> 00:30:45.820
model against that or something like that. Maybe tell us some of the use cases there.

00:30:45.820 --> 00:30:49.180
Yeah. There's a couple of different ways you could use Bokeh for that. So one is that, you know,

00:30:49.180 --> 00:30:51.820
if you have a large data set, you know, you're not going to send a billion points into your browser,

00:30:51.820 --> 00:30:55.400
right? Your browser will just fall over. So you've got to find some ways to sort of minimize the data.

00:30:55.400 --> 00:30:57.960
And that can be done in a variety of ways. And one of the ways is for instance,

00:30:57.960 --> 00:31:01.380
it's downsampling. So if you have a large data set and you've got some reasonable way that makes

00:31:01.380 --> 00:31:05.460
sense for your use case to downsample it, the Bokeh server can just do that downsampling and then show

00:31:05.460 --> 00:31:09.200
you the subset of data that's relevant, right? So that's one way that you can use the Bokeh server

00:31:09.200 --> 00:31:13.180
to handle sort of large data sets. Another way is I mentioned this tool data shader, which is

00:31:13.180 --> 00:31:19.000
actually specifically designed for being able to, you know, very efficacious visualizations, images of,

00:31:19.000 --> 00:31:22.040
you know, hundreds of millions or billions of points, right? It gives you very fine control over the way,

00:31:22.040 --> 00:31:25.820
basically the more sophisticated version of alpha compositing happens. So you can actually try to

00:31:25.820 --> 00:31:30.340
emphasize the things you want to emphasize in a meaningful way. And so you could use data shader

00:31:30.340 --> 00:31:35.240
to data shade those 100 million points. And then that just produces an image and then you can send

00:31:35.240 --> 00:31:39.520
the image to Bokeh. And so that's a very fast operation. So the data shader is sort of a form of,

00:31:39.520 --> 00:31:44.060
you know, data compression in that sense, but it's still very interactive because, you know,

00:31:44.060 --> 00:31:48.680
you can use the events that Bokeh generates to when you, if you resize the plot to get a new image

00:31:48.680 --> 00:31:52.020
generated, if you've, for instance, changed the balance of the plot, if you pan or zoom,

00:31:52.360 --> 00:31:55.820
you can get a new data shader image based on those new, on those new dimensions. And in fact,

00:31:55.820 --> 00:32:00.680
HoloView sort of does that all automatically for you. You can do it by hand with Bokeh and data shader,

00:32:00.680 --> 00:32:04.320
or, you know, at a high level, HoloViews can sort of take care of that for you. That's another way in

00:32:04.320 --> 00:32:07.580
which, you know, you can sort of reduce the amount of data that you're going to send into the browser.

00:32:07.580 --> 00:32:11.820
Coming up next year, I hope we can actually raise though the ceiling of the number of points you can

00:32:11.820 --> 00:32:16.520
send. We're going to try to do some work, hopefully, to better improve the WebGL support in Bokeh,

00:32:16.520 --> 00:32:20.540
and maybe even just have Bokeh be based entirely on WebGL. In which case, I think we could,

00:32:20.640 --> 00:32:23.540
you know, right now, Bokeh, you could send a few hundred thousand points to it,

00:32:23.540 --> 00:32:27.760
and it's typically okay. But I think we could raise that sort of ceiling a little bit higher

00:32:27.760 --> 00:32:29.860
once we are able to render completely in WebGL.

00:32:29.860 --> 00:32:33.020
Yeah, that would be pretty amazing. Is it using like canvases or something now?

00:32:33.020 --> 00:32:37.120
Yeah, exactly. So it uses the HTML canvas. There is currently some level of WebGL support.

00:32:37.120 --> 00:32:40.920
And the person who maintained that and originally wrote that is just, he's moved on to other things.

00:32:40.920 --> 00:32:46.140
And so that WebGL support is sort of, it needs a little work, a little love and care. And we'll

00:32:46.140 --> 00:32:51.080
probably just go ahead and try to do things sort of from the beginning and re-found that in a cleaner,

00:32:51.080 --> 00:32:55.820
better way going forward. But yeah, there's some WebGL support now, but most of the rendering happens

00:32:55.820 --> 00:32:56.600
on HTML canvas.

00:32:56.600 --> 00:33:02.120
Okay. So let's talk a little bit about some of the internal implementations of this. Like,

00:33:02.120 --> 00:33:10.100
when most people interact with Bokeh, they're probably interacting with some Python API. And as far

00:33:10.100 --> 00:33:13.400
as they're concerned, like that's the end of it, right? Like, I call these functions,

00:33:13.520 --> 00:33:14.980
the plot comes up magic.

00:33:14.980 --> 00:33:19.380
Yeah. And actually the API is actually quite light. So by and large, we've turned the problem

00:33:19.380 --> 00:33:24.680
of creating an interactive data visualization web app into the Python problem of creating a bunch of

00:33:24.680 --> 00:33:28.400
objects and setting their properties, right? So, you know, I mentioned this JSON representation and

00:33:28.400 --> 00:33:32.280
that JSON representation actually mirrors on both sides, a set of objects and those objects being a

00:33:32.280 --> 00:33:36.680
graph. So there's a set of objects like a plot, which has, you know, a bunch of renderers and has a

00:33:36.680 --> 00:33:40.860
couple of axes and some ranges and some data sources. Maybe that's in a layout that also has some

00:33:40.860 --> 00:33:45.400
buttons. So there's objects we call the models that represent all of those items. All of those get

00:33:45.400 --> 00:33:49.580
turned into JSON. And then on the JavaScript side, there's a one-to-one correspondence basically of

00:33:49.580 --> 00:33:53.820
objects that those get turned into JavaScript objects. The role of the Bokeh server is just to

00:33:53.820 --> 00:33:57.860
keep those two sets of objects in sync bi-directional, right? But in terms of what you use from Python,

00:33:57.860 --> 00:34:01.640
you create this plot, maybe use the figure function, which sort of puts a lot of these objects

00:34:01.640 --> 00:34:06.000
together for you in a convenient, meaningful way. And then you can twiddle their properties. You can

00:34:06.000 --> 00:34:10.680
change, you know, the start and end of a range, or you can add the data to the data source, or you can

00:34:10.680 --> 00:34:15.840
change various properties of a circle glyph because you want to change how it appears. And so all of

00:34:15.840 --> 00:34:20.800
this is, you know, just setting these properties on these Bokeh models. And that is the main, the main

00:34:20.800 --> 00:34:24.200
thing that people do, I think. Apart from that, you might be writing callbacks. If you're using the

00:34:24.200 --> 00:34:28.120
Bokeh server, you can write callbacks in Python, you know, for if a button gets clicked or a selection

00:34:28.120 --> 00:34:32.420
is made, you can run Python code. But you can also create JavaScript callbacks for the standalone

00:34:32.420 --> 00:34:35.720
case where, you know, I don't have a Bokeh server, but I still want something to happen when a button

00:34:35.720 --> 00:34:39.540
gets clicked or, you know, the selection is made. You can write a little snippet of JavaScript and that

00:34:39.540 --> 00:34:43.860
will, you know, do that amount of work. And typically those callbacks, the end result of that is, again,

00:34:43.860 --> 00:34:47.420
setting some properties on these objects, right? They might update the data source, which causes the

00:34:47.420 --> 00:34:51.380
plot to update, or they might change the range bounds, which causes the plot to zoom out, that sort of

00:34:51.380 --> 00:34:55.420
thing. So there is definitely API. There are functions, you know, there are functions for embedding,

00:34:55.420 --> 00:34:59.240
there are functions for showing things in notebooks, there are functions for creating plots to start with.

00:34:59.440 --> 00:35:04.740
But most of the content of the Bokeh library is these objects, you know, we call models, and they all have

00:35:04.740 --> 00:35:09.960
these typed properties that you can set values for. And that's the main interaction mode.

00:35:09.960 --> 00:35:15.980
Yeah, so very declarative in that sense, right? You set the aspects or the features that you want,

00:35:15.980 --> 00:35:18.280
and it just figures out how to make that interactive.

00:35:18.280 --> 00:35:19.260
Yeah, exactly. Yeah.

00:35:19.260 --> 00:35:23.900
Nice. So it sounds to me like, listening to you talk, there's a lot going on with JavaScript

00:35:24.780 --> 00:35:31.240
here, even though the typical consumer user of it, the developer doesn't have to care or work with it.

00:35:31.240 --> 00:35:35.420
What are you using there? Like, what was the history? Was that always just straight JavaScript?

00:35:35.420 --> 00:35:36.480
Or what's what are you doing?

00:35:36.480 --> 00:35:40.140
Yeah, it's actually never been straight JavaScript. But you're right, the bulk of the work of Bokeh is

00:35:40.140 --> 00:35:42.920
actually in this library, Bokeh JS, right, which is JavaScript library.

00:35:42.920 --> 00:35:43.680
How big is it?

00:35:43.680 --> 00:35:48.960
So minified, I think the main core library is about 600k. It's a pretty hefty library.

00:35:48.960 --> 00:35:49.960
That's a pretty hefty library.

00:35:50.080 --> 00:35:53.860
It is, right. We're looking to make things, you know, as optimized as we can. We definitely could

00:35:53.860 --> 00:35:58.320
use help from, you know, more experienced JavaScript developers. So when Bokeh started, I mean, it was

00:35:58.320 --> 00:36:02.360
started by me and a few other folks who are working in none of us, I think, had a lot of front end

00:36:02.360 --> 00:36:05.920
experience. I didn't have any JavaScript experience when this project started. And so we actually chose

00:36:05.920 --> 00:36:10.220
CoffeeScript at the time. And so that, I think, was maybe a good choice for the time, because it

00:36:10.220 --> 00:36:13.500
allowed us to iterate very quickly and sort of make, you know, mistakes more quickly, I guess.

00:36:13.500 --> 00:36:17.320
You try out things, you know, it's sort of Python looking like, you know, it's one of these

00:36:17.320 --> 00:36:22.100
transpiled languages that turns into JavaScript. But ultimately, once the project grew very large,

00:36:22.100 --> 00:36:26.320
it wasn't really suitable for that. And so we actually did a large effort. Most of that work

00:36:26.320 --> 00:36:31.220
was done. Heavy lifting was done by one of our core contributors, Mateus, to port Bokeh to TypeScript.

00:36:31.220 --> 00:36:34.400
And that's been a huge win for the project. I mean, just in doing the port to TypeScript,

00:36:34.400 --> 00:36:39.200
a lot of latent bugs and problems were uncovered. Certainly since it's been done, you know,

00:36:39.200 --> 00:36:42.720
I've been prevented from checking in things that would have been an error, you know, by the TypeScript

00:36:42.720 --> 00:36:47.020
compiler. So I'm a big fan of that and glad for that. There are certainly new contributors who find it a

00:36:47.020 --> 00:36:50.800
little bit more difficult or daunting sometimes to work with TypeScript so that there is a barrier

00:36:50.800 --> 00:36:55.400
to entry that's a little bit high for Bokeh. And that's actually just in general, been a problem

00:36:55.400 --> 00:37:00.320
for us, I think, to attract sort of contributors on that side, right? Because Bokeh is targeted towards,

00:37:00.320 --> 00:37:03.400
you know, Python developers with the promise that they really don't have to worry about JavaScript

00:37:03.400 --> 00:37:07.180
if they don't want to. But all the work's actually in JavaScript. And so, you know,

00:37:07.180 --> 00:37:11.240
we need JavaScript developers to come help make Bokeh better. And so for the most part,

00:37:11.240 --> 00:37:13.420
and so that's been a challenge for us a little bit.

00:37:13.420 --> 00:37:19.020
You have this bimodal distribution of skills and desires and stuff like the Python folks and the

00:37:19.020 --> 00:37:21.320
JavaScript folks. And yeah, it's interesting.

00:37:21.320 --> 00:37:24.400
So we're trying to make Bokeh itself like a, you know, there are people who use the Bokeh

00:37:24.400 --> 00:37:28.180
JavaScript library just by itself as a JavaScript library. I would say that from my perspective,

00:37:28.180 --> 00:37:32.280
quite a bit of work is needed to do to make that a serious sort of contender for something people

00:37:32.280 --> 00:37:35.760
want to use. But we definitely would like to get that done. And we'd love to get help doing that.

00:37:35.760 --> 00:37:39.960
I think making Bokeh JS as sort of a first class JavaScript library in its own right would be very,

00:37:39.960 --> 00:37:43.980
helpful for our project. And certainly it'd be great to get a community around that as well.

00:37:43.980 --> 00:37:45.200
But that's a longer term goal.

00:37:47.860 --> 00:37:52.380
This portion of Talk Python To Me is brought to you by Linode. Are you looking for hosting that's

00:37:52.380 --> 00:37:57.440
fast, simple, and incredibly affordable? Well, look past that bookstore and check out Linode at

00:37:57.440 --> 00:38:04.700
 talkpython.fm/Linode. That's L-I-N-O-D-E. Plans start at just $5 a month for a dedicated server

00:38:04.700 --> 00:38:09.820
with a gig of RAM. They have 10 data centers across the globe. So no matter where you are or where your

00:38:09.820 --> 00:38:14.620
users are, there's a data center for you. Whether you want to run a Python web app, host a private Git

00:38:14.620 --> 00:38:20.600
server, or just a file server, you'll get native SSDs on all the machines, a newly upgraded 200

00:38:20.600 --> 00:38:26.220
gigabit network, 24-7 friendly support, even on holidays, and a seven-day money-back guarantee.

00:38:26.220 --> 00:38:30.980
Need a little help with your infrastructure? They even offer professional services to help you with

00:38:30.980 --> 00:38:35.540
architecture, migrations, and more. Do you want a dedicated server for free for the next four months?

00:38:35.900 --> 00:38:38.600
Just visit talkpython.fm/Linode.

00:38:38.600 --> 00:38:46.620
It's interesting that you found TypeScript to be a nice way of working and whatnot. And I find it'd be

00:38:46.620 --> 00:38:50.760
pretty nice as well. Certainly, if I had to choose between CoffeeScript and TypeScript, I would

00:38:50.760 --> 00:38:55.600
definitely choose TypeScript. You know, I think TypeScript is interesting in that it's a superset of

00:38:55.600 --> 00:39:00.940
JavaScript. So all your regular JavaScript just works, but you can like typify it and make it have other

00:39:00.940 --> 00:39:07.260
features and capabilities that that language brings. And that's a pretty interesting way to approach that

00:39:07.260 --> 00:39:07.680
problem.

00:39:07.680 --> 00:39:11.960
Oh, definitely. Yeah. And to be clear, I think CoffeeScript was the right choice in 2012. I don't,

00:39:11.960 --> 00:39:15.940
it's not at all the right choice for anything, I don't think, in 2019. I think at the time,

00:39:15.940 --> 00:39:20.200
Bokeh was one of the largest CoffeeScript libraries probably ever developed, which is interesting,

00:39:20.200 --> 00:39:24.820
sort of a bit of trivia. But like I said, it let us move fast, especially not having a lot of

00:39:24.880 --> 00:39:29.000
experience in front-end dev. But, you know, after time, we just needed something more,

00:39:29.000 --> 00:39:30.940
a little more serious, for lack of a better word.

00:39:30.940 --> 00:39:35.380
Yeah, sure. I'd just like to get your thoughts real quick. Like, so TypeScript is all about,

00:39:35.380 --> 00:39:42.460
you know, sort of static typing and checking and whatnot of your code. And we kind of have that

00:39:42.460 --> 00:39:47.460
in Python a little bit now, to the extent that people want to bring it in with mypy and type

00:39:47.460 --> 00:39:51.680
annotations. But it's not really the main zen of the language of Python.

00:39:52.000 --> 00:39:55.540
What are your thoughts of like working in these two languages, kind of side by side on the same

00:39:55.540 --> 00:39:55.880
project?

00:39:55.880 --> 00:39:59.420
Well, so this is a really interesting question. So there is actually a history of various projects

00:39:59.420 --> 00:40:03.180
that add what's called, I think, manifest typing to Python. And so that goes back to,

00:40:03.180 --> 00:40:07.080
there's definitely a project called Traits that Joseph Morrill created that was, you know,

00:40:07.080 --> 00:40:11.800
sort of, you could add types to classes, and those would get checked at runtime. And you could also

00:40:11.800 --> 00:40:15.740
do things like reactive programming and event-based programming based off changes to those values.

00:40:15.740 --> 00:40:20.020
Traits auto-created like QT GUIs, I think, from classes as well, the panels.

00:40:20.780 --> 00:40:24.320
And there's another one called Param. And I think there's now one called Struct. But Bokeh

00:40:24.320 --> 00:40:28.600
also has its own property system. I mentioned these properties of models. Bokeh has its own

00:40:28.600 --> 00:40:33.800
property system, which is rooted in a bunch of fun metaclass programming that lets you add these

00:40:33.800 --> 00:40:38.060
declarative types. So the actual models I mentioned for Bokeh objects are typically have no code in them.

00:40:38.060 --> 00:40:43.720
They're just classes with these property definitions that say, oh, you know, my plot width is an int,

00:40:44.060 --> 00:40:50.360
or my source property is an instance of a column data source, or the range has two floating point

00:40:50.360 --> 00:40:55.080
values start and end. And so we're able to provide runtime feedback. If people try to set, you know,

00:40:55.080 --> 00:40:59.040
the range.start equals some string value, we say, hey, that's not an appropriate value. It needs to

00:40:59.040 --> 00:41:03.260
be an integer. And we also know what properties are on objects. So a feature people have really

00:41:03.260 --> 00:41:07.620
complimented it's about is people sort of fat finger a property name, we'll actually give a suggestion

00:41:07.620 --> 00:41:10.080
and say the nearest property names are named this. And so we-

00:41:10.080 --> 00:41:10.700
Oh, that's nice.

00:41:10.700 --> 00:41:13.940
Kind of a type system. Yeah, a really nice feature. It's sort of one of those simple things

00:41:13.940 --> 00:41:17.760
you don't think about until you see it. But we've had a type system in Bokeh since the beginning,

00:41:17.760 --> 00:41:22.760
right? And so it's a little interesting now that mypy is becoming more popular. We are interested in

00:41:22.760 --> 00:41:28.080
looking to use mypy basically after Bokeh 2.0 comes out and we drop Python 2 support. We're

00:41:28.080 --> 00:41:31.340
interested in trying to integrate mypy, you know, wherever we can. I think it's a useful tool.

00:41:31.340 --> 00:41:35.700
I hadn't used it much until recently, but I have seen it used to good effect. And so I'd like to try to

00:41:35.700 --> 00:41:39.980
improve that. I don't know how much we'll be able to use mypy to replace our existing

00:41:39.980 --> 00:41:43.220
sort of type property system because that would be a huge endeavor because our properties,

00:41:43.220 --> 00:41:47.820
they aren't just the type checking. They also plug into our documentation system so we can auto

00:41:47.820 --> 00:41:49.640
generate our reference documentation. Wow.

00:41:49.640 --> 00:41:53.420
And of course, all the auto synchronization is based on this too, right? A lot of the machinery for the

00:41:53.420 --> 00:41:57.900
automatic synchronization and serialization is based off these property definitions, right?

00:41:57.900 --> 00:42:02.820
Right. Like to notify that something has changed to people who are interested and things like that.

00:42:02.820 --> 00:42:06.520
Yeah. So replacing it with mypy is not something I'm sure we can do for the properties,

00:42:06.640 --> 00:42:10.140
but there's plenty of other places in the library where mypy would be a great benefit

00:42:10.140 --> 00:42:13.640
to help us sort of tighten things up. And so we're looking at that after Bokeh 2.0.

00:42:13.640 --> 00:42:18.700
Okay. Yeah. Yeah. Very cool. Maybe we could do a quick tour of some of the interesting graphs

00:42:18.700 --> 00:42:23.380
or visualizations that you find, you know, like kind of interesting and worth talking about,

00:42:23.380 --> 00:42:29.400
like over at demo.bokeh.org or just bokeh.org and just click on the gallery and demos and stuff.

00:42:29.400 --> 00:42:33.580
There's a bunch of cool ones that has the source code. There's some interactive bits and so on.

00:42:33.620 --> 00:42:35.980
You want to tell us about something you think are worth checking out?

00:42:35.980 --> 00:42:39.820
Yeah. So for sure. So first off, if you go to demo.bokeh.org, these are all specifically

00:42:39.820 --> 00:42:44.480
Bokeh server applications. So these are all backed by running Python process. And when you click a

00:42:44.480 --> 00:42:48.160
button or make a selection, that triggers real Python code. If you go to the gallery on the docs,

00:42:48.160 --> 00:42:52.380
most of those are standalone. And so they don't, they aren't backed by a Bokeh server just to get

00:42:52.380 --> 00:42:55.880
that distinction out of the way. But at demo.bokeh.org, there's a couple of interesting ones here.

00:42:55.960 --> 00:43:00.560
The first one on the upper left is this movie data explorer. And this is actually a fairly direct

00:43:00.560 --> 00:43:05.280
comparison, intentional on our part, to a tool called the Shiny Movie Explorer. So people have

00:43:05.280 --> 00:43:08.860
asked for a long time, where, you know, where is Shiny for Python? So Shiny is this tool for creating

00:43:08.860 --> 00:43:13.720
sort of interactive data visualization applications from the R language. People ask, where is Shiny for

00:43:13.720 --> 00:43:16.860
Python? So we're trying to answer that question. And I think Bokeh is a pretty good, decent answer to

00:43:16.860 --> 00:43:20.400
the question of where is Shiny for Python. But so we made that as a pretty direct comparison. So that's

00:43:20.400 --> 00:43:23.820
one that's interesting. Right next to it, there's this selection histogram, which I think is pretty

00:43:23.820 --> 00:43:27.920
cool. So it's got a couple of distributions of scatter points on a plot. And if you make a

00:43:27.920 --> 00:43:31.600
selection, it shows the histograms on both axes. And if you make a selection across those points of,

00:43:31.600 --> 00:43:35.980
you know, a subset of those points, it then highlights and shows you the histogram of just

00:43:35.980 --> 00:43:39.580
the selected points. And then sort of in the opposite direction, the select the histogram of

00:43:39.580 --> 00:43:43.440
the unselected points and sort of a shadow faded out version. Wow. Yeah, that one's really cool.

00:43:43.440 --> 00:43:46.840
That's a cute one. We've been working on that one for quite a while. It's gone through several

00:43:46.840 --> 00:43:51.680
iterations that actually helped us uncover some problems with the Bokeh server early on. It was just sort

00:43:51.680 --> 00:43:54.780
of behaving in a weird way and stuttering and realized that events were sort of boomeranging,

00:43:54.780 --> 00:43:59.200
sort of making a boomerang effect. And so we had to sort of fix that out. But that was a great example

00:43:59.200 --> 00:44:02.000
to help us figure out some of those problems. And we have a lot more things under a lot more rigorous

00:44:02.000 --> 00:44:07.300
tests now. So that's good. But yeah, I like that example a lot. Another one we have is this

00:44:07.300 --> 00:44:12.080
reproduction of the gap, the gap minder demo. So, you know, Hans Rosling did this, you know,

00:44:12.080 --> 00:44:16.540
famous TED talk where he showed all this data. And so we've reproduced that in Bokeh. We've also

00:44:16.540 --> 00:44:19.480
embedded the YouTube video. We wanted to be able to show being able to use, you know,

00:44:19.540 --> 00:44:23.360
a template to embed Bokeh content in a template with other content. So this also has this YouTube

00:44:23.360 --> 00:44:23.980
video embedded.

00:44:23.980 --> 00:44:30.260
Yeah, that talk by Hans Rosling, you have the video there. It's really worth watching. Like

00:44:30.260 --> 00:44:37.660
that guy really makes statistics and just data like relevant for humanity in a great way.

00:44:37.660 --> 00:44:42.200
Absolutely. No, I'd recommend anyone to go watch the video, regardless of where they look at the

00:44:42.200 --> 00:44:46.720
Bokeh bar. It's a great video. And I think it's a really compelling one. Tells a great story. So

00:44:46.720 --> 00:44:50.500
I'd recommend anyone to go check that out. For sure. Let's see, lower left, there's actually a

00:44:50.500 --> 00:44:54.400
financial chart. So here you can have time series from two sort of financial, you know,

00:44:54.400 --> 00:44:58.400
data sets and you can do sort of a cross correlation between them. And you can see the

00:44:58.400 --> 00:45:02.420
pandas sort of statistical summary there. And you can, you know, use the dropdown to choose

00:45:02.420 --> 00:45:06.580
different time series and then the table updates and the data, you know, the plots update. So that's

00:45:06.580 --> 00:45:10.140
a nice one as well. And then on the bottom right, there's kind of interesting one that's got this 3D

00:45:10.140 --> 00:45:14.320
plot. And this is maybe confusing for some people. Bokeh itself is not a 3D plotting library and has

00:45:14.320 --> 00:45:19.860
no inherent 3D capability built in. But Bokeh is very extensible. At some point, we realized that,

00:45:19.860 --> 00:45:24.460
you know, lots of users have use cases that are eminently reasonable and, you know, really cool

00:45:24.460 --> 00:45:28.560
that we're just not ever going to have the capability or resources to sort of do in the library. I mean,

00:45:28.560 --> 00:45:32.760
you have to sort of limit the scope of the core library at some point. Yeah. So we work to make

00:45:32.760 --> 00:45:36.380
Bokeh extensible. And so you can create these custom extensions that behave just like built-in

00:45:36.380 --> 00:45:41.420
Bokeh models. And they plug in just like, you know, the plot object or a widget object, right,

00:45:41.880 --> 00:45:46.500
into Bokeh content. And so this is an example of that. And so this is a custom extension that wraps

00:45:46.500 --> 00:45:51.500
a little 3D JS library. And you use the standard Bokeh data sources and you update them. And then

00:45:51.500 --> 00:45:55.540
this little 3D plot updates because basically the custom extension just wires together the Bokeh data

00:45:55.540 --> 00:46:00.300
source with whatever this other library expects. And so it's really neat example of that. And there's

00:46:00.300 --> 00:46:04.020
other examples of extensions in the docs as well for different kinds of use cases. If you want to like,

00:46:04.020 --> 00:46:07.640
if you have some really cool JavaScript widget, you want to connect to Bokeh content. If you actually,

00:46:07.720 --> 00:46:12.100
if you have a cool JavaScript widget that you want to connect to, you know, all these PyData tools,

00:46:12.100 --> 00:46:16.900
like you want to connect this JavaScript widget to, you know, scikit-learn or to Dask or to Numbo or,

00:46:16.900 --> 00:46:21.220
you know, pandas, Bokeh is a great bridge for that, right? You can just write a custom extension that wraps

00:46:21.220 --> 00:46:25.880
the JavaScript component and then it's automatically Bokeh server can connect it to all those tools.

00:46:25.880 --> 00:46:29.160
Yeah. And get all the change notification and interactivity and everything. Yeah.

00:46:29.160 --> 00:46:35.340
That's super cool. Okay. Let's see. What else do you want to talk about? You all have Bokeh 2.0 on the

00:46:35.340 --> 00:46:39.600
roadmap. What's going on with that? Yeah, absolutely. I would say we were targeting August,

00:46:39.600 --> 00:46:43.340
but I think maybe a little more realistic at this point is September. We're always a little optimistic

00:46:43.340 --> 00:46:48.460
in our estimates for our schedule. Welcome to software development, right? That's how it goes.

00:46:48.460 --> 00:46:52.260
We're all like that way. I don't even want to speculate the first time we promised Bokeh 1.0 and

00:46:52.260 --> 00:46:57.040
sort of stability. That was probably a couple of years too early, but we're a little more on track

00:46:57.040 --> 00:47:02.320
for Bokeh 2.0. But the main thing about Bokeh 2.0 is just that we are dropping Python 2 support and

00:47:02.320 --> 00:47:06.700
also Python 3.4 support. So Python 3.5 will be the minimum version. As long as we are doing a major

00:47:06.700 --> 00:47:10.500
version bump, we're also going to take the time to clean up a few other minor things. So there's a few

00:47:10.500 --> 00:47:14.720
minor changes that are coming. Hopefully nothing that's too disruptive for anyone. We're going to

00:47:14.720 --> 00:47:18.840
be sure to outline and document all those in a migration guide. But that's the main thing is the

00:47:18.840 --> 00:47:23.780
Python 2 support. And it gives us a chance to do some things like move to native coroutines. So we use

00:47:23.780 --> 00:47:29.420
tornado as the base for the Bokeh server. But if we move to Python 3.5 as a base, we can use native async and

00:47:29.420 --> 00:47:33.640
await coroutines everywhere. I'm still with tornado, but it helps us clean up the code a lot. And just

00:47:33.640 --> 00:47:36.900
in general, it'll help us clean up the code base and make it a lot more maintainable and sort of

00:47:36.900 --> 00:47:39.480
shrink it. And it's always good to delete and shrink code for sure.

00:47:39.480 --> 00:47:44.080
Yeah. If you maintain it by deleting it, like you're good. Yeah, that's a good way to do it.

00:47:44.080 --> 00:47:48.800
Do you think that'll help attract more maintainers to say like, hey, you could work on this cool async

00:47:48.800 --> 00:47:53.380
IO, async and await library rather than, you know, this thing called tornado and these

00:47:53.380 --> 00:47:54.180
coroutines?

00:47:54.180 --> 00:47:57.480
Well, so it's still going to use tornado. And tornado is a really great tool, but I think it may.

00:47:57.480 --> 00:48:02.620
It broadens the thing a little bit to hopefully some more developers. And there are, I stress that

00:48:02.620 --> 00:48:06.120
there's a lot of work in Bokeh TS, but there's plenty of work on the Python side to do as well. And we'd

00:48:06.120 --> 00:48:10.200
love to have contributors. And honestly, there's actually a lot of work that's not coding. I'd love

00:48:10.200 --> 00:48:14.100
to get other contributors involved in all kinds of ways. And if I can speak a minute about that, I mean,

00:48:14.100 --> 00:48:14.800
yeah, go for it.

00:48:14.800 --> 00:48:18.540
Obviously, people talk about, hey, we need testing help and docs and design help and that's,

00:48:18.540 --> 00:48:22.560
or docs help. And that's certainly true for us as well. But other maybe ways people don't think

00:48:22.560 --> 00:48:25.960
about it is, you know, we'd love to get like designers, front end designers to come help

00:48:25.960 --> 00:48:29.800
make our assets better, to come, you know, help us improve the visual appearance of Bokeh. Cause

00:48:29.800 --> 00:48:34.020
you know, we've done okay, but we're not designers. And so it'd be great to get that kind of help.

00:48:34.020 --> 00:48:39.500
We actually have a lot of infrastructure now on places like DigitalOcean and AWS, and it would be

00:48:39.500 --> 00:48:44.180
great to get experienced people that know those, those systems and those DevOps on those systems to

00:48:44.180 --> 00:48:47.780
come help us optimize them for cost, optimize them for usage, you know, whatever.

00:48:47.780 --> 00:48:49.860
Yeah. You guys are doing cool stuff with Docker, right?

00:48:50.080 --> 00:48:53.620
Yeah, we do a couple of things with Docker. So we run the demo sites, actually a Docker image that's

00:48:53.620 --> 00:48:57.580
run on Elastic Beanstalk. And I actually just recently changed some of the instances that that

00:48:57.580 --> 00:49:01.920
was running on to hopefully make them a little bit more cost effective for us. But we also just

00:49:01.920 --> 00:49:06.320
recently had a spike in S3 usage on one of our buckets that I couldn't really explain just yet.

00:49:06.320 --> 00:49:09.720
And so I'd love to get experienced people that can, you know, help with those sorts of things.

00:49:09.720 --> 00:49:13.880
Outreach is another area. We're really trying to ramp up our outreach, both to the community in terms of,

00:49:13.880 --> 00:49:17.220
you know, fundraising, but also talking to companies. And we've had a couple of people help with that.

00:49:17.480 --> 00:49:22.340
And actually just offering support, right? We just moved our mailing list to a discourse instance,

00:49:22.340 --> 00:49:27.140
discourse.bokeh.org, which is infinitely better. I mean, the discourse is great for users because

00:49:27.140 --> 00:49:31.400
there's a lot of features for code highlighting, for math texts, just, you know, all kinds of things

00:49:31.400 --> 00:49:35.560
we could imagine maybe putting an extension to put in actual bokeh content into these discourse posts.

00:49:35.560 --> 00:49:39.760
But it's also great for us as maintainers because discourse has a lot of information about what are

00:49:39.760 --> 00:49:43.700
people searching for, you know, what topics are popular, that sort of thing. So that helps us know maybe

00:49:43.700 --> 00:49:47.880
where attention needs to go. But just answering questions there, people want to go offer support

00:49:47.880 --> 00:49:52.420
and help other people use bokeh. That is also a huge deal. I think bokeh has been successful because

00:49:52.420 --> 00:49:55.980
we've had a few people that have been able to put a lot of time into helping, you know, the community.

00:49:55.980 --> 00:49:59.540
But as the community grows, that's got to scale. It needs to have more and more people helping each

00:49:59.540 --> 00:50:03.080
other. And so that kind of thing would also be a great way to contribute to the project. And so

00:50:03.080 --> 00:50:07.220
there's all kinds of ways people can plug in. And we'd love to, you know, engage with anyone,

00:50:07.220 --> 00:50:08.900
really, about any of those tasks.

00:50:08.900 --> 00:50:12.380
Right, right. If you're a designer and you want to make the website look shiny,

00:50:12.380 --> 00:50:17.400
that'd be great. If you want to make the graphs look better, or maybe you're a visualization

00:50:17.400 --> 00:50:20.760
expert and you've got a different kind of graph you want to bring, whatever, right?

00:50:20.760 --> 00:50:25.220
Yeah, absolutely. Or just even making new examples for the docs, you know, making really cool uses of

00:50:25.220 --> 00:50:29.720
bokeh to show off, to tweet about, to put in our docs and our gallery. I mean, there's all kinds of

00:50:29.720 --> 00:50:33.600
ways to make very valuable contributions to the project just because there's a lot of things to do. And

00:50:33.600 --> 00:50:36.640
you know, presently not enough people do them, probably never enough people do them,

00:50:36.640 --> 00:50:39.100
right. But obviously, the more help we can get, the better.

00:50:39.100 --> 00:50:43.500
Sure. So if I could summarize, you're willing to accept contributors to the project.

00:50:43.500 --> 00:50:46.100
Yeah, absolutely. If I hadn't made that clear, yes.

00:50:46.100 --> 00:50:50.360
That's awesome. Yeah, it's a cool project. It would be fun to work on.

00:50:50.360 --> 00:50:50.600
Yeah.

00:50:50.600 --> 00:50:56.160
As part of this bokeh 2.0 thing and the dropping of Python 2, which I like to refer to as legacy Python,

00:50:56.160 --> 00:51:02.960
and Python 3 just as straight Python. But as part of dropping legacy Python, one of the things you did,

00:51:03.240 --> 00:51:06.980
this is kind of a trend in the data science space, not, I haven't seen it as broadly adopted,

00:51:06.980 --> 00:51:12.100
and I'm not really sure why, you signed the Python 3 statement. You want to tell folks about that?

00:51:12.100 --> 00:51:16.240
Yeah. So the Python 3 statement is just, you know, it's a GitHub repository where projects can go and

00:51:16.240 --> 00:51:20.180
sort of make a PR to list themselves on this website. And it says, we're going to, we pledge to drop

00:51:20.180 --> 00:51:25.220
Python 2 support, you know, by sort of this date or this timeframe, and support Python 3 going forward.

00:51:25.220 --> 00:51:29.660
And so there are a lot of projects that have signed that. And it's interesting, I thought going in that

00:51:29.660 --> 00:51:33.140
bokeh was going to be maybe kind of a leader in this, I wanted to be fairly aggressive. But

00:51:33.140 --> 00:51:37.520
all of a sudden, this year, a ton of projects have started releasing, you know, new releases that sort

00:51:37.520 --> 00:51:42.000
of are cut off from from that. And so like things like I think Matt Potlib, and yeah, and I think,

00:51:42.000 --> 00:51:46.180
you know, Dask, maybe and I forget what else, but there's all these sort of big projects that are

00:51:46.180 --> 00:51:50.400
just suddenly, you know, we're never behind the curve, right? They've already dropped Python 2 support,

00:51:50.400 --> 00:51:54.720
and we're sort of lagging behind. But I think it's time. I mean, bokeh is definitely used a lot in,

00:51:54.720 --> 00:51:57.820
you know, analytics space. And I think things do move a little bit faster there.

00:51:57.820 --> 00:52:02.660
Part of that is because of Conda and Anaconda and Conda Forge, they sort of push things forward.

00:52:02.660 --> 00:52:06.140
I think also data scientists, you know, do a lot of exploratory work, and they're willing to sort of

00:52:06.140 --> 00:52:09.500
move a little bit, you know, in that exploratory work, they're willing to sort of move and put up

00:52:09.500 --> 00:52:14.240
a little bit more change to get new features and to, to get that level of performance better.

00:52:14.240 --> 00:52:17.780
Once things get deployed, that's when things get a bit more sticky. And that's where you see a lot of

00:52:17.780 --> 00:52:21.260
people still using Python 2 and, you know, finance and, you know, other venues like that.

00:52:21.260 --> 00:52:25.380
Yeah, absolutely. I feel like these the data science exploration stuff and the models,

00:52:25.380 --> 00:52:31.900
like the underlying technology is changing so quick there, right? Like TensorFlow has come out and

00:52:31.900 --> 00:52:36.680
pandas and all these things are just changing so quickly that if you're going to come back to it,

00:52:36.680 --> 00:52:41.780
you may want to just move to something new or shiny or better anyway. And you just it's much easier to

00:52:41.780 --> 00:52:46.940
stay on Python on the later version of Python, whereas like, that website that that guy that used to

00:52:46.940 --> 00:52:50.980
work here ran that now we just have to keep running like nobody wants to touch that, right?

00:52:51.120 --> 00:52:55.640
As soon as you touch it, it's your problem to fix it if it ever has a problem. And nobody wants that

00:52:55.640 --> 00:53:00.480
puppy, right? Yeah, yeah. So some of the companies that are projects that sign the Python 3 statement,

00:53:00.480 --> 00:53:06.600
just Python 3 statement, the number three statement.org, TensorFlow, requests, XGBoost,

00:53:06.600 --> 00:53:12.500
NumPy, IPython, like that kind of stuff, right? Cython, Spider. There's a ton of projects here.

00:53:12.500 --> 00:53:13.120
Yeah, it's great.

00:53:13.120 --> 00:53:17.400
A lot of those projects already have. I thought we'd be sort of leading the pack, but we're actually

00:53:17.400 --> 00:53:21.320
behind the curve. And that's what made it very easy for us to say, okay, you know,

00:53:21.320 --> 00:53:24.940
Q4, it's going to be really easy for us to drop Python 2 because all these other projects will

00:53:24.940 --> 00:53:26.080
have already dropped Python 2.

00:53:26.080 --> 00:53:29.760
Right, right. For example, Tornado is in there and you guys are built on that. So in a sense,

00:53:29.760 --> 00:53:32.980
they're kind of calling your, not calling your bluff, but making sure you're going to have to

00:53:32.980 --> 00:53:35.040
follow along anyway if you want to stay in the latest of that, right?

00:53:35.040 --> 00:53:37.100
Yeah, even NumPy, right? I mean, you know, obviously,

00:53:37.100 --> 00:53:40.020
we could pin to a lower version of NumPy, but we don't want to do that.

00:53:40.020 --> 00:53:43.860
Yeah, of course, you wouldn't want to do that. Interesting. So we're just about out of time,

00:53:43.960 --> 00:53:48.380
but you want to talk about Portland real quick? Sure. Yeah. Yeah. So we were both in Portland,

00:53:48.380 --> 00:53:54.540
right? You recently, somewhat recently, not super recently, but you're somewhat new here and you're

00:53:54.540 --> 00:53:57.860
trying to get some stuff going in the data science space in Portland as well, right?

00:53:57.860 --> 00:54:00.880
Yeah, absolutely. Yeah. So I've been here about a year and a half and it's been a really great

00:54:00.880 --> 00:54:06.320
experience being here in Portland. I really love it. But I am trying to get a PyData meetup here

00:54:06.320 --> 00:54:11.540
started. In fact, we have a first meetup scheduled for, I think, August 14th. And we're going to

00:54:11.540 --> 00:54:15.020
alternate sort of between an east side and a west side, you know, downtown location, hopefully,

00:54:15.020 --> 00:54:20.220
every other month. But me and a colleague of mine are getting that off the ground. And I'm really

00:54:20.220 --> 00:54:24.780
excited about it. So PyData is this series of meetups slash conferences, if the meetups get big

00:54:24.780 --> 00:54:28.540
enough, that is sort of sponsored by NumFocus. And, you know, I've been involved with NumFocus since the

00:54:28.540 --> 00:54:31.280
beginning. I think it's a terrific, amazing organization. The people that are there are really

00:54:31.280 --> 00:54:35.240
great. And I think the PyData meetups in particular have been really, really great, you know,

00:54:35.240 --> 00:54:39.620
both meetups and also the PyData conferences are also really good as well. So really excited to get that

00:54:39.620 --> 00:54:42.740
started in Portland. I was almost kind of surprised that it wasn't here already. There's a, you know,

00:54:42.740 --> 00:54:47.500
there's a PyData Seattle meetup and there's PyData meetup. There's like 105 PyData meetups,

00:54:47.500 --> 00:54:51.420
I think, around the world. So it was by far time that Portland gets one. So I'm really excited to

00:54:51.420 --> 00:54:55.480
be helping get that off the ground. Yeah, that's awesome. I mean, that only really is interesting

00:54:55.480 --> 00:54:59.980
to like 5% of the listeners, maybe. But it's still really cool that you're doing that here in

00:54:59.980 --> 00:55:05.240
Portland. And, you know, other folks, they can create a PyData, their city's airport acronym if

00:55:05.240 --> 00:55:08.540
they want, right? Absolutely. I think most places don't use the airport acronym,

00:55:08.640 --> 00:55:11.700
but I'm really fond of PDX. So I invited a PDX on a good.

00:55:11.700 --> 00:55:15.980
Yeah, it's definitely a good one. All right. Well, you know, Bokeh is a really cool project,

00:55:15.980 --> 00:55:21.540
and I'm glad you all have been working on it. And it's great to see all this progress and excitement

00:55:21.540 --> 00:55:24.400
around it. It's a great, great one. So people should definitely check it out.

00:55:24.400 --> 00:55:27.660
Yeah, yeah. Well, thank you very much for having me. I love to have the opportunity to sort of spread

00:55:27.660 --> 00:55:30.020
the word and talk about Bokeh. And it's been really great.

00:55:30.020 --> 00:55:33.200
Yeah, absolutely. Let me ask you the final two questions before you get out of here, though.

00:55:33.680 --> 00:55:37.320
If you're going to write some code, probably Python code, but maybe JavaScript as well,

00:55:37.320 --> 00:55:39.220
I guess. What editor do you use?

00:55:39.220 --> 00:55:40.560
I have been won over by VS Code.

00:55:40.560 --> 00:55:40.920
Okay.

00:55:41.080 --> 00:55:45.980
Yeah, I still use VI binding. So I grew up using VI and that's still in my fingers. And so I love

00:55:45.980 --> 00:55:49.880
VI bindings. But I used to use Sublime Text, but I moved to VS Code and haven't looked back.

00:55:49.880 --> 00:55:53.520
Yeah, that seems a pretty straightforward choice to go from Sublime to VS Code.

00:55:53.520 --> 00:55:58.220
Those are, you know, one has so much more energy and they're super similar in their sort of workflow.

00:55:58.480 --> 00:56:04.820
And then notable PyPI package, I'll go ahead and throw out there Bokeh for you. And what else? If

00:56:04.820 --> 00:56:08.320
there's something like, hey, I ran across this and people might not know about it, but it's really

00:56:08.320 --> 00:56:09.480
amazing. What would you say?

00:56:09.480 --> 00:56:13.220
Yeah, let's see. Well, I'll say PyPI or Konda, right? So don't forget Konda. Very important

00:56:13.220 --> 00:56:21.080
to remember. But, you know, it's hard to say. I'm so focused on, you know, using and working on Bokeh.

00:56:21.160 --> 00:56:25.020
That's like my day to day. Honestly, I have a little bit of tunnel vision, maybe to put it one

00:56:25.020 --> 00:56:29.120
way. But, you know, I think a lot of the tools that are built on top of Bokeh are really interesting to

00:56:29.120 --> 00:56:32.360
me. And so I like, you know, looking at what is happening with them and seeing what developments

00:56:32.360 --> 00:56:37.080
are going. Obviously, I think all the tools in the PyData ecosystem are amazing. I think Numba in

00:56:37.080 --> 00:56:41.260
particular is really interesting. So Numba is a compiler for Python, lets you really accelerate,

00:56:41.260 --> 00:56:45.300
you know, certain kinds of code. And it was originally created again by Travis, you know,

00:56:45.300 --> 00:56:50.420
Oliphant, but it's been moved on since then. And it's actually grown really successful in certain

00:56:50.420 --> 00:56:53.740
kinds of venues. So I think Numba is a pretty interesting use case. And I certainly, of course,

00:56:53.740 --> 00:56:57.880
think Dask is really fantastic as well. Yeah, those are definitely good ones. All right,

00:56:57.880 --> 00:57:01.520
Brian, final call to action. People want to get started with Bokeh. What do they do?

00:57:01.520 --> 00:57:06.060
Yeah, absolutely. Love to get people involved. So if you want to, you know, talk about development or

00:57:06.060 --> 00:57:09.980
have questions about support, we have this discourse, discourse.bokeh.org. If you want to just

00:57:09.980 --> 00:57:14.140
get started from a very high level, just bokeh.org is a great one stop to get to a lot of other

00:57:14.140 --> 00:57:19.040
resources like documentation, like the gallery, like the GitHub page, and just to see what,

00:57:19.680 --> 00:57:23.820
going on. But in terms of like talking to us, yeah, the discourse is a great spot to make a

00:57:23.820 --> 00:57:27.960
poster topic there. And of course, GitHub is a great place if you have ideas for suggestions,

00:57:27.960 --> 00:57:31.380
you know, or want to report problems, of course, you know, GitHub is a great place to contact us.

00:57:31.380 --> 00:57:32.880
Yeah, for sure. And PRs are accepted.

00:57:32.880 --> 00:57:34.700
PRs are always accepted. Yes.

00:57:34.700 --> 00:57:36.620
Yeah, very cool. At least considered.

00:57:36.620 --> 00:57:37.200
Consider.

00:57:37.200 --> 00:57:38.600
At least considered for sure.

00:57:38.600 --> 00:57:41.700
Cool. All right. Well, thanks so much for being on the show. It's good to talk with you.

00:57:41.700 --> 00:57:42.980
Absolutely. Thank you so much, Michael.

00:57:42.980 --> 00:57:43.460
Yeah, bye.

00:57:43.460 --> 00:57:43.700
Bye.

00:57:43.760 --> 00:57:50.060
This has been another episode of Talk Python To Me. Our guest on this episode was Brian Vandevin,

00:57:50.060 --> 00:57:55.400
and it's been brought to you by Ting and Linode. Ting is the fast mobile network custom built for

00:57:55.400 --> 00:58:01.900
technical folks. Use their savings calculator to see exactly what you'd pay. Visit python.ting.com

00:58:01.900 --> 00:58:08.580
to get a $25 credit and get started without a contract. Linode is your go-to hosting for whatever

00:58:08.580 --> 00:58:14.980
you're building with Python. Get four months free at talkpython.fm/linode. That's L-I-N-O-D-E.

00:58:14.980 --> 00:58:21.540
Want to level up your Python? If you're just getting started, try my Python Jumpstart by Building 10 Apps

00:58:21.540 --> 00:58:27.000
course. Or if you're looking for something more advanced, check out our new async course that digs

00:58:27.000 --> 00:58:31.780
into all the different types of async programming you can do in Python. And of course, if you're interested

00:58:31.780 --> 00:58:35.880
in more than one of these, be sure to check out our everything bundle. It's like a subscription

00:58:35.880 --> 00:58:41.200
that never expires. Be sure to subscribe to the show. Open your favorite podcatcher and search for

00:58:41.200 --> 00:58:46.320
Python. We should be right at the top. You can also find the iTunes feed at /itunes, the Google

00:58:46.320 --> 00:58:53.200
Play feed at /play, and the direct RSS feed at /rss on talkpython.fm. This is your host,

00:58:53.200 --> 00:58:57.420
Michael Kennedy. Thanks so much for listening. I really appreciate it. Now get out there and write

00:58:57.420 --> 00:58:58.140
some Python code.

00:59:01.660 --> 00:59:18.760
We'll see you next time.