Skip to content

Commit 3323bff

Browse files
committed
Lightning talk notebook cleanup
1 parent 854f1c5 commit 3323bff

12 files changed

+1024
-283
lines changed

__init__.py

Whitespace-only changes.

notebooks/SF_Python_Lightning_Talk_Dec_2019.ipynb

+130-82
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<style>
2+
h1 {
3+
margin: 2em 0 0 0;
4+
color: #2e484c;
5+
font-family: 'Julius Sans One', sans-serif;
6+
font-size: 1.8em;
7+
text-transform: uppercase;
8+
}
9+
a:link {
10+
font-weight: bold;
11+
text-decoration: none;
12+
color: #0d8ba1;
13+
}
14+
a:visited {
15+
font-weight: bold;
16+
text-decoration: none;
17+
color: #1a5952;
18+
}
19+
a:hover, a:focus, a:active {
20+
text-decoration: underline;
21+
color: #9685BA;
22+
}
23+
p {
24+
font: "Libre Baskerville", sans-serif;
25+
text-align: justify;
26+
text-justify: inter-word;
27+
}
28+
code {
29+
color: #336699;
30+
}
31+
</style>
32+
33+
<h1>Fourier Transformation Illustration</h1>
34+
35+
<p><strong>credit: Bokeh Maintainers! (bokeh.org)</strong></p>
36+
<p><i>https://github.com/bokeh/bokeh/blob/master/examples/app/fourier_animated.py</i></p>
37+
<p><strong>Fourier Transform background: </strong><i>https://jackschaedler.github.io/circles-sines-signals/dft_introduction.html</i></p>
38+
39+
<p>
40+
This example shows how Bokeh can be used to illustrate continuous processing of a stream through a Bokeh Server.
41+
</p>
+237
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
''' Show a streaming, updating representation of Fourier Series.
2+
The example was inspired by `this video`_.
3+
Use the ``bokeh serve`` command to run the example by executing:
4+
bokeh serve main.py
5+
at your command prompt. Then navigate to the URL
6+
http://localhost:5006/fourier_animated
7+
in your browser.
8+
.. _this video: https://www.youtube.com/watch?v=LznjC4Lo7lE
9+
'''
10+
from collections import OrderedDict
11+
12+
from os.path import dirname, join
13+
import numpy as np
14+
from numpy import pi
15+
16+
from bokeh.driving import repeat
17+
from bokeh.io import curdoc
18+
from bokeh.layouts import column
19+
from bokeh.models import ColumnDataSource
20+
from bokeh.models import Div
21+
from bokeh.plotting import figure
22+
23+
N = 100
24+
newx = x = np.linspace(0, 2 * pi, N)
25+
shift = 2.2
26+
base_x = x + shift
27+
28+
period = pi / 2
29+
palette = ['#08519c', '#3182bd', '#6baed6', '#bdd7e7']
30+
31+
plot_width = 1200
32+
plot_height = int(round(plot_width / 2.654867, 0))
33+
34+
filename = join(dirname(__file__), "description_fourier.html")
35+
desc_fourier = Div(text=open(filename).read(),
36+
render_as_text=False, width=plot_width)
37+
38+
39+
def new_source():
40+
return dict(
41+
curve=ColumnDataSource(dict(x=[], base_x=[], y=[])),
42+
lines=ColumnDataSource(dict(line_x=[], line_y=[], radius_x=[], radius_y=[])),
43+
circle_point=ColumnDataSource(dict(x=[], y=[], r=[])),
44+
circleds=ColumnDataSource(dict(x=[], y=[]))
45+
)
46+
47+
48+
def create_circle_glyphs(p, color, sources):
49+
p.circle('x', 'y', size=1., line_color=color, color=None, source=sources['circleds'])
50+
p.circle('x', 'y', size=5, line_color=color, color=color, source=sources['circle_point'])
51+
p.line('radius_x', 'radius_y', line_color=color, color=color, alpha=0.5, source=sources['lines'])
52+
53+
54+
def create_plot(foos, title='', r=1, y_range=None, period=pi / 2, cfoos=None):
55+
if y_range is None:
56+
y_range = [-2, 2]
57+
58+
# create new figure
59+
p = figure(title=title, tools="", plot_width=plot_width, plot_height=plot_height, x_range=[-2, 9], y_range=y_range,
60+
sizing_mode="stretch_width")
61+
p.xgrid.bounds = (-2, 2)
62+
p.xaxis.bounds = (-2, 2)
63+
64+
_sources = []
65+
cx, cy = 0, 0
66+
for i, foo in enumerate(foos):
67+
sources = new_source()
68+
get_new_sources(x, foo, sources, cfoos[i], cx, cy, i == 0)
69+
cp = sources['circle_point'].data
70+
cx, cy = cp['x'][0], cp['y'][0]
71+
72+
if i == 0:
73+
# compute the full fourier eq
74+
full_y = sum(foo(x) for foo in foos)
75+
# replace the foo curve with the full fourier eq
76+
sources['curve'] = ColumnDataSource(dict(x=x, base_x=base_x, y=full_y))
77+
# draw the line
78+
p.line('base_x', 'y', color="orange", line_width=2, source=sources['curve'])
79+
80+
if i == len(foos) - 1:
81+
# if it's the last foo let's draw a circle on the head of the curve
82+
sources['floating_point'] = ColumnDataSource({'x': [shift], 'y': [cy]})
83+
p.line('line_x', 'line_y', color=palette[i], line_width=2, source=sources['lines'])
84+
p.circle('x', 'y', size=10, line_color=palette[i], color=palette[i], source=sources['floating_point'])
85+
86+
# draw the circle, radius and circle point related to foo domain
87+
create_circle_glyphs(p, palette[i], sources)
88+
_sources.append(sources)
89+
90+
return p, _sources
91+
92+
93+
def get_new_sources(xs, foo, sources, cfoo, cx=0, cy=0, compute_curve=True):
94+
if compute_curve:
95+
ys = foo(xs)
96+
sources['curve'].data = dict(x=xs, base_x=base_x, y=ys)
97+
98+
r = foo(period)
99+
y = foo(xs[0]) + cy
100+
x = cfoo(xs[0]) + cx
101+
102+
sources['lines'].data = {
103+
'line_x': [x, shift], 'line_y': [y, y],
104+
'radius_x': [0, x], 'radius_y': [0, y]
105+
}
106+
sources['circle_point'].data = {'x': [x], 'y': [y], 'r': [r]}
107+
sources['circleds'].data = dict(
108+
x=cx + np.cos(np.linspace(0, 2 * pi, N)) * r,
109+
y=cy + np.sin(np.linspace(0, 2 * pi, N)) * r,
110+
)
111+
112+
113+
def update_sources(sources, foos, newx, ind, cfoos):
114+
cx, cy = 0, 0
115+
116+
for i, foo in enumerate(foos):
117+
get_new_sources(newx, foo, sources[i], cfoos[i], cx, cy, compute_curve=i != 0)
118+
119+
if i == 0:
120+
full_y = sum(foo(newx) for foo in foos)
121+
sources[i]['curve'].data = dict(x=newx, base_x=base_x, y=full_y)
122+
123+
cp = sources[i]['circle_point'].data
124+
cx, cy = cp['x'][0], cp['y'][0]
125+
126+
if i == len(foos) - 1:
127+
sources[i]['floating_point'].data['x'] = [shift]
128+
sources[i]['floating_point'].data['y'] = [cy]
129+
130+
131+
def update_centric_sources(sources, foos, newx, ind, cfoos):
132+
for i, foo in enumerate(foos):
133+
get_new_sources(newx, foo, sources[i], cfoos[i])
134+
135+
136+
def create_centric_plot(foos, title='', r=1, y_range=(-2, 2), period=pi / 2, cfoos=None):
137+
p = figure(title=title, tools="", plot_width=plot_width, plot_height=plot_height, x_range=[-2, 9], y_range=y_range,
138+
sizing_mode="stretch_width")
139+
p.xgrid.bounds = (-2, 2)
140+
p.xaxis.bounds = (-2, 2)
141+
142+
_sources = []
143+
for i, foo in enumerate(foos):
144+
sources = new_source()
145+
get_new_sources(x, foo, sources, cfoos[i])
146+
_sources.append(sources)
147+
148+
if i:
149+
legend_label = "4sin(%(c)sx)/%(c)spi" % {'c': i * 2 + 1}
150+
else:
151+
legend_label = "4sin(x)/pi"
152+
153+
p.line('base_x', 'y', color=palette[i], line_width=2, source=sources['curve'])
154+
p.line('line_x', 'line_y', color=palette[i], line_width=2,
155+
source=sources['lines'], legend_label=legend_label)
156+
157+
create_circle_glyphs(p, palette[i], sources)
158+
159+
p.legend.location = "top_right"
160+
p.legend.orientation = "horizontal"
161+
p.legend.padding = 6
162+
p.legend.margin = 6
163+
p.legend.spacing = 6
164+
165+
return p, _sources
166+
167+
168+
# create the series partials
169+
def f1(x):
170+
return (4 * np.sin(x)) / pi
171+
172+
173+
def f2(x):
174+
return (4 * np.sin(3 * x)) / (3 * pi)
175+
176+
177+
def f3(x):
178+
return (4 * np.sin(5 * x)) / (5 * pi)
179+
180+
181+
def f4(x):
182+
return (4 * np.sin(7 * x)) / (7 * pi)
183+
184+
185+
def cf1(x):
186+
return (4 * np.cos(x)) / pi
187+
188+
189+
def cf2(x):
190+
return (4 * np.cos(3 * x)) / (3 * pi)
191+
192+
193+
def cf3(x):
194+
return (4 * np.cos(5 * x)) / (5 * pi)
195+
196+
197+
def cf4(x):
198+
return (4 * np.cos(7 * x)) / (7 * pi)
199+
200+
201+
fourier = OrderedDict(
202+
fourier_4={
203+
'f': lambda x: f1(x) + f2(x) + f3(x) + f4(x),
204+
'fs': [f1, f2, f3, f4],
205+
'cfs': [cf1, cf2, cf3, cf4]
206+
},
207+
)
208+
209+
for k, p in fourier.items():
210+
p['plot'], p['sources'] = create_plot(
211+
p['fs'], 'Fourier (Sum of the first 4 Harmonic Circles)', r=p['f'](period), cfoos=p['cfs']
212+
)
213+
214+
for k, p in fourier.items():
215+
p['cplot'], p['csources'] = create_centric_plot(
216+
p['fs'], 'Fourier First 4 Harmonics & Harmonic Circles', r=p['f'](period), cfoos=p['cfs']
217+
)
218+
219+
layout = column(*[f['plot'] for f in fourier.values()] + [f['cplot'] for f in fourier.values()])
220+
221+
222+
@repeat(range(N))
223+
def cb(gind):
224+
global newx
225+
oldx = np.delete(newx, 0)
226+
newx = np.hstack([oldx, [oldx[-1] + 2 * pi / N]])
227+
228+
for k, p in fourier.items():
229+
update_sources(p['sources'], p['fs'], newx, gind, p['cfs'])
230+
update_centric_sources(p['csources'], p['fs'], newx, gind, p['cfs'])
231+
232+
233+
curdoc().title = "Fourier Animated"
234+
curdoc().add_root(desc_fourier)
235+
curdoc().add_root(layout)
236+
237+
curdoc().add_periodic_callback(cb, 100)
Binary file not shown.

