import%20marimo%0A%0A__generated_with%20%3D%20%220.25.2%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22)%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20r%22%22%22%0A%20%20%20%20%20%20%20%20%23%20Persistent%20homology%20of%20an%20image%20with%20%60phlite%60%0A%0A%20%20%20%20%20%20%20%20We%20build%20the%20cubical%20complex%20of%20a%20greyscale%20image%20ourselves%2C%20as%20Python%20cells%2C%20attach%20the%20**lower-star%0A%20%20%20%20%20%20%20%20filtration**%20(a%20cell%20appears%20with%20its%20brightest%20pixel)%2C%20and%20read%20off%20the%20barcode%20and%20a%20**representative%20loop**%0A%20%20%20%20%20%20%20%20for%20each%20ring%20in%20the%20image.%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%20(mo%2C)%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20itertools%0A%0A%20%20%20%20import%20altair%20as%20alt%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20phlite%0A%20%20%20%20import%20polars%20as%20pl%0A%0A%20%20%20%20return%20alt%2C%20itertools%2C%20np%2C%20phlite%2C%20pl%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20np)%3A%0A%20%20%20%20%23%20An%20image%20with%20three%20dark%20rings%2C%20plus%20a%20little%20noise%0A%20%20%20%20size%20%3D%2064%0A%20%20%20%20rng%20%3D%20np.random.default_rng(0)%0A%20%20%20%20yy%2C%20xx%20%3D%20np.mgrid%5B0%3Asize%2C%200%3Asize%5D%0A%20%20%20%20rings%20%3D%20%5B((18%2C%2020)%2C%2010)%2C%20((44%2C%2022)%2C%207)%2C%20((32%2C%2046)%2C%2013)%5D%0A%20%20%20%20image%20%3D%20np.full((size%2C%20size)%2C%20np.inf)%0A%20%20%20%20for%20(cy%2C%20cx)%2C%20radius%20in%20rings%3A%0A%20%20%20%20%20%20%20%20distance%20%3D%20np.hypot(yy%20-%20cy%2C%20xx%20-%20cx)%0A%20%20%20%20%20%20%20%20image%20%3D%20np.minimum(image%2C%20np.abs(distance%20-%20radius))%0A%20%20%20%20image%20%3D%20np.minimum(image%2C%208)%20%2B%20rng.normal(scale%3D0.4%2C%20size%3Dimage.shape)%0A%20%20%20%20mo.md(f%22A%20%7Bsize%7D%20%C3%97%20%7Bsize%7D%20image%3A%20dark%20(low)%20pixels%20on%20three%20rings.%22)%0A%20%20%20%20return%20image%2C%20size%0A%0A%0A%40app.cell%0Adef%20_(alt%2C%20image%2C%20np%2C%20pl%2C%20size)%3A%0A%20%20%20%20_row%2C%20_col%20%3D%20np.divmod(np.arange(size%20*%20size)%2C%20size)%0A%20%20%20%20pixels%20%3D%20pl.DataFrame(%7B%22row%22%3A%20_row%2C%20%22col%22%3A%20_col%2C%20%22value%22%3A%20image.ravel()%7D)%0A%0A%20%20%20%20def%20picture(pixels)%3A%0A%20%20%20%20%20%20%20%20%22%22%22The%20image%20as%20a%20heatmap%2C%20in%20pixel%20coordinates%20(row%20down%2C%20column%20across).%22%22%22%0A%20%20%20%20%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20alt.Chart(pixels)%0A%20%20%20%20%20%20%20%20%20%20%20%20.transform_calculate(x%3D%22datum.col%20-%200.5%22%2C%20x2%3D%22datum.col%20%2B%200.5%22%2C%20y%3D%22datum.row%20-%200.5%22%2C%20y2%3D%22datum.row%20%2B%200.5%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20.mark_rect()%0A%20%20%20%20%20%20%20%20%20%20%20%20.encode(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20x%3Dalt.X(%22x%3AQ%22%2C%20axis%3DNone%2C%20scale%3Dalt.Scale(domain%3D%5B-0.5%2C%20size%20-%200.5%5D%2C%20nice%3DFalse))%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20x2%3D%22x2%3AQ%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20y%3Dalt.Y(%22y%3AQ%22%2C%20axis%3DNone%2C%20scale%3Dalt.Scale(domain%3D%5B-0.5%2C%20size%20-%200.5%5D%2C%20nice%3DFalse%2C%20reverse%3DTrue))%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20y2%3D%22y2%3AQ%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20color%3Dalt.Color(%22value%3AQ%22%2C%20scale%3Dalt.Scale(scheme%3D%22greys%22%2C%20reverse%3DTrue)%2C%20legend%3DNone)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20.properties(width%3D320%2C%20height%3D320)%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20picture(pixels).properties(title%3D%22the%20image%22)%0A%20%20%20%20return%20picture%2C%20pixels%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20The%20cubical%20complex%2C%20as%20Python%20cells%0A%0A%20%20%20%20Pixels%20are%20vertices%3B%20cells%20sit%20on%20a%20grid%20twice%20as%20fine%2C%20at%20%60(r%2C%20c)%60%3A%20a%20vertex%20where%20both%20coordinates%20are%20even%2C%0A%20%20%20%20an%20edge%20where%20one%20is%20odd%2C%20a%20square%20where%20both%20are.%20A%20cell's%20faces%20are%20one%20step%20either%20way%20along%20each%20odd%0A%20%20%20%20coordinate.%20We%20describe%20cells%20as%20plain%20tuples%20and%20tell%20%60phlite%60%20how%20to%20get%20their%20dimension%20and%20boundary.%0A%0A%20%20%20%20Cells%20with%20equal%20values%20enter%20in%20the%20order%20they%20are%20listed%2C%20so%20every%20face%20must%20be%20listed%20before%20its%20cofaces%3A%0A%20%20%20%20we%20list%20vertices%2C%20then%20edges%2C%20then%20squares.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(itertools%2C%20phlite%2C%20size)%3A%0A%20%20%20%20side%20%3D%202%20*%20size%20-%201%0A%0A%20%20%20%20def%20dimension(cell)%3A%0A%20%20%20%20%20%20%20%20return%20cell%5B0%5D%20%25%202%20%2B%20cell%5B1%5D%20%25%202%0A%0A%20%20%20%20def%20boundary(cell)%3A%0A%20%20%20%20%20%20%20%20r%2C%20c%20%3D%20cell%0A%20%20%20%20%20%20%20%20faces%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20if%20r%20%25%202%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20faces%20%2B%3D%20%5B(r%20-%201%2C%20c)%2C%20(r%20%2B%201%2C%20c)%5D%0A%20%20%20%20%20%20%20%20if%20c%20%25%202%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20faces%20%2B%3D%20%5B(r%2C%20c%20-%201)%2C%20(r%2C%20c%20%2B%201)%5D%0A%20%20%20%20%20%20%20%20return%20faces%0A%0A%20%20%20%20cells%20%3D%20sorted(itertools.product(range(side)%2C%20range(side))%2C%20key%3Ddimension)%0A%20%20%20%20chain%20%3D%20phlite.ChainComplex.from_cells(cells%2C%20dimension%3Ddimension%2C%20boundary%3Dboundary)%0A%20%20%20%20chain%0A%20%20%20%20return%20(chain%2C)%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20The%20lower-star%20filtration%0A%0A%20%20%20%20We%20only%20give%20values%20to%20the%20vertices%20(pixels)%3B%20%60extend%3DTrue%60%20gives%20every%20other%20cell%20the%20largest%20value%20of%20its%0A%20%20%20%20faces%2C%20which%20is%20exactly%20the%20lower-star%20filtration.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(chain%2C%20image%2C%20pl%2C%20size)%3A%0A%20%20%20%20pixel_values%20%3D%20%7B(2%20*%20i%2C%202%20*%20j)%3A%20float(image%5Bi%2C%20j%5D)%20for%20i%20in%20range(size)%20for%20j%20in%20range(size)%7D%0A%20%20%20%20barcode%20%3D%20chain.filtration(pixel_values%2C%20extend%3DTrue).persistence(representatives%3DTrue)%0A%20%20%20%20%23%20Essential%20bars%20never%20die%3A%20their%20death%20is%20null%20(charts%20need%20finite%20numbers)%2C%20and%20%60end%60%20is%20where%20to%20stop%20drawing%0A%20%20%20%20bars%20%3D%20(%0A%20%20%20%20%20%20%20%20pl.DataFrame(%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%22dimension%22%3A%20f%22H%7Bb.dimension%7D%22%2C%20%22birth%22%3A%20b.birth_value%2C%20%22death%22%3A%20None%20if%20b.is_essential%20else%20b.death_value%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20for%20b%20in%20barcode.bars%0A%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20schema%3D%7B%22dimension%22%3A%20pl.String%2C%20%22birth%22%3A%20pl.Float64%2C%20%22death%22%3A%20pl.Float64%7D%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20.with_columns(end%3Dpl.col(%22death%22).fill_null(9.5))%0A%20%20%20%20%20%20%20%20.with_columns(persistence%3Dpl.col(%22end%22)%20-%20pl.col(%22birth%22))%0A%20%20%20%20)%0A%20%20%20%20barcode%0A%20%20%20%20return%20barcode%2C%20bars%0A%0A%0A%40app.cell%0Adef%20_(alt%2C%20bars%2C%20pl)%3A%0A%20%20%20%20_finite%20%3D%20bars.filter(pl.col(%22death%22).is_not_null())%0A%20%20%20%20_diagonal%20%3D%20alt.Chart(pl.DataFrame(%7B%22t%22%3A%20%5B_finite%5B%22birth%22%5D.min()%2C%20_finite%5B%22death%22%5D.max()%5D%7D)).mark_line(%0A%20%20%20%20%20%20%20%20color%3D%22grey%22%2C%20strokeWidth%3D1%0A%20%20%20%20).encode(x%3D%22t%3AQ%22%2C%20y%3D%22t%3AQ%22)%0A%20%20%20%20_diagram%20%3D%20_diagonal%20%2B%20alt.Chart(_finite).mark_circle(size%3D30).encode(%0A%20%20%20%20%20%20%20%20x%3Dalt.X(%22birth%3AQ%22%2C%20title%3D%22birth%22)%2C%0A%20%20%20%20%20%20%20%20y%3Dalt.Y(%22death%3AQ%22%2C%20title%3D%22death%22)%2C%0A%20%20%20%20%20%20%20%20color%3Dalt.Color(%22dimension%3AN%22%2C%20title%3DNone)%2C%0A%20%20%20%20%20%20%20%20tooltip%3D%5B%22dimension%22%2C%20%22birth%22%2C%20%22death%22%5D%2C%0A%20%20%20%20).properties(width%3D360%2C%20height%3D360%2C%20title%3D%22persistence%20diagram%22)%0A%0A%20%20%20%20def%20barcode_panel(dimension)%3A%0A%20%20%20%20%20%20%20%20%22%22%22The%20bars%20of%20one%20dimension%20longer%20than%200.25%2C%20sorted%20by%20birth%20(essential%20bars%20run%20off%20the%20right).%22%22%22%0A%20%20%20%20%20%20%20%20frame%20%3D%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20bars.filter((pl.col(%22dimension%22)%20%3D%3D%20dimension)%20%26%20(pl.col(%22persistence%22)%20%3E%200.25))%0A%20%20%20%20%20%20%20%20%20%20%20%20.sort(%22birth%22%2C%20%22end%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20.with_row_index(%22bar%22)%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20alt.Chart(frame)%0A%20%20%20%20%20%20%20%20%20%20%20%20.mark_rule(strokeWidth%3D1.2)%0A%20%20%20%20%20%20%20%20%20%20%20%20.encode(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20x%3Dalt.X(%22birth%3AQ%22%2C%20title%3D%22filtration%20value%22%2C%20scale%3Dalt.Scale(domain%3D%5B-1.5%2C%209.5%5D))%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20x2%3D%22end%3AQ%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20y%3Dalt.Y(%22bar%3AO%22%2C%20axis%3DNone)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20color%3Dalt.Color(%22dimension%3AN%22%2C%20title%3DNone)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20tooltip%3D%5B%22dimension%22%2C%20%22birth%22%2C%20%22death%22%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20.properties(width%3D300%2C%20height%3D230%2C%20title%3Df%22%7Bdimension%7D%20barcode%20(%7Blen(frame)%7D%20bars%20longer%20than%200.25)%22)%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20_diagram%20%7C%20(barcode_panel(%22H0%22)%20%26%20barcode_panel(%22H1%22))%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Three%20H1%20bars%20stand%20out%3A%20the%20three%20rings%2C%20each%20born%20when%20its%20ring%20of%20dark%20pixels%20closes%20up%20and%20dying%20when%20its%0A%20%20%20%20brighter%20centre%20fills%20in.%20Their%20**representatives**%20are%20loops%20of%20edges%2C%20which%20we%20can%20draw%20on%20the%20image%20(an%20edge%0A%20%20%20%20between%20grid%20points%20%60(r%2C%20c)%60%20sits%20between%20the%20pixels%20at%20half%20those%20coordinates).%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(alt%2C%20barcode%2C%20picture%2C%20pixels%2C%20pl)%3A%0A%20%20%20%20loops%20%3D%20sorted((b%20for%20b%20in%20barcode.bars%20if%20b.dimension%20%3D%3D%201)%2C%20key%3Dlambda%20b%3A%20b.persistence%2C%20reverse%3DTrue)%5B%3A3%5D%0A%20%20%20%20_segments%20%3D%20%5B%5D%0A%20%20%20%20for%20_bar%20in%20loops%3A%0A%20%20%20%20%20%20%20%20_label%20%3D%20f%22%5B%7B_bar.birth_value%3A.2f%7D%2C%20%7B_bar.death_value%3A.2f%7D)%22%0A%20%20%20%20%20%20%20%20for%20(_r%2C%20_c)%2C%20_coefficient%20in%20_bar.representative%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20The%20edge's%20two%20pixels%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20_r%20%25%202%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(_y0%2C%20_x0)%2C%20(_y1%2C%20_x1)%20%3D%20((_r%20-%201)%20%2F%202%2C%20_c%20%2F%202)%2C%20((_r%20%2B%201)%20%2F%202%2C%20_c%20%2F%202)%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(_y0%2C%20_x0)%2C%20(_y1%2C%20_x1)%20%3D%20(_r%20%2F%202%2C%20(_c%20-%201)%20%2F%202)%2C%20(_r%20%2F%202%2C%20(_c%20%2B%201)%20%2F%202)%0A%20%20%20%20%20%20%20%20%20%20%20%20_segments.append(%7B%22loop%22%3A%20_label%2C%20%22x%22%3A%20_x0%2C%20%22y%22%3A%20_y0%2C%20%22x2%22%3A%20_x1%2C%20%22y2%22%3A%20_y1%7D)%0A%20%20%20%20_edges%20%3D%20alt.Chart(pl.DataFrame(_segments)).mark_rule(strokeWidth%3D2.5).encode(%0A%20%20%20%20%20%20%20%20x%3D%22x%3AQ%22%2C%20y%3D%22y%3AQ%22%2C%20x2%3D%22x2%3AQ%22%2C%20y2%3D%22y2%3AQ%22%2C%20color%3Dalt.Color(%22loop%3AN%22%2C%20title%3D%22H1%20bar%22)%0A%20%20%20%20)%0A%20%20%20%20(picture(pixels)%20%2B%20_edges).properties(title%3D%22representatives%20of%20the%20three%20longest%20H1%20bars%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Watching%20the%20filtration%0A%0A%20%20%20%20The%20sublevel%20set%20at%20time%20%5C(t%5C)%20is%20every%20pixel%20darker%20than%20%5C(t%5C)%20(with%20the%20edges%20and%20squares%20between%20them).%20As%0A%20%20%20%20%5C(t%5C)%20grows%2C%20components%20(H0)%20appear%20in%20the%20dark%20pixels%20and%20merge%2C%20and%20loops%20(H1)%20close%20up%20around%20each%20ring%20and%0A%20%20%20%20are%20filled%20in%20when%20the%20brighter%20centre%20arrives.%20On%20the%20right%2C%20the%20bars%20alive%20at%20%5C(t%5C)%20are%20highlighted.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(bars%2C%20image%2C%20mo%2C%20np%2C%20pl)%3A%0A%20%20%20%20import%20base64%0A%20%20%20%20import%20tempfile%0A%0A%20%20%20%20import%20matplotlib%0A%0A%20%20%20%20matplotlib.use(%22Agg%22)%0A%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%20%20%20%20from%20matplotlib.animation%20import%20FuncAnimation%2C%20PillowWriter%0A%0A%20%20%20%20def%20animate(draw%2C%20times%2C%20figsize%3D(9%2C%203.8)%2C%20fps%3D6)%3A%0A%20%20%20%20%20%20%20%20%22%22%22An%20animated%20GIF%20of%20%60draw(axes%2C%20t)%60%20over%20%60times%60%2C%20as%20an%20image%20to%20display.%22%22%22%0A%20%20%20%20%20%20%20%20fig%2C%20axes%20%3D%20plt.subplots(1%2C%202%2C%20figsize%3Dfigsize%2C%20gridspec_kw%3D%7B%22width_ratios%22%3A%20%5B1%2C%201.2%5D%7D)%0A%20%20%20%20%20%20%20%20animation%20%3D%20FuncAnimation(fig%2C%20lambda%20t%3A%20draw(axes%2C%20t)%2C%20frames%3Dtimes)%0A%20%20%20%20%20%20%20%20with%20tempfile.NamedTemporaryFile(suffix%3D%22.gif%22)%20as%20file%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20animation.save(file.name%2C%20writer%3DPillowWriter(fps%3Dfps)%2C%20dpi%3D72)%0A%20%20%20%20%20%20%20%20%20%20%20%20plt.close(fig)%0A%20%20%20%20%20%20%20%20%20%20%20%20data%20%3D%20base64.b64encode(open(file.name%2C%20%22rb%22).read()).decode()%0A%20%20%20%20%20%20%20%20return%20mo.Html(f'%3Cimg%20src%3D%22data%3Aimage%2Fgif%3Bbase64%2C%7Bdata%7D%22%20style%3D%22max-width%3A%20100%25%22%20%2F%3E')%0A%0A%20%20%20%20def%20draw_barcode(ax%2C%20frame%2C%20t%2C%20colours%2C%20top)%3A%0A%20%20%20%20%20%20%20%20%22%22%22Bars%20as%20horizontal%20lines%2C%20those%20alive%20at%20%60t%60%20in%20colour%2C%20the%20rest%20faded%2C%20and%20a%20line%20at%20%60t%60.%22%22%22%0A%20%20%20%20%20%20%20%20ax.clear()%0A%20%20%20%20%20%20%20%20for%20y%2C%20(dimension%2C%20birth%2C%20death)%20in%20enumerate(frame.iter_rows())%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20end%20%3D%20top%20if%20death%20is%20None%20else%20death%0A%20%20%20%20%20%20%20%20%20%20%20%20alive%20%3D%20birth%20%3C%3D%20t%20and%20(death%20is%20None%20or%20t%20%3C%20death)%0A%20%20%20%20%20%20%20%20%20%20%20%20ax.plot(%5Bbirth%2C%20end%5D%2C%20%5By%2C%20y%5D%2C%20color%3Dcolours%5Bdimension%5D%2C%20lw%3D2.2%2C%20alpha%3D1.0%20if%20alive%20else%200.15)%0A%20%20%20%20%20%20%20%20ax.axvline(t%2C%20color%3D%22black%22%2C%20lw%3D1)%0A%20%20%20%20%20%20%20%20ax.set_yticks(%5B%5D)%0A%20%20%20%20%20%20%20%20ax.set_xlim(frame%5B%22birth%22%5D.min()%20-%200.3%2C%20top)%0A%20%20%20%20%20%20%20%20ax.set_title(f%22barcode%2C%20t%20%3D%20%7Bt%3A.2f%7D%22)%0A%0A%20%20%20%20_shown%20%3D%20(%0A%20%20%20%20%20%20%20%20bars.filter(pl.col(%22persistence%22)%20%3E%200.6)%0A%20%20%20%20%20%20%20%20.sort(%22dimension%22%2C%20%22birth%22)%0A%20%20%20%20%20%20%20%20.select(%22dimension%22%2C%20%22birth%22%2C%20%22death%22)%0A%20%20%20%20)%0A%20%20%20%20_colours%20%3D%20%7B%22H0%22%3A%20%22tab%3Ablue%22%2C%20%22H1%22%3A%20%22tab%3Aorange%22%7D%0A%0A%20%20%20%20def%20_draw(axes%2C%20t)%3A%0A%20%20%20%20%20%20%20%20axes%5B0%5D.clear()%0A%20%20%20%20%20%20%20%20axes%5B0%5D.imshow(np.where(image%20%3C%3D%20t%2C%20image%2C%20np.nan)%2C%20cmap%3D%22gray%22%2C%20vmin%3Dimage.min()%2C%20vmax%3Dimage.max())%0A%20%20%20%20%20%20%20%20axes%5B0%5D.set_facecolor(%22white%22)%0A%20%20%20%20%20%20%20%20axes%5B0%5D.set_axis_off()%0A%20%20%20%20%20%20%20%20axes%5B0%5D.set_title(%22pixels%20below%20t%22)%0A%20%20%20%20%20%20%20%20draw_barcode(axes%5B1%5D%2C%20_shown%2C%20t%2C%20_colours%2C%209.5)%0A%0A%20%20%20%20animate(_draw%2C%20np.linspace(image.min()%2C%209.0%2C%2048))%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
75b22767f314ae1cb9e054821c3d7a38