Skeleton cache (connectomekg.skeleton_cache)¶
connectomekg.skeleton_cache
¶
Simplified skeletons and somas, cached per dataset from one pass over the SWC download.
The Codex skeleton download is 31 GB of SWC text, one file per neuron
(:func:connectomekg.skeletons.skeleton_path). Two things in it are worth
keeping and the rest is not:
- The soma. A neuron node's
x/y/zis FlyWire's marked point, an anchor that can sit tens of microns from the cell body. The soma is theLabel 1row of the skeleton, and it is what every fly atlas draws. :func:write_somascopies it into the neuron node's metadata assoma_x/soma_y/soma_zwith ahas_somaflag, so the graph answers for it without the download and so does every query over it. - The shape, simplified. At :data:
DEFAULT_CACHE_STEPa skeleton keeps about 29 % of its points and all of its topology (see :func:connectomekg.skeletons.segments), which is what the 3-D circuit view draws anyway. The cache is a directory of Parquet shards holding every neuron's kept points -- 212 M of them in 2.5 GB on FAFB v783, against the download's 31 GB -- so a render needs neither the download nor an SWC parse.
Both come out of the same pass, so :func:build_skeleton_cache does both and
connkg skeletons writes both. The pass reads every file once: 19m 30s on
one core for FAFB v783, or 2m 39s across twelve, since parsing SWC is pure
Python and splits cleanly across processes. Nothing else in the module needs
the download afterwards.
The cache carries each kept point's radius, which is what lets the circuit
view taper a drawn neuron instead of piping it at one width. Its labels are
reconstructed, not stored: a cached skeleton's only label is the soma's.
Everything else about it round-trips, so
:func:connectomekg.skeletons.segments, :func:connectomekg.skeletons.polylines
and :func:connectomekg.skeletons.soma read a cached skeleton exactly as they
read a parsed one.
A format-1 cache, written before the radius column existed, still loads: its
radii read back as zeros and its skeletons draw at a constant width, which is
what they did when it was written. Re-running connkg skeletons is what
adds the taper.
CacheReport(n_cached, n_missing, n_unreadable, n_soma, n_points, step, bytes_written, n_shards=1)
dataclass
¶
What one :func:build_skeleton_cache pass found.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_cached
|
int
|
Neurons written to the cache. |
required |
n_missing
|
int
|
Requested neurons with no SWC file. |
required |
n_unreadable
|
int
|
Neurons whose SWC file failed to parse. |
required |
n_soma
|
int
|
Cached neurons with a real |
required |
n_points
|
int
|
Kept points across every cached skeleton. |
required |
step
|
int
|
The stride the cache was built at. |
required |
bytes_written
|
int
|
Total size of the cache's Parquet shards. |
required |
n_shards
|
int
|
Shards written, one per worker. |
1
|
build_skeleton_cache(data_dir, root_ids, dest, *, step=DEFAULT_CACHE_STEP, jobs=1, progress=None)
¶
Read every neuron's SWC file once, writing the cache and collecting somas.
Parsing an SWC file is pure Python and holds the GIL, so the pass is bound
by one core until it is split across processes: jobs of them, each
taking a contiguous range of root ids and writing its own shard, after
proteusPy's DisulfideExtractor_mp. The cache is the directory of
those shards, which :func:load_cached_skeletons reads as one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data_dir
|
str | Path
|
Root of the skeleton download (default layout: |
required |
root_ids
|
Iterable[int]
|
Neuron root ids to read, in any order; the cache is written in ascending root-id order regardless. |
required |
dest
|
str | Path
|
The cache directory to write, usually
|
required |
step
|
int
|
Simplification stride, at least 1. |
DEFAULT_CACHE_STEP
|
jobs
|
int
|
Worker processes; 1 runs in this process and starts no pool. Above the number of neurons it is reduced to that. |
1
|
progress
|
Callable[[str], None] | None
|
Called with a short message as each shard finishes. |
None
|
Returns:
| Type | Description |
|---|---|
tuple[CacheReport, dict[int, tuple[ndarray, bool]]]
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/connectomekg/skeleton_cache.py
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 | |
cache_info(path)
¶
A cache's stride and neuron count, read from its Parquet metadata alone.
Every shard records the same stride, so the stride comes from the first of them; the neuron count is summed across all of them, since each shard counts only its own.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str | Path
|
The cache directory. |
required |
Returns:
| Type | Description |
|---|---|
tuple[int, int]
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If the directory holds no shard this module wrote. |
Source code in src/connectomekg/skeleton_cache.py
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 | |
effective_step(requested, cache_step)
¶
The stride to draw a cached skeleton with, given the one the caller asked for.
A cached skeleton has already been simplified at cache_step, so passing
the caller's stride straight to :func:connectomekg.skeletons.segments
would simplify it a second time and thin it to their product. Dividing
instead makes the drawn stride approximately the requested one, and a
request at or below cache_step draws the cache as it stands -- the
cache's own stride is the finest detail it holds.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
requested
|
int
|
The caller's |
required |
cache_step
|
int
|
The stride the cache was built at. |
required |
Returns:
| Type | Description |
|---|---|
int
|
The stride to pass to :func: |
Source code in src/connectomekg/skeleton_cache.py
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | |
load_cached_skeletons(path, root_ids)
¶
Read whichever of root_ids the cache holds, reporting the rest.
Mirrors :func:connectomekg.skeletons.load_skeletons, so a caller can use
either source.
The cache is a directory of shards; pyarrow reads it as one table, and because each shard holds a disjoint span of root ids their row-group statistics prune a filtered read down to the few shards that can match.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str | Path
|
The cache directory. |
required |
root_ids
|
Iterable[int]
|
Neuron root ids to read. |
required |
Returns:
| Type | Description |
|---|---|
tuple[dict[int, Skeleton], list[int]]
|
|
Source code in src/connectomekg/skeleton_cache.py
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 | |
skeleton_cache_path(db_path)
¶
Where a dataset's skeleton cache lives: beside its graph.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
db_path
|
str | Path
|
The dataset's |
required |
Returns:
| Type | Description |
|---|---|
Path
|
|
Source code in src/connectomekg/skeleton_cache.py
154 155 156 157 158 159 160 | |
write_somas(store, somas)
¶
Copy somas into their neuron nodes' metadata, in one transaction.
Adds soma_x, soma_y, soma_z and has_soma to each neuron
node that has a soma here, leaving the marked point (x/y/z) and
every other key as they were. Running again overwrites the four keys, so a
second pass over a corrected download is safe.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
store
|
GraphStore
|
The open store to update. |
required |
somas
|
dict[int, tuple[ndarray, bool]]
|
|
required |
Returns:
| Type | Description |
|---|---|
int
|
Neuron nodes updated. |
Source code in src/connectomekg/skeleton_cache.py
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 | |