@@ -634,33 +634,10 @@ <h2>3. Labels: segmentation masks as centroids<a class="headerlink" href="#label
634634</ section >
635635< section id ="the-speed-trade-off ">
636636< h2 > 4. The speed trade-off< a class ="headerlink " href ="#the-speed-trade-off " title ="Link to this heading "> #</ a > </ h2 >
637- < p > First, the whole section drawn both ways: all 167780 cells, coloured by EPCAM. At
638- this zoom each cell is only a few microns across, well under one pixel, so the
639- full-geometry circles render sparse and speckled while < code class ="docutils literal notranslate "> < span class ="pre "> as_points</ span > </ code > spreads each
640- cell into a visible marker. On the datashader backend < code class ="docutils literal notranslate "> < span class ="pre "> size</ span > </ code > sets how far each
641- dot spreads, so a larger value fills the gaps into continuous coverage. The
642- centroid view is the cleaner overview here, and, as the timings below show, much
643- the faster one.</ p >
644- < div class ="cell docutils container ">
645- < div class ="cell_input docutils container ">
646- < div class ="highlight-ipython3 notranslate "> < div class ="highlight "> < pre > < span > </ span > < span class ="n "> fig</ span > < span class ="p "> ,</ span > < span class ="n "> axes</ span > < span class ="o "> =</ span > < span class ="n "> plt</ span > < span class ="o "> .</ span > < span class ="n "> subplots</ span > < span class ="p "> (</ span > < span class ="mi "> 1</ span > < span class ="p "> ,</ span > < span class ="mi "> 2</ span > < span class ="p "> ,</ span > < span class ="n "> figsize</ span > < span class ="o "> =</ span > < span class ="p "> (</ span > < span class ="mi "> 12</ span > < span class ="p "> ,</ span > < span class ="mf "> 5.5</ span > < span class ="p "> ))</ span >
647- < span class ="n "> sdata</ span > < span class ="o "> .</ span > < span class ="n "> pl</ span > < span class ="o "> .</ span > < span class ="n "> render_shapes</ span > < span class ="p "> (</ span >
648- < span class ="s2 "> "cell_circles"</ span > < span class ="p "> ,</ span > < span class ="n "> color</ span > < span class ="o "> =</ span > < span class ="s2 "> "EPCAM"</ span > < span class ="p "> ,</ span > < span class ="n "> cmap</ span > < span class ="o "> =</ span > < span class ="s2 "> "magma"</ span > < span class ="p "> ,</ span > < span class ="n "> outline_alpha</ span > < span class ="o "> =</ span > < span class ="mf "> 0.0</ span >
649- < span class ="p "> )</ span > < span class ="o "> .</ span > < span class ="n "> pl</ span > < span class ="o "> .</ span > < span class ="n "> show</ span > < span class ="p "> (</ span > < span class ="n "> ax</ span > < span class ="o "> =</ span > < span class ="n "> axes</ span > < span class ="p "> [</ span > < span class ="mi "> 0</ span > < span class ="p "> ],</ span > < span class ="n "> title</ span > < span class ="o "> =</ span > < span class ="s2 "> "full geometry (167780 circles)"</ span > < span class ="p "> ,</ span > < span class ="n "> colorbar</ span > < span class ="o "> =</ span > < span class ="kc "> False</ span > < span class ="p "> )</ span >
650- < span class ="n "> sdata</ span > < span class ="o "> .</ span > < span class ="n "> pl</ span > < span class ="o "> .</ span > < span class ="n "> render_shapes</ span > < span class ="p "> (</ span >
651- < span class ="s2 "> "cell_circles"</ span > < span class ="p "> ,</ span > < span class ="n "> color</ span > < span class ="o "> =</ span > < span class ="s2 "> "EPCAM"</ span > < span class ="p "> ,</ span > < span class ="n "> cmap</ span > < span class ="o "> =</ span > < span class ="s2 "> "magma"</ span > < span class ="p "> ,</ span > < span class ="n "> as_points</ span > < span class ="o "> =</ span > < span class ="kc "> True</ span > < span class ="p "> ,</ span > < span class ="n "> method</ span > < span class ="o "> =</ span > < span class ="s2 "> "datashader"</ span > < span class ="p "> ,</ span > < span class ="n "> size</ span > < span class ="o "> =</ span > < span class ="mi "> 12</ span >
652- < span class ="p "> )</ span > < span class ="o "> .</ span > < span class ="n "> pl</ span > < span class ="o "> .</ span > < span class ="n "> show</ span > < span class ="p "> (</ span > < span class ="n "> ax</ span > < span class ="o "> =</ span > < span class ="n "> axes</ span > < span class ="p "> [</ span > < span class ="mi "> 1</ span > < span class ="p "> ],</ span > < span class ="n "> title</ span > < span class ="o "> =</ span > < span class ="s2 "> "as_points (167780 dots)"</ span > < span class ="p "> ,</ span > < span class ="n "> colorbar</ span > < span class ="o "> =</ span > < span class ="kc "> False</ span > < span class ="p "> )</ span >
653- < span class ="n "> fig</ span > < span class ="o "> .</ span > < span class ="n "> tight_layout</ span > < span class ="p "> ()</ span >
654- </ pre > </ div >
655- </ div >
656- </ div >
657- < div class ="cell_output docutils container ">
658- < img alt ="../../_images/855c78a30dd38c3528985c35cc96e52656289abe0ca81ab6881bb6c162f740e3.png " src ="../../_images/855c78a30dd38c3528985c35cc96e52656289abe0ca81ab6881bb6c162f740e3.png " />
659- </ div >
660- </ div >
661- < p > To put numbers on it, we subsample the real cells across a range of counts, up to
662- the full 167780, and time each render. The backend is held at matplotlib, so the
663- comparison is drawing N polygons or masks against drawing N dots.</ p >
637+ < p > < code class ="docutils literal notranslate "> < span class ="pre "> as_points</ span > </ code > exists mainly for speed. We subsample the real cells across a range
638+ of counts, up to the full 167780, and time each render. The backend is held at
639+ matplotlib, so the comparison is drawing N polygons or masks against drawing N
640+ dots.</ p >
664641< div class ="cell docutils container ">
665642< div class ="cell_input docutils container ">
666643< div class ="highlight-ipython3 notranslate "> < div class ="highlight "> < pre > < span > </ span > < span class ="k "> def</ span > < span class ="w "> </ span > < span class ="nf "> time_best</ span > < span class ="p "> (</ span > < span class ="n "> fn</ span > < span class ="p "> ,</ span > < span class ="n "> repeat</ span > < span class ="o "> =</ span > < span class ="mi "> 3</ span > < span class ="p "> ):</ span >
@@ -694,12 +671,12 @@ <h2>4. The speed trade-off<a class="headerlink" href="#the-speed-trade-off" titl
694671</ div >
695672</ div >
696673< div class ="cell_output docutils container ">
697- < div class ="output stream highlight-myst-ansi notranslate "> < div class ="highlight "> < pre > < span > </ span > N= 1000: full 0.03s as_points 0.01s (3x )
698- N= 5000: full 0.13s as_points 0.02s (9x)
699- N= 20000: full 0.52s as_points 0.04s (13x)
700- N= 50000: full 1.26s as_points 0.09s (15x )
701- N= 100000: full 2.54s as_points 0.17s (15x)
702- N= 167780: full 4.23s as_points 0.26s (16x)
674+ < div class ="output stream highlight-myst-ansi notranslate "> < div class ="highlight "> < pre > < span > </ span > N= 1000: full 0.03s as_points 0.01s (4x )
675+ N= 5000: full 0.14s as_points 0.02s (9x)
676+ N= 20000: full 0.51s as_points 0.04s (13x)
677+ N= 50000: full 1.29s as_points 0.09s (14x )
678+ N= 100000: full 2.53s as_points 0.16s (15x)
679+ N= 167780: full 4.31s as_points 0.27s (16x)
703680</ pre > </ div >
704681</ div >
705682</ div >
@@ -737,7 +714,7 @@ <h2>4. The speed trade-off<a class="headerlink" href="#the-speed-trade-off" titl
737714</ div >
738715< div class ="cell_output docutils container ">
739716< div class ="output stream highlight-myst-ansi notranslate "> < div class ="highlight "> < pre > < span > </ span > N= 424: full mask 0.10s as_points 0.09s
740- N= 5833: full mask 0.10s as_points 0.10s
717+ N= 5833: full mask 0.11s as_points 0.10s
741718N= 18606: full mask 0.12s as_points 0.12s
742719N= 39125: full mask 0.17s as_points 0.15s
743720</ pre > </ div >
@@ -765,7 +742,7 @@ <h2>4. The speed trade-off<a class="headerlink" href="#the-speed-trade-off" titl
765742</ div >
766743</ div >
767744< div class ="cell_output docutils container ">
768- < img alt ="../../_images/22ae510ed0e3f6e3afdb800839f28d1bd202a8f51cb3b517864df6d2a569f9cf .png " src ="../../_images/22ae510ed0e3f6e3afdb800839f28d1bd202a8f51cb3b517864df6d2a569f9cf .png " />
745+ < img alt ="../../_images/afcfc277052b7e4bca010e00717bebda3f74d8df53528a2615951e595f1f175e .png " src ="../../_images/afcfc277052b7e4bca010e00717bebda3f74d8df53528a2615951e595f1f175e .png " />
769746</ div >
770747</ div >
771748< p > The two panels behave differently:</ p >
@@ -793,13 +770,28 @@ <h2>5. Backend and the 50000 rule<a class="headerlink" href="#backend-and-the-50
793770centroids (< code class ="docutils literal notranslate "> < span class ="pre "> AS_POINTS_DS_AUTO</ span > < span class ="pre "> =</ span > < span class ="pre "> 50000</ span > </ code > ), because matplotlib’s per-glyph cost
794771starts to dominate around there.</ p > </ li >
795772</ ul >
796- < p > The full-section < code class ="docutils literal notranslate "> < span class ="pre "> as_points</ span > </ code > panel above uses the datashader backend, which is
797- also what the default selects above 50000 cells. Passing < code class ="docutils literal notranslate "> < span class ="pre "> method="matplotlib"</ span > </ code >
798- forces per-glyph scatter instead, one marker per cell; < code class ="docutils literal notranslate "> < span class ="pre "> method="datashader"</ span > </ code >
799- forces the raster at any size.</ p >
800773< p > datashader aggregates and then shades, so it cannot represent one distinct random
801774colour per cell, which is the default colouring of a labels element with no
802- colour column. In that case it falls back to matplotlib with a warning.</ p >
775+ colour column. In that case it falls back to matplotlib with a warning. With a
776+ real colour column, as below, both backends work and differ only in appearance.</ p >
777+ < div class ="cell docutils container ">
778+ < div class ="cell_input docutils container ">
779+ < div class ="highlight-ipython3 notranslate "> < div class ="highlight "> < pre > < span > </ span > < span class ="n "> fig</ span > < span class ="p "> ,</ span > < span class ="n "> axes</ span > < span class ="o "> =</ span > < span class ="n "> plt</ span > < span class ="o "> .</ span > < span class ="n "> subplots</ span > < span class ="p "> (</ span > < span class ="mi "> 1</ span > < span class ="p "> ,</ span > < span class ="mi "> 2</ span > < span class ="p "> ,</ span > < span class ="n "> figsize</ span > < span class ="o "> =</ span > < span class ="p "> (</ span > < span class ="mi "> 11</ span > < span class ="p "> ,</ span > < span class ="mf "> 5.5</ span > < span class ="p "> ))</ span >
780+ < span class ="c1 "> # Shared EPCAM scale, so the colourbar is drawn once on the right panel.</ span >
781+ < span class ="n "> sdata</ span > < span class ="o "> .</ span > < span class ="n "> pl</ span > < span class ="o "> .</ span > < span class ="n "> render_shapes</ span > < span class ="p "> (</ span >
782+ < span class ="s2 "> "cell_circles"</ span > < span class ="p "> ,</ span > < span class ="n "> color</ span > < span class ="o "> =</ span > < span class ="s2 "> "EPCAM"</ span > < span class ="p "> ,</ span > < span class ="n "> cmap</ span > < span class ="o "> =</ span > < span class ="s2 "> "magma"</ span > < span class ="p "> ,</ span > < span class ="n "> as_points</ span > < span class ="o "> =</ span > < span class ="kc "> True</ span > < span class ="p "> ,</ span > < span class ="n "> method</ span > < span class ="o "> =</ span > < span class ="s2 "> "matplotlib"</ span > < span class ="p "> ,</ span > < span class ="n "> colorbar</ span > < span class ="o "> =</ span > < span class ="kc "> False</ span >
783+ < span class ="p "> )</ span > < span class ="o "> .</ span > < span class ="n "> pl</ span > < span class ="o "> .</ span > < span class ="n "> show</ span > < span class ="p "> (</ span > < span class ="n "> ax</ span > < span class ="o "> =</ span > < span class ="n "> axes</ span > < span class ="p "> [</ span > < span class ="mi "> 0</ span > < span class ="p "> ],</ span > < span class ="n "> title</ span > < span class ="o "> =</ span > < span class ="s2 "> "matplotlib (167780 dots)"</ span > < span class ="p "> )</ span >
784+ < span class ="n "> sdata</ span > < span class ="o "> .</ span > < span class ="n "> pl</ span > < span class ="o "> .</ span > < span class ="n "> render_shapes</ span > < span class ="p "> (</ span >
785+ < span class ="s2 "> "cell_circles"</ span > < span class ="p "> ,</ span > < span class ="n "> color</ span > < span class ="o "> =</ span > < span class ="s2 "> "EPCAM"</ span > < span class ="p "> ,</ span > < span class ="n "> cmap</ span > < span class ="o "> =</ span > < span class ="s2 "> "magma"</ span > < span class ="p "> ,</ span > < span class ="n "> as_points</ span > < span class ="o "> =</ span > < span class ="kc "> True</ span > < span class ="p "> ,</ span > < span class ="n "> method</ span > < span class ="o "> =</ span > < span class ="s2 "> "datashader"</ span >
786+ < span class ="p "> )</ span > < span class ="o "> .</ span > < span class ="n "> pl</ span > < span class ="o "> .</ span > < span class ="n "> show</ span > < span class ="p "> (</ span > < span class ="n "> ax</ span > < span class ="o "> =</ span > < span class ="n "> axes</ span > < span class ="p "> [</ span > < span class ="mi "> 1</ span > < span class ="p "> ],</ span > < span class ="n "> title</ span > < span class ="o "> =</ span > < span class ="s2 "> "datashader"</ span > < span class ="p "> )</ span >
787+ < span class ="n "> fig</ span > < span class ="o "> .</ span > < span class ="n "> tight_layout</ span > < span class ="p "> ()</ span >
788+ </ pre > </ div >
789+ </ div >
790+ </ div >
791+ < div class ="cell_output docutils container ">
792+ < img alt ="../../_images/e28f798adecfd1ca661a777460494c2bb3ac4ac13ed8edd3311e084d60e5daab.png " src ="../../_images/e28f798adecfd1ca661a777460494c2bb3ac4ac13ed8edd3311e084d60e5daab.png " />
793+ </ div >
794+ </ div >
803795</ section >
804796< section id ="when-to-reach-for-as-points ">
805797< h2 > When to reach for < code class ="docutils literal notranslate "> < span class ="pre "> as_points</ span > </ code > < a class ="headerlink " href ="#when-to-reach-for-as-points " title ="Link to this heading "> #</ a > </ h2 >
0 commit comments