diff --git a/deploy/datasets/index.js b/deploy/datasets/index.js index 3b27cab5f053aebae6859acf5b98ecfb76cda481..abb1ef174225f58b62f5e9afdb3c9696589a5f05 100644 --- a/deploy/datasets/index.js +++ b/deploy/datasets/index.js @@ -130,6 +130,7 @@ datasetsRouter.post("/downloadParcellationThemself", (req,res, next) => { + //ToDo: Need to download files dynamically. Nii folder should be removed if (req.body['niiFiles']) { var nii = zip.folder("nifti") diff --git a/src/atlasViewer/atlasViewer.apiService.service.ts b/src/atlasViewer/atlasViewer.apiService.service.ts index bdaf63c10763e0cf58075995cb2f570262a40552..5173ec7a7825790bb058a09b56aa5cf0cb8c6c11 100644 --- a/src/atlasViewer/atlasViewer.apiService.service.ts +++ b/src/atlasViewer/atlasViewer.apiService.service.ts @@ -172,6 +172,10 @@ export interface InteractiveViewerInterface{ mouseEvent : Observable<{eventName:string,event:MouseEvent}> mouseOverNehuba : Observable<{labelIndex : number, foundRegion : any | null}> + /** + * TODO add to documentation + */ + mouseOverNehubaLayers: Observable<{layer:{name:string}, segment: any | number }[]> getNgHash : () => string } diff --git a/src/atlasViewer/atlasViewer.component.ts b/src/atlasViewer/atlasViewer.component.ts index e29300da822e75e5d95832beb918489482a1458f..f2dac903f512b6be381c220af79f39029407cc6f 100644 --- a/src/atlasViewer/atlasViewer.component.ts +++ b/src/atlasViewer/atlasViewer.component.ts @@ -94,7 +94,6 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { public sidePanelOpen$: Observable<boolean> - handleToast get toggleMessage(){ return this.constantsService.toggleMessage @@ -228,6 +227,9 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { this.subscriptions.push( this.selectedParcellation$.subscribe(parcellation => { this.selectedParcellation = parcellation + this.niiFileSize = 0 + + if ((this.selectedParcellation['properties'] && (this.selectedParcellation['properties']['publications'] || this.selectedParcellation['properties']['description'])) @@ -245,6 +247,7 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { ) } + private selectedParcellation$: Observable<any> private selectedParcellation: any diff --git a/src/components/radiolist/radiolist.style.css b/src/components/radiolist/radiolist.style.css index ec1b53c976ab0c77e438409e547ceb5457024838..c6ee787207299fff88b50d856d84dcfb0fd0621d 100644 --- a/src/components/radiolist/radiolist.style.css +++ b/src/components/radiolist/radiolist.style.css @@ -1,3 +1,4 @@ +/*@import "~@angular/material/prebuilt-themes/indigo-pink.css";*/ :host-context([darktheme="true"]) ul { @@ -58,6 +59,7 @@ ul,span.dropdown-item-1 text-overflow: ellipsis } + .infoIcon { margin-left: 5px; display: inline-block; diff --git a/src/components/radiolist/radiolist.template.html b/src/components/radiolist/radiolist.template.html index c81d8b7c004fcedd72a538d6b9d19325a31e0a37..eb1d111ba65c6fef07f5e135905ea1af38621c20 100644 --- a/src/components/radiolist/radiolist.template.html +++ b/src/components/radiolist/radiolist.template.html @@ -2,6 +2,7 @@ [ngClass]="ulClass" class="radioListMenu" role="menu"> + <li *ngFor="let input of inputArray; let i = index" class="d-flex justify-content-between" diff --git a/src/index.html b/src/index.html index 3a45da9bca5a8f7038f93470f1089bdfe3d696b6..3cd64e66e8db5f00b99f0cdf2a6a97b985fc9a92 100644 --- a/src/index.html +++ b/src/index.html @@ -8,6 +8,8 @@ <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous"> <link rel = "stylesheet" href = "extra_styles.css"> <link rel = "stylesheet" href = "plugin_styles.css"> + <link rel = "stylesheet" href = "../node_modules/@angular/material/prebuilt-themes/indigo-pink.css"> + <title>Interactive Atlas Viewer</title> </head> <body> diff --git a/src/res/ext/MNI152.json b/src/res/ext/MNI152.json index 6f90ede30f6dd636f568866d1d8e0791fbb99a4c..657e54448a563c3824f615d880f980a6abeac658 100644 --- a/src/res/ext/MNI152.json +++ b/src/res/ext/MNI152.json @@ -1,5 +1,5 @@ { - "name": "MNI 152 ICBM 2009c Nonlinear Asymmetric", + "name": "ICBM 2009c Nonlinear Asymmetric", "type": "template", "species": "Human", "useTheme": "dark", @@ -6916,6 +6916,6 @@ ], "properties": { "name": "MNI 152", - "description": "Description of MNI152 (Probably also be more specific on which MNI152)" + "description": "An unbiased non-linear average of multiple subjects from the MNI152 database, which provides high-spatial resolution and signal-to-noise while not being biased towards a single brain (Fonov et al., 2011). This template space is widely used as a reference space in neuroimaging. HBP provides the JuBrain probabilistic cytoarchitectonic atlas (Amunts/Zilles, 2015) as well as a probabilistic atlas of large fibre bundles (Guevara, Mangin et al., 2017) in this space." } } \ No newline at end of file diff --git a/src/res/ext/bigbrain.json b/src/res/ext/bigbrain.json index ee281176d8238f65782385574149b92ee38d6405..e0d7fa074009c70a22aa086556cae70e47ca5201 100644 --- a/src/res/ext/bigbrain.json +++ b/src/res/ext/bigbrain.json @@ -1 +1 @@ -{"name":"Big Brain (Histology)","type":"template","species":"Human","useTheme":"light","nehubaId":" grey value: ","nehubaConfigURL":"nehubaConfig/bigbrainNehubaConfig","parcellations":[{"name":"Grey/White matter","type":"parcellation","ngData":null,"ngId":" tissue type: ","regions":[{"name":"Grey matter","labelIndex":100,"rgb":[200,200,200],"children":[]},{"name":"White matter","labelIndex":200,"rgb":[255,255,255],"children":[]}]},{"name":"Cytoarchitectonic Maps","properties":{"description":"This dataset contains cytoarchitectonic maps of brain regions in the BigBrain space [Amunts et al. 2013]. The mappings were created using the semi-automatic method presented in Schleicher et al. 1999, based on coronal histological sections on 1 micron resolution. Mappings are available on approximately every 100th section for each region. They were then transformed to the sections of the 3D reconstructed BigBrain space using the transformations used in Amunts et al. 2013, which were provided by Claude Lepage (McGill). Only a few cytoarchitectonic maps in the Big Brain are currently **fully mapped**, based on a workflow that automatically fills in missing sections based on expert annotations. Other 3D maps are available in a preliminary version, in which the expert annotations in the Big Brain space were simply **interpolated**."},"regions":[{"name":"telencephalon","children":[{"name":"cerebral cortex","children":[{"name":"temporal lobe","children":[{"name":"Heschl's gyrus","children":[{"name":"Area TE 1.0 (HESCHL)","ngId":"interpolated","status":"interpolated","labelIndex":4,"rgb":[0,146,63],"children":[],"position":[4363384,836825,4887117]},{"name":"Area TE 1.1 (HESCHL)","ngId":"interpolated","status":"interpolated","labelIndex":5,"rgb":[132,194,37],"children":[],"position":[-11860944,-3841071,6062770]},{"name":"Area TE 1.2 (HESCHL)","ngId":"interpolated","status":"interpolated","labelIndex":6,"rgb":[117,197,240],"children":[],"position":[19474750,7932494,3511322]}]},{"name":"superior temporal gyrus","children":[{"name":"Area TE 3 (STG)","ngId":"interpolated","status":"interpolated","labelIndex":7,"rgb":[231,120,23],"children":[],"position":[3479937,2702958,3819372]}]},{"name":"superior temporal sulcus","children":[{"name":"Area STS1 (STS)","ngId":"interpolated","status":"interpolated","labelIndex":24,"children":[],"position":[-3185950,3919067,-8346900]},{"name":"Area STS2 (STS)","ngId":"interpolated","status":"interpolated","labelIndex":25,"children":[],"position":[8584703,6170348,-11790982]}]}]},{"name":"frontal lobe","children":[{"name":"precentral gyrus","children":[{"name":"Area 6d1 (PreCG)","ngId":"interpolated","status":"interpolated","labelIndex":1,"children":[],"position":[-10496194,13643679,42286812]},{"name":"Area 6d2 (PreCG)","ngId":"interpolated","status":"interpolated","labelIndex":2,"children":[],"position":[-9255504,27432072,43445689]},{"name":"Area 6ma (preSMA, mesial SFG)","ngId":"interpolated","status":"interpolated","labelIndex":22,"children":[],"position":[-9349145,27783957,38734627]},{"name":"Area 6mp (SMA, mesial SFG)","ngId":"interpolated","status":"interpolated","labelIndex":23,"children":[],"position":[-11566856,15797100,42172031]}]},{"name":"superior frontal sulcus","children":[{"name":"Area 6d3 (SFS)","ngId":"interpolated","status":"interpolated","labelIndex":3,"children":[],"position":[-8973604,28973429,35691250]}]},{"name":"inferior frontal sulcus","children":[{"name":"Area ifj1 (IFS/PreCS)","ngId":"interpolated","status":"interpolated","labelIndex":9,"children":[],"position":[-7394436,33562602,19086364]},{"name":"Area ifj2 (IFS/PreCS)","ngId":"interpolated","status":"interpolated","labelIndex":10,"children":[],"position":[-26787581,30975651,16855869]},{"name":"Area ifs1 (IFS)","ngId":"interpolated","status":"interpolated","labelIndex":11,"children":[],"position":[-4044465,40212624,17596493]},{"name":"Area ifs2 (IFS)","ngId":"interpolated","status":"interpolated","labelIndex":12,"children":[],"position":[6807265,40114241,18114896]},{"name":"Area ifs3 (IFS)","ngId":"interpolated","status":"interpolated","labelIndex":13,"children":[],"position":[-2260366,37593844,19960703]},{"name":"Area ifs4 (IFS)","ngId":"interpolated","status":"interpolated","labelIndex":14,"children":[],"position":[-3440565,37895181,17378851]}]}]},{"name":"limbic lobe","children":[{"name":"hippocampal formation","children":[{"name":"Entorhinal Cortex","ngId":"interpolated","status":"interpolated","labelIndex":8,"rgb":[153,153,255],"children":[],"position":[4800238,8859989,-24872710]}]}]},{"name":"parietal lobe","children":[{"name":"intraparietal sulcus","children":[{"name":"Area hIP4 (IPS)","ngId":"interpolated","status":"interpolated","labelIndex":15,"children":[],"position":[-5671181,-44793673,21692004]},{"name":"Area hIP5 (IPS)","ngId":"interpolated","status":"interpolated","labelIndex":16,"children":[],"position":[-13546343,-38230309,26252296]},{"name":"Area hIP6 (IPS)","ngId":"interpolated","status":"interpolated","labelIndex":17,"children":[],"position":[-3723403,-33064127,32569712]},{"name":"Area hIP7 (IPS)","ngId":"interpolated","status":"interpolated","labelIndex":18,"children":[],"position":[-5344588,-43655931,24702722]}]},{"name":"parieto-occipital sulcus","children":[{"name":"Area hPO1 (POS)","ngId":"interpolated","status":"interpolated","labelIndex":21,"children":[],"position":[-4455614,-44097379,28855803]}]}]},{"name":"occipital lobe","children":[{"name":"occipital cortex","children":[{"name":"Area hOc1 (V1, 17, CalcS)","ngId":"v1","status":"fully mapped","labelIndex":1,"position":[3187941,-50436479,3430986],"rgb":[250,30,250],"children":[]},{"name":"Area hOc2 (V2, 18)","ngId":"v2","status":"fully mapped","labelIndex":1,"position":[311768,-54882875,4142912],"rgb":[155,100,250],"children":[]},{"name":"dorsal occipital cortex","children":[{"name":"Area hOc6 (POS)","ngId":"interpolated","status":"interpolated","labelIndex":20,"children":[],"position":[-4399437,-36706104,15113374]}]}]}]}]}]}]},{"name":"BigBrain Cortical Layers Segmentation","ngId":"cortical layers","properties":{"description":"The cerebral isocortex has six cytoarchitectonic layers that vary depending on cortical area and local morphology. This datasets provides a 3D segmentation of all cortical and laminar surfaces in the BigBrain, a high-resolution, 3D histological model of the human brain. The segmentation has been computed automatically based on histological intensities along 3D cortical profiles which were sampled between the pial and white matter throughout the dataset. These cortical profiles were segmented into layers using a convolutional neural network. Training profiles were generated from examples of manually segmented layers on cortical regions from 2D histological sections of the BigBrain. From the segmented intensity profiles, surface meshes and voxel masks of all six cortical layers in the space of the Big Brain have been computed.","publications":[{"doi":"https://doi.org/10.1101/580597","citation":"Konrad Wagstyl, Stéphanie Larocque, Guillem Cucurull, Claude Lepage, Joseph Paul Cohen, Sebastian Bludau, Nicola Palomero-Gallagher, Thomas Funck, Hannah Spitzer, Timo Dicksheid, Paul C Fletcher, Adriana Romero, Karl Zilles, Katrin Amunts, Yoshua Bengio, Alan C. Evans (2019) Automated segmentation of cortical layers in BigBrain reveals divergent cortical and laminar thickness gradients in sensory and motor cortices. bioRxiv 580597; doi: https://doi.org/10.1101/580597"}]},"regions":[{"name":"telencephalon","children":[{"name":"cortical layer 1","labelIndex":1,"rgb":[128,128,0],"children":[]},{"name":"cortical layer 2","labelIndex":2,"rgb":[250,190,190],"children":[]},{"name":"cortical layer 3","labelIndex":3,"rgb":[255,215,180],"children":[]},{"name":"cortical layer 4","labelIndex":4,"rgb":[255,250,200],"children":[]},{"name":"cortical layer 5","labelIndex":5,"rgb":[0,128,128],"children":[]},{"name":"cortical layer 6","labelIndex":6,"rgb":[230,190,255],"children":[]},{"name":"non-cortical structures","labelIndex":7,"rgb":[255,255,255],"children":[]}]}]}],"properties":{"name":"Big Brain (Histology)","description":"An ultrahigh resolution 3D model of a complete human brain (20 micron isotropic resolution), developed in a collaborative effort between the teams of Dr. Katrin Amunts and Dr. Karl Zilles (Forschungszentrum Jülich) and Dr. Alan Evans (Montreal Neurological Institute). Based on 7404 digitized histological brain sections, this so far unique reconstruction provides unprecedented neuroanatomical insight. The dataset contains a complete gray and white matter classification with corresponding surface reconstructions","publications":[{"doi":"https://doi.org/10.1126/science.1235381","citation":"K. Amunts, A. Evans et al.: BigBrain: An Ultrahigh-Resolution 3D Human Brain Model. Science 2013"},{"doi":"http://bigbrain.loris.ca","citation":"http://bigbrain.loris.ca"}]}} \ No newline at end of file +{"name":"Big Brain (Histology)","type":"template","species":"Human","useTheme":"light","nehubaId":" grey value: ","nehubaConfigURL":"nehubaConfig/bigbrainNehubaConfig","parcellations":[{"name":"Grey/White matter","type":"parcellation","ngData":null,"ngId":" tissue type: ","regions":[{"name":"Grey matter","labelIndex":100,"rgb":[200,200,200],"children":[]},{"name":"White matter","labelIndex":200,"rgb":[255,255,255],"children":[]}]},{"name":"Cytoarchitectonic Maps","properties":{"description":"This dataset contains cytoarchitectonic maps of brain regions in the BigBrain space [Amunts et al. 2013]. The mappings were created using the semi-automatic method presented in Schleicher et al. 1999, based on coronal histological sections on 1 micron resolution. Mappings are available on approximately every 100th section for each region. They were then transformed to the sections of the 3D reconstructed BigBrain space using the transformations used in Amunts et al. 2013, which were provided by Claude Lepage (McGill). Only a few cytoarchitectonic maps in the Big Brain are currently **fully mapped**, based on a workflow that automatically fills in missing sections based on expert annotations. Other 3D maps are available in a preliminary version, in which the expert annotations in the Big Brain space were simply **interpolated**."},"regions":[{"name":"telencephalon","children":[{"name":"cerebral cortex","children":[{"name":"temporal lobe","children":[{"name":"Heschl's gyrus","children":[{"name":"Area TE 1.0 (HESCHL)","ngId":"interpolated","status":"interpolated","labelIndex":4,"rgb":[0,146,63],"children":[],"position":[4363384,836825,4887117]},{"name":"Area TE 1.1 (HESCHL)","ngId":"interpolated","status":"interpolated","labelIndex":5,"rgb":[132,194,37],"children":[],"position":[-11860944,-3841071,6062770]},{"name":"Area TE 1.2 (HESCHL)","ngId":"interpolated","status":"interpolated","labelIndex":6,"rgb":[117,197,240],"children":[],"position":[19474750,7932494,3511322]}]},{"name":"superior temporal gyrus","children":[{"name":"Area TE 3 (STG)","ngId":"interpolated","status":"interpolated","labelIndex":7,"rgb":[231,120,23],"children":[],"position":[3479937,2702958,3819372]}]},{"name":"superior temporal sulcus","children":[{"name":"Area STS1 (STS)","ngId":"interpolated","status":"interpolated","labelIndex":24,"children":[],"position":[-3185950,3919067,-8346900]},{"name":"Area STS2 (STS)","ngId":"interpolated","status":"interpolated","labelIndex":25,"children":[],"position":[8584703,6170348,-11790982]}]}]},{"name":"frontal lobe","children":[{"name":"precentral gyrus","children":[{"name":"Area 6d1 (PreCG)","ngId":"interpolated","status":"interpolated","labelIndex":1,"children":[],"position":[-10496194,13643679,42286812]},{"name":"Area 6d2 (PreCG)","ngId":"interpolated","status":"interpolated","labelIndex":2,"children":[],"position":[-9255504,27432072,43445689]},{"name":"Area 6ma (preSMA, mesial SFG)","ngId":"interpolated","status":"interpolated","labelIndex":22,"children":[],"position":[-9349145,27783957,38734627]},{"name":"Area 6mp (SMA, mesial SFG)","ngId":"interpolated","status":"interpolated","labelIndex":23,"children":[],"position":[-11566856,15797100,42172031]}]},{"name":"superior frontal sulcus","children":[{"name":"Area 6d3 (SFS)","ngId":"interpolated","status":"interpolated","labelIndex":3,"children":[],"position":[-8973604,28973429,35691250]}]},{"name":"inferior frontal sulcus","children":[{"name":"Area ifj1 (IFS/PreCS)","ngId":"interpolated","status":"interpolated","labelIndex":9,"children":[],"position":[-7394436,33562602,19086364]},{"name":"Area ifj2 (IFS/PreCS)","ngId":"interpolated","status":"interpolated","labelIndex":10,"children":[],"position":[-26787581,30975651,16855869]},{"name":"Area ifs1 (IFS)","ngId":"interpolated","status":"interpolated","labelIndex":11,"children":[],"position":[-4044465,40212624,17596493]},{"name":"Area ifs2 (IFS)","ngId":"interpolated","status":"interpolated","labelIndex":12,"children":[],"position":[6807265,40114241,18114896]},{"name":"Area ifs3 (IFS)","ngId":"interpolated","status":"interpolated","labelIndex":13,"children":[],"position":[-2260366,37593844,19960703]},{"name":"Area ifs4 (IFS)","ngId":"interpolated","status":"interpolated","labelIndex":14,"children":[],"position":[-3440565,37895181,17378851]}]}]},{"name":"limbic lobe","children":[{"name":"hippocampal formation","children":[{"name":"Entorhinal Cortex","ngId":"interpolated","status":"interpolated","labelIndex":8,"rgb":[153,153,255],"children":[],"position":[4800238,8859989,-24872710]}]}]},{"name":"parietal lobe","children":[{"name":"intraparietal sulcus","children":[{"name":"Area hIP4 (IPS)","ngId":"interpolated","status":"interpolated","labelIndex":15,"children":[],"position":[-5671181,-44793673,21692004]},{"name":"Area hIP5 (IPS)","ngId":"interpolated","status":"interpolated","labelIndex":16,"children":[],"position":[-13546343,-38230309,26252296]},{"name":"Area hIP6 (IPS)","ngId":"interpolated","status":"interpolated","labelIndex":17,"children":[],"position":[-3723403,-33064127,32569712]},{"name":"Area hIP7 (IPS)","ngId":"interpolated","status":"interpolated","labelIndex":18,"children":[],"position":[-5344588,-43655931,24702722]}]},{"name":"parieto-occipital sulcus","children":[{"name":"Area hPO1 (POS)","ngId":"interpolated","status":"interpolated","labelIndex":21,"children":[],"position":[-4455614,-44097379,28855803]}]}]},{"name":"occipital lobe","children":[{"name":"occipital cortex","children":[{"name":"Area hOc1 (V1, 17, CalcS)","ngId":"v1","status":"fully mapped","labelIndex":1,"position":[3187941,-50436479,3430986],"rgb":[250,30,250],"children":[]},{"name":"Area hOc2 (V2, 18)","ngId":"v2","status":"fully mapped","labelIndex":1,"position":[311768,-54882875,4142912],"rgb":[155,100,250],"children":[]},{"name":"dorsal occipital cortex","children":[{"name":"Area hOc6 (POS)","ngId":"interpolated","status":"interpolated","labelIndex":20,"children":[],"position":[-4399437,-36706104,15113374]}]}]}]}]}]}]},{"name":"BigBrain Cortical Layers Segmentation","ngId":"cortical layers","properties":{"description":"The cerebral isocortex has six cytoarchitectonic layers that vary depending on cortical area and local morphology. This datasets provides a 3D segmentation of all cortical and laminar surfaces in the BigBrain, a high-resolution, 3D histological model of the human brain. The segmentation has been computed automatically based on histological intensities along 3D cortical profiles which were sampled between the pial and white matter throughout the dataset. These cortical profiles were segmented into layers using a convolutional neural network. Training profiles were generated from examples of manually segmented layers on cortical regions from 2D histological sections of the BigBrain. From the segmented intensity profiles, surface meshes and voxel masks of all six cortical layers in the space of the Big Brain have been computed.","publications":[{"doi":"https://doi.org/10.1101/580597","citation":"Konrad Wagstyl, Stéphanie Larocque, Guillem Cucurull, Claude Lepage, Joseph Paul Cohen, Sebastian Bludau, Nicola Palomero-Gallagher, Thomas Funck, Hannah Spitzer, Timo Dicksheid, Paul C Fletcher, Adriana Romero, Karl Zilles, Katrin Amunts, Yoshua Bengio, Alan C. Evans (2019) Automated segmentation of cortical layers in BigBrain reveals divergent cortical and laminar thickness gradients in sensory and motor cortices. bioRxiv 580597; doi: https://doi.org/10.1101/580597"}]},"regions":[{"name":"telencephalon","children":[{"name":"cortical layer 1","labelIndex":1,"rgb":[128,128,0],"children":[]},{"name":"cortical layer 2","labelIndex":2,"rgb":[250,190,190],"children":[]},{"name":"cortical layer 3","labelIndex":3,"rgb":[255,215,180],"children":[]},{"name":"cortical layer 4","labelIndex":4,"rgb":[255,250,200],"children":[]},{"name":"cortical layer 5","labelIndex":5,"rgb":[0,128,128],"children":[]},{"name":"cortical layer 6","labelIndex":6,"rgb":[230,190,255],"children":[]},{"name":"non-cortical structures","labelIndex":7,"rgb":[255,255,255],"children":[]}]}]}],"properties":{"name":"Big Brain (Histology)","description":"A microscopic resolution 3D model of a complete human brain, based on a 3D reconstruction from 7404 digitized histological brain sections (Amunts, Evans et al., Science 2013). The BigBrain model provides a highly detailed anatomical reference space which resolves individual cortical layers and large cell bodies. Maps of cytoarchitectonic areas (Amunts et al.) and cortical layers (Wagstyl et al.) are available.","publications":[{"doi":"https://doi.org/10.1126/science.1235381","citation":"K. Amunts, A. Evans et al.: BigBrain: An Ultrahigh-Resolution 3D Human Brain Model. Science 2013"},{"doi":"http://bigbrain.loris.ca","citation":"http://bigbrain.loris.ca"}]}} \ No newline at end of file diff --git a/src/res/ext/colin.json b/src/res/ext/colin.json index f0a34ad3f8b3e3dafb8956e7470194f8330714e9..4e6e3f948e7408a2bad396a3f971f842c2812b67 100644 --- a/src/res/ext/colin.json +++ b/src/res/ext/colin.json @@ -5683,6 +5683,6 @@ ], "properties": { "name": "MNI Colin 27", - "description": "This is a stereotaxic average of 27 T1-weighted MRI scans of the same individual. In 1998, a new atlas with much higher definition than MNI305s was created at the MNI. One individual (CJH) was scanned 27 times and the images linearly registered to create an average with high SNR and structure definition (Holmes et al., 1998). This average was linearly registered to the average 305. Ironically, this dataset was not originally intended for use as a stereotaxic template but as the sub- strate for an ROI parcellation scheme to be used with ANIMAL non-linear spatial normalization (Collins et al., 1995), i.e. it was intended for the purpose of segmentation, NOT stereotaxy. As a single brain atlas, it did not capture anatomical variability and was, to some degree, a reversion to the Talairach approach. However, the high definition proved too attractive to the community and, after non-linear mapping to fit the MNI305 space, it has been adopted by many groups as a stereotaxic template (e.g., AFNI, Cox,; Brainstorm, Tadel et al., 2011; SPM, Litvak et al., 2011; Fieldtrip, Oostenveld et al., 2011)." + "description": "A stereotaxic average of 27 T1-weighted MRI scans of the same individual. (Holmes et al., 1998), mapped to fit the MNI305 space. Although not capturing brain variability, it is well established in neuroscience due to its high definition. HBP provides the JuBrain probabilistic cytoarchitectonic atlas (Amunts et al.) in this space." } } \ No newline at end of file diff --git a/src/res/images/AllenadultmousebrainreferenceatlasV3BrainAtlas.png b/src/res/images/AllenadultmousebrainreferenceatlasV3BrainAtlas.png new file mode 100644 index 0000000000000000000000000000000000000000..897168863448a2efce76cd5496cd4154cc48545e Binary files /dev/null and b/src/res/images/AllenadultmousebrainreferenceatlasV3BrainAtlas.png differ diff --git a/src/res/images/BigBrainHistology.png b/src/res/images/BigBrainHistology.png new file mode 100644 index 0000000000000000000000000000000000000000..94cc67bd8cae7c3701d9c3c6c15f2dc9be8400b6 Binary files /dev/null and b/src/res/images/BigBrainHistology.png differ diff --git a/src/res/images/ICBM2009cNonlinearAsymmetric.png b/src/res/images/ICBM2009cNonlinearAsymmetric.png new file mode 100644 index 0000000000000000000000000000000000000000..a5d2276eff480aefe8ab7116c500d82b1201fbfa Binary files /dev/null and b/src/res/images/ICBM2009cNonlinearAsymmetric.png differ diff --git a/src/res/images/MNI152.png b/src/res/images/MNI152.png new file mode 100644 index 0000000000000000000000000000000000000000..a5d2276eff480aefe8ab7116c500d82b1201fbfa Binary files /dev/null and b/src/res/images/MNI152.png differ diff --git a/src/res/images/MNIColin27.png b/src/res/images/MNIColin27.png new file mode 100644 index 0000000000000000000000000000000000000000..6993e50d6ef7484530a7df17b8ca5bee7bdac249 Binary files /dev/null and b/src/res/images/MNIColin27.png differ diff --git a/src/res/images/WaxholmSpaceratbrainatlasv20.png b/src/res/images/WaxholmSpaceratbrainatlasv20.png new file mode 100644 index 0000000000000000000000000000000000000000..0a2b6cef1d493cad67ab3850d0bdd1969e7a6e21 Binary files /dev/null and b/src/res/images/WaxholmSpaceratbrainatlasv20.png differ diff --git a/src/ui/nehubaContainer/nehubaContainer.component.ts b/src/ui/nehubaContainer/nehubaContainer.component.ts index a4b62b13cc30648f4c0e3646d9400d3079ed70c4..74849c89679efbafd7a776c58dabed4306d8f5b6 100644 --- a/src/ui/nehubaContainer/nehubaContainer.component.ts +++ b/src/ui/nehubaContainer/nehubaContainer.component.ts @@ -113,6 +113,7 @@ export class NehubaContainer implements OnInit, OnDestroy{ private userLandmarks$ : Observable<UserLandmark[]> public onHoverSegmentName$ : Observable<string> public onHoverSegment$ : Observable<any> + public onHoverSegments$: Observable<any[]> private onHoverLandmark$ : Observable<any|null> private navigationChanges$ : Observable<any> @@ -228,25 +229,86 @@ export class NehubaContainer implements OnInit, OnDestroy{ distinctUntilChanged(userLmUnchanged) ) - const segmentsUnchangedChanged = (s1,s2)=> - !(typeof s1 === typeof s2 ? - typeof s2 === 'undefined' ? - false : - typeof s2 === 'number' ? - s2 !== s1 : - s1 === s2 ? - false : - s1 === null || s2 === null ? - true : - s2.name !== s1.name : - true) - - - this.onHoverSegment$ = this.store.pipe( + this.onHoverSegments$ = this.store.pipe( select('uiState'), - filter(state=>isDefined(state)), - map(state=>state.mouseOverSegment), - distinctUntilChanged(segmentsUnchangedChanged) + select('mouseOverSegments'), + filter(v => !!v), + distinctUntilChanged((o, n) => o.length === n.length + && n.every(segment => + o.find(oSegment => oSegment.layer.name === segment.layer.name + && oSegment.segment === segment.segment))) + ) + + const sortByFreshness: (acc: any[], curr: any[]) => any[] = (acc, curr) => { + + const getLayerName = ({layer} = {layer:{}}) => { + const { name } = <any>layer + return name + } + + const newEntries = curr.filter(entry => { + const name = getLayerName(entry) + return acc.map(getLayerName).indexOf(name) < 0 + }) + + const entryChanged: (itemPrevState, newArr) => boolean = (itemPrevState, newArr) => { + const layerName = getLayerName(itemPrevState) + const { segment } = itemPrevState + const foundItem = newArr.find((_item) => + getLayerName(_item) === layerName) + + if (foundItem) { + const { segment:foundSegment } = foundItem + return segment !== foundSegment + } else { + /** + * if item was not found in the new array, meaning hovering nothing + */ + return segment !== null + } + } + + const getItemFromLayerName = (item, arr) => { + const foundItem = arr.find(i => getLayerName(i) === getLayerName(item)) + return foundItem + ? foundItem + : { + layer: item.layer, + segment: null + } + } + + const getReduceExistingLayers = (newArr) => ([changed, unchanged], _curr) => { + const changedFlag = entryChanged(_curr, newArr) + return changedFlag + ? [ changed.concat( getItemFromLayerName(_curr, newArr) ), unchanged ] + : [ changed, unchanged.concat(_curr) ] + } + + /** + * now, for all the previous layers, separate into changed and unchanged layers + */ + const [changed, unchanged] = acc.reduce(getReduceExistingLayers(curr), [[], []]) + return [...newEntries, ...changed, ...unchanged] + } + + this.onHoverSegment$ = this.onHoverSegments$.pipe( + scan(sortByFreshness, []), + /** + * take the first element after sort by freshness + */ + map(arr => arr[0]), + /** + * map to the older interface + */ + filter(v => !!v), + map(({ segment }) => { + + return { + labelIndex: (isNaN(segment) && Number(segment.labelIndex)) || null, + foundRegion: (isNaN(segment) && segment) || null + } + }) ) this.onHoverLandmark$ = this.store.pipe( @@ -825,19 +887,12 @@ export class NehubaContainer implements OnInit, OnDestroy{ }) ) - const onhoverSegments$ = this.store.pipe( - select('uiState'), - select('mouseOverSegments'), - filter(v => !!v), - distinctUntilChanged((o, n) => o.length === n.length && n.every(segment => o.find(oSegment => oSegment.layer.name === segment.layer.name && oSegment.segment === segment.segment) ) ) - ) - // TODO hack, even though octant is hidden, it seems with vtk one can mouse on hover this.nehubaViewerSubscriptions.push( this.nehubaViewer.regionSelectionEmitter.pipe( withLatestFrom(this.onHoverLandmark$), filter(results => results[1] === null), - withLatestFrom(onhoverSegments$), + withLatestFrom(this.onHoverSegments$), map(results => results[1]), filter(arr => arr.length > 0), map(arr => { @@ -970,7 +1025,10 @@ export class NehubaContainer implements OnInit, OnDestroy{ map((ev:MouseEvent)=>({eventName :'mouseup',event:ev})) ), ) , - mouseOverNehuba : this.onHoverSegment$, + mouseOverNehuba : this.onHoverSegment$.pipe( + tap(() => console.warn('mouseOverNehuba observable is becoming deprecated. use mouseOverNehubaLayers instead.')) + ), + mouseOverNehubaLayers: this.onHoverSegments$, getNgHash : this.nehubaViewer.getNgHash } } diff --git a/src/ui/nehubaContainer/splashScreen/splashScreen.component.ts b/src/ui/nehubaContainer/splashScreen/splashScreen.component.ts index f1178af037d26f65036bc8c02d54d6218f00a567..eb27393a77f1c284743cc34314d09db21040946f 100644 --- a/src/ui/nehubaContainer/splashScreen/splashScreen.component.ts +++ b/src/ui/nehubaContainer/splashScreen/splashScreen.component.ts @@ -17,8 +17,9 @@ export class SplashScreen{ loadedTemplate$ : Observable<any[]> constructor( private store:Store<ViewerStateInterface>, - private constanceService: AtlasViewerConstantsServices - ){ + private constanceService: AtlasViewerConstantsServices, + private constantsService: AtlasViewerConstantsServices, +){ this.loadedTemplate$ = this.store.pipe( select('viewerState'), filter((state:ViewerStateInterface)=> typeof state !== 'undefined' && typeof state.fetchedTemplates !== 'undefined' && state.fetchedTemplates !== null), @@ -36,4 +37,12 @@ export class SplashScreen{ get totalTemplates(){ return this.constanceService.templateUrls.length } + + correctString(name){ + return name.replace(/[|&;$%@()+,\s./]/g, '') + } + + get isMobile(){ + return this.constantsService.mobile + } } \ No newline at end of file diff --git a/src/ui/nehubaContainer/splashScreen/splashScreen.style.css b/src/ui/nehubaContainer/splashScreen/splashScreen.style.css index d08929f3d9aaa5df9529eaf14714e71c60d7ca2a..23f295b2ea0e74248e2ac37b796d450b8215e034 100644 --- a/src/ui/nehubaContainer/splashScreen/splashScreen.style.css +++ b/src/ui/nehubaContainer/splashScreen/splashScreen.style.css @@ -1,8 +1,118 @@ div[splashScreenContainer] { - height:100%; + height: 100%; + display:flex; + flex-direction: column; + justify-content: flex-start; + align-items: center; + overflow-y:auto; +} + +div[splashScreenHeader] { + min-height: 90px; + max-height: 100px; + width: 100%; + background-color: #EF5450; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + color: #FFFFFF; +} + + +.splashScreenHeaderTitle { + font-size: 45px; } + +.splashScreenHeaderLogoContainer { + flex: 1; +} +.splashScreenHeaderLogo { + margin-left: 50px; + width: 100px; + height: auto; +} + +.spaceForFill { + flex: 1; +} + +div[splashScreenTemplate] { + + width: 100%; + margin: 20px 20px; + display: flex; + flex-wrap: wrap; + justify-content: center; + +} + +div[splashScreenTemplateItem] { + max-width: 600px; + width: 400px; + margin: 20px 20px; + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: center; + +} + +div[splashScreenTemplateHeader] { + align-self: center; + text-align: center; + font-size: 30px; + margin: 0 0 20px 0; + +} + +div[splashScreenTemplateBody] { + display: flex; + flex-direction: column; +} + +div[splashScreenTemplateBodyDescription] { + flex: 1; + text-align: justify; + margin: 0 10px 10px 10px; +} +div[splashScreenTemplateBodyImage] { + flex: 1; +} + +.template-image { + width: 100%; + height: auto; +} + +.template-card { + width: 100%; + cursor: pointer; + background: #fff; + border-radius: 2px; + box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); + transition: all 0.3s cubic-bezier(.25,.8,.25,1); +} + +.template-card:hover { + box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 5px 5px rgba(0,0,0,0.22); +} + +@media screen and (max-width: 670px) { + .splashScreenHeaderTitle { + visibility: hidden; + } + div[splashScreenTemplate] { + margin: 20px 20px; + } + div[splashScreenTemplateBody] { + flex-direction: column; + } +} + +/* div[templateCardContainer] { height:100%; @@ -10,13 +120,10 @@ div[templateCardContainer] flex-direction: row; flex-wrap:nowrap; align-items: center; - overflow-x:auto; } - div[templateCard] { - position:relative; flex: 0 1 25em; min-width: 20em; @@ -25,12 +132,10 @@ div[templateCard] padding: 0em 1em; margin : 0em 1em; box-sizing: border-box; - background-color:rgb(242,242,242); box-shadow: 0 4px 6px 0 rgba(0,0,0,0.12); } - div[templateCard]:hover { background-color:rgba(242,242,242,0.8); -} \ No newline at end of file +} */ diff --git a/src/ui/nehubaContainer/splashScreen/splashScreen.template.html b/src/ui/nehubaContainer/splashScreen/splashScreen.template.html index 5ccf9fcc70d27efb6d52b2f8da7dc415691fa8b2..a59505918f5c5c1b253d35af8e1bbc244e9a99fb 100644 --- a/src/ui/nehubaContainer/splashScreen/splashScreen.template.html +++ b/src/ui/nehubaContainer/splashScreen/splashScreen.template.html @@ -1,14 +1,48 @@ +<div splashScreenContainer> + <div splashScreenHeader> + <div class="splashScreenHeaderLogoContainer"><img class="splashScreenHeaderLogo " src="./res/image/HBP_Primary_RGB_WhiteText.png"> </div> + <span class="splashScreenHeaderTitle" media="screen and (min-width: 670px)">HBP Atlas Viewer</span> + <div class="spaceForFill"> + <signin-banner *ngIf="!isMobile"> + </signin-banner> + </div> + </div> + <div splashScreenTemplate> + <div *ngFor="let template of loadedTemplate$ | async | filterNull" splashScreenTemplateItem> + <div class="template-card" (click) = "selectTemplate(template)"> + + <div splashScreenTemplateHeader> + {{template.properties.name}} + </div> + <div splashScreenTemplateBody> + <div splashScreenTemplateBodyImage> + <img class="template-image" [src]="'./res/image/' + correctString(template.properties.name) + '.png'"> + </div> + <div splashScreenTemplateBodyDescription> + {{template.properties.description}} + </div> + </div> + + </div> + </div> + + </div> +</div> + + + +<!-- <div class = "container-fluid" splashScreenContainer> - <div - class = "row" + <div + class = "row" templateCardContainer> - + <div - *ngFor = "let template of loadedTemplate$ | async | filterNull" + *ngFor = "let template of loadedTemplate$ | async | filterNull" (click) = "selectTemplate(template)" templateCard hoverable> - + <h2>{{ template.properties.name }}</h2> <readmore-component> <small>{{ template.properties.description }}</small> @@ -25,4 +59,4 @@ </h1> </div> </div> -</div> \ No newline at end of file +</div> --> \ No newline at end of file diff --git a/src/ui/signinBanner/signinBanner.components.ts b/src/ui/signinBanner/signinBanner.components.ts index 83f06a09c7905823c4c1184959c0cf3b28a73104..80fc79fb55464aaabb80b0afdaf40b06e70f46a3 100644 --- a/src/ui/signinBanner/signinBanner.components.ts +++ b/src/ui/signinBanner/signinBanner.components.ts @@ -31,6 +31,7 @@ export class SigninBanner implements OnInit, OnDestroy{ public selectedParcellation$: Observable<any> public selectedRegions$: Observable<any[]> private selectedRegions: any[] = [] + selectedTemplate: any @Input() darktheme: boolean @ViewChild('publicationTemplate', {read:TemplateRef}) publicationTemplate: TemplateRef<any> @@ -78,6 +79,9 @@ export class SigninBanner implements OnInit, OnDestroy{ this.selectedRegions = regions }) ) + this.subscriptions.push( + this.selectedTemplate$.subscribe(template => this.selectedTemplate = template) + ) } ngOnDestroy(){ diff --git a/src/ui/signinBanner/signinBanner.style.css b/src/ui/signinBanner/signinBanner.style.css index 126c598d6d8544ae5e1727d105ac6e20dd089c26..1d53a9f509d6124afce0b454cc5826c211b4cfa6 100644 --- a/src/ui/signinBanner/signinBanner.style.css +++ b/src/ui/signinBanner/signinBanner.style.css @@ -46,12 +46,26 @@ dropdown-component .login-button-panel-mobile { order: -1; - align-self: flex-start; + align-self: flex-start; width: 100%; display: flex; justify-content: space-between; } +.login-button-panel-splash { + display: flex; + flex-direction: column; + justify-content: space-between; + margin-left: auto; + text-align: right +} +.login-button-splash > button { + color: #FFFFFF; + outline: none; + background-color: coral; + margin: 5px; +} + .login-button-mobile > button { outline: none; background-color: transparent; diff --git a/src/ui/signinBanner/signinBanner.template.html b/src/ui/signinBanner/signinBanner.template.html index 093a9e4417d1c942cd42755c3b524d4e40fd1a2a..d5991ef576160478525ef34583ca6ef697dae914 100644 --- a/src/ui/signinBanner/signinBanner.template.html +++ b/src/ui/signinBanner/signinBanner.template.html @@ -3,6 +3,7 @@ [ngClass]="{ 'flex-column w-100 align-items-stretch' : isMobile}" > <dropdown-component + *ngIf="selectedTemplate || isMobile" (itemSelected)="changeTemplate($event)" [activeDisplay]="displayActiveTemplate" [selectedItem]="selectedTemplate$ | async" @@ -40,7 +41,7 @@ <!-- help btn --> <div class="btnWrapper"> <div - *ngIf="!isMobile" + *ngIf="!isMobile && selectedTemplate" (click)="showHelp()" class="btn btn-outline-secondary btn-sm rounded-circle login-icon"> <i class="fas fa-question-circle"></i> @@ -52,7 +53,7 @@ <div class="btnWrapper"> <div - *ngIf="!isMobile" + *ngIf="!isMobile && selectedTemplate" (click)="showSignin()" class="btn btn-outline-secondary btn-sm rounded-circle login-icon"> <i @@ -97,4 +98,4 @@ </div> </ng-template> </div> -</ng-template> +</ng-template> \ No newline at end of file