@vitessce/spatial-utils 3.6.11 → 3.6.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect } from 'vitest';
2
- import { coordinateTransformationsToMatrix, normalizeCoordinateTransformations, getSwapAxesMatrix, } from './spatial.js';
2
+ import { coordinateTransformationsToMatrix, normalizeCoordinateTransformations, getSwapAxesMatrix, coordinateTransformationsToMatrixForSpatialData, } from './spatial.js';
3
3
  const defaultAxes = [
4
4
  { type: 'time', name: 't' },
5
5
  { type: 'channel', name: 'c' },
@@ -300,6 +300,44 @@ describe('Spatial.js', () => {
300
300
  // the user to specify this somehow and use that information to filter which transforms
301
301
  // are included here.
302
302
  {
303
+ input: {
304
+ axes: [
305
+ {
306
+ name: 'c',
307
+ type: 'channel',
308
+ },
309
+ {
310
+ name: 'y',
311
+ type: 'space',
312
+ unit: 'unit',
313
+ },
314
+ {
315
+ name: 'x',
316
+ type: 'space',
317
+ unit: 'unit',
318
+ },
319
+ ],
320
+ name: 'cyx',
321
+ },
322
+ output: {
323
+ axes: [
324
+ {
325
+ name: 'c',
326
+ type: 'channel',
327
+ },
328
+ {
329
+ name: 'y',
330
+ type: 'space',
331
+ unit: 'unit',
332
+ },
333
+ {
334
+ name: 'x',
335
+ type: 'space',
336
+ unit: 'unit',
337
+ },
338
+ ],
339
+ name: 'ST8059048',
340
+ },
303
341
  scale: [
304
342
  1.0,
305
343
  8.670500183814605,
@@ -310,4 +348,509 @@ describe('Spatial.js', () => {
310
348
  ]);
311
349
  });
312
350
  });
351
+ describe('coordinateTransformationsToMatrixForSpatialData', () => {
352
+ it('supports transformations from visium_hd_3.0.0_io.zip labels/rasterized_016um element', () => {
353
+ const zattrs = {
354
+ 'image-label': {
355
+ version: '0.4-dev-spatialdata',
356
+ },
357
+ multiscales: [
358
+ {
359
+ axes: [
360
+ {
361
+ name: 'y',
362
+ type: 'space',
363
+ },
364
+ {
365
+ name: 'x',
366
+ type: 'space',
367
+ },
368
+ ],
369
+ coordinateTransformations: [
370
+ {
371
+ input: {
372
+ axes: [
373
+ {
374
+ name: 'y',
375
+ type: 'space',
376
+ unit: 'unit',
377
+ },
378
+ {
379
+ name: 'x',
380
+ type: 'space',
381
+ unit: 'unit',
382
+ },
383
+ ],
384
+ name: 'yx',
385
+ },
386
+ output: {
387
+ axes: [
388
+ {
389
+ name: 'x',
390
+ type: 'space',
391
+ unit: 'unit',
392
+ },
393
+ {
394
+ name: 'y',
395
+ type: 'space',
396
+ unit: 'unit',
397
+ },
398
+ ],
399
+ name: 'Visium_HD_Mouse_Small_Intestine',
400
+ },
401
+ transformations: [
402
+ {
403
+ input: {
404
+ axes: [
405
+ {
406
+ name: 'y',
407
+ type: 'space',
408
+ unit: 'unit',
409
+ },
410
+ {
411
+ name: 'x',
412
+ type: 'space',
413
+ unit: 'unit',
414
+ },
415
+ ],
416
+ name: 'yx',
417
+ },
418
+ output: {
419
+ axes: [
420
+ {
421
+ name: 'x',
422
+ type: 'space',
423
+ unit: 'unit',
424
+ },
425
+ {
426
+ name: 'y',
427
+ type: 'space',
428
+ unit: 'unit',
429
+ },
430
+ ],
431
+ name: 'global',
432
+ },
433
+ transformations: [
434
+ {
435
+ affine: [
436
+ [
437
+ -0.38,
438
+ 58.43,
439
+ 257.07,
440
+ ],
441
+ [
442
+ -58.42,
443
+ -0.38,
444
+ 24102.79,
445
+ ],
446
+ ],
447
+ input: {
448
+ axes: [
449
+ {
450
+ name: 'y',
451
+ type: 'space',
452
+ unit: 'unit',
453
+ },
454
+ {
455
+ name: 'x',
456
+ type: 'space',
457
+ unit: 'unit',
458
+ },
459
+ ],
460
+ name: 'yx',
461
+ },
462
+ output: {
463
+ axes: [
464
+ {
465
+ name: 'x',
466
+ type: 'space',
467
+ unit: 'unit',
468
+ },
469
+ {
470
+ name: 'y',
471
+ type: 'space',
472
+ unit: 'unit',
473
+ },
474
+ ],
475
+ name: 'global',
476
+ },
477
+ type: 'affine',
478
+ },
479
+ ],
480
+ type: 'sequence',
481
+ },
482
+ {
483
+ input: {
484
+ axes: [
485
+ {
486
+ name: 'x',
487
+ type: 'space',
488
+ unit: 'unit',
489
+ },
490
+ {
491
+ name: 'y',
492
+ type: 'space',
493
+ unit: 'unit',
494
+ },
495
+ ],
496
+ name: 'xy',
497
+ },
498
+ output: {
499
+ axes: [
500
+ {
501
+ name: 'x',
502
+ type: 'space',
503
+ unit: 'unit',
504
+ },
505
+ {
506
+ name: 'y',
507
+ type: 'space',
508
+ unit: 'unit',
509
+ },
510
+ ],
511
+ name: 'global',
512
+ },
513
+ type: 'identity',
514
+ },
515
+ ],
516
+ type: 'sequence',
517
+ },
518
+ {
519
+ input: {
520
+ axes: [
521
+ {
522
+ name: 'y',
523
+ type: 'space',
524
+ unit: 'unit',
525
+ },
526
+ {
527
+ name: 'x',
528
+ type: 'space',
529
+ unit: 'unit',
530
+ },
531
+ ],
532
+ name: 'yx',
533
+ },
534
+ output: {
535
+ axes: [
536
+ {
537
+ name: 'x',
538
+ type: 'space',
539
+ unit: 'unit',
540
+ },
541
+ {
542
+ name: 'y',
543
+ type: 'space',
544
+ unit: 'unit',
545
+ },
546
+ ],
547
+ name: 'Visium_HD_Mouse_Small_Intestine_downscaled_hires',
548
+ },
549
+ transformations: [
550
+ {
551
+ input: {
552
+ axes: [
553
+ {
554
+ name: 'y',
555
+ type: 'space',
556
+ unit: 'unit',
557
+ },
558
+ {
559
+ name: 'x',
560
+ type: 'space',
561
+ unit: 'unit',
562
+ },
563
+ ],
564
+ name: 'yx',
565
+ },
566
+ output: {
567
+ axes: [
568
+ {
569
+ name: 'x',
570
+ type: 'space',
571
+ unit: 'unit',
572
+ },
573
+ {
574
+ name: 'y',
575
+ type: 'space',
576
+ unit: 'unit',
577
+ },
578
+ ],
579
+ name: 'global',
580
+ },
581
+ transformations: [
582
+ {
583
+ affine: [
584
+ [
585
+ -0.38,
586
+ 58.43,
587
+ 257.07,
588
+ ],
589
+ [
590
+ -58.42,
591
+ -0.38,
592
+ 24102.79,
593
+ ],
594
+ ],
595
+ input: {
596
+ axes: [
597
+ {
598
+ name: 'y',
599
+ type: 'space',
600
+ unit: 'unit',
601
+ },
602
+ {
603
+ name: 'x',
604
+ type: 'space',
605
+ unit: 'unit',
606
+ },
607
+ ],
608
+ name: 'yx',
609
+ },
610
+ output: {
611
+ axes: [
612
+ {
613
+ name: 'x',
614
+ type: 'space',
615
+ unit: 'unit',
616
+ },
617
+ {
618
+ name: 'y',
619
+ type: 'space',
620
+ unit: 'unit',
621
+ },
622
+ ],
623
+ name: 'global',
624
+ },
625
+ type: 'affine',
626
+ },
627
+ ],
628
+ type: 'sequence',
629
+ },
630
+ {
631
+ input: {
632
+ axes: [
633
+ {
634
+ name: 'x',
635
+ type: 'space',
636
+ unit: 'unit',
637
+ },
638
+ {
639
+ name: 'y',
640
+ type: 'space',
641
+ unit: 'unit',
642
+ },
643
+ ],
644
+ name: 'xy',
645
+ },
646
+ output: {
647
+ axes: [
648
+ {
649
+ name: 'x',
650
+ type: 'space',
651
+ unit: 'unit',
652
+ },
653
+ {
654
+ name: 'y',
655
+ type: 'space',
656
+ unit: 'unit',
657
+ },
658
+ ],
659
+ name: 'global',
660
+ },
661
+ scale: [
662
+ 0.25,
663
+ 0.25,
664
+ ],
665
+ type: 'scale',
666
+ },
667
+ ],
668
+ type: 'sequence',
669
+ },
670
+ {
671
+ input: {
672
+ axes: [
673
+ {
674
+ name: 'y',
675
+ type: 'space',
676
+ unit: 'unit',
677
+ },
678
+ {
679
+ name: 'x',
680
+ type: 'space',
681
+ unit: 'unit',
682
+ },
683
+ ],
684
+ name: 'yx',
685
+ },
686
+ output: {
687
+ axes: [
688
+ {
689
+ name: 'x',
690
+ type: 'space',
691
+ unit: 'unit',
692
+ },
693
+ {
694
+ name: 'y',
695
+ type: 'space',
696
+ unit: 'unit',
697
+ },
698
+ ],
699
+ name: 'Visium_HD_Mouse_Small_Intestine_downscaled_lowres',
700
+ },
701
+ transformations: [
702
+ {
703
+ input: {
704
+ axes: [
705
+ {
706
+ name: 'y',
707
+ type: 'space',
708
+ unit: 'unit',
709
+ },
710
+ {
711
+ name: 'x',
712
+ type: 'space',
713
+ unit: 'unit',
714
+ },
715
+ ],
716
+ name: 'yx',
717
+ },
718
+ output: {
719
+ axes: [
720
+ {
721
+ name: 'x',
722
+ type: 'space',
723
+ unit: 'unit',
724
+ },
725
+ {
726
+ name: 'y',
727
+ type: 'space',
728
+ unit: 'unit',
729
+ },
730
+ ],
731
+ name: 'global',
732
+ },
733
+ transformations: [
734
+ {
735
+ affine: [
736
+ [
737
+ -0.38,
738
+ 58.43,
739
+ 257.07,
740
+ ],
741
+ [
742
+ -58.42,
743
+ -0.38,
744
+ 24102.79,
745
+ ],
746
+ ],
747
+ input: {
748
+ axes: [
749
+ {
750
+ name: 'y',
751
+ type: 'space',
752
+ unit: 'unit',
753
+ },
754
+ {
755
+ name: 'x',
756
+ type: 'space',
757
+ unit: 'unit',
758
+ },
759
+ ],
760
+ name: 'yx',
761
+ },
762
+ output: {
763
+ axes: [
764
+ {
765
+ name: 'x',
766
+ type: 'space',
767
+ unit: 'unit',
768
+ },
769
+ {
770
+ name: 'y',
771
+ type: 'space',
772
+ unit: 'unit',
773
+ },
774
+ ],
775
+ name: 'global',
776
+ },
777
+ type: 'affine',
778
+ },
779
+ ],
780
+ type: 'sequence',
781
+ },
782
+ {
783
+ input: {
784
+ axes: [
785
+ {
786
+ name: 'x',
787
+ type: 'space',
788
+ unit: 'unit',
789
+ },
790
+ {
791
+ name: 'y',
792
+ type: 'space',
793
+ unit: 'unit',
794
+ },
795
+ ],
796
+ name: 'xy',
797
+ },
798
+ output: {
799
+ axes: [
800
+ {
801
+ name: 'x',
802
+ type: 'space',
803
+ unit: 'unit',
804
+ },
805
+ {
806
+ name: 'y',
807
+ type: 'space',
808
+ unit: 'unit',
809
+ },
810
+ ],
811
+ name: 'global',
812
+ },
813
+ scale: [
814
+ 0.025,
815
+ 0.025,
816
+ ],
817
+ type: 'scale',
818
+ },
819
+ ],
820
+ type: 'sequence',
821
+ },
822
+ ],
823
+ datasets: [
824
+ {
825
+ coordinateTransformations: [
826
+ {
827
+ scale: [
828
+ 1.0,
829
+ 1.0,
830
+ ],
831
+ type: 'scale',
832
+ },
833
+ ],
834
+ path: '0',
835
+ },
836
+ ],
837
+ name: 'rasterized_016um',
838
+ version: '0.4-dev-spatialdata',
839
+ },
840
+ ],
841
+ spatialdata_attrs: {
842
+ version: '0.2',
843
+ },
844
+ };
845
+ const firstMultiscales = zattrs.multiscales[0];
846
+ const targetCoordinateSystem = 'Visium_HD_Mouse_Small_Intestine';
847
+ const matrix = coordinateTransformationsToMatrixForSpatialData(firstMultiscales, targetCoordinateSystem);
848
+ expect(matrix).toEqual([
849
+ 58.43, -0.38, 0, 0,
850
+ -0.38, -58.42, 0, 0,
851
+ 0, 0, 1, 0,
852
+ 257.07, 24102.79, 0, 1,
853
+ ]);
854
+ });
855
+ });
313
856
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vitessce/spatial-utils",
3
- "version": "3.6.11",
3
+ "version": "3.6.13",
4
4
  "author": "HIDIVE Lab at HMS",
5
5
  "homepage": "http://vitessce.io",
6
6
  "repository": {
@@ -20,12 +20,13 @@
20
20
  "zarrita": "0.5.2",
21
21
  "math.gl": "^3.5.6",
22
22
  "mathjs": "^9.2.0",
23
- "@vitessce/gl": "3.6.11",
24
- "@vitessce/utils": "3.6.11",
25
- "@vitessce/zarr-utils": "3.6.11",
26
- "@vitessce/constants-internal": "3.6.11",
27
- "@vitessce/globals": "3.6.11",
28
- "@vitessce/error": "3.6.11"
23
+ "internmap": "^2.0.3",
24
+ "@vitessce/gl": "3.6.13",
25
+ "@vitessce/utils": "3.6.13",
26
+ "@vitessce/zarr-utils": "3.6.13",
27
+ "@vitessce/constants-internal": "3.6.13",
28
+ "@vitessce/globals": "3.6.13",
29
+ "@vitessce/error": "3.6.13"
29
30
  },
30
31
  "scripts": {
31
32
  "bundle": "pnpm exec vite build -c ../../../scripts/vite.config.js",
package/src/dag.js ADDED
@@ -0,0 +1,83 @@
1
+ import { InternMap } from 'internmap';
2
+
3
+
4
+ // Simple DAG class, with minimum functionality:
5
+ // to find a path from targetInput-to-targetOutput.
6
+ // Edges can have arbitrary attributes.
7
+ export class DAG {
8
+ /**
9
+ * DAG constructor.
10
+ * @param {{ from: string, to: string, attributes: any}[]} edges
11
+ */
12
+ constructor(edges) {
13
+ /**
14
+ * Adjacency list representation of the DAG.
15
+ * Maps each input to an array of outputs.
16
+ * @type {Map<string, string[]>}
17
+ */
18
+ this.graph = new Map();
19
+ /**
20
+ * Mapping from [from, to] pairs to edge data.
21
+ * @type {InternMap<[string, string], any>}
22
+ */
23
+ this.edgeData = new InternMap([], JSON.stringify);
24
+
25
+ // Build adjacency list
26
+ edges.forEach((edge) => {
27
+ const { from, to } = edge;
28
+ if (!this.graph.has(from)) {
29
+ this.graph.set(from, []);
30
+ }
31
+ this.graph.get(from).push(to);
32
+ this.edgeData.set([from, to], edge.attributes);
33
+ });
34
+ }
35
+
36
+ /**
37
+ * Find a path from start to end using DFS.
38
+ * @param {string} start
39
+ * @param {string} end
40
+ * @returns {{ from: string, to: string, attributes: any }[] | null} Returns
41
+ * the path as an array of edges or null if no path exists.
42
+ */
43
+ findPath(start, end) {
44
+ const path = [];
45
+ const visited = new Set();
46
+
47
+ // Depth-first search (DFS) to find a path from start to end.
48
+ const dfs = (node) => {
49
+ if (node === end) {
50
+ return true;
51
+ }
52
+ visited.add(node);
53
+
54
+ const neighbors = this.graph.get(node) || [];
55
+ // Do not use forEach to allow early exit (returning).
56
+ // eslint-disable-next-line no-restricted-syntax
57
+ for (const neighbor of neighbors) {
58
+ if (!visited.has(neighbor)) {
59
+ path.push([node, neighbor]);
60
+ if (dfs(neighbor)) {
61
+ return true;
62
+ }
63
+ path.pop(); // backtrack
64
+ }
65
+ }
66
+
67
+ return false;
68
+ };
69
+
70
+ // Start DFS from the start node.
71
+ const found = dfs(start);
72
+ if (found) {
73
+ // Convert path to a list of edge objects with info
74
+ return path.map(([from, to]) => ({
75
+ from,
76
+ to,
77
+ attributes: this.edgeData.get([from, to]),
78
+ }));
79
+ }
80
+ // If no path is found, return null.
81
+ return null;
82
+ }
83
+ }