from pathlib import Path
import utils
import trackmate_utils
import holoviews as hv
import panel as pn
pn.extension('tabulator')
hv.extension('bokeh')
1. Run Full Pipeline¶
Define data paths for data and configs. Using the utils.run_analysis()
method we get a segmentation map and TrackMate results.
base_data_path = Path(r"data/fucci_60_frames")
red_stack_path = base_data_path / 'red.tif'
green_stack_path = base_data_path / 'green.tif'
base_model_path = Path(r"models")
red_segmentation_model = base_model_path / 'cellpose/nuclei_red_v2'
green_segmentation_model = base_model_path / 'cellpose/nuclei_green_v2'
trackmate_settings_xml = base_model_path / Path(r"trackmate/basic_settings.xml")
# utils.run_pipeline(red_stack_path, red_segmentation_model, trackmate_settings_xml)
# utils.run_pipeline(green_stack_path, green_segmentation_model, trackmate_settings_xml)
2. Measure Flouresence Over Time¶
Add plot
%load_ext autoreload
%autoreload 2
red_segmentation_map = utils.read_stack(base_data_path / 'red_segmented.tiff')
tm_red = trackmate_utils.TrackmateXML(base_data_path / 'red_segmented.tiff.xml')
red_stack = utils.read_stack(base_data_path / 'red.tif')
green_stack = utils.read_stack(base_data_path / 'green.tif')
import trackmate_utils
track = tm_red.trace_track(0)
trackmate_utils.draw_fucci_measurement(track, segmentation_map=red_segmentation_map, red_stack=red_stack, green_stack=green_stack)
trackmate_utils.view_track([red_stack, green_stack], frame=54, track=track, zoom=True).cols(2)
3. Identify Matching Tracks¶
As S phase progresses, contrast on red channel decreases while increasing in the green channel. These contrast dynamics bleed into the segmentation and vary the size of a segment. As such, the S phase, during which segmentation on both channels is possible, provides an option to both merge tracks from each channel and getting a better estimate of the size of the nucleus.
For a given pair of tracks $R$, $G$ that overlap for $t_{overlap}$ we can define a Cartesian similarity metric of the form: $$S=\frac{\sum_{t_{overlap,min}}^{t_{overlap,max}}\sqrt{[R_{X}(t)-G_{X}(t)]^{2}+[R_{Y}(t)-G_{Y}(t)]^{2}}}{t_{overlap,max}-t_{overlap,min}}$$ Where $$min(t_{R})<=t_{overlap}<=max(t_{G})$$ Which estimates the average deviation between the two tracks in units of $\frac{pixel}{frame}$
green_segmentation_map = utils.read_stack(base_data_path / 'green_segmented.tiff')
tm_green = trackmate_utils.TrackmateXML(base_data_path / 'green_segmented.tiff.xml')
red_track = tm_red.trace_track(0)
green_track = tm_green.trace_track(0)
Let's look at candidate tracks red-0 and green-0:
red_track.head()
ID | frame | POSITION_X | POSITION_Y | PERIMETER | image_id | AREA | ROI | roi_polygon | ELLIPSE_MAJOR | ELLIPSE_MINOR | mean_red | std_red | mean_green | std_green | low_red | high_red | low_green | high_green | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 856 | 0 | 247.581341 | 293.123523 | 95.61413819380628 | 41 | 606.5 | [(5.918658972245112, 18.376477054135762), (8.9... | POLYGON ((254 312, 257 307, 258 305, 259 299, ... | 17.470730857452068 | 11.618046610171142 | 0.010738 | 0.104057 | 0.077642 | 0.076447 | -0.093318 | 0.114795 | 0.001195 | 0.154089 |
1 | 894 | 1 | 262.158762 | 285.241765 | 105.93964862074475 | 38 | 759.0 | [(6.34123847167325, 18.258234519104064), (8.34... | POLYGON ((269 304, 271 303, 271 301, 274 298, ... | 18.674833874323685 | 13.922507990542325 | 0.000000 | 0.112771 | 0.043456 | 0.080206 | -0.112771 | 0.112771 | -0.036750 | 0.123662 |
2 | 518 | 2 | 275.38465 | 265.978358 | 104.46013970824129 | 34 | 747.0 | [(7.1153502900490935, 14.521642124051766), (9.... | POLYGON ((283 281, 285 280, 286 278, 288 278, ... | 17.035068889833056 | 14.472832948601143 | 0.001430 | 0.118055 | 0.000000 | 0.077172 | -0.116626 | 0.119485 | -0.077172 | 0.077172 |
3 | 401 | 3 | 283.703855 | 262.742857 | 104.04837559547113 | 31 | 735.0 | [(7.796145124716531, 13.757142857142867), (12.... | POLYGON ((292 277, 297 274, 299 273, 300 271, ... | 17.695714184876877 | 13.549831667188052 | 0.059190 | 0.143261 | 0.052387 | 0.079176 | -0.084072 | 0.202451 | -0.026789 | 0.131563 |
4 | 517 | 4 | 288.930523 | 260.915313 | 100.04485365944433 | 40 | 646.5 | [(8.569476669244636, 11.584686774941986), (13.... | POLYGON ((298 273, 303 270, 305 269, 306 267, ... | 18.732363212188634 | 11.12487641414746 | 0.145866 | 0.128231 | 0.098255 | 0.074736 | 0.017635 | 0.274098 | 0.023519 | 0.172990 |
green_track.head()
ID | frame | POSITION_X | POSITION_Y | PERIMETER | image_id | AREA | ROI | roi_polygon | ELLIPSE_MAJOR | ELLIPSE_MINOR | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 247 | 5 | 263.440317 | 291.522857 | 88.41281378798725 | 10 | 525.0 | [(11.05968253968257, 11.977142857142837), (12.... | POLYGON ((275 304, 276 302, 278 301, 278 299, ... | 14.998985013007266 | 11.790381737370799 |
1 | 166 | 6 | 272.387504 | 287.83557 | 87.00580543253196 | 10 | 521.5 | [(9.112496005113428, 11.664429530201346), (11.... | POLYGON ((282 300, 284 299, 286 296, 287 294, ... | 14.692405636710518 | 11.773727659511218 |
2 | 17 | 7 | 280.07243 | 287.447819 | 94.78718006414792 | 10 | 642.0 | [(6.427570093457916, 14.05218068535828), (10.4... | POLYGON ((287 302, 291 298, 293 297, 294 295, ... | 15.405565107375924 | 13.793580452722283 |
3 | 288 | 8 | 286.350168 | 286.534632 | 99.54663927460682 | 10 | 693.0 | [(7.14983164983164, 12.965367965367989), (9.14... | POLYGON ((294 300, 296 299, 297 297, 299 297, ... | 17.23530044573699 | 13.18728497136877 |
4 | 389 | 9 | 288.332898 | 284.215622 | 105.08835412502395 | 10 | 766.0 | [(5.16710182767622, 13.284377719756321), (7.16... | POLYGON ((294 298, 296 297, 298 297, 300 297, ... | 19.236280991492926 | 13.179491125152014 |
The frame column indicates the tracks are overlapping temporally. Let's see if they overlap spatially:
trackmate_utils.view_red_green_track([red_stack, green_stack], red_track, green_track, frame=8)
As seen above, the tracks intersect, but do not follow a similar path. It's also clear that at frame 8, the cell location does not overlap. As indicated above, we can calculate a similarity metric for these two tracks:
metric = trackmate_utils.CartesianSimilarity(tm_red, tm_green)
metric.calculate_metric(red_track_id=0, green_track_id=0)
53.954147393090814
Similarly, we can calculate a metric for all possible track pairs:
metric_df = metric.calculate_metric_for_all_tracks()
metric_df.sort_values('metric', ascending=True).head()
Calculating similarity metric: 100%|██████████| 5184/5184 [00:15<00:00, 340.06it/s]
red_track | green_track | metric | |
---|---|---|---|
0 | 32 | 40 | 1.018302 |
1 | 19 | 9 | 1.101308 |
2 | 10 | 53 | 1.123107 |
3 | 31 | 1 | 1.134302 |
4 | 29 | 11 | 1.153568 |
Based on the table above, red track 32 and green track 40 should match up pretty well:
red_track = tm_red.trace_track(32)
green_track = tm_green.trace_track(40)
trackmate_utils.view_red_green_track([red_stack, green_stack], red_track, green_track)
metric_df.query('metric < 10').metric.hvplot.hist()
metric_df.query('2 < metric < 10')
red_track | green_track | metric | |
---|---|---|---|
29 | 30 | 21 | 2.004808 |
30 | 3 | 52 | 2.027253 |
31 | 22 | 59 | 2.470495 |
32 | 15 | 66 | 2.984784 |
33 | 55 | 63 | 3.131836 |
34 | 43 | 19 | 6.059927 |
# red_track = tm_red.trace_track(43)
# green_track = tm_green.trace_track(19)
red_track = tm_red.trace_track(30)
green_track = tm_green.trace_track(21)
trackmate_utils.view_red_green_track([red_stack, green_stack], red_track, green_track, frame=42)
4. Measure Merged Tracks¶
Colorful plot showing red/yellow/green tracks and a flouresence time plot\
df = metric.merge_tracks(red_track_id=30, green_track_id=21)
df.sort_values('frame')
ID | frame | POSITION_X | POSITION_Y | PERIMETER | image_id | AREA | ROI | roi_polygon | ELLIPSE_MAJOR | ELLIPSE_MINOR | color | source_track | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 718 | 0 | 145.030227 | 163.693012 | 125.33054812633623 | 22 | 901.5 | [(11.4697726012202, 11.806988352745435), (13.4... | POLYGON ((157 176, 159 175, 163 175, 164 174, ... | 26.299283446267776 | 11.48226335338557 | red | red |
1 | 741 | 1 | 149.173954 | 168.741993 | 128.99426723294698 | 20 | 983.5 | [(20.326046432808, 12.758007117437728), (21.32... | POLYGON ((170 182, 171 180, 171 178, 173 177, ... | 27.0710084671051 | 11.769487268328414 | red | red |
2 | 492 | 2 | 152.348485 | 171.77013 | 130.94655166861943 | 21 | 962.5 | [(17.151515151515156, 13.729870129870136), (18... | POLYGON ((170 186, 171 184, 173 184, 174 182, ... | 26.91498053377485 | 11.757541165177717 | red | red |
3 | 390 | 3 | 156.796843 | 176.663781 | 129.06424194635238 | 20 | 982.0 | [(15.703156822810598, 14.836218601493528), (22... | POLYGON ((173 192, 180 188, 181 186, 183 183, ... | 26.35417119999956 | 11.903600703556869 | red | red |
4 | 443 | 4 | 169.444444 | 177.348399 | 131.4679621358243 | 26 | 1062.0 | [(16.055555555555543, 16.151600753295668), (19... | POLYGON ((186 194, 189 192, 191 191, 194 186, ... | 26.806163063017053 | 13.124673158309058 | red | red |
5 | 338 | 5 | 181.742109 | 173.718119 | 131.36082021898807 | 25 | 1056.0 | [(15.757891414141426, 17.781881313131294), (17... | POLYGON ((198 192, 200 191, 202 188, 204 187, ... | 25.84557839311181 | 13.381886075280141 | red | red |
6 | 1585 | 6 | 194.315309 | 170.128553 | 130.98605948579228 | 26 | 1049.5 | [(8.184691122756874, 20.37144672066063), (10.1... | POLYGON ((203 191, 205 190, 207 190, 209 190, ... | 25.092830921966282 | 13.903626146657459 | red | red |
7 | 763 | 7 | 206.218106 | 167.849004 | 123.60216180843078 | 28 | 978.5 | [(14.281894055527175, 18.650996423096586), (18... | POLYGON ((221 187, 225 183, 226 181, 226 175, ... | 24.482642026064465 | 13.379202097509504 | red | red |
8 | 2101 | 8 | 214.156015 | 164.848577 | 120.86521463430552 | 27 | 907.5 | [(7.343985307621665, 19.651423324150585), (10.... | POLYGON ((222 185, 225 183, 227 182, 229 182, ... | 23.664448506950603 | 12.433145032904472 | red | red |
9 | 731 | 9 | 220.131111 | 167.885185 | 121.22565986229465 | 25 | 900.0 | [(10.368888888888875, 18.61481481481482), (13.... | POLYGON ((231 187, 234 185, 236 184, 239 179, ... | 23.108214931082493 | 12.781370643871394 | red | red |
10 | 944 | 10 | 225.79107 | 172.066755 | 123.95114441827712 | 29 | 942.5 | [(11.708930150309442, 19.43324491600356), (15.... | POLYGON ((238 192, 242 188, 244 187, 245 183, ... | 24.15816248847182 | 12.685061884072159 | red | red |
11 | 960 | 11 | 232.071949 | 171.887614 | 123.61291164546542 | 25 | 915.0 | [(7.428051001821473, 20.612386156648455), (9.4... | POLYGON ((240 193, 242 192, 244 192, 245 191, ... | 23.729931824392796 | 12.428093187422572 | red | red |
12 | 1101 | 12 | 233.151844 | 168.834816 | 118.24712223146368 | 25 | 899.5 | [(8.34815638317582, 19.665184361682435), (13.3... | POLYGON ((242 189, 247 186, 249 185, 250 181, ... | 23.096285858644507 | 12.866044729139361 | red | red |
13 | 1247 | 13 | 235.302352 | 160.544058 | 126.27382070233604 | 23 | 949.5 | [(10.197647884851676, 19.955941723714233), (12... | POLYGON ((246 181, 248 180, 249 179, 252 176, ... | 24.15249115417699 | 12.627237489354933 | red | red |
14 | 1032 | 14 | 238.531952 | 152.851473 | 128.5628046122555 | 23 | 1001.5 | [(11.968047928107836, 18.648527209186227), (13... | POLYGON ((251 172, 253 171, 255 171, 259 167, ... | 25.38667506538604 | 12.895847321307675 | red | red |
15 | 127 | 15 | 240.522328 | 148.489549 | 132.82193283195625 | 21 | 1052.5 | [(13.977672209026139, 19.0104513064133), (14.9... | POLYGON ((255 168, 256 166, 258 166, 260 165, ... | 25.563152203774727 | 13.072850182631 | red | red |
16 | 1237 | 16 | 241.973095 | 141.511344 | 141.2619136665493 | 21 | 1146.0 | [(13.526905177428716, 19.988656195462482), (15... | POLYGON ((256 162, 258 161, 260 161, 264 157, ... | 28.19661504505331 | 13.360532462155327 | red | red |
17 | 1226 | 17 | 248.769481 | 136.605597 | 136.82378353388197 | 22 | 1078.0 | [(16.73051948051949, 18.894403215831773), (18.... | POLYGON ((266 156, 268 155, 269 154, 272 149, ... | 27.9071087451404 | 12.649391882194358 | red | red |
18 | 891 | 18 | 249.824427 | 131.430821 | 134.0791209031914 | 19 | 1048.0 | [(14.675572519083971, 19.06917938931298), (17.... | POLYGON ((265 151, 268 149, 270 148, 272 144, ... | 27.296024106779782 | 12.271062423129175 | red | red |
19 | 54 | 19 | 250.445381 | 127.749376 | 135.48573019755784 | 22 | 1068.0 | [(17.054619225967514, 17.75062421972534), (19.... | POLYGON ((268 146, 270 145, 272 142, 274 141, ... | 28.00559225619811 | 12.351566673187254 | red | red |
20 | 1051 | 20 | 254.497906 | 125.766338 | 136.086419052908 | 23 | 1114.5 | [(14.002093614475825, 19.733662329893818), (16... | POLYGON ((269 146, 271 145, 272 144, 275 141, ... | 27.76621408053037 | 12.960925284817689 | red | red |
21 | 142 | 21 | 256.189006 | 126.409906 | 137.79744455399282 | 22 | 1134.0 | [(17.310993533215765, 19.090094062316282), (19... | POLYGON ((274 146, 276 145, 276 143, 278 142, ... | 27.877599504419102 | 13.293614436060066 | red | red |
22 | 141 | 22 | 258.955238 | 126.993333 | 141.5390818709381 | 23 | 1225.0 | [(15.544761904761913, 19.50666666666666), (18.... | POLYGON ((275 147, 278 145, 280 144, 282 140, ... | 28.04285428292613 | 14.164202448222582 | red | red |
23 | 1144 | 23 | 261.845357 | 128.93807 | 136.8748279180853 | 21 | 1150.5 | [(15.654642908880191, 17.561929595827905), (17... | POLYGON ((278 147, 280 146, 281 145, 284 142, ... | 26.73983563215506 | 14.019659805100623 | red | red |
24 | 1608 | 24 | 259.566951 | 126.989837 | 136.812267298496 | 21 | 1172.5 | [(14.933049040511719, 17.51016346837241), (19.... | POLYGON ((275 145, 280 142, 282 141, 283 139, ... | 27.122272161881092 | 14.285077935245377 | red | red |
27 | 1615 | 25 | 266.878741 | 125.806623 | 135.1169069292797 | 21 | 1141.5 | [(16.621258577894594, 16.404730617608408), (18... | POLYGON ((284 142, 286 141, 287 140, 290 137, ... | 26.83942671707665 | 13.835804507770662 | yellow | red |
28 | 1799 | 26 | 271.636779 | 115.25946 | 140.48433766379102 | 20 | 1132.0 | [(19.863221436984702, 16.462897526501763), (21... | POLYGON ((292 132, 294 131, 296 131, 296 129, ... | 29.268474203297547 | 12.604463541927396 | yellow | red |
29 | 1932 | 27 | 284.954156 | 110.713004 | 142.9881729591448 | 19 | 1127.0 | [(19.545844424726454, 17.251848565513157), (20... | POLYGON ((305 128, 306 126, 308 126, 312 119, ... | 30.22263116758034 | 12.398260790127539 | yellow | red |
30 | 2042 | 28 | 292.859839 | 103.279019 | 144.94307400523576 | 18 | 1201.0 | [(15.640160976963614, 18.862614487926734), (20... | POLYGON ((309 122, 314 119, 316 118, 316 116, ... | 28.72953234164841 | 13.60065841044609 | yellow | red |
31 | 1315 | 29 | 294.923801 | 87.094489 | 140.6249006881293 | 16 | 1133.0 | [(18.57619888202413, 18.987202118270076), (20.... | POLYGON ((314 106, 316 105, 316 103, 317 101, ... | 28.06173377761514 | 13.060552691169141 | yellow | red |
32 | 2325 | 30 | 293.779073 | 74.822738 | 139.99034726589903 | 13 | 1136.5 | [(17.720926822114677, 18.10881360903359), (19.... | POLYGON ((312 93, 314 92, 315 91, 316 89, 318 ... | 29.455371086094015 | 12.489612085154226 | yellow | red |
33 | 18 | 31 | 299.536421 | 67.359804 | 139.11984777958693 | 12 | 1112.0 | [(14.963579136690669, 17.547362110311752), (15... | POLYGON ((315 85, 316 83, 318 83, 319 81, 321 ... | 27.60148830311041 | 13.104101910283019 | yellow | red |
34 | 554 | 32 | 301.627546 | 59.920107 | 134.74052824587886 | 10 | 1088.5 | [(13.872454448017152, 16.780278670953912), (15... | POLYGON ((316 77, 318 76, 320 76, 321 74, 322 ... | 26.572024402815025 | 13.098016190049485 | yellow | red |
35 | 454 | 33 | 304.127693 | 53.814788 | 133.6679912674727 | 10 | 1013.5 | [(15.37230718631804, 16.051307350764674), (16.... | POLYGON ((320 70, 321 68, 323 68, 324 66, 326 ... | 26.469694692071474 | 12.458949900894075 | yellow | red |
36 | 444 | 34 | 309.374932 | 53.813522 | 127.3604291992227 | 5 | 919.5 | [(15.125067971723752, 15.4205183976799), (18.1... | POLYGON ((325 70, 328 67, 330 67, 331 65, 333 ... | 26.000167015793096 | 11.440255231463105 | yellow | green |
37 | 637 | 35 | 308.934026 | 53.79858 | 129.91010582746156 | 5 | 890.5 | [(16.565974171813593, 14.505334081976414), (17... | POLYGON ((326 69, 327 67, 329 67, 331 66, 332 ... | 27.5980621754936 | 10.387840098881021 | yellow | green |
38 | 591 | 36 | 310.106737 | 51.838931 | 132.04286187524482 | 6 | 851.0 | [(18.393262828045465, 13.527614571092833), (20... | POLYGON ((329 66, 331 65, 331 63, 333 62, 334 ... | 27.655478106308475 | 9.688110840495888 | yellow | green |
39 | 671 | 37 | 307.409933 | 50.207912 | 122.2625311414868 | 7 | 792.0 | [(17.090067340067378, 11.292087542087543), (22... | POLYGON ((325 62, 330 59, 331 57, 331 51, 331 ... | 26.997829194646965 | 9.844547128835986 | yellow | green |
40 | 720 | 38 | 307.700038 | 51.625051 | 128.3373467592068 | 7 | 876.5 | [(15.799961969956314, 12.932876972808515), (20... | POLYGON ((324 65, 329 62, 331 61, 332 57, 333 ... | 27.45433104761784 | 10.351862959314394 | yellow | green |
41 | 534 | 39 | 305.75884 | 52.343755 | 127.5163814176686 | 6 | 839.0 | [(17.741160111243573, 11.981922924116013), (19... | POLYGON ((324 65, 326 64, 326 62, 328 61, 329 ... | 26.92581219921457 | 10.411247271377048 | yellow | green |
42 | 706 | 40 | 307.257904 | 51.633318 | 130.85965406226356 | 7 | 922.5 | [(19.242095754290858, 10.84878048780488), (22.... | POLYGON ((327 63, 330 61, 332 60, 334 54, 334 ... | 27.313279390612177 | 11.13093992039244 | yellow | green |
43 | 499 | 41 | 312.977087 | 49.130937 | 121.44125444160726 | 6 | 796.5 | [(16.52291274325171, 11.262816488805193), (20.... | POLYGON ((330 61, 334 57, 336 56, 336 52, 337 ... | 24.798528612278783 | 10.337600433691717 | yellow | green |
25 | 753 | 42 | 301.775593 | 42.119199 | 99.02562265223223 | 6 | 470.5 | [(-2.27559334041797, 18.38080056677294), (2.72... | POLYGON ((300 61, 305 52, 306 51, 306 49, 306 ... | 19.138897317023822 | 7.609520524225114 | green | green |
26 | 562 | 43 | 300.408819 | 35.671898 | 59.64942284741085 | 6 | 223.0 | [(2.091180866965601, 9.828101644245145), (3.09... | POLYGON ((303 46, 304 44, 306 43, 306 41, 306 ... | 10.560586044446321 | 7.031626777227055 | green | green |
red_track.hvplot.line(x='frame', y='AREA').opts(color='red') * green_track.hvplot.line(x='frame', y='AREA').opts(color='green')
df.sort_values('frame').hvplot.line(x='frame', y='AREA')
trackmate_utils.draw_fucci_measurement_merged_track(df.sort_values('frame'), red_segmentation_map=red_segmentation_map, green_segmentation_map=green_segmentation_map, red_stack=red_stack, green_stack=green_stack)
metric_df.query('red_track == 0').sort_values('metric')
red_track | green_track | metric | |
---|---|---|---|
8 | 0 | 41 | 1.218965 |
100 | 0 | 0 | 53.954147 |
133 | 0 | 51 | 59.848973 |
179 | 0 | 54 | 69.392551 |
188 | 0 | 23 | 71.639376 |
... | ... | ... | ... |
4081 | 0 | 70 | inf |
4071 | 0 | 13 | inf |
4070 | 0 | 12 | inf |
4074 | 0 | 26 | inf |
4092 | 0 | 71 | inf |
72 rows × 3 columns
red_track = tm_red.trace_track(0)
green_track = tm_green.trace_track(41)
(trackmate_utils.draw_fucci_measurement(red_track, segmentation_map=red_segmentation_map, red_stack=red_stack, green_stack=green_stack) + trackmate_utils.draw_fucci_measurement(green_track, segmentation_map=green_segmentation_map, red_stack=red_stack, green_stack=green_stack)).cols(1)
merged_track = metric.merge_tracks(red_track_id=0, green_track_id=41).sort_values('frame')
trackmate_utils.draw_fucci_measurement_merged_track(merged_track, red_segmentation_map=red_segmentation_map,green_segmentation_map=green_segmentation_map, red_stack=red_stack, green_stack=green_stack)