notebooks/app/spectrogram/audio.py

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
from time import sleep
2+
3+
import numpy as np
4+
import scipy as sp
5+
from scipy.integrate import simps
6+
7+
NUM_SAMPLES = 1024
8+
SAMPLING_RATE = 44100.
9+
MAX_FREQ = SAMPLING_RATE / 2
10+
FREQ_SAMPLES = NUM_SAMPLES / 8
11+
TIMESLICE = 100 # ms
12+
NUM_BINS = 16
13+
14+
data = {'values': None}
15+
16+
try:
17+
import pyaudio
18+
19+
def update_audio_data():
20+
pa = pyaudio.PyAudio()
21+
stream = pa.open(
22+
format=pyaudio.paInt16,
23+
channels=1,
24+
rate=int(SAMPLING_RATE),
25+
input=True,
26+
frames_per_buffer=NUM_SAMPLES
27+
)
28+
29+
while True:
30+
try:
31+
raw_data = np.fromstring(stream.read(NUM_SAMPLES), dtype=np.int16)
32+
signal = raw_data / 32768.0
33+
fft = sp.fft(signal)
34+
spectrum = abs(fft)[:int(NUM_SAMPLES/2)]
35+
power = spectrum**2
36+
bins = simps(np.split(power, NUM_BINS))
37+
data['values'] = signal, spectrum, bins
38+
except:
39+
continue
40+
41+
except:
42+
print()
43+
print(" *** Pyaudio package not installed, using synthesized audio data ***")
44+
print()
45+
46+
def fm_modulation(x, f_carrier = 220, f_mod =220, Ind_mod = 1):
47+
y = np.sin(2*np.pi*f_carrier*x + Ind_mod*np.sin(2*np.pi*f_mod*x))
48+
return y
49+
50+
# These are basically picked out of a hat to show something vaguely interesting
51+
_t = np.arange(0, NUM_SAMPLES/SAMPLING_RATE, 1.0/SAMPLING_RATE)
52+
_f_carrier = 2000
53+
_f_mod = 1000
54+
_ind_mod = 1
55+
56+
def update_audio_data():
57+
while True:
58+
# Generate FM signal with drifting carrier and mod frequencies
59+
global _f_carrier, _f_mod, _ind_mod
60+
_f_carrier = max([_f_carrier+np.random.randn()*50, 0])
61+
_f_mod = max([_f_mod+np.random.randn()*20, 0])
62+
_ind_mod = max([_ind_mod+np.random.randn()*0.1, 0])
63+
A = 0.4 + 0.05 * np.random.random()
64+
signal = A * fm_modulation(_t, _f_carrier, _f_mod, _ind_mod)
65+
66+
fft = sp.fft(signal)
67+
spectrum = abs(fft)[:int(NUM_SAMPLES/2)]
68+
power = spectrum**2
69+
bins = simps(np.split(power, NUM_BINS))
70+
data['values'] = signal, spectrum, bins
71+
sleep(1.0/12)
+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<style>
2+
h1 {
3+
margin: 2em 0 0 0;
4+
color: #2e484c;
5+
font-family: 'Julius Sans One', sans-serif;
6+
font-size: 1.8em;
7+
text-transform: uppercase;
8+
}
9+
a:link {
10+
font-weight: bold;
11+
text-decoration: none;
12+
color: #0d8ba1;
13+
}
14+
a:visited {
15+
font-weight: bold;
16+
text-decoration: none;
17+
color: #1a5952;
18+
}
19+
a:hover, a:focus, a:active {
20+
text-decoration: underline;
21+
color: #9685BA;
22+
}
23+
p {
24+
font: "Libre Baskerville", sans-serif;
25+
text-align: justify;
26+
text-justify: inter-word;
27+
}
28+
code {
29+
color: #336699;
30+
}
31+
</style>
32+
33+
<h1>A Live Audio Spectrogam</h1>
34+
35+
<p><strong>credit: Bokeh Maintainers! (bokeh.org)</strong></p>
36+
<p><i>https://github.com/bokeh/bokeh/tree/master/examples/app/spectrogram</i></p>
37+
<p>
38+
This example shows how Bokeh custom extension models can be used with
39+
Bokeh server applications. While there are many great features built
40+
into Bokeh, with custom extensions, and the Bokeh server, it becomes
41+
simple to connect powerful Python tools for data analytics to almost
42+
any web tool, widget, or framework, even if it is not built into
43+
Bokeh natively.
44+
</p>

0 commit comments

Comments
 (0)