diff --git a/.github/workflows/release-ci.yml b/.github/workflows/release-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..bdbaaec8eab1b2765bc7b8427518841597eaf93e --- /dev/null +++ b/.github/workflows/release-ci.yml @@ -0,0 +1,42 @@ +name: Release CI +on: + pull_request: + branches: + - master + +jobs: + check_version: + if: always() + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - run: | + MASTER_VERSION=$(git show origin/master:package.json | jq '.version') + THIS_VERSION=$(jq '.version' < package.json) + test "$MASTER_VERSION" == "$THIS_VERSION" && exit 1 || exit 0 + + check_release: + if: always() + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - run: | + VERSION_NUM=$(jq '.version' < package.json) + VERSION_NUM=${VERSION_NUM#\"} + VERSION_NUM=${VERSION_NUM%\"} + test -f docs/releases/v$VERSION_NUM.md && exit 0 || exit 1 + + release_linked_mkdocs: + if: always() + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - run: | + VERSION_NUM=$(jq '.version' < package.json) + VERSION_NUM=${VERSION_NUM#\"} + VERSION_NUM=${VERSION_NUM%\"} + echo "VERSION_NUM: $VERSION_NUM" + cat mkdocs.yml + GREP_VERSION_NUM=$(cat mkdocs.yml | grep $VERSION_NUM) + echo GREP_VERSION_NUM: $GREP_VERSION_NUM + test -z "$GREP_VERSION_NUM" && exit 1 || exit 0 \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index dc136836c17253be4056c83d497da3e3339fbc8c..e3766792780d1d42c25b17d98208b6193c286826 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,23 +1,26 @@ -name: '[release]' - -# on push to master, create release +name: Release on: - push: + push: branches: - - 'master' + - master jobs: check-version: + outputs: + package-version: ${{ steps.set-version.outputs.package-version-from-json }} runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v1 - - run: | + - name: Set version + id: set-version + run: | PACKAGEJSON_VER=v$(cat package.json | jq -r '.version') - echo 'PACKAGEJSON_VER='$PACKAGEJSON_VER >> $GITHUB_ENV - + echo "::set-output name=package-version-from-json::$PACKAGEJSON_VER" + create-release: + needs: check-version if: success() runs-on: ubuntu-latest steps: @@ -27,7 +30,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - tag_name: ${{ env.PACKAGEJSON_VER }} - release_name: Release ${{ env.PACKAGEJSON_VER }} + tag_name: ${{ needs.check-version.outputs.package-version }} + release_name: Release ${{ needs.check-version.outputs.package-version }} draft: false prerelease: false diff --git a/common/helpOnePager.md b/common/helpOnePager.md index 35b4ff7191af002402aa57c576dae3e2f2c14cb6..f23b9a498e529d2cfc65b5856c0b313142f29448 100644 --- a/common/helpOnePager.md +++ b/common/helpOnePager.md @@ -10,7 +10,7 @@ | Zoom | `[hover]` on any slice views, `[click]` magnifier | | Next slice | `<ctrl>` + `[mousewheel]` | | Next 10 slice | `<ctrl>` + `<shift>` + `[mousewheel]` | -| Toggle delineation | | +| Toggle delineation | `[q]` | --- diff --git a/deploy/atlas/index.js b/deploy/atlas/index.js index eb96d883cff1593df8dfd59cdeeae8b235567342..9bf745f2e071849efba3128ebb53f329bf44f27f 100644 --- a/deploy/atlas/index.js +++ b/deploy/atlas/index.js @@ -5,11 +5,12 @@ const path = require('path') const { detEncoding } = require('nomiseco') const { getAllAtlases, getAtlasById, isReady } = require('./query') const HOSTNAME = process.env.HOSTNAME || 'http://localhost:3000' - +const HOST_PATHNAME = process.env.HOST_PATHNAME || '' const { getTemplate } = require('../templates/query') const { getHandleErrorFn } = require('../util/streamHandleError') -const getPreviewFn = ({ res, lastpart }) => HOSTNAME.replace(/\/$/, '') + '/' + +const getPreviewFn = ({ res, lastpart }) => HOSTNAME.replace(/\/$/, '') + + HOST_PATHNAME.replace(/\/$/, '') + '/' + (res.locals.routePathname ? url.resolve(`${res.locals.routePathname}/`, lastpart) : lastpart) diff --git a/deploy/datasets/query.js b/deploy/datasets/query.js index 47eef557694dbf01971ecd09d2bcf9a6eff81e60..1b4ce0d4c5d13479e6f59a05df634fa741b403d8 100644 --- a/deploy/datasets/query.js +++ b/deploy/datasets/query.js @@ -113,8 +113,11 @@ const getPublicDs = async () => { throw `cached Data not yet resolved, neither is get public ds defined` } - -const getDs = ({ user }) => (user +/** + * force get only public ds + * getting individual ds is too slow + */ +const getDs = ({ user }) => (false && user ? fetchDatasetFromKg({ user }).then(({ results }) => results) : getPublicDs() ).then(async datasets => { diff --git a/deploy/datasets/util.js b/deploy/datasets/util.js index c5487ed6dfd5458a46d28dd32845b87b6d68becf..229b03891d1c0b498d734d017655d6a7127ad892 100644 --- a/deploy/datasets/util.js +++ b/deploy/datasets/util.js @@ -21,8 +21,9 @@ const getUserKGRequestParam = async ({ user }) => { let publicAccessToken /** * n.b. ACCESS_TOKEN env var is usually only set during dev + * user.type any other than 'hbp-oidc' (v1 of oidc) will result in timeout/error */ - const accessToken = (user && user.tokenset && user.tokenset.access_token) || process.env.ACCESS_TOKEN + const accessToken = (user && user.type === 'hbp-oidc' && user.tokenset && user.tokenset.access_token) || process.env.ACCESS_TOKEN const releasedOnly = !accessToken if (!accessToken && getPublicAccessToken) { publicAccessToken = await getPublicAccessToken() diff --git a/docs/releases/v2.3.0.md b/docs/releases/v2.3.0.md index bd3c04a72e17891577f1027cb2da88d59d969b3d..2ffdd59932e3d4b2a5c66942f089ca30fa56717e 100644 --- a/docs/releases/v2.3.0.md +++ b/docs/releases/v2.3.0.md @@ -1,5 +1,7 @@ # v2.3.0 +11 Dec 2020 + ## New features - update dataset preview functionality, allow the previewing of png @@ -16,7 +18,7 @@ - reworked regional dataset previews (iEEG & receptor density) - **experimental** : previewing of curated regional features: iEEG coordinates -## Bugfixes: +## Bugfixes - dataset list view explicitly show loading status - fixed a few typos diff --git a/docs/releases/v2.3.1.md b/docs/releases/v2.3.1.md new file mode 100644 index 0000000000000000000000000000000000000000..5517468d33961969d036e9c12430c69785a72975 --- /dev/null +++ b/docs/releases/v2.3.1.md @@ -0,0 +1,7 @@ +# v2.3.1 + +## Bugfixes + +- fixes iEEG panel sometimes not loading spatial data (#816 #744) +- fixes fetching of non-existent data when in big brain reference space (#817) +- restore CI for staging/release \ No newline at end of file diff --git a/docs/releases/v2.3.2.md b/docs/releases/v2.3.2.md new file mode 100644 index 0000000000000000000000000000000000000000..0280a2ddffcd34b46c6c14198f724f365477a734 --- /dev/null +++ b/docs/releases/v2.3.2.md @@ -0,0 +1,5 @@ +# v2.3.2 + +## Bugfixes + +- change URL source for connectivity browser. diff --git a/docs/releases/v2.3.3.md b/docs/releases/v2.3.3.md new file mode 100644 index 0000000000000000000000000000000000000000..daf21d1b8a1090df33fa4ff89351285bf271ea1e --- /dev/null +++ b/docs/releases/v2.3.3.md @@ -0,0 +1,6 @@ +# v2.3.3 + +## Bugfixes + +- fix backwards compatibility with some URLs +- fix bug where fetching of regional features does not complete for logged in users (#826). (the viewer will only fetch released datasets) diff --git a/docs/releases/v2.3.4.md b/docs/releases/v2.3.4.md new file mode 100644 index 0000000000000000000000000000000000000000..7874ad49313a9e874ae5b80787a9e25c10ef0a35 --- /dev/null +++ b/docs/releases/v2.3.4.md @@ -0,0 +1,5 @@ +# v2.3.4 + +## Bugfixes + +- fix connectivity dataset external link diff --git a/docs/releases/v2.3.5.md b/docs/releases/v2.3.5.md new file mode 100644 index 0000000000000000000000000000000000000000..b066cc07a9f4cde4b1df3d98c236967287ab9d16 --- /dev/null +++ b/docs/releases/v2.3.5.md @@ -0,0 +1,6 @@ +# v2.3.5 + +## Under the hood stuff + +- Temporarily disable Colin 27 template. +- Update to JulichBrain v2.5 diff --git a/docs/releases/v2.3.6.md b/docs/releases/v2.3.6.md new file mode 100644 index 0000000000000000000000000000000000000000..4249e5ba896565f7ab2c6f3bac6e965ea3629201 --- /dev/null +++ b/docs/releases/v2.3.6.md @@ -0,0 +1,5 @@ +# v2.3.6 + +## Bugfixes + +- fix backwards compatibility with some URLs \ No newline at end of file diff --git a/docs/releases/v2.3.7.md b/docs/releases/v2.3.7.md new file mode 100644 index 0000000000000000000000000000000000000000..ad4b523b115c3ff80f37fe14df676e899cc13933 --- /dev/null +++ b/docs/releases/v2.3.7.md @@ -0,0 +1,5 @@ +# v2.3.7 + +## Under the hood stuff + +- Enable CI for release workflow. diff --git a/docs/releases/v2.3.8.md b/docs/releases/v2.3.8.md new file mode 100644 index 0000000000000000000000000000000000000000..9a10601b60180d727fc0e1b0fa9e91314df882c4 --- /dev/null +++ b/docs/releases/v2.3.8.md @@ -0,0 +1,5 @@ +# v2.3.8 + +## New Features + +- Adding control allowing delineation control \ No newline at end of file diff --git a/docs/releases/v2.3.9.md b/docs/releases/v2.3.9.md new file mode 100644 index 0000000000000000000000000000000000000000..510ef7cf02181199f427e52b6c65a1d425dbab4d --- /dev/null +++ b/docs/releases/v2.3.9.md @@ -0,0 +1,5 @@ +# v2.3.9 + +## Bugfixes + +- Explore in other templates sometimes bugs out. \ No newline at end of file diff --git a/docs/releases/v2.4.0.md b/docs/releases/v2.4.0.md index d10152cc2e9b0d91fb59a774864db361172c286c..8bae0f274f49d9690cc13820501a925945794a43 100644 --- a/docs/releases/v2.4.0.md +++ b/docs/releases/v2.4.0.md @@ -12,6 +12,7 @@ - only top level mesh(es) will be loaded (#890). This should drastically improve atlases with hierarchical surface meshes (e.g. Allen CCF v3). - Preliminary support for displaying of SWC (#907) - Preliminary support for freesurfer (#900) +- Allow for finer controls over meshes display (#883, #470) ## Under the hood stuff diff --git a/e2e/src/advanced/urlParsing.prod.e2e-spec.js b/e2e/src/advanced/urlParsing.prod.e2e-spec.js index 832da7bc2f04294e37b033bef18d74b609efec10..7e239a89d51b86fd02e0fd8e31466e1af18482e5 100644 --- a/e2e/src/advanced/urlParsing.prod.e2e-spec.js +++ b/e2e/src/advanced/urlParsing.prod.e2e-spec.js @@ -70,8 +70,23 @@ describe('> url parsing', () => { expect(red).toEqual(blue) }) + it('> [bkwards compat] if ill defined labelIndex for regionsSelected are defined, should handle gracefully', async () => { + const url = '/?parcellationSelected=JuBrain+Cytoarchitectonic+Atlas&templateSelected=MNI+Colin+27&navigation=0_0_0_1__-0.2753947079181671_0.6631333827972412_-0.6360703706741333_0.2825356423854828__3000000__-17800000_-6700000_-7500000__200000®ionsSelected=142&niftiLayers=https%3A%2F%2Fneuroglancer.humanbrainproject.org%2Fprecomputed%2FJuBrain%2Fv2.2c%2FPMaps%2FBforebrain_4.nii' + await iavPage.goto(url) + await iavPage.clearAlerts() + await iavPage.wait(5000) + await iavPage.waitForAsync() + const log = await iavPage.getLog() + const filteredLog = log.filter(({ message }) => !/Access-Control-Allow-Origin/.test(message)) + + // expecting some errors in the console. In catastrophic event, there will most likely be looped errors (on each render cycle) + expect( + filteredLog.length + ).toBeLessThan(50) + }) + it('> if niftiLayers are defined, parcellation layer should be hidden', async () => { - const url = `/?templateSelected=MNI+152+ICBM+2009c+Nonlinear+Asymmetric&parcellationSelected=JuBrain+Cytoarchitectonic+Atlas&niftiLayers=https%3A%2F%2Fneuroglancer.humanbrainproject.eu%2Fprecomputed%2FJuBrain%2F17%2Ficbm152casym%2Fpmaps%2FVisual_hOc1_r_N10_nlin2MNI152ASYM2009C_2.4_publicP_a48ca5d938781ebaf1eaa25f59df74d0.nii.gz` + const url = `/?parcellationSelected=JuBrain+Cytoarchitectonic+Atlas&templateSelected=MNI+Colin+27&navigation=0_0_0_1__-0.2753947079181671_0.6631333827972412_-0.6360703706741333_0.2825356423854828__3000000__-17800000_-6700000_-7500000__200000®ionsSelected=142&niftiLayers=https%3A%2F%2Fneuroglancer.humanbrainproject.org%2Fprecomputed%2FJuBrain%2Fv2.2c%2FPMaps%2FBforebrain_4.nii` await iavPage.goto(url) await iavPage.clearAlerts() @@ -121,38 +136,4 @@ describe('> url parsing', () => { )) }) - /** - * encoding of dataset previews in url is current not enabled - */ - it('> if datasetPreview is set, should load with previews', - // async () => { - // const url = `http://localhost:3000/?templateSelected=MNI+152+ICBM+2009c+Nonlinear+Asymmetric&parcellationSelected=JuBrain+Cytoarchitectonic+Atlas&previewingDatasetFiles=%5B%7B%22datasetId%22%3A%22e715e1f7-2079-45c4-a67f-f76b102acfce%22%2C%22filename%22%3A%22fingerprint%22%7D%2C%7B%22datasetId%22%3A%22e715e1f7-2079-45c4-a67f-f76b102acfce%22%2C%22filename%22%3A%22GABA%E1%B4%80%28BZ%29%2Fautoradiography%22%7D%2C%7B%22datasetId%22%3A%22e715e1f7-2079-45c4-a67f-f76b102acfce%22%2C%22filename%22%3A%22GABA%E1%B4%80%28BZ%29%2Fprofile%22%7D%5D` - // const datasetPreview = [ - // { - // "datasetId": "e715e1f7-2079-45c4-a67f-f76b102acfce", - // "filename": "fingerprint" - // }, - // { - // "datasetId": "e715e1f7-2079-45c4-a67f-f76b102acfce", - // "filename": "GABAá´€(BZ)/autoradiography" - // }, - // { - // "datasetId": "e715e1f7-2079-45c4-a67f-f76b102acfce", - // "filename": "GABAá´€(BZ)/profile" - // } - // ] - - // const searchParam = new URLSearchParams() - - // searchParam.set('templateSelected', 'MNI 152 ICBM 2009c Nonlinear Asymmetric') - // searchParam.set('parcellationSelected', 'JuBrain Cytoarchitectonic Atlas') - // searchParam.set('previewingDatasetFiles', JSON.stringify(datasetPreview)) - // await iavPage.goto(`/?${searchParam.toString()}`) - - // const visibleArr = await iavPage.areVisible(`[aria-label="${ARIA_LABELS.DATASET_FILE_PREVIEW}"]`) - // expect(visibleArr.length).toEqual(3) - // expect(visibleArr).toEqual([true, true, true]) - // } - - ) }) diff --git a/e2e/util/selenium/base.js b/e2e/util/selenium/base.js index e16f7465664396a0cad688e34e81e7a197f8ccdd..88312daf3cd2eadb52f2b47a390e9d1e6d33c89b 100644 --- a/e2e/util/selenium/base.js +++ b/e2e/util/selenium/base.js @@ -99,6 +99,11 @@ class WdBase{ return result } + async getLog() { + const browserLog = await this._browser.manage().logs().get('browser') + return browserLog + } + async getRgbAt({ position } = {}, cssSelector = null){ if (!position) throw new Error(`position is required for getRgbAt`) const { x, y } = verifyPosition(position) diff --git a/mkdocs.yml b/mkdocs.yml index 02d1d42676e5cae500b176d9800c6c1eacef7574..cf071e557a17313d0771db193adeebe6258c0aa7 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -41,6 +41,15 @@ pages: - Display non-atlas volumes: 'advanced/otherVolumes.md' - Release notes: - v2.4.0: 'releases/v2.4.0.md' + - v2.3.9: 'releases/v2.3.9.md' + - v2.3.8: 'releases/v2.3.8.md' + - v2.3.7: 'releases/v2.3.7.md' + - v2.3.6: 'releases/v2.3.6.md' + - v2.3.5: 'releases/v2.3.5.md' + - v2.3.4: 'releases/v2.3.4.md' + - v2.3.3: 'releases/v2.3.3.md' + - v2.3.2: 'releases/v2.3.2.md' + - v2.3.1: 'releases/v2.3.1.md' - v2.3.0: 'releases/v2.3.0.md' - v2.2.7: 'releases/v2.2.7.md' - v2.2.6: 'releases/v2.2.6.md' @@ -61,4 +70,4 @@ pages: - v0.2.9: 'releases/v0.2.9.md' - v0.2.0: 'releases/v0.2.0.md' - v0.1.0: 'releases/v0.1.0.md' - - legacy: 'releases/legacy.md' \ No newline at end of file + - legacy: 'releases/legacy.md' diff --git a/package.json b/package.json index bd788abf8094f1783038d06b4e2683c79ab96ac9..94e9b5e53d806f06f32a25921c0f1f2120283280 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,7 @@ "@ngrx/effects": "^9.1.1", "@ngrx/store": "^9.1.1", "@types/node": "12.12.39", - "export-nehuba": "0.0.7", + "export-nehuba": "0.0.8", "hbp-connectivity-component": "^0.3.18", "zone.js": "^0.10.2" } diff --git a/src/atlasComponents/connectivity/connectivityBrowser/connectivityBrowser.component.spec.ts b/src/atlasComponents/connectivity/connectivityBrowser/connectivityBrowser.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..5c46a0f721a4991140e75f3bd41b4fcdc48dbeb4 --- /dev/null +++ b/src/atlasComponents/connectivity/connectivityBrowser/connectivityBrowser.component.spec.ts @@ -0,0 +1,108 @@ +import {ConnectivityBrowserComponent} from "./connectivityBrowser.component"; +import {async, ComponentFixture, TestBed} from "@angular/core/testing"; +import {Action} from "@ngrx/store"; +import {HttpClientModule} from "@angular/common/http"; +import {CUSTOM_ELEMENTS_SCHEMA, Directive, Input} from "@angular/core"; +import {provideMockActions} from "@ngrx/effects/testing"; +import {MockStore, provideMockStore} from "@ngrx/store/testing"; +import {Observable, of} from "rxjs"; +import { viewerStateAllRegionsFlattenedRegionSelector, viewerStateOverwrittenColorMapSelector } from "src/services/state/viewerState/selectors"; +import { ngViewerSelectorClearViewEntries } from "src/services/state/ngViewerState.store.helper"; + +/** + * injecting databrowser module is bad idea + * since it relies on its own selectors + * since the only reason why data browser is imported is to use show dataset dialogue + * just use a dummy directive + */ + +@Directive({ + selector: '[iav-dataset-show-dataset-dialog]' +}) + +class DummyDirective{ + @Input('iav-dataset-show-dataset-dialog-name') + name: string + @Input('iav-dataset-show-dataset-dialog-description') + description: string + @Input('iav-dataset-show-dataset-dialog-kgid') + kgId: string + @Input('iav-dataset-show-dataset-dialog-kgschema') + kgSchema: string +} + +describe('ConnectivityComponent', () => { + + let component: ConnectivityBrowserComponent; + let fixture: ComponentFixture<ConnectivityBrowserComponent>; + const actions$: Observable<Action> = of({type: 'TEST'}) + + let datasetList = [ + { + id: 'id1', + name: 'n1', + description: 'd1', + kgId: 'kgId1', + kgschema: 'kgschema1' + }, { + id: 'id2', + name: 'n2', + description: 'd2', + kgId: 'kgId2', + kgschema: 'kgschema2' + } + ] + + beforeEach(async (() => { + TestBed.configureTestingModule({ + imports: [ + HttpClientModule, + ], + providers: [ + provideMockActions(() => actions$), + provideMockStore() + ], + declarations: [ + ConnectivityBrowserComponent, + DummyDirective, + ], + schemas: [ + CUSTOM_ELEMENTS_SCHEMA, + ], + }).compileComponents() + + })); + + beforeEach(() => { + const mockStore = TestBed.inject(MockStore) + mockStore.overrideSelector(viewerStateAllRegionsFlattenedRegionSelector, []) + mockStore.overrideSelector(viewerStateOverwrittenColorMapSelector, null) + mockStore.overrideSelector(ngViewerSelectorClearViewEntries, []) + }) + + it('> component can be created', async () => { + fixture = TestBed.createComponent(ConnectivityBrowserComponent) + component = fixture.componentInstance + expect(component).toBeTruthy() + }) + + it('> change dataset changes description, kgId and kgschema', () => { + fixture = TestBed.createComponent(ConnectivityBrowserComponent) + component = fixture.componentInstance + + component.datasetList = datasetList + + component.changeDataset({value: 'n1'}) + + expect(component.selectedDatasetDescription).toEqual('d1') + expect(component.selectedDatasetKgId).toEqual('kgId1') + expect(component.selectedDatasetKgSchema).toEqual('kgschema1') + + component.changeDataset({value: 'n2'}) + + expect(component.selectedDatasetDescription).toEqual('d2') + expect(component.selectedDatasetKgId).toEqual('kgId2') + expect(component.selectedDatasetKgSchema).toEqual('kgschema2') + }) + +}); \ No newline at end of file diff --git a/src/atlasComponents/connectivity/connectivityBrowser/connectivityBrowser.component.ts b/src/atlasComponents/connectivity/connectivityBrowser/connectivityBrowser.component.ts index d9764a702610d555906f45360e715f017849543b..7be783d314f81b62d69045d3cdc75538205acc30 100644 --- a/src/atlasComponents/connectivity/connectivityBrowser/connectivityBrowser.component.ts +++ b/src/atlasComponents/connectivity/connectivityBrowser/connectivityBrowser.component.ts @@ -12,15 +12,9 @@ import { import {select, Store} from "@ngrx/store"; import {fromEvent, Observable, Subscription, Subject, combineLatest} from "rxjs"; import {distinctUntilChanged, filter, map} from "rxjs/operators"; -import { - CLEAR_CONNECTIVITY_REGION, - SELECT_REGIONS, - SET_OVERWRITTEN_COLOR_MAP -} from "src/services/state/viewerState.store"; -import {safeFilter} from "src/services/stateStore.service"; -import {viewerStateNavigateToRegion} from "src/services/state/viewerState.store.helper"; -import {ngViewerActionClearView} from "src/services/state/ngViewerState/actions"; -import {ngViewerSelectorClearViewEntries} from "src/services/state/ngViewerState/selectors"; + +import { viewerStateNavigateToRegion, viewerStateSetSelectedRegions } from "src/services/state/viewerState.store.helper"; +import { ngViewerSelectorClearViewEntries, ngViewerActionClearView } from "src/services/state/ngViewerState.store.helper"; import { viewerStateAllRegionsFlattenedRegionSelector, viewerStateOverwrittenColorMapSelector @@ -44,7 +38,7 @@ export class ConnectivityBrowserComponent implements OnInit, AfterViewInit, OnDe */ private _isFirstUpdate = true - public connectivityUrl = 'https://connectivity-query-v1-1-connectivity.apps-dev.hbp.eu/v1.1/studies' + public connectivityUrl = 'https://connectivity-query-v1-1-connectivity.apps.hbp.eu/v1.1/studies' private accordionIsExpanded = false @@ -66,7 +60,7 @@ export class ConnectivityBrowserComponent implements OnInit, AfterViewInit, OnDe }) ) this.store$.dispatch({ - type: SET_OVERWRITTEN_COLOR_MAP, + type: 'SET_OVERWRITTEN_COLOR_MAP', payload: flag? CONNECTIVITY_NAME_PLATE : false, }) } @@ -88,7 +82,7 @@ export class ConnectivityBrowserComponent implements OnInit, AfterViewInit, OnDe if (!val) { this.store$.dispatch({ - type: SET_OVERWRITTEN_COLOR_MAP, + type: 'SET_OVERWRITTEN_COLOR_MAP', payload: false, }) return @@ -115,6 +109,8 @@ export class ConnectivityBrowserComponent implements OnInit, AfterViewInit, OnDe public datasetList: any[] = [] public selectedDataset: any public selectedDatasetDescription: string = '' + public selectedDatasetKgId: string = '' + public selectedDatasetKgSchema: string = '' public connectedAreas = [] private selectedParcellationFlatRegions$ = this.store$.pipe( @@ -139,9 +135,7 @@ export class ConnectivityBrowserComponent implements OnInit, AfterViewInit, OnDe ) { this.overwrittenColorMap$ = this.store$.pipe( - select('viewerState'), - safeFilter('overwrittenColorMap'), - map(state => state.overwrittenColorMap), + select(viewerStateOverwrittenColorMapSelector), distinctUntilChanged() ) } @@ -239,19 +233,14 @@ export class ConnectivityBrowserComponent implements OnInit, AfterViewInit, OnDe if (flag) { this.addNewColorMap() this.store$.dispatch({ - type: SET_OVERWRITTEN_COLOR_MAP, + type: 'SET_OVERWRITTEN_COLOR_MAP', payload: 'connectivity', }) } else { this.restoreDefaultColormap() - this.store$.dispatch({type: SET_OVERWRITTEN_COLOR_MAP, payload: null}) + this.store$.dispatch({type: 'SET_OVERWRITTEN_COLOR_MAP', payload: null}) - /** - * TODO - * may no longer be necessary - */ - this.store$.dispatch({type: CLEAR_CONNECTIVITY_REGION}) } } }) @@ -304,7 +293,10 @@ export class ConnectivityBrowserComponent implements OnInit, AfterViewInit, OnDe changeDataset(event = null) { if (event) { this.selectedDataset = event.value - this.selectedDatasetDescription = this.datasetList.find(d => d.name === this.selectedDataset).description + const foundDataset = this.datasetList.find(d => d.name === this.selectedDataset) + this.selectedDatasetDescription = foundDataset?.description + this.selectedDatasetKgId = foundDataset?.kgId || null + this.selectedDatasetKgSchema = foundDataset?.kgschema || null } if (this.datasetList.length && this.selectedDataset) { const selectedDatasetId = this.datasetList.find(d => d.name === this.selectedDataset).id @@ -325,10 +317,11 @@ export class ConnectivityBrowserComponent implements OnInit, AfterViewInit, OnDe } selectRegion(region) { - this.store$.dispatch({ - type: SELECT_REGIONS, - selectRegions: [region], - }) + this.store$.dispatch( + viewerStateSetSelectedRegions({ + selectRegions: [ region ] + }) + ) } getRegionWithName(region) { @@ -407,7 +400,7 @@ export class ConnectivityBrowserComponent implements OnInit, AfterViewInit, OnDe } public exportFullConnectivity() { - this.fullConnectivityGridElement.nativeElement['downloadCSV']() + this.fullConnectivityGridElement?.nativeElement['downloadCSV']() } } diff --git a/src/atlasComponents/connectivity/connectivityBrowser/connectivityBrowser.template.html b/src/atlasComponents/connectivity/connectivityBrowser/connectivityBrowser.template.html index fa47192a66062082a8d29c557871a35bb6726a49..178cab32f593d5eb1690fcd46c89ab1cb44b4ea5 100644 --- a/src/atlasComponents/connectivity/connectivityBrowser/connectivityBrowser.template.html +++ b/src/atlasComponents/connectivity/connectivityBrowser/connectivityBrowser.template.html @@ -39,7 +39,10 @@ <button class="flex-grow-0 flex-shrink-0" mat-icon-button iav-dataset-show-dataset-dialog [iav-dataset-show-dataset-dialog-name]="selectedDataset" - [iav-dataset-show-dataset-dialog-description]="selectedDatasetDescription"> + [iav-dataset-show-dataset-dialog-description]="selectedDatasetDescription" + [iav-dataset-show-dataset-dialog-kgid]="selectedDatasetKgId? selectedDatasetKgId : null" + [iav-dataset-show-dataset-dialog-kgschema]="selectedDatasetKgSchema? selectedDatasetKgSchema : null" + > <i class="fas fa-info"></i> </button> <button class="flex-grow-0 flex-shrink-0" diff --git a/src/atlasComponents/databrowserModule/singleDataset/sideNavView/sDsSideNavView.template.html b/src/atlasComponents/databrowserModule/singleDataset/sideNavView/sDsSideNavView.template.html index 78daaefedf86e26108902a5d0004084cfc6e3245..455219a1825c31e207e94e6ea46a36774c6871ad 100644 --- a/src/atlasComponents/databrowserModule/singleDataset/sideNavView/sDsSideNavView.template.html +++ b/src/atlasComponents/databrowserModule/singleDataset/sideNavView/sDsSideNavView.template.html @@ -135,7 +135,8 @@ <ng-template [ngIf]="matExpansionPanel.expanded"> <feature-container [feature]="feature" - [region]="region$ | async"> + [region]="region$ | async" + (viewChanged)="detectChange()"> </feature-container> </ng-template> </mat-expansion-panel> diff --git a/src/atlasComponents/parcellationRegion/region.base.spec.ts b/src/atlasComponents/parcellationRegion/region.base.spec.ts index 93899584dd99b1fbc99d994e0432e280263087bd..712e323298045aa049c7e8e2961fbb58480f9be2 100644 --- a/src/atlasComponents/parcellationRegion/region.base.spec.ts +++ b/src/atlasComponents/parcellationRegion/region.base.spec.ts @@ -1,5 +1,6 @@ import { TestBed } from '@angular/core/testing' import { MockStore, provideMockStore } from '@ngrx/store/testing' +import { viewerStateNewViewer } from 'src/services/state/viewerState/actions' import { RegionBase, regionInOtherTemplateSelector, getRegionParentParcRefSpace } from './region.base' const util = require('common/util') @@ -329,16 +330,22 @@ const getRegionInOtherTemplateSelectorBundle = (version: EnumParcRegVersion) => describe('> region.base.ts', () => { describe('> regionInOtherTemplateSelector', () => { + // TODO + it('> only selects region in the template specified by selected atlas') + for (const enumKey of Object.keys(EnumParcRegVersion)) { describe(`> selector version for ${enumKey}`, () => { const { mockFetchedTemplates, mr0, mt2, mt0, mp0, mt1, mp1h, mr0lh, mt3, mr0rh } = getRegionInOtherTemplateSelectorBundle(enumKey as EnumParcRegVersion) + let selectedAtlas = { + templateSpaces: mockFetchedTemplates + } describe('> no hemisphere selected, simulates big brain cyto map', () => { let result: any[] beforeAll(() => { - result = regionInOtherTemplateSelector.projector(mockFetchedTemplates, mt0, { region: mr0 }) + result = regionInOtherTemplateSelector.projector(selectedAtlas, mockFetchedTemplates, mt0, { region: mr0 }) }) it('> length checks out', () => { @@ -410,7 +417,7 @@ describe('> region.base.ts', () => { describe('> hemisphere data selected (left hemisphere), simulates julich-brain in mni152', () => { let result beforeAll(() => { - result = regionInOtherTemplateSelector.projector(mockFetchedTemplates, mt2, { region: mr0lh }) + result = regionInOtherTemplateSelector.projector(selectedAtlas, mockFetchedTemplates, mt2, { region: mr0lh }) }) it('> length checks out', () => { @@ -444,19 +451,20 @@ describe('> region.base.ts', () => { }) describe('> RegionBase', () => { + let regionBase: RegionBase + let mockStore: MockStore beforeEach(() => { TestBed.configureTestingModule({ providers: [ provideMockStore() ] }) + mockStore = TestBed.inject(MockStore) + mockStore.overrideSelector(regionInOtherTemplateSelector, []) + mockStore.overrideSelector(getRegionParentParcRefSpace, { template: null, parcellation: null }) }) describe('> position', () => { - let regionBase: RegionBase beforeEach(() => { - const mockStore = TestBed.inject(MockStore) - mockStore.overrideSelector(regionInOtherTemplateSelector, []) - mockStore.overrideSelector(getRegionParentParcRefSpace, { template: null, parcellation: null }) regionBase = new RegionBase(mockStore) }) it('> does not populate if position property is absent', () => { @@ -609,7 +617,85 @@ describe('> region.base.ts', () => { regionBase.rgbString ).toEqual(`rgb(255,200,200)`) }) + }) + }) + describe('> changeView', () => { + const fakeTmpl = { + name: 'fakeTmpl' + } + const fakeParc = { + name: 'fakeParc' + } + beforeEach(() => { + regionBase = new RegionBase(mockStore) + }) + + describe('> if sameRegion has position attribute', () => { + let dispatchSpy: jasmine.Spy + + beforeEach(() => { + dispatchSpy = spyOn(mockStore, 'dispatch') + }) + afterEach(() => { + dispatchSpy.calls.reset() + }) + it('> malformed position is not an array > do not pass position', () => { + regionBase.changeView({ + template: fakeTmpl, + parcellation: fakeParc, + region: { + position: 'hello wolrd' + } + }) + + expect(dispatchSpy).toHaveBeenCalledWith( + viewerStateNewViewer({ + selectTemplate: fakeTmpl, + selectParcellation: fakeParc, + navigation: {} + }) + ) + }) + + it('> malformed position is an array of incorrect size > do not pass position', () => { + + regionBase.changeView({ + template: fakeTmpl, + parcellation: fakeParc, + region: { + position: [] + } + }) + + expect(dispatchSpy).toHaveBeenCalledWith( + viewerStateNewViewer({ + selectTemplate: fakeTmpl, + selectParcellation: fakeParc, + navigation: {} + }) + ) + }) + + it('> correct position > pass position', () => { + regionBase.changeView({ + template: fakeTmpl, + parcellation: fakeParc, + region: { + position: [1,2,3] + } + }) + + expect(dispatchSpy).toHaveBeenCalledWith( + viewerStateNewViewer({ + selectTemplate: fakeTmpl, + selectParcellation: fakeParc, + navigation: { + position: [1,2,3] + } + }) + ) + }) }) }) }) diff --git a/src/atlasComponents/parcellationRegion/region.base.ts b/src/atlasComponents/parcellationRegion/region.base.ts index 68b83999af0e147d48eaf7fc7a2bab91e13c67db..33f84531de4c0bcc599b53542d8c5209ccd9f8e7 100644 --- a/src/atlasComponents/parcellationRegion/region.base.ts +++ b/src/atlasComponents/parcellationRegion/region.base.ts @@ -173,6 +173,9 @@ export class RegionBase { region } = sameRegion const { position } = region + const navigation = Array.isArray(position) && position.length === 3 + ? { position } + : { } this.closeRegionMenu.emit() /** @@ -182,9 +185,7 @@ export class RegionBase { this.store$.dispatch(viewerStateNewViewer ({ selectTemplate: template, selectParcellation: parcellation, - navigation: { - position - }, + navigation, })) } @@ -261,9 +262,11 @@ export class RenderViewOriginDatasetLabelPipe implements PipeTransform{ } export const regionInOtherTemplateSelector = createSelector( + viewerStateGetSelectedAtlas, viewerStateFetchedTemplatesSelector, viewerStateSelectedTemplateSelector, - (fetchedTemplates, templateSelected, prop) => { + (atlas, fetchedTemplates, templateSelected, prop) => { + const atlasTemplateSpacesIds = atlas.templateSpaces.map(({ ['@id']: id, fullId }) => id || fullId) const { region: regionOfInterest } = prop const returnArr = [] @@ -272,7 +275,13 @@ export const regionInOtherTemplateSelector = createSelector( const regionOfInterestId = getIdFromFullId(regionOfInterest.fullId) if (!templateSelected) return [] const selectedTemplateId = getIdFromFullId(templateSelected.fullId) - const otherTemplates = fetchedTemplates.filter(({ fullId }) => getIdFromFullId(fullId) !== selectedTemplateId) + + // need to ensure that the templates are defined in atlas definition + // atlas is the single source of truth + + const otherTemplates = fetchedTemplates + .filter(({ fullId }) => getIdFromFullId(fullId) !== selectedTemplateId) + .filter(({ ['@id']: id, fullId }) => atlasTemplateSpacesIds.includes(id || fullId)) for (const template of otherTemplates) { for (const parcellation of template.parcellations) { const flattenedRegions = flattenRegions(parcellation.regions) diff --git a/src/atlasComponents/regionalFeatures/featureContainer/featureContainer.component.spec.ts b/src/atlasComponents/regionalFeatures/featureContainer/featureContainer.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..627b097c977eb8fbef6171fb205a0b6f690abd6e --- /dev/null +++ b/src/atlasComponents/regionalFeatures/featureContainer/featureContainer.component.spec.ts @@ -0,0 +1,169 @@ +import { CommonModule } from "@angular/common" +import { ChangeDetectorRef, Component, ComponentRef, EventEmitter, NgModule } from "@angular/core" +import { async, TestBed } from "@angular/core/testing" +import { By } from "@angular/platform-browser" +import { RegionalFeaturesService } from "../regionalFeature.service" +import { ISingleFeature } from "../singleFeatures/interfaces" +import { FeatureContainer } from "./featureContainer.component" + +const dummyCmpType = 'dummyType' + +@Component({ + template: `{{ text }}` +}) + +class DummyComponent implements ISingleFeature{ + text = 'hello world' + feature: any + region: any + viewChanged = new EventEmitter<boolean>() +} + +@Component({ + template: '' +}) + +class HostCmp{ + public feature: any + public region: any + + constructor(public cdr: ChangeDetectorRef){ + + } + + detectChange(){ + this.cdr.detectChanges() + } +} + +const serviceStub = { + mapFeatToCmp: new Map([ + [dummyCmpType, DummyComponent] + ]) +} + +@NgModule({ + declarations: [ + FeatureContainer, + DummyComponent, + ], + entryComponents: [ + DummyComponent + ], + providers: [ + { + provide: RegionalFeaturesService, + useValue: serviceStub + } + ], + exports: [ + FeatureContainer, + DummyComponent, + ] +}) + +class DummyModule{} + +describe('> featureContainer.component.ts', () => { + describe('> FeatureContainer', () => { + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + CommonModule, + DummyModule, + ], + declarations: [ + HostCmp, + ], + }).overrideComponent(HostCmp, { + set: { + template: ` + <feature-container + [feature]="feature" + [region]="region" + (viewChanged)="detectChange()"> + </feature-container>` + } + }).compileComponents() + + })) + + it('> can be created', () => { + const fixture = TestBed.createComponent(HostCmp) + expect(fixture).toBeTruthy() + const featContainer = fixture.debugElement.query(By.directive(FeatureContainer)) + expect(featContainer).toBeTruthy() + }) + + describe('> if inputs change', () => { + it('> if input changed, but feature is not one of them, map.get will not be called', () => { + const fixture = TestBed.createComponent(HostCmp) + // const featContainer = fixture.debugElement.query(By.directive(FeatureContainer)) + spyOn(serviceStub.mapFeatToCmp, 'get').and.callThrough() + fixture.componentInstance.region = { + name: 'tesla' + } + fixture.detectChanges() + expect(serviceStub.mapFeatToCmp.get).not.toHaveBeenCalled() + }) + + it('> if input changed, feature is one of them, will not call map.get', () => { + const fixture = TestBed.createComponent(HostCmp) + const dummyFeature = { + type: dummyCmpType + } + spyOn(serviceStub.mapFeatToCmp, 'get').and.callThrough() + fixture.componentInstance.feature = dummyFeature + fixture.detectChanges() + expect(serviceStub.mapFeatToCmp.get).toHaveBeenCalledWith(dummyCmpType) + }) + + it('> should render default txt', () => { + const fixture = TestBed.createComponent(HostCmp) + const dummyFeature = { + type: dummyCmpType + } + fixture.componentInstance.feature = dummyFeature + fixture.detectChanges() + const text = fixture.nativeElement.textContent + expect(text).toContain('hello world') + }) + + it('> if inner component changes, if view changed does not emit, will not change ui', () => { + + const fixture = TestBed.createComponent(HostCmp) + const dummyFeature = { + type: dummyCmpType + } + fixture.componentInstance.feature = dummyFeature + fixture.detectChanges() + const featureContainer = fixture.debugElement.query( + By.directive(FeatureContainer) + ) + const cr = (featureContainer.componentInstance as FeatureContainer)['cr'] as ComponentRef<DummyComponent> + cr.instance.text = 'foo bar' + const text = fixture.nativeElement.textContent + expect(text).toContain('hello world') + }) + + it('> if inner component changes, and viewChanged is emitted, ui should change accordingly', () => { + + const fixture = TestBed.createComponent(HostCmp) + const dummyFeature = { + type: dummyCmpType + } + fixture.componentInstance.feature = dummyFeature + fixture.detectChanges() + const featureContainer = fixture.debugElement.query( + By.directive(FeatureContainer) + ) + const cr = (featureContainer.componentInstance as FeatureContainer)['cr'] as ComponentRef<DummyComponent> + cr.instance.text = 'foo bar' + cr.instance.viewChanged.emit(true) + const text = fixture.nativeElement.textContent + expect(text).toContain('foo bar') + }) + }) + }) +}) diff --git a/src/atlasComponents/regionalFeatures/featureContainer/featureContainer.component.ts b/src/atlasComponents/regionalFeatures/featureContainer/featureContainer.component.ts index d6752dae47b53d81f94c067ff653366f59c1a375..2b2391599494ac22cadc250fa479255fa39d2179 100644 --- a/src/atlasComponents/regionalFeatures/featureContainer/featureContainer.component.ts +++ b/src/atlasComponents/regionalFeatures/featureContainer/featureContainer.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ComponentFactoryResolver, ComponentRef, Input, OnChanges, SimpleChanges, ViewContainerRef } from "@angular/core"; +import { ChangeDetectionStrategy, Component, ComponentFactoryResolver, ComponentRef, Input, OnChanges, Output, SimpleChanges, ViewContainerRef, EventEmitter } from "@angular/core"; import { Subscription } from "rxjs"; import { IFeature, RegionalFeaturesService } from "../regionalFeature.service"; import { ISingleFeature } from "../singleFeatures/interfaces"; @@ -16,13 +16,15 @@ export class FeatureContainer implements OnChanges{ @Input() region: any + @Output() + viewChanged: EventEmitter<boolean> = new EventEmitter() + private cr: ComponentRef<ISingleFeature> constructor( private vCRef: ViewContainerRef, private rService: RegionalFeaturesService, private cfr: ComponentFactoryResolver, - private cdr: ChangeDetectorRef ){ } @@ -33,15 +35,22 @@ export class FeatureContainer implements OnChanges{ const { currentValue, previousValue } = simpleChanges.feature if (currentValue === previousValue) return this.clear() + + /** + * catching instances where currentValue for feature is falsy + */ + if (!currentValue) return + /** * TODO catch if map is undefined */ const comp = this.rService.mapFeatToCmp.get(currentValue.type) + if (!comp) throw new Error(`mapFeatToCmp for ${currentValue.type} not defined`) const cf = this.cfr.resolveComponentFactory<ISingleFeature>(comp) this.cr = this.vCRef.createComponent(cf) this.cr.instance.feature = this.feature this.cr.instance.region = this.region - this.viewChangedSub = this.cr.instance.viewChanged.subscribe(() => this.cdr.detectChanges()) + this.viewChangedSub = this.cr.instance.viewChanged.subscribe(() => this.viewChanged.emit(true)) } clear(){ diff --git a/src/atlasComponents/regionalFeatures/singleFeatures/iEEGRecordings/iEEGRecordings/iEEGRecordings.component.ts b/src/atlasComponents/regionalFeatures/singleFeatures/iEEGRecordings/iEEGRecordings/iEEGRecordings.component.ts index af0dcab8913fa06d2f7ad55f6ffadc309aae69dc..072cbabf90ec1d731fe4a767dcd78ee76ba7d4b9 100644 --- a/src/atlasComponents/regionalFeatures/singleFeatures/iEEGRecordings/iEEGRecordings/iEEGRecordings.component.ts +++ b/src/atlasComponents/regionalFeatures/singleFeatures/iEEGRecordings/iEEGRecordings/iEEGRecordings.component.ts @@ -31,7 +31,7 @@ export class IEEGRecordingsCmp extends RegionFeatureBase implements ISingleFeatu super(regionFeatureService) } - public viewChanged = new EventEmitter<null>() + public viewChanged = new EventEmitter<boolean>() ngOnInit(){ if (this.regClickIntp) { @@ -71,7 +71,7 @@ export class IEEGRecordingsCmp extends RegionFeatureBase implements ISingleFeatu ) this.sub.push( - this.dataIsLoading$.subscribe(() => this.viewChanged.emit(null)) + this.dataIsLoading$.subscribe(() => this.viewChanged.emit(true)) ) this.onDestroyCb.push(() => { diff --git a/src/atlasComponents/regionalFeatures/singleFeatures/interfaces.ts b/src/atlasComponents/regionalFeatures/singleFeatures/interfaces.ts index 37abcd4479aa87e9dabed72e589d2a3b82a091bd..bd3861d391b4bcc90d262ee16e124b51e4affee2 100644 --- a/src/atlasComponents/regionalFeatures/singleFeatures/interfaces.ts +++ b/src/atlasComponents/regionalFeatures/singleFeatures/interfaces.ts @@ -4,5 +4,5 @@ import { IFeature } from "../regionalFeature.service"; export interface ISingleFeature{ feature: IFeature region: any - viewChanged: EventEmitter<null> + viewChanged: EventEmitter<boolean> } diff --git a/src/atlasComponents/uiSelectors/atlasLayerSelector/atlasLayerSelector.component.ts b/src/atlasComponents/uiSelectors/atlasLayerSelector/atlasLayerSelector.component.ts index 088c98dbefb4b85f4eb19b0f88ff9efcf59cf263..046aa3448b8566a3c9fcd0179560e5d6aa1908ef 100644 --- a/src/atlasComponents/uiSelectors/atlasLayerSelector/atlasLayerSelector.component.ts +++ b/src/atlasComponents/uiSelectors/atlasLayerSelector/atlasLayerSelector.component.ts @@ -1,6 +1,6 @@ import { Component, OnInit, ViewChildren, QueryList, HostBinding } from "@angular/core"; import { select, Store } from "@ngrx/store"; -import { distinctUntilChanged, map, withLatestFrom, shareReplay, groupBy, mergeMap, toArray, switchMap, scan, filter } from "rxjs/operators"; +import { distinctUntilChanged, map, withLatestFrom, shareReplay, groupBy, mergeMap, toArray, switchMap, scan, filter, startWith } from "rxjs/operators"; import { Observable, Subscription, from, zip, of, combineLatest } from "rxjs"; import { viewerStateSelectTemplateWithId, viewerStateToggleLayer } from "src/services/state/viewerState.store.helper"; import { MatMenuTrigger } from "@angular/material/menu"; diff --git a/src/atlasViewer/atlasViewer.apiService.service.ts b/src/atlasViewer/atlasViewer.apiService.service.ts index d77129d69ba46c90ac2eee782cac01fb1948112a..5b3fe24f2717e0df81e7bb2951ac799165b17e1f 100644 --- a/src/atlasViewer/atlasViewer.apiService.service.ts +++ b/src/atlasViewer/atlasViewer.apiService.service.ts @@ -437,14 +437,8 @@ export interface IVIewerHandle { showAllSegments: () => void hideAllSegments: () => void - // TODO deprecate - segmentColourMap: Map<number, {red: number, green: number, blue: number}> - getLayersSegmentColourMap: () => Map<string, Map<number, {red: number, green: number, blue: number}>> - // TODO deprecate - applyColourMap: (newColourMap: Map<number, {red: number, green: number, blue: number}>) => void - applyLayersColourMap: (newLayerColourMap: Map<string, Map<number, {red: number, green: number, blue: number}>>) => void loadLayer: (layerobj: any) => any diff --git a/src/atlasViewer/atlasViewer.component.ts b/src/atlasViewer/atlasViewer.component.ts index d80b8e60f4868cbd2e1e30f820f495cc0b555a66..7a2af6e9ed3a85bac69a58b7ae6422232377180e 100644 --- a/src/atlasViewer/atlasViewer.component.ts +++ b/src/atlasViewer/atlasViewer.component.ts @@ -90,8 +90,6 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { public onhoverLandmark$: Observable<{landmarkName: string, datasets: any} | null> - public overwrittenColorMap$: Observable<any> - private subscriptions: Subscription[] = [] public unsupportedPreviewIdx: number = 0 @@ -180,13 +178,6 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { ) - this.overwrittenColorMap$ = this.store.pipe( - select('viewerState'), - safeFilter('overwrittenColorMap'), - map(state => state.overwrittenColorMap), - distinctUntilChanged() - ) - const error = this.el.nativeElement.getAttribute('data-error') if (error) { diff --git a/src/glue.ts b/src/glue.ts index d2c6756cd0d534834fddb900464e406317641cb7..451e16b0968e76c0b5c0d0d677fc2c5cf012374e 100644 --- a/src/glue.ts +++ b/src/glue.ts @@ -631,6 +631,7 @@ export class DatasetPreviewGlue implements IDatasetPreviewGlue, OnDestroy{ } public datasetPreviewDisplayed(file: DatasetPreview, dataset?: IKgDataEntry){ + if (!file) return of(false) return this.previewingDatasetFiles$.pipe( map(datasetPreviews => { const { filename, datasetId } = file diff --git a/src/plugin_examples/migrationGuide.md b/src/plugin_examples/migrationGuide.md index 9cd95c535efd5699d03ed3d04e2d57afc5ad554a..fcd5e040b9333b262dbbac60b6d3237859fe7f1c 100644 --- a/src/plugin_examples/migrationGuide.md +++ b/src/plugin_examples/migrationGuide.md @@ -34,7 +34,6 @@ Plugin APIs have changed drastically from v0.1.0 to v0.2.0. Here is a list of pl - *showAllSegments()* : Function that selects all segments. - *hideAllSegments()* : Function that deselects all segments. - *loadLayer(layerObject)* : Function that loads a custom neuroglancer compatible layer into the viewer (e.g. precomputed, NIFTI, etc). Does not influence UI. - - ~~*reapplyNehubaMeshFix()* Function that reapplies the cosmetic change to NehubaViewer (such as custom colour map, if defined)~~ removed. use **applyColourMap(colourMap)** instead - *mouseEvent* RxJs Observable. Read more at [rxjs doc](http://reactivex.io/rxjs/) - *mouseEvent.filter(filterFn:({eventName : String, event: Event})=>boolean)* returns an Observable. Filters the event stream according to the filter function. - *mouseEvent.map(mapFn:({eventName : String, event: Event})=>any)* returns an Observable. Map the event stream according to the map function. diff --git a/src/res/css/extra_styles.css b/src/res/css/extra_styles.css index 88e4a8d10e17d410aa6dcce4fbd3a842cb437766..3aa834fd880fdbb63398bba87fb98fa8cbf3bd5f 100644 --- a/src/res/css/extra_styles.css +++ b/src/res/css/extra_styles.css @@ -176,6 +176,11 @@ markdown-dom pre code white-space:pre; } +markdown-dom p +{ + margin: 0; +} + .highlight { background-color:rgba(150,150,0,0.5); diff --git a/src/res/ext/MNI152.json b/src/res/ext/MNI152.json index f7b08d8e701937661663eb5d3ebbaca05a710952..c47348065055770a66277a9b384fdc05962200c0 100644 --- a/src/res/ext/MNI152.json +++ b/src/res/ext/MNI152.json @@ -7,6 +7,23 @@ "species": "Human", "useTheme": "dark", "ngId": "mni152", + "auxMeshes": [{ + "name": "ICBM152 2009c nonlinear asymmetric - Cortex", + "displayName": "Cortex", + "@id": "icbm2009c_nonlin_asym_cortex", + "ngId": "auxMesh", + "labelIndicies": [ 65500, 65510 ], + "rgb": [255, 255, 255], + "visible": true + },{ + "name": "ICBM152 2009c nonlinear asymmetric - Sulci", + "displayName": "Sulci", + "@id": "icbm2009c_nonlin_asym_sulci", + "ngId": "auxMesh", + "labelIndicies": [ 65501, 65511 ], + "rgb": [255, 255, 255], + "visible": false + }], "nehubaConfigURL": "nehubaConfig/MNI152NehubaConfig", "parcellations": [ { @@ -14,16 +31,13 @@ "@id": "minds/core/parcellationatlas/v1.0.0/94c1125b-b87e-45e4-901c-00daee7f2579-25", "name": "Cytoarchitectonic Maps - v2.5.1", "displayName": "Cytoarchitectonic Maps", - "auxillaryMeshIndices": [ - 65535 - ], "hasAdditionalViewMode": [ "connectivity" ], "originDatasets": [ { "kgSchema": "minds/core/dataset/v1.0.0", - "kgId": "ef48c5e9-6b3c-4d5a-a9a9-e678fe10bdf6" + "kgId": "2eaa3dc6-a21b-41c1-b703-bf06f82adf25" } ], "properties": { @@ -62,12 +76,20 @@ { "name": "Ch 123 (Basal Forebrain)", "status": "left hemisphere", - "labelIndex": 62, + "labelIndex": 79, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Ch 123 (Basal Forebrain)", "gray": "79" + }, + "xml253": { + "_": "Ch 123 (Basal Forebrain)", + "$": { + "num": "78", + "id": "286", + "grayvalue": "79" + } } }, "originDatasets": [ @@ -97,12 +119,20 @@ { "name": "Ch 123 (Basal Forebrain)", "status": "right hemisphere", - "labelIndex": 62, + "labelIndex": 79, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Ch 123 (Basal Forebrain)", "gray": "79" + }, + "xml253": { + "_": "Ch 123 (Basal Forebrain)", + "$": { + "num": "78", + "id": "286", + "grayvalue": "79" + } } }, "originDatasets": [ @@ -153,12 +183,20 @@ { "name": "Ch 4 (Basal Forebrain)", "status": "left hemisphere", - "labelIndex": 97, + "labelIndex": 13, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Ch 4 (Basal Forebrain)", "gray": "13" + }, + "xml253": { + "_": "Ch 4 (Basal Forebrain)", + "$": { + "num": "12", + "id": "264", + "grayvalue": "13" + } } }, "originDatasets": [ @@ -188,12 +226,20 @@ { "name": "Ch 4 (Basal Forebrain)", "status": "right hemisphere", - "labelIndex": 97, + "labelIndex": 13, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Ch 4 (Basal Forebrain)", "gray": "13" + }, + "xml253": { + "_": "Ch 4 (Basal Forebrain)", + "$": { + "num": "12", + "id": "264", + "grayvalue": "13" + } } }, "originDatasets": [ @@ -244,12 +290,20 @@ { "name": "Ch 123 (Basal Forebrain)", "status": "left hemisphere", - "labelIndex": 62, + "labelIndex": 79, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Ch 123 (Basal Forebrain)", "gray": "79" + }, + "xml253": { + "_": "Ch 123 (Basal Forebrain)", + "$": { + "num": "78", + "id": "286", + "grayvalue": "79" + } } }, "originDatasets": [ @@ -279,12 +333,20 @@ { "name": "Ch 123 (Basal Forebrain)", "status": "right hemisphere", - "labelIndex": 62, + "labelIndex": 79, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Ch 123 (Basal Forebrain)", "gray": "79" + }, + "xml253": { + "_": "Ch 123 (Basal Forebrain)", + "$": { + "num": "78", + "id": "286", + "grayvalue": "79" + } } }, "originDatasets": [ @@ -340,12 +402,20 @@ { "name": "LB (Amygdala)", "status": "left hemisphere", - "labelIndex": 41, + "labelIndex": 94, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "LB (Amygdala)", "gray": "94" + }, + "xml253": { + "_": "LB (Amygdala)", + "$": { + "num": "93", + "id": "187", + "grayvalue": "94" + } } }, "originDatasets": [ @@ -375,12 +445,20 @@ { "name": "LB (Amygdala)", "status": "right hemisphere", - "labelIndex": 41, + "labelIndex": 94, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "LB (Amygdala)", "gray": "94" + }, + "xml253": { + "_": "LB (Amygdala)", + "$": { + "num": "93", + "id": "187", + "grayvalue": "94" + } } }, "originDatasets": [ @@ -431,12 +509,20 @@ { "name": "CM (Amygdala)", "status": "left hemisphere", - "labelIndex": 85, + "labelIndex": 44, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "CM (Amygdala)", "gray": "44" + }, + "xml253": { + "_": "CM (Amygdala)", + "$": { + "num": "43", + "id": "290", + "grayvalue": "44" + } } }, "originDatasets": [ @@ -466,12 +552,20 @@ { "name": "CM (Amygdala)", "status": "right hemisphere", - "labelIndex": 85, + "labelIndex": 44, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "CM (Amygdala)", "gray": "44" + }, + "xml253": { + "_": "CM (Amygdala)", + "$": { + "num": "43", + "id": "290", + "grayvalue": "44" + } } }, "originDatasets": [ @@ -517,12 +611,20 @@ { "name": "SF (Amygdala)", "status": "left hemisphere", - "labelIndex": 5, + "labelIndex": 111, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "SF (Amygdala)", "gray": "110" + }, + "xml253": { + "_": "SF (Amygdala)", + "$": { + "num": "110", + "id": "185", + "grayvalue": "111" + } } }, "originDatasets": [ @@ -552,12 +654,20 @@ { "name": "SF (Amygdala)", "status": "right hemisphere", - "labelIndex": 5, + "labelIndex": 110, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "SF (Amygdala)", "gray": "110" + }, + "xml253": { + "_": "SF (Amygdala)", + "$": { + "num": "109", + "id": "185", + "grayvalue": "110" + } } }, "originDatasets": [ @@ -608,12 +718,20 @@ { "name": "VTM (Amygdala)", "status": "left hemisphere", - "labelIndex": 109, + "labelIndex": 83, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "VTM (Amygdala)", "gray": "83" + }, + "xml253": { + "_": "VTM (Amygdala)", + "$": { + "num": "82", + "id": "228", + "grayvalue": "83" + } } }, "originDatasets": [ @@ -643,12 +761,20 @@ { "name": "VTM (Amygdala)", "status": "right hemisphere", - "labelIndex": 109, + "labelIndex": 83, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "VTM (Amygdala)", "gray": "83" + }, + "xml253": { + "_": "VTM (Amygdala)", + "$": { + "num": "82", + "id": "228", + "grayvalue": "83" + } } }, "originDatasets": [ @@ -694,12 +820,20 @@ { "name": "IF (Amygdala)", "status": "left hemisphere", - "labelIndex": 46, + "labelIndex": 61, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "IF (Amygdala)", "gray": "61" + }, + "xml253": { + "_": "IF (Amygdala)", + "$": { + "num": "60", + "id": "237", + "grayvalue": "61" + } } }, "originDatasets": [ @@ -729,12 +863,20 @@ { "name": "IF (Amygdala)", "status": "right hemisphere", - "labelIndex": 46, + "labelIndex": 61, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "IF (Amygdala)", "gray": "61" + }, + "xml253": { + "_": "IF (Amygdala)", + "$": { + "num": "60", + "id": "237", + "grayvalue": "61" + } } }, "originDatasets": [ @@ -780,12 +922,20 @@ { "name": "MF (Amygdala)", "status": "left hemisphere", - "labelIndex": 123, + "labelIndex": 104, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "MF (Amygdala)", "gray": "104" + }, + "xml253": { + "_": "MF (Amygdala)", + "$": { + "num": "103", + "id": "235", + "grayvalue": "104" + } } }, "originDatasets": [ @@ -815,12 +965,20 @@ { "name": "MF (Amygdala)", "status": "right hemisphere", - "labelIndex": 123, + "labelIndex": 104, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "MF (Amygdala)", "gray": "104" + }, + "xml253": { + "_": "MF (Amygdala)", + "$": { + "num": "103", + "id": "235", + "grayvalue": "104" + } } }, "originDatasets": [ @@ -871,12 +1029,20 @@ { "name": "CM (Amygdala)", "status": "left hemisphere", - "labelIndex": 85, + "labelIndex": 44, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "CM (Amygdala)", "gray": "44" + }, + "xml253": { + "_": "CM (Amygdala)", + "$": { + "num": "43", + "id": "290", + "grayvalue": "44" + } } }, "originDatasets": [ @@ -906,12 +1072,20 @@ { "name": "CM (Amygdala)", "status": "right hemisphere", - "labelIndex": 85, + "labelIndex": 44, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "CM (Amygdala)", "gray": "44" + }, + "xml253": { + "_": "CM (Amygdala)", + "$": { + "num": "43", + "id": "290", + "grayvalue": "44" + } } }, "originDatasets": [ @@ -972,12 +1146,20 @@ { "name": "Area 5L (SPL)", "status": "left hemisphere", - "labelIndex": 83, + "labelIndex": 97, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 5L (SPL)", "gray": "98" + }, + "xml253": { + "_": "Area 5L (SPL)", + "$": { + "num": "96", + "id": "130", + "grayvalue": "97" + } } }, "originDatasets": [ @@ -1007,12 +1189,20 @@ { "name": "Area 5L (SPL)", "status": "right hemisphere", - "labelIndex": 83, + "labelIndex": 97, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 5L (SPL)", "gray": "97" + }, + "xml253": { + "_": "Area 5L (SPL)", + "$": { + "num": "96", + "id": "130", + "grayvalue": "97" + } } }, "originDatasets": [ @@ -1058,12 +1248,20 @@ { "name": "Area 7M (SPL)", "status": "left hemisphere", - "labelIndex": 124, + "labelIndex": 89, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 7M (SPL)", "gray": "89" + }, + "xml253": { + "_": "Area 7M (SPL)", + "$": { + "num": "88", + "id": "135", + "grayvalue": "89" + } } }, "originDatasets": [ @@ -1087,12 +1285,20 @@ { "name": "Area 7M (SPL)", "status": "right hemisphere", - "labelIndex": 124, + "labelIndex": 88, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 7M (SPL)", "gray": "89" + }, + "xml253": { + "_": "Area 7M (SPL)", + "$": { + "num": "87", + "id": "135", + "grayvalue": "88" + } } }, "originDatasets": [ @@ -1132,12 +1338,20 @@ { "name": "Area 7PC (SPL)", "status": "left hemisphere", - "labelIndex": 4, + "labelIndex": 121, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 7PC (SPL)", "gray": "121" + }, + "xml253": { + "_": "Area 7PC (SPL)", + "$": { + "num": "120", + "id": "132", + "grayvalue": "121" + } } }, "originDatasets": [ @@ -1167,12 +1381,20 @@ { "name": "Area 7PC (SPL)", "status": "right hemisphere", - "labelIndex": 4, + "labelIndex": 121, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 7PC (SPL)", "gray": "121" + }, + "xml253": { + "_": "Area 7PC (SPL)", + "$": { + "num": "120", + "id": "132", + "grayvalue": "121" + } } }, "originDatasets": [ @@ -1218,12 +1440,20 @@ { "name": "Area 5M (SPL)", "status": "left hemisphere", - "labelIndex": 26, + "labelIndex": 98, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 5M (SPL)", "gray": "97" + }, + "xml253": { + "_": "Area 5M (SPL)", + "$": { + "num": "97", + "id": "131", + "grayvalue": "98" + } } }, "originDatasets": [ @@ -1253,12 +1483,20 @@ { "name": "Area 5M (SPL)", "status": "right hemisphere", - "labelIndex": 26, + "labelIndex": 98, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 5M (SPL)", "gray": "98" + }, + "xml253": { + "_": "Area 5M (SPL)", + "$": { + "num": "97", + "id": "131", + "grayvalue": "98" + } } }, "originDatasets": [ @@ -1304,12 +1542,20 @@ { "name": "Area 7P (SPL)", "status": "left hemisphere", - "labelIndex": 24, + "labelIndex": 35, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 7P (SPL)", "gray": "35" + }, + "xml253": { + "_": "Area 7P (SPL)", + "$": { + "num": "34", + "id": "208", + "grayvalue": "35" + } } }, "originDatasets": [ @@ -1339,12 +1585,20 @@ { "name": "Area 7P (SPL)", "status": "right hemisphere", - "labelIndex": 24, + "labelIndex": 35, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 7P (SPL)", "gray": "36" + }, + "xml253": { + "_": "Area 7P (SPL)", + "$": { + "num": "34", + "id": "208", + "grayvalue": "35" + } } }, "originDatasets": [ @@ -1390,12 +1644,20 @@ { "name": "Area 5Ci (SPL)", "status": "left hemisphere", - "labelIndex": 88, + "labelIndex": 73, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 5Ci (SPL)", "gray": "73" + }, + "xml253": { + "_": "Area 5Ci (SPL)", + "$": { + "num": "72", + "id": "136", + "grayvalue": "73" + } } }, "originDatasets": [ @@ -1425,12 +1687,20 @@ { "name": "Area 5Ci (SPL)", "status": "right hemisphere", - "labelIndex": 88, + "labelIndex": 73, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 5Ci (SPL)", "gray": "73" + }, + "xml253": { + "_": "Area 5Ci (SPL)", + "$": { + "num": "72", + "id": "136", + "grayvalue": "73" + } } }, "originDatasets": [ @@ -1476,12 +1746,20 @@ { "name": "Area 7A (SPL)", "status": "left hemisphere", - "labelIndex": 17, + "labelIndex": 85, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 7A (SPL)", "gray": "85" + }, + "xml253": { + "_": "Area 7A (SPL)", + "$": { + "num": "84", + "id": "134", + "grayvalue": "85" + } } }, "originDatasets": [ @@ -1511,12 +1789,20 @@ { "name": "Area 7A (SPL)", "status": "right hemisphere", - "labelIndex": 17, + "labelIndex": 85, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 7A (SPL)", "gray": "85" + }, + "xml253": { + "_": "Area 7A (SPL)", + "$": { + "num": "84", + "id": "134", + "grayvalue": "85" + } } }, "originDatasets": [ @@ -1567,12 +1853,20 @@ { "name": "Area OP3 (POperc)", "status": "left hemisphere", - "labelIndex": 22, + "labelIndex": 84, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area OP3 (POperc)", "gray": "84" + }, + "xml253": { + "_": "Area OP3 (POperc)", + "$": { + "num": "83", + "id": "75", + "grayvalue": "84" + } } }, "originDatasets": [ @@ -1602,12 +1896,20 @@ { "name": "Area OP3 (POperc)", "status": "right hemisphere", - "labelIndex": 22, + "labelIndex": 84, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area OP3 (POperc)", "gray": "84" + }, + "xml253": { + "_": "Area OP3 (POperc)", + "$": { + "num": "83", + "id": "75", + "grayvalue": "84" + } } }, "originDatasets": [ @@ -1653,12 +1955,20 @@ { "name": "Area OP4 (POperc)", "status": "left hemisphere", - "labelIndex": 14, + "labelIndex": 11, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area OP4 (POperc)", "gray": "11" + }, + "xml253": { + "_": "Area OP4 (POperc)", + "$": { + "num": "10", + "id": "72", + "grayvalue": "11" + } } }, "originDatasets": [ @@ -1688,12 +1998,20 @@ { "name": "Area OP4 (POperc)", "status": "right hemisphere", - "labelIndex": 14, + "labelIndex": 11, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area OP4 (POperc)", "gray": "11" + }, + "xml253": { + "_": "Area OP4 (POperc)", + "$": { + "num": "10", + "id": "72", + "grayvalue": "11" + } } }, "originDatasets": [ @@ -1739,12 +2057,20 @@ { "name": "Area OP2 (POperc)", "status": "left hemisphere", - "labelIndex": 122, + "labelIndex": 17, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area OP2 (POperc)", "gray": "17" + }, + "xml253": { + "_": "Area OP2 (POperc)", + "$": { + "num": "16", + "id": "74", + "grayvalue": "17" + } } }, "originDatasets": [ @@ -1774,12 +2100,20 @@ { "name": "Area OP2 (POperc)", "status": "right hemisphere", - "labelIndex": 122, + "labelIndex": 16, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area OP2 (POperc)", "gray": "17" + }, + "xml253": { + "_": "Area OP2 (POperc)", + "$": { + "num": "15", + "id": "74", + "grayvalue": "16" + } } }, "originDatasets": [ @@ -1825,12 +2159,20 @@ { "name": "Area OP1 (POperc)", "status": "left hemisphere", - "labelIndex": 1, + "labelIndex": 57, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area OP1 (POperc)", "gray": "56" + }, + "xml253": { + "_": "Area OP1 (POperc)", + "$": { + "num": "56", + "id": "73", + "grayvalue": "57" + } } }, "originDatasets": [ @@ -1860,12 +2202,20 @@ { "name": "Area OP1 (POperc)", "status": "right hemisphere", - "labelIndex": 1, + "labelIndex": 56, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area OP1 (POperc)", "gray": "57" + }, + "xml253": { + "_": "Area OP1 (POperc)", + "$": { + "num": "55", + "id": "73", + "grayvalue": "56" + } } }, "originDatasets": [ @@ -1916,12 +2266,20 @@ { "name": "Area 3b (PostCG)", "status": "left hemisphere", - "labelIndex": 37, + "labelIndex": 2, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 3b (PostCG)", "gray": "2" + }, + "xml253": { + "_": "Area 3b (PostCG)", + "$": { + "num": "1", + "id": "127", + "grayvalue": "2" + } } }, "originDatasets": [ @@ -1951,12 +2309,20 @@ { "name": "Area 3b (PostCG)", "status": "right hemisphere", - "labelIndex": 37, + "labelIndex": 2, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 3b (PostCG)", "gray": "2" + }, + "xml253": { + "_": "Area 3b (PostCG)", + "$": { + "num": "1", + "id": "127", + "grayvalue": "2" + } } }, "originDatasets": [ @@ -2002,12 +2368,20 @@ { "name": "Area 1 (PostCG)", "status": "left hemisphere", - "labelIndex": 116, + "labelIndex": 12, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 1 (PostCG)", "gray": "12" + }, + "xml253": { + "_": "Area 1 (PostCG)", + "$": { + "num": "11", + "id": "125", + "grayvalue": "12" + } } }, "originDatasets": [ @@ -2037,12 +2411,20 @@ { "name": "Area 1 (PostCG)", "status": "right hemisphere", - "labelIndex": 116, + "labelIndex": 12, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 1 (PostCG)", "gray": "12" + }, + "xml253": { + "_": "Area 1 (PostCG)", + "$": { + "num": "11", + "id": "125", + "grayvalue": "12" + } } }, "originDatasets": [ @@ -2088,12 +2470,20 @@ { "name": "Area 2 (PostCS)", "status": "left hemisphere", - "labelIndex": 49, + "labelIndex": 78, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 2 (PostCS)", "gray": "78" + }, + "xml253": { + "_": "Area 2 (PostCS)", + "$": { + "num": "77", + "id": "252", + "grayvalue": "78" + } } }, "originDatasets": [ @@ -2123,12 +2513,20 @@ { "name": "Area 2 (PostCS)", "status": "right hemisphere", - "labelIndex": 49, + "labelIndex": 78, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 2 (PostCS)", "gray": "78" + }, + "xml253": { + "_": "Area 2 (PostCS)", + "$": { + "num": "77", + "id": "252", + "grayvalue": "78" + } } }, "originDatasets": [ @@ -2174,12 +2572,20 @@ { "name": "Area 3a (PostCG)", "status": "left hemisphere", - "labelIndex": 121, + "labelIndex": 105, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 3a (PostCG)", "gray": "105" + }, + "xml253": { + "_": "Area 3a (PostCG)", + "$": { + "num": "104", + "id": "126", + "grayvalue": "105" + } } }, "originDatasets": [ @@ -2209,12 +2615,20 @@ { "name": "Area 3a (PostCG)", "status": "right hemisphere", - "labelIndex": 121, + "labelIndex": 105, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 3a (PostCG)", "gray": "105" + }, + "xml253": { + "_": "Area 3a (PostCG)", + "$": { + "num": "104", + "id": "126", + "grayvalue": "105" + } } }, "originDatasets": [ @@ -2265,12 +2679,20 @@ { "name": "Area PF (IPL)", "status": "left hemisphere", - "labelIndex": 12, + "labelIndex": 5, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area PF (IPL)", "gray": "5" + }, + "xml253": { + "_": "Area PF (IPL)", + "$": { + "num": "4", + "id": "206", + "grayvalue": "5" + } } }, "originDatasets": [ @@ -2300,12 +2722,20 @@ { "name": "Area PF (IPL)", "status": "right hemisphere", - "labelIndex": 12, + "labelIndex": 4, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area PF (IPL)", "gray": "4" + }, + "xml253": { + "_": "Area PF (IPL)", + "$": { + "num": "3", + "id": "206", + "grayvalue": "4" + } } }, "originDatasets": [ @@ -2351,12 +2781,20 @@ { "name": "Area PFcm (IPL)", "status": "left hemisphere", - "labelIndex": 103, + "labelIndex": 33, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area PFcm (IPL)", "gray": "32" + }, + "xml253": { + "_": "Area PFcm (IPL)", + "$": { + "num": "32", + "id": "113", + "grayvalue": "33" + } } }, "originDatasets": [ @@ -2386,12 +2824,20 @@ { "name": "Area PFcm (IPL)", "status": "right hemisphere", - "labelIndex": 103, + "labelIndex": 32, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area PFcm (IPL)", "gray": "32" + }, + "xml253": { + "_": "Area PFcm (IPL)", + "$": { + "num": "31", + "id": "113", + "grayvalue": "32" + } } }, "originDatasets": [ @@ -2437,12 +2883,20 @@ { "name": "Area PGa (IPL)", "status": "left hemisphere", - "labelIndex": 81, + "labelIndex": 76, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area PGa (IPL)", "gray": "76" + }, + "xml253": { + "_": "Area PGa (IPL)", + "$": { + "num": "75", + "id": "110", + "grayvalue": "76" + } } }, "originDatasets": [ @@ -2472,12 +2926,20 @@ { "name": "Area PGa (IPL)", "status": "right hemisphere", - "labelIndex": 81, + "labelIndex": 76, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area PGa (IPL)", "gray": "76" + }, + "xml253": { + "_": "Area PGa (IPL)", + "$": { + "num": "75", + "id": "110", + "grayvalue": "76" + } } }, "originDatasets": [ @@ -2523,12 +2985,20 @@ { "name": "Area PFt (IPL)", "status": "left hemisphere", - "labelIndex": 20, + "labelIndex": 27, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area PFt (IPL)", "gray": "27" + }, + "xml253": { + "_": "Area PFt (IPL)", + "$": { + "num": "26", + "id": "109", + "grayvalue": "27" + } } }, "originDatasets": [ @@ -2558,12 +3028,20 @@ { "name": "Area PFt (IPL)", "status": "right hemisphere", - "labelIndex": 20, + "labelIndex": 28, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area PFt (IPL)", "gray": "27" + }, + "xml253": { + "_": "Area PFt (IPL)", + "$": { + "num": "27", + "id": "109", + "grayvalue": "28" + } } }, "originDatasets": [ @@ -2609,12 +3087,20 @@ { "name": "Area PFm (IPL)", "status": "left hemisphere", - "labelIndex": 102, + "labelIndex": 92, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area PFm (IPL)", "gray": "92" + }, + "xml253": { + "_": "Area PFm (IPL)", + "$": { + "num": "91", + "id": "112", + "grayvalue": "92" + } } }, "originDatasets": [ @@ -2644,12 +3130,20 @@ { "name": "Area PFm (IPL)", "status": "right hemisphere", - "labelIndex": 102, + "labelIndex": 91, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area PFm (IPL)", "gray": "92" + }, + "xml253": { + "_": "Area PFm (IPL)", + "$": { + "num": "90", + "id": "112", + "grayvalue": "91" + } } }, "originDatasets": [ @@ -2695,12 +3189,20 @@ { "name": "Area PGp (IPL)", "status": "left hemisphere", - "labelIndex": 65, + "labelIndex": 23, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area PGp (IPL)", "gray": "23" + }, + "xml253": { + "_": "Area PGp (IPL)", + "$": { + "num": "22", + "id": "108", + "grayvalue": "23" + } } }, "originDatasets": [ @@ -2730,12 +3232,20 @@ { "name": "Area PGp (IPL)", "status": "right hemisphere", - "labelIndex": 65, + "labelIndex": 23, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area PGp (IPL)", "gray": "23" + }, + "xml253": { + "_": "Area PGp (IPL)", + "$": { + "num": "22", + "id": "108", + "grayvalue": "23" + } } }, "originDatasets": [ @@ -2781,12 +3291,20 @@ { "name": "Area PFop (IPL)", "status": "left hemisphere", - "labelIndex": 94, + "labelIndex": 115, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area PFop (IPL)", "gray": "114" + }, + "xml253": { + "_": "Area PFop (IPL)", + "$": { + "num": "114", + "id": "111", + "grayvalue": "115" + } } }, "originDatasets": [ @@ -2816,12 +3334,20 @@ { "name": "Area PFop (IPL)", "status": "right hemisphere", - "labelIndex": 94, + "labelIndex": 114, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area PFop (IPL)", "gray": "115" + }, + "xml253": { + "_": "Area PFop (IPL)", + "$": { + "num": "113", + "id": "111", + "grayvalue": "114" + } } }, "originDatasets": [ @@ -2872,12 +3398,20 @@ { "name": "Area hPO1 (POS)", "status": "left hemisphere", - "labelIndex": 69, + "labelIndex": 15, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hPO1 (POS)", "gray": "15" + }, + "xml253": { + "_": "Area hPO1 (POS)", + "$": { + "num": "14", + "id": "297", + "grayvalue": "15" + } } }, "originDatasets": [ @@ -2907,12 +3441,20 @@ { "name": "Area hPO1 (POS)", "status": "right hemisphere", - "labelIndex": 69, + "labelIndex": 15, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hPO1 (POS)", "gray": "15" + }, + "xml253": { + "_": "Area hPO1 (POS)", + "$": { + "num": "14", + "id": "297", + "grayvalue": "15" + } } }, "originDatasets": [ @@ -2963,12 +3505,20 @@ { "name": "Area hIP1 (IPS)", "status": "left hemisphere", - "labelIndex": 32, + "labelIndex": 77, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hIP1 (IPS)", "gray": "77" + }, + "xml253": { + "_": "Area hIP1 (IPS)", + "$": { + "num": "76", + "id": "128", + "grayvalue": "77" + } } }, "originDatasets": [ @@ -2998,12 +3548,20 @@ { "name": "Area hIP1 (IPS)", "status": "right hemisphere", - "labelIndex": 32, + "labelIndex": 77, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hIP1 (IPS)", "gray": "77" + }, + "xml253": { + "_": "Area hIP1 (IPS)", + "$": { + "num": "76", + "id": "128", + "grayvalue": "77" + } } }, "originDatasets": [ @@ -3049,12 +3607,20 @@ { "name": "Area hIP7 (IPS)", "status": "left hemisphere", - "labelIndex": 35, + "labelIndex": 119, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hIP7 (IPS)", "gray": "120" + }, + "xml253": { + "_": "Area hIP7 (IPS)", + "$": { + "num": "118", + "id": "296", + "grayvalue": "119" + } } }, "originDatasets": [ @@ -3084,12 +3650,20 @@ { "name": "Area hIP7 (IPS)", "status": "right hemisphere", - "labelIndex": 35, + "labelIndex": 119, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hIP7 (IPS)", "gray": "120" + }, + "xml253": { + "_": "Area hIP7 (IPS)", + "$": { + "num": "118", + "id": "296", + "grayvalue": "119" + } } }, "originDatasets": [ @@ -3135,12 +3709,20 @@ { "name": "Area hIP3 (IPS)", "status": "left hemisphere", - "labelIndex": 75, + "labelIndex": 42, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hIP3 (IPS)", "gray": "43" + }, + "xml253": { + "_": "Area hIP3 (IPS)", + "$": { + "num": "41", + "id": "133", + "grayvalue": "42" + } } }, "originDatasets": [ @@ -3170,12 +3752,20 @@ { "name": "Area hIP3 (IPS)", "status": "right hemisphere", - "labelIndex": 75, + "labelIndex": 42, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hIP3 (IPS)", "gray": "43" + }, + "xml253": { + "_": "Area hIP3 (IPS)", + "$": { + "num": "41", + "id": "133", + "grayvalue": "42" + } } }, "originDatasets": [ @@ -3221,12 +3811,20 @@ { "name": "Area hIP2 (IPS)", "status": "left hemisphere", - "labelIndex": 59, + "labelIndex": 68, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hIP2 (IPS)", "gray": "68" + }, + "xml253": { + "_": "Area hIP2 (IPS)", + "$": { + "num": "67", + "id": "129", + "grayvalue": "68" + } } }, "originDatasets": [ @@ -3256,12 +3854,20 @@ { "name": "Area hIP2 (IPS)", "status": "right hemisphere", - "labelIndex": 59, + "labelIndex": 68, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hIP2 (IPS)", "gray": "68" + }, + "xml253": { + "_": "Area hIP2 (IPS)", + "$": { + "num": "67", + "id": "129", + "grayvalue": "68" + } } }, "originDatasets": [ @@ -3307,12 +3913,20 @@ { "name": "Area hIP4 (IPS)", "status": "left hemisphere", - "labelIndex": 115, + "labelIndex": 38, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hIP4 (IPS)", "gray": "38" + }, + "xml253": { + "_": "Area hIP4 (IPS)", + "$": { + "num": "37", + "id": "294", + "grayvalue": "38" + } } }, "originDatasets": [ @@ -3342,12 +3956,20 @@ { "name": "Area hIP4 (IPS)", "status": "right hemisphere", - "labelIndex": 115, + "labelIndex": 38, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hIP4 (IPS)", "gray": "38" + }, + "xml253": { + "_": "Area hIP4 (IPS)", + "$": { + "num": "37", + "id": "294", + "grayvalue": "38" + } } }, "originDatasets": [ @@ -3393,12 +4015,20 @@ { "name": "Area hIP5 (IPS)", "status": "left hemisphere", - "labelIndex": 7, + "labelIndex": 34, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hIP5 (IPS)", "gray": "34" + }, + "xml253": { + "_": "Area hIP5 (IPS)", + "$": { + "num": "33", + "id": "295", + "grayvalue": "34" + } } }, "originDatasets": [ @@ -3428,12 +4058,20 @@ { "name": "Area hIP5 (IPS)", "status": "right hemisphere", - "labelIndex": 7, + "labelIndex": 34, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hIP5 (IPS)", "gray": "34" + }, + "xml253": { + "_": "Area hIP5 (IPS)", + "$": { + "num": "33", + "id": "295", + "grayvalue": "34" + } } }, "originDatasets": [ @@ -3479,12 +4117,20 @@ { "name": "Area hIP6 (IPS)", "status": "left hemisphere", - "labelIndex": 95, + "labelIndex": 41, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hIP6 (IPS)", "gray": "41" + }, + "xml253": { + "_": "Area hIP6 (IPS)", + "$": { + "num": "40", + "id": "292", + "grayvalue": "41" + } } }, "originDatasets": [ @@ -3514,12 +4160,20 @@ { "name": "Area hIP6 (IPS)", "status": "right hemisphere", - "labelIndex": 95, + "labelIndex": 41, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hIP6 (IPS)", "gray": "41" + }, + "xml253": { + "_": "Area hIP6 (IPS)", + "$": { + "num": "40", + "id": "292", + "grayvalue": "41" + } } }, "originDatasets": [ @@ -3565,12 +4219,20 @@ { "name": "Area hIP8 (IPS)", "status": "left hemisphere", - "labelIndex": 50, + "labelIndex": 59, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hIP8 (IPS)", "gray": "60" + }, + "xml253": { + "_": "Area hIP8 (IPS)", + "$": { + "num": "58", + "id": "293", + "grayvalue": "59" + } } }, "originDatasets": [ @@ -3600,12 +4262,20 @@ { "name": "Area hIP8 (IPS)", "status": "right hemisphere", - "labelIndex": 50, + "labelIndex": 60, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hIP8 (IPS)", "gray": "60" + }, + "xml253": { + "_": "Area hIP8 (IPS)", + "$": { + "num": "59", + "id": "293", + "grayvalue": "60" + } } }, "originDatasets": [ @@ -3661,12 +4331,20 @@ { "name": "Area hOc6 (POS)", "status": "left hemisphere", - "labelIndex": 72, + "labelIndex": 48, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hOc6 (POS)", "gray": "49" + }, + "xml253": { + "_": "Area hOc6 (POS)", + "$": { + "num": "47", + "id": "291", + "grayvalue": "48" + } } }, "originDatasets": [ @@ -3696,12 +4374,20 @@ { "name": "Area hOc6 (POS)", "status": "right hemisphere", - "labelIndex": 72, + "labelIndex": 49, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hOc6 (POS)", "gray": "49" + }, + "xml253": { + "_": "Area hOc6 (POS)", + "$": { + "num": "48", + "id": "291", + "grayvalue": "49" + } } }, "originDatasets": [ @@ -3747,12 +4433,20 @@ { "name": "Area hOc4d (Cuneus)", "status": "left hemisphere", - "labelIndex": 44, + "labelIndex": 9, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hOc4d (Cuneus)", "gray": "9" + }, + "xml253": { + "_": "Area hOc4d (Cuneus)", + "$": { + "num": "8", + "id": "119", + "grayvalue": "9" + } } }, "originDatasets": [ @@ -3782,12 +4476,20 @@ { "name": "Area hOc4d (Cuneus)", "status": "right hemisphere", - "labelIndex": 44, + "labelIndex": 9, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hOc4d (Cuneus)", "gray": "9" + }, + "xml253": { + "_": "Area hOc4d (Cuneus)", + "$": { + "num": "8", + "id": "119", + "grayvalue": "9" + } } }, "originDatasets": [ @@ -3833,12 +4535,20 @@ { "name": "Area hOc3d (Cuneus)", "status": "left hemisphere", - "labelIndex": 106, + "labelIndex": 82, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hOc3d (Cuneus)", "gray": "81" + }, + "xml253": { + "_": "Area hOc3d (Cuneus)", + "$": { + "num": "81", + "id": "120", + "grayvalue": "82" + } } }, "originDatasets": [ @@ -3868,12 +4578,20 @@ { "name": "Area hOc3d (Cuneus)", "status": "right hemisphere", - "labelIndex": 106, + "labelIndex": 82, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hOc3d (Cuneus)", "gray": "82" + }, + "xml253": { + "_": "Area hOc3d (Cuneus)", + "$": { + "num": "81", + "id": "120", + "grayvalue": "82" + } } }, "originDatasets": [ @@ -3924,12 +4642,20 @@ { "name": "Area hOc3v (LingG)", "status": "left hemisphere", - "labelIndex": 77, + "labelIndex": 30, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hOc3v (LingG)", "gray": "30" + }, + "xml253": { + "_": "Area hOc3v (LingG)", + "$": { + "num": "29", + "id": "10", + "grayvalue": "30" + } } }, "originDatasets": [ @@ -3959,12 +4685,20 @@ { "name": "Area hOc3v (LingG)", "status": "right hemisphere", - "labelIndex": 77, + "labelIndex": 30, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hOc3v (LingG)", "gray": "30" + }, + "xml253": { + "_": "Area hOc3v (LingG)", + "$": { + "num": "29", + "id": "10", + "grayvalue": "30" + } } }, "originDatasets": [ @@ -4010,12 +4744,20 @@ { "name": "Area hOc4v (LingG)", "status": "left hemisphere", - "labelIndex": 58, + "labelIndex": 114, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hOc4v (LingG)", "gray": "115" + }, + "xml253": { + "_": "Area hOc4v (LingG)", + "$": { + "num": "113", + "id": "9", + "grayvalue": "114" + } } }, "originDatasets": [ @@ -4045,12 +4787,20 @@ { "name": "Area hOc4v (LingG)", "status": "right hemisphere", - "labelIndex": 58, + "labelIndex": 115, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hOc4v (LingG)", "gray": "114" + }, + "xml253": { + "_": "Area hOc4v (LingG)", + "$": { + "num": "114", + "id": "9", + "grayvalue": "115" + } } }, "originDatasets": [ @@ -4101,12 +4851,20 @@ { "name": "Area hOc2 (V2, 18)", "status": "left hemisphere", - "labelIndex": 21, + "labelIndex": 6, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hOc2 (V2, 18)", "gray": "6" + }, + "xml253": { + "_": "Area hOc2 (V2, 18)", + "$": { + "num": "5", + "id": "7", + "grayvalue": "6" + } } }, "originDatasets": [ @@ -4136,12 +4894,20 @@ { "name": "Area hOc2 (V2, 18)", "status": "right hemisphere", - "labelIndex": 21, + "labelIndex": 6, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hOc2 (V2, 18)", "gray": "6" + }, + "xml253": { + "_": "Area hOc2 (V2, 18)", + "$": { + "num": "5", + "id": "7", + "grayvalue": "6" + } } }, "originDatasets": [ @@ -4187,12 +4953,20 @@ { "name": "Area hOc1 (V1, 17, CalcS)", "status": "left hemisphere", - "labelIndex": 120, + "labelIndex": 117, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hOc1 (V1, 17, CalcS)", "gray": "117" + }, + "xml253": { + "_": "Area hOc1 (V1, 17, CalcS)", + "$": { + "num": "116", + "id": "8", + "grayvalue": "117" + } } }, "originDatasets": [ @@ -4222,12 +4996,20 @@ { "name": "Area hOc1 (V1, 17, CalcS)", "status": "right hemisphere", - "labelIndex": 120, + "labelIndex": 117, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hOc1 (V1, 17, CalcS)", "gray": "117" + }, + "xml253": { + "_": "Area hOc1 (V1, 17, CalcS)", + "$": { + "num": "116", + "id": "8", + "grayvalue": "117" + } } }, "originDatasets": [ @@ -4278,12 +5060,20 @@ { "name": "Area hOc4lp (LOC)", "status": "left hemisphere", - "labelIndex": 51, + "labelIndex": 122, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hOc4lp (LOC)", "gray": "122" + }, + "xml253": { + "_": "Area hOc4lp (LOC)", + "$": { + "num": "121", + "id": "117", + "grayvalue": "122" + } } }, "originDatasets": [ @@ -4313,12 +5103,20 @@ { "name": "Area hOc4lp (LOC)", "status": "right hemisphere", - "labelIndex": 51, + "labelIndex": 122, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hOc4lp (LOC)", "gray": "122" + }, + "xml253": { + "_": "Area hOc4lp (LOC)", + "$": { + "num": "121", + "id": "117", + "grayvalue": "122" + } } }, "originDatasets": [ @@ -4364,12 +5162,20 @@ { "name": "Area hOc5 (LOC)", "status": "left hemisphere", - "labelIndex": 16, + "labelIndex": 106, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hOc5 (LOC)", "gray": "106" + }, + "xml253": { + "_": "Area hOc5 (LOC)", + "$": { + "num": "105", + "id": "6", + "grayvalue": "106" + } } }, "originDatasets": [ @@ -4399,12 +5205,20 @@ { "name": "Area hOc5 (LOC)", "status": "right hemisphere", - "labelIndex": 16, + "labelIndex": 107, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hOc5 (LOC)", "gray": "107" + }, + "xml253": { + "_": "Area hOc5 (LOC)", + "$": { + "num": "106", + "id": "6", + "grayvalue": "107" + } } }, "originDatasets": [ @@ -4450,12 +5264,20 @@ { "name": "Area hOc4la (LOC)", "status": "left hemisphere", - "labelIndex": 29, + "labelIndex": 4, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hOc4la (LOC)", "gray": "4" + }, + "xml253": { + "_": "Area hOc4la (LOC)", + "$": { + "num": "3", + "id": "118", + "grayvalue": "4" + } } }, "originDatasets": [ @@ -4485,12 +5307,20 @@ { "name": "Area hOc4la (LOC)", "status": "right hemisphere", - "labelIndex": 29, + "labelIndex": 5, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area hOc4la (LOC)", "gray": "5" + }, + "xml253": { + "_": "Area hOc4la (LOC)", + "$": { + "num": "4", + "id": "118", + "grayvalue": "5" + } } }, "originDatasets": [ @@ -4546,12 +5376,20 @@ { "name": "Area 44 (IFG)", "status": "left hemisphere", - "labelIndex": 92, + "labelIndex": 69, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 44 (IFG)", "gray": "69" + }, + "xml253": { + "_": "Area 44 (IFG)", + "$": { + "num": "68", + "id": "2", + "grayvalue": "69" + } } }, "originDatasets": [ @@ -4581,12 +5419,20 @@ { "name": "Area 44 (IFG)", "status": "right hemisphere", - "labelIndex": 92, + "labelIndex": 69, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 44 (IFG)", "gray": "69" + }, + "xml253": { + "_": "Area 44 (IFG)", + "$": { + "num": "68", + "id": "2", + "grayvalue": "69" + } } }, "originDatasets": [ @@ -4632,12 +5478,20 @@ { "name": "Area 45 (IFG)", "status": "left hemisphere", - "labelIndex": 112, + "labelIndex": 71, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 45 (IFG)", "gray": "71" + }, + "xml253": { + "_": "Area 45 (IFG)", + "$": { + "num": "70", + "id": "1", + "grayvalue": "71" + } } }, "originDatasets": [ @@ -4667,12 +5521,20 @@ { "name": "Area 45 (IFG)", "status": "right hemisphere", - "labelIndex": 112, + "labelIndex": 71, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 45 (IFG)", "gray": "71" + }, + "xml253": { + "_": "Area 45 (IFG)", + "$": { + "num": "70", + "id": "1", + "grayvalue": "71" + } } }, "originDatasets": [ @@ -4723,12 +5585,20 @@ { "name": "Area 6d2 (PreCG)", "status": "left hemisphere", - "labelIndex": 82, + "labelIndex": 7, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 6d2 (PreCG)", "gray": "7" + }, + "xml253": { + "_": "Area 6d2 (PreCG)", + "$": { + "num": "6", + "id": "288", + "grayvalue": "7" + } } }, "originDatasets": [ @@ -4758,12 +5628,20 @@ { "name": "Area 6d2 (PreCG)", "status": "right hemisphere", - "labelIndex": 82, + "labelIndex": 7, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 6d2 (PreCG)", "gray": "7" + }, + "xml253": { + "_": "Area 6d2 (PreCG)", + "$": { + "num": "6", + "id": "288", + "grayvalue": "7" + } } }, "originDatasets": [ @@ -4809,12 +5687,20 @@ { "name": "Area 6d1 (PreCG)", "status": "left hemisphere", - "labelIndex": 90, + "labelIndex": 36, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 6d1 (PreCG)", "gray": "36" + }, + "xml253": { + "_": "Area 6d1 (PreCG)", + "$": { + "num": "35", + "id": "287", + "grayvalue": "36" + } } }, "originDatasets": [ @@ -4844,12 +5730,20 @@ { "name": "Area 6d1 (PreCG)", "status": "right hemisphere", - "labelIndex": 90, + "labelIndex": 36, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 6d1 (PreCG)", "gray": "35" + }, + "xml253": { + "_": "Area 6d1 (PreCG)", + "$": { + "num": "35", + "id": "287", + "grayvalue": "36" + } } }, "originDatasets": [ @@ -4900,12 +5794,20 @@ { "name": "Area 6ma (preSMA, mesial SFG)", "status": "left hemisphere", - "labelIndex": 70, + "labelIndex": 25, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 6ma (preSMA, mesial SFG)", "gray": "25" + }, + "xml253": { + "_": "Area 6ma (preSMA, mesial SFG)", + "$": { + "num": "24", + "id": "299", + "grayvalue": "25" + } } }, "originDatasets": [ @@ -4935,12 +5837,20 @@ { "name": "Area 6ma (preSMA, mesial SFG)", "status": "right hemisphere", - "labelIndex": 70, + "labelIndex": 25, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 6ma (preSMA, mesial SFG)", "gray": "25" + }, + "xml253": { + "_": "Area 6ma (preSMA, mesial SFG)", + "$": { + "num": "24", + "id": "299", + "grayvalue": "25" + } } }, "originDatasets": [ @@ -4991,12 +5901,20 @@ { "name": "Area 6d3 (SFS)", "status": "left hemisphere", - "labelIndex": 68, + "labelIndex": 65, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 6d3 (SFS)", "gray": "66" + }, + "xml253": { + "_": "Area 6d3 (SFS)", + "$": { + "num": "64", + "id": "289", + "grayvalue": "65" + } } }, "originDatasets": [ @@ -5026,12 +5944,20 @@ { "name": "Area 6d3 (SFS)", "status": "right hemisphere", - "labelIndex": 68, + "labelIndex": 66, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 6d3 (SFS)", "gray": "66" + }, + "xml253": { + "_": "Area 6d3 (SFS)", + "$": { + "num": "65", + "id": "289", + "grayvalue": "66" + } } }, "originDatasets": [ @@ -5082,12 +6008,20 @@ { "name": "Area Fp1 (FPole)", "status": "left hemisphere", - "labelIndex": 107, + "labelIndex": 101, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Fp1 (FPole)", "gray": "101" + }, + "xml253": { + "_": "Area Fp1 (FPole)", + "$": { + "num": "100", + "id": "212", + "grayvalue": "101" + } } }, "originDatasets": [ @@ -5117,12 +6051,20 @@ { "name": "Area Fp1 (FPole)", "status": "right hemisphere", - "labelIndex": 107, + "labelIndex": 101, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Fp1 (FPole)", "gray": "101" + }, + "xml253": { + "_": "Area Fp1 (FPole)", + "$": { + "num": "100", + "id": "212", + "grayvalue": "101" + } } }, "originDatasets": [ @@ -5168,12 +6110,20 @@ { "name": "Area Fp2 (FPole)", "status": "left hemisphere", - "labelIndex": 101, + "labelIndex": 52, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Fp2 (FPole)", "gray": "52" + }, + "xml253": { + "_": "Area Fp2 (FPole)", + "$": { + "num": "51", + "id": "211", + "grayvalue": "52" + } } }, "originDatasets": [ @@ -5203,12 +6153,20 @@ { "name": "Area Fp2 (FPole)", "status": "right hemisphere", - "labelIndex": 101, + "labelIndex": 52, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Fp2 (FPole)", "gray": "52" + }, + "xml253": { + "_": "Area Fp2 (FPole)", + "$": { + "num": "51", + "id": "211", + "grayvalue": "52" + } } }, "originDatasets": [ @@ -5259,12 +6217,20 @@ { "name": "Area 4p (PreCG)", "status": "left hemisphere", - "labelIndex": 9, + "labelIndex": 46, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 4p (PreCG)", "gray": "46" + }, + "xml253": { + "_": "Area 4p (PreCG)", + "$": { + "num": "45", + "id": "123", + "grayvalue": "46" + } } }, "originDatasets": [ @@ -5294,12 +6260,20 @@ { "name": "Area 4p (PreCG)", "status": "right hemisphere", - "labelIndex": 9, + "labelIndex": 46, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 4p (PreCG)", "gray": "46" + }, + "xml253": { + "_": "Area 4p (PreCG)", + "$": { + "num": "45", + "id": "123", + "grayvalue": "46" + } } }, "originDatasets": [ @@ -5345,12 +6319,20 @@ { "name": "Area 4a (PreCG)", "status": "left hemisphere", - "labelIndex": 100, + "labelIndex": 95, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 4a (PreCG)", "gray": "95" + }, + "xml253": { + "_": "Area 4a (PreCG)", + "$": { + "num": "94", + "id": "124", + "grayvalue": "95" + } } }, "originDatasets": [ @@ -5380,12 +6362,20 @@ { "name": "Area 4a (PreCG)", "status": "right hemisphere", - "labelIndex": 100, + "labelIndex": 96, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 4a (PreCG)", "gray": "96" + }, + "xml253": { + "_": "Area 4a (PreCG)", + "$": { + "num": "95", + "id": "124", + "grayvalue": "96" + } } }, "originDatasets": [ @@ -5436,12 +6426,20 @@ { "name": "Area 6mp (SMA, mesial SFG)", "status": "left hemisphere", - "labelIndex": 108, + "labelIndex": 21, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 6mp (SMA, mesial SFG)", "gray": "21" + }, + "xml253": { + "_": "Area 6mp (SMA, mesial SFG)", + "$": { + "num": "20", + "id": "298", + "grayvalue": "21" + } } }, "originDatasets": [ @@ -5471,12 +6469,20 @@ { "name": "Area 6mp (SMA, mesial SFG)", "status": "right hemisphere", - "labelIndex": 108, + "labelIndex": 21, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 6mp (SMA, mesial SFG)", "gray": "20" + }, + "xml253": { + "_": "Area 6mp (SMA, mesial SFG)", + "$": { + "num": "20", + "id": "298", + "grayvalue": "21" + } } }, "originDatasets": [ @@ -5527,12 +6533,20 @@ { "name": "Area Fo1 (OFC)", "status": "left hemisphere", - "labelIndex": 47, + "labelIndex": 110, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Fo1 (OFC)", "gray": "111" + }, + "xml253": { + "_": "Area Fo1 (OFC)", + "$": { + "num": "109", + "id": "3", + "grayvalue": "110" + } } }, "originDatasets": [ @@ -5562,12 +6576,20 @@ { "name": "Area Fo1 (OFC)", "status": "right hemisphere", - "labelIndex": 47, + "labelIndex": 111, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Fo1 (OFC)", "gray": "111" + }, + "xml253": { + "_": "Area Fo1 (OFC)", + "$": { + "num": "110", + "id": "3", + "grayvalue": "111" + } } }, "originDatasets": [ @@ -5613,12 +6635,20 @@ { "name": "Area Fo3 (OFC)", "status": "left hemisphere", - "labelIndex": 48, + "labelIndex": 124, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Fo3 (OFC)", "gray": "123" + }, + "xml253": { + "_": "Area Fo3 (OFC)", + "$": { + "num": "123", + "id": "5", + "grayvalue": "124" + } } }, "originDatasets": [ @@ -5648,12 +6678,20 @@ { "name": "Area Fo3 (OFC)", "status": "right hemisphere", - "labelIndex": 48, + "labelIndex": 123, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Fo3 (OFC)", "gray": "123" + }, + "xml253": { + "_": "Area Fo3 (OFC)", + "$": { + "num": "122", + "id": "5", + "grayvalue": "123" + } } }, "originDatasets": [ @@ -5699,12 +6737,20 @@ { "name": "Area Fo2 (OFC)", "status": "left hemisphere", - "labelIndex": 67, + "labelIndex": 118, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Fo2 (OFC)", "gray": "118" + }, + "xml253": { + "_": "Area Fo2 (OFC)", + "$": { + "num": "117", + "id": "4", + "grayvalue": "118" + } } }, "originDatasets": [ @@ -5734,12 +6780,20 @@ { "name": "Area Fo2 (OFC)", "status": "right hemisphere", - "labelIndex": 67, + "labelIndex": 118, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Fo2 (OFC)", "gray": "118" + }, + "xml253": { + "_": "Area Fo2 (OFC)", + "$": { + "num": "117", + "id": "4", + "grayvalue": "118" + } } }, "originDatasets": [ @@ -5790,12 +6844,20 @@ { "name": "Area OP6 (Frontal Operculum)", "status": "left hemisphere", - "labelIndex": 31, + "labelIndex": 39, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area OP6 (Frontal Operculum)", "gray": "39" + }, + "xml253": { + "_": "Area OP6 (Frontal Operculum)", + "$": { + "num": "38", + "id": "349", + "grayvalue": "39" + } } }, "originDatasets": [ @@ -5825,12 +6887,20 @@ { "name": "Area OP6 (Frontal Operculum)", "status": "right hemisphere", - "labelIndex": 31, + "labelIndex": 39, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area OP6 (Frontal Operculum)", "gray": "39" + }, + "xml253": { + "_": "Area OP6 (Frontal Operculum)", + "$": { + "num": "38", + "id": "349", + "grayvalue": "39" + } } }, "originDatasets": [ @@ -5876,12 +6946,20 @@ { "name": "Area OP8 (Frontal Operculum)", "status": "left hemisphere", - "labelIndex": 40, + "labelIndex": 86, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area OP8 (Frontal Operculum)", "gray": "86" + }, + "xml253": { + "_": "Area OP8 (Frontal Operculum)", + "$": { + "num": "85", + "id": "273", + "grayvalue": "86" + } } }, "originDatasets": [ @@ -5906,12 +6984,20 @@ { "name": "Area OP8 (Frontal Operculum)", "status": "right hemisphere", - "labelIndex": 40, + "labelIndex": 86, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area OP8 (Frontal Operculum)", "gray": "86" + }, + "xml253": { + "_": "Area OP8 (Frontal Operculum)", + "$": { + "num": "85", + "id": "273", + "grayvalue": "86" + } } }, "originDatasets": [ @@ -5952,12 +7038,20 @@ { "name": "Area OP5 (Frontal Operculum)", "status": "left hemisphere", - "labelIndex": 43, + "labelIndex": 90, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area OP5 (Frontal Operculum)", "gray": "90" + }, + "xml253": { + "_": "Area OP5 (Frontal Operculum)", + "$": { + "num": "89", + "id": "348", + "grayvalue": "90" + } } }, "originDatasets": [ @@ -5982,12 +7076,20 @@ { "name": "Area OP5 (Frontal Operculum)", "status": "right hemisphere", - "labelIndex": 43, + "labelIndex": 90, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area OP5 (Frontal Operculum)", "gray": "91" + }, + "xml253": { + "_": "Area OP5 (Frontal Operculum)", + "$": { + "num": "89", + "id": "348", + "grayvalue": "90" + } } }, "originDatasets": [ @@ -6028,12 +7130,20 @@ { "name": "Area OP9 (Frontal Operculum)", "status": "left hemisphere", - "labelIndex": 117, + "labelIndex": 62, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area OP9 (Frontal Operculum)", "gray": "62" + }, + "xml253": { + "_": "Area OP9 (Frontal Operculum)", + "$": { + "num": "61", + "id": "274", + "grayvalue": "62" + } } }, "originDatasets": [ @@ -6058,12 +7168,20 @@ { "name": "Area OP9 (Frontal Operculum)", "status": "right hemisphere", - "labelIndex": 117, + "labelIndex": 62, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area OP9 (Frontal Operculum)", "gray": "62" + }, + "xml253": { + "_": "Area OP9 (Frontal Operculum)", + "$": { + "num": "61", + "id": "274", + "grayvalue": "62" + } } }, "originDatasets": [ @@ -6104,12 +7222,20 @@ { "name": "Area OP7 (Frontal Operculum)", "status": "left hemisphere", - "labelIndex": 60, + "labelIndex": 45, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area OP7 (Frontal Operculum)", "gray": "45" + }, + "xml253": { + "_": "Area OP7 (Frontal Operculum)", + "$": { + "num": "44", + "id": "350", + "grayvalue": "45" + } } }, "originDatasets": [ @@ -6139,12 +7265,20 @@ { "name": "Area OP7 (Frontal Operculum)", "status": "right hemisphere", - "labelIndex": 60, + "labelIndex": 45, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area OP7 (Frontal Operculum)", "gray": "45" + }, + "xml253": { + "_": "Area OP7 (Frontal Operculum)", + "$": { + "num": "44", + "id": "350", + "grayvalue": "45" + } } }, "originDatasets": [ @@ -6195,12 +7329,20 @@ { "name": "Area Fo6 (OFC)", "status": "left hemisphere", - "labelIndex": 36, + "labelIndex": 113, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Fo6 (OFC)", "gray": "113" + }, + "xml253": { + "_": "Area Fo6 (OFC)", + "$": { + "num": "112", + "id": "326", + "grayvalue": "113" + } } }, "originDatasets": [ @@ -6230,12 +7372,20 @@ { "name": "Area Fo6 (OFC)", "status": "right hemisphere", - "labelIndex": 36, + "labelIndex": 113, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Fo6 (OFC)", "gray": "113" + }, + "xml253": { + "_": "Area Fo6 (OFC)", + "$": { + "num": "112", + "id": "326", + "grayvalue": "113" + } } }, "originDatasets": [ @@ -6281,12 +7431,20 @@ { "name": "Area Fo5 (OFC)", "status": "left hemisphere", - "labelIndex": 76, + "labelIndex": 43, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Fo5 (OFC)", "gray": "42" + }, + "xml253": { + "_": "Area Fo5 (OFC)", + "$": { + "num": "42", + "id": "325", + "grayvalue": "43" + } } }, "originDatasets": [ @@ -6316,12 +7474,20 @@ { "name": "Area Fo5 (OFC)", "status": "right hemisphere", - "labelIndex": 76, + "labelIndex": 43, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Fo5 (OFC)", "gray": "42" + }, + "xml253": { + "_": "Area Fo5 (OFC)", + "$": { + "num": "42", + "id": "325", + "grayvalue": "43" + } } }, "originDatasets": [ @@ -6367,12 +7533,20 @@ { "name": "Area Fo7 (OFC)", "status": "left hemisphere", - "labelIndex": 52, + "labelIndex": 70, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Fo7 (OFC)", "gray": "70" + }, + "xml253": { + "_": "Area Fo7 (OFC)", + "$": { + "num": "69", + "id": "327", + "grayvalue": "70" + } } }, "originDatasets": [ @@ -6402,12 +7576,20 @@ { "name": "Area Fo7 (OFC)", "status": "right hemisphere", - "labelIndex": 52, + "labelIndex": 70, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Fo7 (OFC)", "gray": "70" + }, + "xml253": { + "_": "Area Fo7 (OFC)", + "$": { + "num": "69", + "id": "327", + "grayvalue": "70" + } } }, "originDatasets": [ @@ -6453,12 +7635,20 @@ { "name": "Area Fo4 (OFC)", "status": "left hemisphere", - "labelIndex": 80, + "labelIndex": 10, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Fo4 (OFC)", "gray": "10" + }, + "xml253": { + "_": "Area Fo4 (OFC)", + "$": { + "num": "9", + "id": "324", + "grayvalue": "10" + } } }, "originDatasets": [ @@ -6488,12 +7678,20 @@ { "name": "Area Fo4 (OFC)", "status": "right hemisphere", - "labelIndex": 80, + "labelIndex": 10, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Fo4 (OFC)", "gray": "10" + }, + "xml253": { + "_": "Area Fo4 (OFC)", + "$": { + "num": "9", + "id": "324", + "grayvalue": "10" + } } }, "originDatasets": [ @@ -6549,12 +7747,20 @@ { "name": "Area Ig3 (Insula)", "status": "left hemisphere", - "labelIndex": 105, + "labelIndex": 8, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Ig3 (Insula)", "gray": "8" + }, + "xml253": { + "_": "Area Ig3 (Insula)", + "$": { + "num": "7", + "id": "336", + "grayvalue": "8" + } } }, "originDatasets": [ @@ -6584,12 +7790,20 @@ { "name": "Area Ig3 (Insula)", "status": "right hemisphere", - "labelIndex": 105, + "labelIndex": 8, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Ig3 (Insula)", "gray": "8" + }, + "xml253": { + "_": "Area Ig3 (Insula)", + "$": { + "num": "7", + "id": "336", + "grayvalue": "8" + } } }, "originDatasets": [ @@ -6635,12 +7849,20 @@ { "name": "Area Ig1 (Insula)", "status": "left hemisphere", - "labelIndex": 25, + "labelIndex": 24, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Ig1 (Insula)", "gray": "24" + }, + "xml253": { + "_": "Area Ig1 (Insula)", + "$": { + "num": "23", + "id": "115", + "grayvalue": "24" + } } }, "originDatasets": [ @@ -6670,12 +7892,20 @@ { "name": "Area Ig1 (Insula)", "status": "right hemisphere", - "labelIndex": 25, + "labelIndex": 24, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Ig1 (Insula)", "gray": "24" + }, + "xml253": { + "_": "Area Ig1 (Insula)", + "$": { + "num": "23", + "id": "115", + "grayvalue": "24" + } } }, "originDatasets": [ @@ -6721,12 +7951,20 @@ { "name": "Area Ig2 (Insula)", "status": "left hemisphere", - "labelIndex": 45, + "labelIndex": 50, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Ig2 (Insula)", "gray": "50" + }, + "xml253": { + "_": "Area Ig2 (Insula)", + "$": { + "num": "49", + "id": "114", + "grayvalue": "50" + } } }, "originDatasets": [ @@ -6756,12 +7994,20 @@ { "name": "Area Ig2 (Insula)", "status": "right hemisphere", - "labelIndex": 45, + "labelIndex": 50, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Ig2 (Insula)", "gray": "50" + }, + "xml253": { + "_": "Area Ig2 (Insula)", + "$": { + "num": "49", + "id": "114", + "grayvalue": "50" + } } }, "originDatasets": [ @@ -6812,12 +8058,20 @@ { "name": "Area Ia (Insula)", "status": "left hemisphere", - "labelIndex": 118, + "labelIndex": 81, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Ia (Insula)", "gray": "80" + }, + "xml253": { + "_": "Area Ia (Insula)", + "$": { + "num": "80", + "id": "339", + "grayvalue": "81" + } } }, "originDatasets": [ @@ -6847,12 +8101,20 @@ { "name": "Area Ia (Insula)", "status": "right hemisphere", - "labelIndex": 118, + "labelIndex": 81, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Ia (Insula)", "gray": "80" + }, + "xml253": { + "_": "Area Ia (Insula)", + "$": { + "num": "80", + "id": "339", + "grayvalue": "81" + } } }, "originDatasets": [ @@ -6903,12 +8165,20 @@ { "name": "Area Id7 (Insula)", "status": "left hemisphere", - "labelIndex": 18, + "labelIndex": 107, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Id7 (Insula)", "gray": "107" + }, + "xml253": { + "_": "Area Id7 (Insula)", + "$": { + "num": "106", + "id": "159", + "grayvalue": "107" + } } }, "originDatasets": [ @@ -6938,12 +8208,20 @@ { "name": "Area Id7 (Insula)", "status": "right hemisphere", - "labelIndex": 18, + "labelIndex": 106, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Id7 (Insula)", "gray": "106" + }, + "xml253": { + "_": "Area Id7 (Insula)", + "$": { + "num": "105", + "id": "159", + "grayvalue": "106" + } } }, "originDatasets": [ @@ -6994,12 +8272,20 @@ { "name": "Area Id2 (Insula)", "status": "left hemisphere", - "labelIndex": 99, + "labelIndex": 55, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Id2 (Insula)", "gray": "55" + }, + "xml253": { + "_": "Area Id2 (Insula)", + "$": { + "num": "54", + "id": "56", + "grayvalue": "55" + } } }, "originDatasets": [ @@ -7029,12 +8315,20 @@ { "name": "Area Id2 (Insula)", "status": "right hemisphere", - "labelIndex": 99, + "labelIndex": 54, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Id2 (Insula)", "gray": "55" + }, + "xml253": { + "_": "Area Id2 (Insula)", + "$": { + "num": "53", + "id": "56", + "grayvalue": "54" + } } }, "originDatasets": [ @@ -7080,12 +8374,20 @@ { "name": "Area Id1 (Insula)", "status": "left hemisphere", - "labelIndex": 78, + "labelIndex": 72, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Id1 (Insula)", "gray": "72" + }, + "xml253": { + "_": "Area Id1 (Insula)", + "$": { + "num": "71", + "id": "116", + "grayvalue": "72" + } } }, "originDatasets": [ @@ -7115,12 +8417,20 @@ { "name": "Area Id1 (Insula)", "status": "right hemisphere", - "labelIndex": 78, + "labelIndex": 72, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Id1 (Insula)", "gray": "72" + }, + "xml253": { + "_": "Area Id1 (Insula)", + "$": { + "num": "71", + "id": "116", + "grayvalue": "72" + } } }, "originDatasets": [ @@ -7166,12 +8476,20 @@ { "name": "Area Id5 (Insula)", "status": "left hemisphere", - "labelIndex": 104, + "labelIndex": 74, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Id5 (Insula)", "gray": "75" + }, + "xml253": { + "_": "Area Id5 (Insula)", + "$": { + "num": "73", + "id": "338", + "grayvalue": "74" + } } }, "originDatasets": [ @@ -7201,12 +8519,20 @@ { "name": "Area Id5 (Insula)", "status": "right hemisphere", - "labelIndex": 104, + "labelIndex": 75, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Id5 (Insula)", "gray": "75" + }, + "xml253": { + "_": "Area Id5 (Insula)", + "$": { + "num": "74", + "id": "338", + "grayvalue": "75" + } } }, "originDatasets": [ @@ -7252,12 +8578,20 @@ { "name": "Area Id6 (Insula)", "status": "left hemisphere", - "labelIndex": 11, + "labelIndex": 58, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Id6 (Insula)", "gray": "58" + }, + "xml253": { + "_": "Area Id6 (Insula)", + "$": { + "num": "57", + "id": "340", + "grayvalue": "58" + } } }, "originDatasets": [ @@ -7287,12 +8621,20 @@ { "name": "Area Id6 (Insula)", "status": "right hemisphere", - "labelIndex": 11, + "labelIndex": 58, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Id6 (Insula)", "gray": "58" + }, + "xml253": { + "_": "Area Id6 (Insula)", + "$": { + "num": "57", + "id": "340", + "grayvalue": "58" + } } }, "originDatasets": [ @@ -7338,12 +8680,20 @@ { "name": "Area Id4 (Insula)", "status": "left hemisphere", - "labelIndex": 53, + "labelIndex": 54, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Id4 (Insula)", "gray": "54" + }, + "xml253": { + "_": "Area Id4 (Insula)", + "$": { + "num": "53", + "id": "337", + "grayvalue": "54" + } } }, "originDatasets": [ @@ -7373,12 +8723,20 @@ { "name": "Area Id4 (Insula)", "status": "right hemisphere", - "labelIndex": 53, + "labelIndex": 55, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Id4 (Insula)", "gray": "54" + }, + "xml253": { + "_": "Area Id4 (Insula)", + "$": { + "num": "54", + "id": "337", + "grayvalue": "55" + } } }, "originDatasets": [ @@ -7424,12 +8782,20 @@ { "name": "Area Id3 (Insula)", "status": "left hemisphere", - "labelIndex": 54, + "labelIndex": 20, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Id3 (Insula)", "gray": "20" + }, + "xml253": { + "_": "Area Id3 (Insula)", + "$": { + "num": "19", + "id": "57", + "grayvalue": "20" + } } }, "originDatasets": [ @@ -7459,12 +8825,20 @@ { "name": "Area Id3 (Insula)", "status": "right hemisphere", - "labelIndex": 54, + "labelIndex": 20, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area Id3 (Insula)", "gray": "21" + }, + "xml253": { + "_": "Area Id3 (Insula)", + "$": { + "num": "19", + "id": "57", + "grayvalue": "20" + } } }, "originDatasets": [ @@ -7520,12 +8894,20 @@ { "name": "Area STS2 (STS)", "status": "left hemisphere", - "labelIndex": 98, + "labelIndex": 19, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area STS2 (STS)", "gray": "19" + }, + "xml253": { + "_": "Area STS2 (STS)", + "$": { + "num": "18", + "id": "272", + "grayvalue": "19" + } } }, "originDatasets": [ @@ -7555,12 +8937,20 @@ { "name": "Area STS2 (STS)", "status": "right hemisphere", - "labelIndex": 98, + "labelIndex": 19, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area STS2 (STS)", "gray": "19" + }, + "xml253": { + "_": "Area STS2 (STS)", + "$": { + "num": "18", + "id": "272", + "grayvalue": "19" + } } }, "originDatasets": [ @@ -7606,12 +8996,20 @@ { "name": "Area STS1 (STS)", "status": "left hemisphere", - "labelIndex": 114, + "labelIndex": 96, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area STS1 (STS)", "gray": "96" + }, + "xml253": { + "_": "Area STS1 (STS)", + "$": { + "num": "95", + "id": "271", + "grayvalue": "96" + } } }, "originDatasets": [ @@ -7641,12 +9039,20 @@ { "name": "Area STS1 (STS)", "status": "right hemisphere", - "labelIndex": 114, + "labelIndex": 95, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area STS1 (STS)", "gray": "95" + }, + "xml253": { + "_": "Area STS1 (STS)", + "$": { + "num": "94", + "id": "271", + "grayvalue": "95" + } } }, "originDatasets": [ @@ -7697,12 +9103,20 @@ { "name": "Area TE 3 (STG)", "status": "left hemisphere", - "labelIndex": 15, + "labelIndex": 31, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area TE 3 (STG)", "gray": "31" + }, + "xml253": { + "_": "Area TE 3 (STG)", + "$": { + "num": "30", + "id": "31", + "grayvalue": "31" + } } }, "originDatasets": [ @@ -7732,12 +9146,20 @@ { "name": "Area TE 3 (STG)", "status": "right hemisphere", - "labelIndex": 15, + "labelIndex": 31, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area TE 3 (STG)", "gray": "31" + }, + "xml253": { + "_": "Area TE 3 (STG)", + "$": { + "num": "30", + "id": "31", + "grayvalue": "31" + } } }, "originDatasets": [ @@ -7783,12 +9205,20 @@ { "name": "Area TE 2.2 (STG)", "status": "left hemisphere", - "labelIndex": 93, + "labelIndex": 120, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area TE 2.2 (STG)", "gray": "119" + }, + "xml253": { + "_": "Area TE 2.2 (STG)", + "$": { + "num": "119", + "id": "34", + "grayvalue": "120" + } } }, "originDatasets": [ @@ -7818,12 +9248,20 @@ { "name": "Area TE 2.2 (STG)", "status": "right hemisphere", - "labelIndex": 93, + "labelIndex": 120, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area TE 2.2 (STG)", "gray": "119" + }, + "xml253": { + "_": "Area TE 2.2 (STG)", + "$": { + "num": "119", + "id": "34", + "grayvalue": "120" + } } }, "originDatasets": [ @@ -7869,12 +9307,20 @@ { "name": "Area TE 2.1 (STG)", "status": "left hemisphere", - "labelIndex": 19, + "labelIndex": 80, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area TE 2.1 (STG)", "gray": "82" + }, + "xml253": { + "_": "Area TE 2.1 (STG)", + "$": { + "num": "79", + "id": "28", + "grayvalue": "80" + } } }, "originDatasets": [ @@ -7904,12 +9350,20 @@ { "name": "Area TE 2.1 (STG)", "status": "right hemisphere", - "labelIndex": 19, + "labelIndex": 80, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area TE 2.1 (STG)", "gray": "81" + }, + "xml253": { + "_": "Area TE 2.1 (STG)", + "$": { + "num": "79", + "id": "28", + "grayvalue": "80" + } } }, "originDatasets": [ @@ -7960,12 +9414,20 @@ { "name": "Area TI (STG)", "status": "left hemisphere", - "labelIndex": 13, + "labelIndex": 26, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area TI (STG)", "gray": "26" + }, + "xml253": { + "_": "Area TI (STG)", + "$": { + "num": "25", + "id": "243", + "grayvalue": "26" + } } }, "originDatasets": [ @@ -7995,12 +9457,20 @@ { "name": "Area TI (STG)", "status": "right hemisphere", - "labelIndex": 13, + "labelIndex": 26, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area TI (STG)", "gray": "26" + }, + "xml253": { + "_": "Area TI (STG)", + "$": { + "num": "25", + "id": "243", + "grayvalue": "26" + } } }, "originDatasets": [ @@ -8046,12 +9516,20 @@ { "name": "Area TeI (STG)", "status": "left hemisphere", - "labelIndex": 79, + "labelIndex": 123, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area TeI (STG)", "gray": "124" + }, + "xml253": { + "_": "Area TeI (STG)", + "$": { + "num": "122", + "id": "242", + "grayvalue": "123" + } } }, "originDatasets": [ @@ -8081,12 +9559,20 @@ { "name": "Area TeI (STG)", "status": "right hemisphere", - "labelIndex": 79, + "labelIndex": 124, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area TeI (STG)", "gray": "124" + }, + "xml253": { + "_": "Area TeI (STG)", + "$": { + "num": "123", + "id": "242", + "grayvalue": "124" + } } }, "originDatasets": [ @@ -8137,12 +9623,20 @@ { "name": "Area TE 1.2 (HESCHL)", "status": "left hemisphere", - "labelIndex": 86, + "labelIndex": 75, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area TE 1.2 (HESCHL)", "gray": "74" + }, + "xml253": { + "_": "Area TE 1.2 (HESCHL)", + "$": { + "num": "74", + "id": "30", + "grayvalue": "75" + } } }, "originDatasets": [ @@ -8172,12 +9666,20 @@ { "name": "Area TE 1.2 (HESCHL)", "status": "right hemisphere", - "labelIndex": 86, + "labelIndex": 74, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area TE 1.2 (HESCHL)", "gray": "74" + }, + "xml253": { + "_": "Area TE 1.2 (HESCHL)", + "$": { + "num": "73", + "id": "30", + "grayvalue": "74" + } } }, "originDatasets": [ @@ -8223,12 +9725,20 @@ { "name": "Area TE 1.1 (HESCHL)", "status": "left hemisphere", - "labelIndex": 39, + "labelIndex": 1, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area TE 1.1 (HESCHL)", "gray": "1" + }, + "xml253": { + "_": "Area TE 1.1 (HESCHL)", + "$": { + "num": "0", + "id": "33", + "grayvalue": "1" + } } }, "originDatasets": [ @@ -8258,12 +9768,20 @@ { "name": "Area TE 1.1 (HESCHL)", "status": "right hemisphere", - "labelIndex": 39, + "labelIndex": 1, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area TE 1.1 (HESCHL)", "gray": "1" + }, + "xml253": { + "_": "Area TE 1.1 (HESCHL)", + "$": { + "num": "0", + "id": "33", + "grayvalue": "1" + } } }, "originDatasets": [ @@ -8309,12 +9827,20 @@ { "name": "Area TE 1.0 (HESCHL)", "status": "left hemisphere", - "labelIndex": 34, + "labelIndex": 18, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area TE 1.0 (HESCHL)", "gray": "18" + }, + "xml253": { + "_": "Area TE 1.0 (HESCHL)", + "$": { + "num": "17", + "id": "27", + "grayvalue": "18" + } } }, "originDatasets": [ @@ -8344,12 +9870,20 @@ { "name": "Area TE 1.0 (HESCHL)", "status": "right hemisphere", - "labelIndex": 34, + "labelIndex": 17, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area TE 1.0 (HESCHL)", "gray": "18" + }, + "xml253": { + "_": "Area TE 1.0 (HESCHL)", + "$": { + "num": "16", + "id": "27", + "grayvalue": "17" + } } }, "originDatasets": [ @@ -8400,12 +9934,20 @@ { "name": "Area FG2 (FusG)", "status": "left hemisphere", - "labelIndex": 28, + "labelIndex": 40, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area FG2 (FusG)", "gray": "40" + }, + "xml253": { + "_": "Area FG2 (FusG)", + "$": { + "num": "39", + "id": "106", + "grayvalue": "40" + } } }, "originDatasets": [ @@ -8435,12 +9977,20 @@ { "name": "Area FG2 (FusG)", "status": "right hemisphere", - "labelIndex": 28, + "labelIndex": 40, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area FG2 (FusG)", "gray": "40" + }, + "xml253": { + "_": "Area FG2 (FusG)", + "$": { + "num": "39", + "id": "106", + "grayvalue": "40" + } } }, "originDatasets": [ @@ -8486,12 +10036,20 @@ { "name": "Area FG3 (FusG)", "status": "left hemisphere", - "labelIndex": 42, + "labelIndex": 100, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area FG3 (FusG)", "gray": "99" + }, + "xml253": { + "_": "Area FG3 (FusG)", + "$": { + "num": "99", + "id": "239", + "grayvalue": "100" + } } }, "originDatasets": [ @@ -8521,12 +10079,20 @@ { "name": "Area FG3 (FusG)", "status": "right hemisphere", - "labelIndex": 42, + "labelIndex": 99, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area FG3 (FusG)", "gray": "99" + }, + "xml253": { + "_": "Area FG3 (FusG)", + "$": { + "num": "98", + "id": "239", + "grayvalue": "99" + } } }, "originDatasets": [ @@ -8572,12 +10138,20 @@ { "name": "Area FG1 (FusG)", "status": "left hemisphere", - "labelIndex": 84, + "labelIndex": 37, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area FG1 (FusG)", "gray": "37" + }, + "xml253": { + "_": "Area FG1 (FusG)", + "$": { + "num": "36", + "id": "107", + "grayvalue": "37" + } } }, "originDatasets": [ @@ -8607,12 +10181,20 @@ { "name": "Area FG1 (FusG)", "status": "right hemisphere", - "labelIndex": 84, + "labelIndex": 37, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area FG1 (FusG)", "gray": "37" + }, + "xml253": { + "_": "Area FG1 (FusG)", + "$": { + "num": "36", + "id": "107", + "grayvalue": "37" + } } }, "originDatasets": [ @@ -8658,12 +10240,20 @@ { "name": "Area FG4 (FusG)", "status": "left hemisphere", - "labelIndex": 55, + "labelIndex": 108, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area FG4 (FusG)", "gray": "108" + }, + "xml253": { + "_": "Area FG4 (FusG)", + "$": { + "num": "107", + "id": "238", + "grayvalue": "108" + } } }, "originDatasets": [ @@ -8693,12 +10283,20 @@ { "name": "Area FG4 (FusG)", "status": "right hemisphere", - "labelIndex": 55, + "labelIndex": 108, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area FG4 (FusG)", "gray": "108" + }, + "xml253": { + "_": "Area FG4 (FusG)", + "$": { + "num": "107", + "id": "238", + "grayvalue": "108" + } } }, "originDatasets": [ @@ -8754,12 +10352,20 @@ { "name": "Frontal-to-Occipital (GapMap)", "status": "left hemisphere", - "labelIndex": 33, + "labelIndex": 32, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Frontal-to-Occipital (GapMap)", "gray": "33" + }, + "xml253": { + "_": "Frontal-to-Occipital (GapMap)", + "$": { + "num": "31", + "id": "504", + "grayvalue": "32" + } } }, "originDatasets": [ @@ -8790,6 +10396,14 @@ "xml": { "name": "Frontal-to-Occipital (GapMap)", "gray": "33" + }, + "xml253": { + "_": "Frontal-to-Occipital (GapMap)", + "$": { + "num": "32", + "id": "504", + "grayvalue": "33" + } } }, "originDatasets": [ @@ -8830,12 +10444,20 @@ { "name": "Temporal-to-Parietal (GapMap)", "status": "left hemisphere", - "labelIndex": 2, + "labelIndex": 64, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Temporal-to-Parietal (GapMap)", "gray": "64" + }, + "xml253": { + "_": "Temporal-to-Parietal (GapMap)", + "$": { + "num": "63", + "id": "503", + "grayvalue": "64" + } } }, "originDatasets": [ @@ -8860,12 +10482,20 @@ { "name": "Temporal-to-Parietal (GapMap)", "status": "right hemisphere", - "labelIndex": 2, + "labelIndex": 64, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Temporal-to-Parietal (GapMap)", "gray": "64" + }, + "xml253": { + "_": "Temporal-to-Parietal (GapMap)", + "$": { + "num": "63", + "id": "503", + "grayvalue": "64" + } } }, "originDatasets": [ @@ -8906,12 +10536,20 @@ { "name": "Frontal-I (GapMap)", "status": "left hemisphere", - "labelIndex": 71, + "labelIndex": 14, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Frontal-I (GapMap)", "gray": "14" + }, + "xml253": { + "_": "Frontal-I (GapMap)", + "$": { + "num": "13", + "id": "500", + "grayvalue": "14" + } } }, "originDatasets": [ @@ -8936,12 +10574,20 @@ { "name": "Frontal-I (GapMap)", "status": "right hemisphere", - "labelIndex": 71, + "labelIndex": 14, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Frontal-I (GapMap)", "gray": "14" + }, + "xml253": { + "_": "Frontal-I (GapMap)", + "$": { + "num": "13", + "id": "500", + "grayvalue": "14" + } } }, "originDatasets": [ @@ -8982,12 +10628,20 @@ { "name": "Frontal-to-Temporal (GapMap)", "status": "left hemisphere", - "labelIndex": 110, + "labelIndex": 99, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Frontal-to-Temporal (GapMap)", "gray": "100" + }, + "xml253": { + "_": "Frontal-to-Temporal (GapMap)", + "$": { + "num": "98", + "id": "502", + "grayvalue": "99" + } } }, "originDatasets": [ @@ -9012,12 +10666,20 @@ { "name": "Frontal-to-Temporal (GapMap)", "status": "right hemisphere", - "labelIndex": 110, + "labelIndex": 100, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Frontal-to-Temporal (GapMap)", "gray": "100" + }, + "xml253": { + "_": "Frontal-to-Temporal (GapMap)", + "$": { + "num": "99", + "id": "502", + "grayvalue": "100" + } } }, "originDatasets": [ @@ -9058,12 +10720,20 @@ { "name": "Frontal-II (GapMap)", "status": "left hemisphere", - "labelIndex": 27, + "labelIndex": 93, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Frontal-II (GapMap)", "gray": "93" + }, + "xml253": { + "_": "Frontal-II (GapMap)", + "$": { + "num": "92", + "id": "501", + "grayvalue": "93" + } } }, "originDatasets": [ @@ -9088,12 +10758,20 @@ { "name": "Frontal-II (GapMap)", "status": "right hemisphere", - "labelIndex": 27, + "labelIndex": 93, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Frontal-II (GapMap)", "gray": "93" + }, + "xml253": { + "_": "Frontal-II (GapMap)", + "$": { + "num": "92", + "id": "501", + "grayvalue": "93" + } } }, "originDatasets": [ @@ -9144,12 +10822,20 @@ { "name": "Area p24c (pACC)", "status": "left hemisphere", - "labelIndex": 57, + "labelIndex": 29, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area p24c (pACC)", "gray": "29" + }, + "xml253": { + "_": "Area p24c (pACC)", + "$": { + "num": "28", + "id": "232", + "grayvalue": "29" + } } }, "originDatasets": [ @@ -9179,12 +10865,20 @@ { "name": "Area p24c (pACC)", "status": "right hemisphere", - "labelIndex": 57, + "labelIndex": 29, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area p24c (pACC)", "gray": "29" + }, + "xml253": { + "_": "Area p24c (pACC)", + "$": { + "num": "28", + "id": "232", + "grayvalue": "29" + } } }, "originDatasets": [ @@ -9230,12 +10924,20 @@ { "name": "Area 25 (sACC)", "status": "left hemisphere", - "labelIndex": 3, + "labelIndex": 88, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 25 (sACC)", "gray": "88" + }, + "xml253": { + "_": "Area 25 (sACC)", + "$": { + "num": "87", + "id": "184", + "grayvalue": "88" + } } }, "originDatasets": [ @@ -9265,12 +10967,20 @@ { "name": "Area 25 (sACC)", "status": "right hemisphere", - "labelIndex": 3, + "labelIndex": 89, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 25 (sACC)", "gray": "88" + }, + "xml253": { + "_": "Area 25 (sACC)", + "$": { + "num": "88", + "id": "184", + "grayvalue": "89" + } } }, "originDatasets": [ @@ -9316,12 +11026,20 @@ { "name": "Area p24ab (pACC)", "status": "left hemisphere", - "labelIndex": 63, + "labelIndex": 28, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area p24ab (pACC)", "gray": "28" + }, + "xml253": { + "_": "Area p24ab (pACC)", + "$": { + "num": "27", + "id": "231", + "grayvalue": "28" + } } }, "originDatasets": [ @@ -9351,12 +11069,20 @@ { "name": "Area p24ab (pACC)", "status": "right hemisphere", - "labelIndex": 63, + "labelIndex": 27, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area p24ab (pACC)", "gray": "28" + }, + "xml253": { + "_": "Area p24ab (pACC)", + "$": { + "num": "26", + "id": "231", + "grayvalue": "27" + } } }, "originDatasets": [ @@ -9402,12 +11128,20 @@ { "name": "Area s32 (sACC)", "status": "left hemisphere", - "labelIndex": 74, + "labelIndex": 103, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area s32 (sACC)", "gray": "102" + }, + "xml253": { + "_": "Area s32 (sACC)", + "$": { + "num": "102", + "id": "46", + "grayvalue": "103" + } } }, "originDatasets": [ @@ -9437,12 +11171,20 @@ { "name": "Area s32 (sACC)", "status": "right hemisphere", - "labelIndex": 74, + "labelIndex": 103, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area s32 (sACC)", "gray": "103" + }, + "xml253": { + "_": "Area s32 (sACC)", + "$": { + "num": "102", + "id": "46", + "grayvalue": "103" + } } }, "originDatasets": [ @@ -9488,12 +11230,20 @@ { "name": "Area 33 (ACC)", "status": "left hemisphere", - "labelIndex": 96, + "labelIndex": 47, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 33 (ACC)", "gray": "47" + }, + "xml253": { + "_": "Area 33 (ACC)", + "$": { + "num": "46", + "id": "39", + "grayvalue": "47" + } } }, "originDatasets": [ @@ -9523,12 +11273,20 @@ { "name": "Area 33 (ACC)", "status": "right hemisphere", - "labelIndex": 96, + "labelIndex": 47, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area 33 (ACC)", "gray": "47" + }, + "xml253": { + "_": "Area 33 (ACC)", + "$": { + "num": "46", + "id": "39", + "grayvalue": "47" + } } }, "originDatasets": [ @@ -9574,12 +11332,20 @@ { "name": "Area p32 (pACC)", "status": "left hemisphere", - "labelIndex": 113, + "labelIndex": 116, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area p32 (pACC)", "gray": "116" + }, + "xml253": { + "_": "Area p32 (pACC)", + "$": { + "num": "115", + "id": "47", + "grayvalue": "116" + } } }, "originDatasets": [ @@ -9609,12 +11375,20 @@ { "name": "Area p32 (pACC)", "status": "right hemisphere", - "labelIndex": 113, + "labelIndex": 116, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area p32 (pACC)", "gray": "116" + }, + "xml253": { + "_": "Area p32 (pACC)", + "$": { + "num": "115", + "id": "47", + "grayvalue": "116" + } } }, "originDatasets": [ @@ -9660,12 +11434,20 @@ { "name": "Area s24 (sACC)", "status": "left hemisphere", - "labelIndex": 73, + "labelIndex": 112, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area s24 (sACC)", "gray": "112" + }, + "xml253": { + "_": "Area s24 (sACC)", + "$": { + "num": "111", + "id": "183", + "grayvalue": "112" + } } }, "originDatasets": [ @@ -9695,12 +11477,20 @@ { "name": "Area s24 (sACC)", "status": "right hemisphere", - "labelIndex": 73, + "labelIndex": 112, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Area s24 (sACC)", "gray": "112" + }, + "xml253": { + "_": "Area s24 (sACC)", + "$": { + "num": "111", + "id": "183", + "grayvalue": "112" + } } }, "originDatasets": [ @@ -9751,12 +11541,20 @@ { "name": "HC-Presubiculum (Hippocampus)", "status": "left hemisphere", - "labelIndex": 87, + "labelIndex": 3, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "HC-Presubiculum (Hippocampus)", "gray": "3" + }, + "xml253": { + "_": "HC-Presubiculum (Hippocampus)", + "$": { + "num": "2", + "id": "63", + "grayvalue": "3" + } } }, "originDatasets": [ @@ -9780,12 +11578,20 @@ { "name": "HC-Presubiculum (Hippocampus)", "status": "right hemisphere", - "labelIndex": 87, + "labelIndex": 3, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "HC-Presubiculum (Hippocampus)", "gray": "3" + }, + "xml253": { + "_": "HC-Presubiculum (Hippocampus)", + "$": { + "num": "2", + "id": "63", + "grayvalue": "3" + } } }, "originDatasets": [ @@ -9825,12 +11631,20 @@ { "name": "HATA (Hippocampus)", "status": "left hemisphere", - "labelIndex": 56, + "labelIndex": 67, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "HATA (Hippocampus)", "gray": "67" + }, + "xml253": { + "_": "HATA (Hippocampus)", + "$": { + "num": "66", + "id": "68", + "grayvalue": "67" + } } }, "originDatasets": [ @@ -9860,12 +11674,20 @@ { "name": "HATA (Hippocampus)", "status": "right hemisphere", - "labelIndex": 56, + "labelIndex": 67, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "HATA (Hippocampus)", "gray": "67" + }, + "xml253": { + "_": "HATA (Hippocampus)", + "$": { + "num": "66", + "id": "68", + "grayvalue": "67" + } } }, "originDatasets": [ @@ -9911,12 +11733,20 @@ { "name": "Entorhinal Cortex", "status": "left hemisphere", - "labelIndex": 64, + "labelIndex": 53, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Entorhinal Cortex", "gray": "53" + }, + "xml253": { + "_": "Entorhinal Cortex", + "$": { + "num": "52", + "id": "60", + "grayvalue": "53" + } } }, "originDatasets": [ @@ -9946,12 +11776,20 @@ { "name": "Entorhinal Cortex", "status": "right hemisphere", - "labelIndex": 64, + "labelIndex": 53, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Entorhinal Cortex", "gray": "53" + }, + "xml253": { + "_": "Entorhinal Cortex", + "$": { + "num": "52", + "id": "60", + "grayvalue": "53" + } } }, "originDatasets": [ @@ -9997,12 +11835,20 @@ { "name": "CA3 (Hippocampus)", "status": "left hemisphere", - "labelIndex": 119, + "labelIndex": 91, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "CA3 (Hippocampus)", "gray": "91" + }, + "xml253": { + "_": "CA3 (Hippocampus)", + "$": { + "num": "90", + "id": "59", + "grayvalue": "91" + } } }, "originDatasets": [ @@ -10032,12 +11878,20 @@ { "name": "CA3 (Hippocampus)", "status": "right hemisphere", - "labelIndex": 119, + "labelIndex": 92, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "CA3 (Hippocampus)", "gray": "90" + }, + "xml253": { + "_": "CA3 (Hippocampus)", + "$": { + "num": "91", + "id": "59", + "grayvalue": "92" + } } }, "originDatasets": [ @@ -10083,12 +11937,20 @@ { "name": "HC-Transsubiculum (Hippocampus)", "status": "left hemisphere", - "labelIndex": 66, + "labelIndex": 87, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "HC-Transsubiculum (Hippocampus)", "gray": "87" + }, + "xml253": { + "_": "HC-Transsubiculum (Hippocampus)", + "$": { + "num": "86", + "id": "305", + "grayvalue": "87" + } } }, "originDatasets": [ @@ -10112,12 +11974,20 @@ { "name": "HC-Transsubiculum (Hippocampus)", "status": "right hemisphere", - "labelIndex": 66, + "labelIndex": 87, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "HC-Transsubiculum (Hippocampus)", "gray": "87" + }, + "xml253": { + "_": "HC-Transsubiculum (Hippocampus)", + "$": { + "num": "86", + "id": "305", + "grayvalue": "87" + } } }, "originDatasets": [ @@ -10157,12 +12027,20 @@ { "name": "HC-Subiculum (Hippocampus)", "status": "left hemisphere", - "labelIndex": 10, + "labelIndex": 63, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "HC-Subiculum (Hippocampus)", "gray": "63" + }, + "xml253": { + "_": "HC-Subiculum (Hippocampus)", + "$": { + "num": "62", + "id": "67", + "grayvalue": "63" + } } }, "originDatasets": [ @@ -10186,12 +12064,20 @@ { "name": "HC-Subiculum (Hippocampus)", "status": "right hemisphere", - "labelIndex": 10, + "labelIndex": 63, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "HC-Subiculum (Hippocampus)", "gray": "63" + }, + "xml253": { + "_": "HC-Subiculum (Hippocampus)", + "$": { + "num": "62", + "id": "67", + "grayvalue": "63" + } } }, "originDatasets": [ @@ -10231,12 +12117,20 @@ { "name": "HC-Prosubiculum (Hippocampus)", "status": "left hemisphere", - "labelIndex": 6, + "labelIndex": 49, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "HC-Prosubiculum (Hippocampus)", "gray": "48" + }, + "xml253": { + "_": "HC-Prosubiculum (Hippocampus)", + "$": { + "num": "48", + "id": "64", + "grayvalue": "49" + } } }, "originDatasets": [ @@ -10260,12 +12154,20 @@ { "name": "HC-Prosubiculum (Hippocampus)", "status": "right hemisphere", - "labelIndex": 6, + "labelIndex": 48, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "HC-Prosubiculum (Hippocampus)", "gray": "48" + }, + "xml253": { + "_": "HC-Prosubiculum (Hippocampus)", + "$": { + "num": "47", + "id": "64", + "grayvalue": "48" + } } }, "originDatasets": [ @@ -10305,12 +12207,20 @@ { "name": "HC-Parasubiculum (Hippocampus)", "status": "left hemisphere", - "labelIndex": 8, + "labelIndex": 60, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "HC-Parasubiculum (Hippocampus)", "gray": "59" + }, + "xml253": { + "_": "HC-Parasubiculum (Hippocampus)", + "$": { + "num": "59", + "id": "62", + "grayvalue": "60" + } } }, "originDatasets": [ @@ -10334,12 +12244,20 @@ { "name": "HC-Parasubiculum (Hippocampus)", "status": "right hemisphere", - "labelIndex": 8, + "labelIndex": 59, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "HC-Parasubiculum (Hippocampus)", "gray": "59" + }, + "xml253": { + "_": "HC-Parasubiculum (Hippocampus)", + "$": { + "num": "58", + "id": "62", + "grayvalue": "59" + } } }, "originDatasets": [ @@ -10379,12 +12297,20 @@ { "name": "DG (Hippocampus)", "status": "left hemisphere", - "labelIndex": 91, + "labelIndex": 22, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "DG (Hippocampus)", "gray": "22" + }, + "xml253": { + "_": "DG (Hippocampus)", + "$": { + "num": "21", + "id": "61", + "grayvalue": "22" + } } }, "originDatasets": [ @@ -10414,12 +12340,20 @@ { "name": "DG (Hippocampus)", "status": "right hemisphere", - "labelIndex": 91, + "labelIndex": 22, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "DG (Hippocampus)", "gray": "22" + }, + "xml253": { + "_": "DG (Hippocampus)", + "$": { + "num": "21", + "id": "61", + "grayvalue": "22" + } } }, "originDatasets": [ @@ -10465,12 +12399,20 @@ { "name": "CA2 (Hippocampus)", "status": "left hemisphere", - "labelIndex": 23, + "labelIndex": 51, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "CA2 (Hippocampus)", "gray": "51" + }, + "xml253": { + "_": "CA2 (Hippocampus)", + "$": { + "num": "50", + "id": "58", + "grayvalue": "51" + } } }, "originDatasets": [ @@ -10500,12 +12442,20 @@ { "name": "CA2 (Hippocampus)", "status": "right hemisphere", - "labelIndex": 23, + "labelIndex": 51, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "CA2 (Hippocampus)", "gray": "51" + }, + "xml253": { + "_": "CA2 (Hippocampus)", + "$": { + "num": "50", + "id": "58", + "grayvalue": "51" + } } }, "originDatasets": [ @@ -10551,12 +12501,20 @@ { "name": "CA1 (Hippocampus)", "status": "left hemisphere", - "labelIndex": 61, + "labelIndex": 56, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "CA1 (Hippocampus)", "gray": "57" + }, + "xml253": { + "_": "CA1 (Hippocampus)", + "$": { + "num": "55", + "id": "66", + "grayvalue": "56" + } } }, "originDatasets": [ @@ -10586,12 +12544,20 @@ { "name": "CA1 (Hippocampus)", "status": "right hemisphere", - "labelIndex": 61, + "labelIndex": 57, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "CA1 (Hippocampus)", "gray": "56" + }, + "xml253": { + "_": "CA1 (Hippocampus)", + "$": { + "num": "56", + "id": "66", + "grayvalue": "57" + } } }, "originDatasets": [ @@ -10657,12 +12623,20 @@ { "name": "Interposed Nucleus (Cerebellum)", "status": "left hemisphere", - "labelIndex": 30, + "labelIndex": 109, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Interposed Nucleus (Cerebellum)", "gray": "109" + }, + "xml253": { + "_": "Interposed Nucleus (Cerebellum)", + "$": { + "num": "108", + "id": "251", + "grayvalue": "109" + } } }, "originDatasets": [ @@ -10692,12 +12666,20 @@ { "name": "Interposed Nucleus (Cerebellum)", "status": "right hemisphere", - "labelIndex": 30, + "labelIndex": 109, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Interposed Nucleus (Cerebellum)", "gray": "109" + }, + "xml253": { + "_": "Interposed Nucleus (Cerebellum)", + "$": { + "num": "108", + "id": "251", + "grayvalue": "109" + } } }, "originDatasets": [ @@ -10748,12 +12730,20 @@ { "name": "Dorsal Dentate Nucleus (Cerebellum)", "status": "left hemisphere", - "labelIndex": 111, + "labelIndex": 16, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Dorsal Dentate Nucleus (Cerebellum)", "gray": "16" + }, + "xml253": { + "_": "Dorsal Dentate Nucleus (Cerebellum)", + "$": { + "num": "15", + "id": "240", + "grayvalue": "16" + } } }, "originDatasets": [ @@ -10783,12 +12773,20 @@ { "name": "Dorsal Dentate Nucleus (Cerebellum)", "status": "right hemisphere", - "labelIndex": 111, + "labelIndex": 18, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Dorsal Dentate Nucleus (Cerebellum)", "gray": "16" + }, + "xml253": { + "_": "Dorsal Dentate Nucleus (Cerebellum)", + "$": { + "num": "17", + "id": "240", + "grayvalue": "18" + } } }, "originDatasets": [ @@ -10834,12 +12832,20 @@ { "name": "Ventral Dentate Nucleus (Cerebellum)", "status": "left hemisphere", - "labelIndex": 38, + "labelIndex": 66, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Ventral Dentate Nucleus (Cerebellum)", "gray": "65" + }, + "xml253": { + "_": "Ventral Dentate Nucleus (Cerebellum)", + "$": { + "num": "65", + "id": "241", + "grayvalue": "66" + } } }, "originDatasets": [ @@ -10869,12 +12875,20 @@ { "name": "Ventral Dentate Nucleus (Cerebellum)", "status": "right hemisphere", - "labelIndex": 38, + "labelIndex": 65, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Ventral Dentate Nucleus (Cerebellum)", "gray": "65" + }, + "xml253": { + "_": "Ventral Dentate Nucleus (Cerebellum)", + "$": { + "num": "64", + "id": "241", + "grayvalue": "65" + } } }, "originDatasets": [ @@ -10925,12 +12939,20 @@ { "name": "Fastigial Nucleus (Cerebellum)", "status": "left hemisphere", - "labelIndex": 89, + "labelIndex": 102, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Fastigial Nucleus (Cerebellum)", "gray": "103" + }, + "xml253": { + "_": "Fastigial Nucleus (Cerebellum)", + "$": { + "num": "101", + "id": "219", + "grayvalue": "102" + } } }, "originDatasets": [ @@ -10960,12 +12982,20 @@ { "name": "Fastigial Nucleus (Cerebellum)", "status": "right hemisphere", - "labelIndex": 89, + "labelIndex": 102, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Fastigial Nucleus (Cerebellum)", "gray": "102" + }, + "xml253": { + "_": "Fastigial Nucleus (Cerebellum)", + "$": { + "num": "101", + "id": "219", + "grayvalue": "102" + } } }, "originDatasets": [ @@ -11016,12 +13046,20 @@ { "name": "Interposed Nucleus (Cerebellum)", "status": "left hemisphere", - "labelIndex": 30, + "labelIndex": 109, "ngId": "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Interposed Nucleus (Cerebellum)", "gray": "109" + }, + "xml253": { + "_": "Interposed Nucleus (Cerebellum)", + "$": { + "num": "108", + "id": "251", + "grayvalue": "109" + } } }, "originDatasets": [ @@ -11051,12 +13089,20 @@ { "name": "Interposed Nucleus (Cerebellum)", "status": "right hemisphere", - "labelIndex": 30, + "labelIndex": 109, "ngId": "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE", "_": { "xml": { "name": "Interposed Nucleus (Cerebellum)", "gray": "109" + }, + "xml253": { + "_": "Interposed Nucleus (Cerebellum)", + "$": { + "num": "108", + "id": "251", + "grayvalue": "109" + } } }, "originDatasets": [ @@ -11107,14 +13153,11 @@ ] , "_": { - "@src": "https://gin.g-node.org/FZJ-INM1-BDA/20201204_JulichBrainV3_0_hemisphereSplit_metadata/src/58efbff4f6599cd66246945eb1ffbbb239840295/output/nehubaUI/julich-brain-v3.0-icbm152-pos.json" + "@src": "https://gin.g-node.org/FZJ-INM1-BDA/20210209_JulichBrain_v2_5_3_hierarchy/src/5ea4494af794d24406672b189a04eea70d03c8b9/output/newHierarchy.json" } },{ "@id": "juelich/iav/atlas/v1.0.0/79cbeaa4ee96d5d3dfe2876e9f74b3dc3d3ffb84304fb9b965b1776563a1069c", "ngId": "superficial-white-bundle-HCP", - "auxillaryMeshIndices": [ - 65535 - ], "name": "Short Fiber Bundles - HCP", "originDatasets": [ { @@ -32964,9 +35007,6 @@ "fullId": "juelich/iav/atlas/v1.0.0/8", "name": "Cytoarchitectonic maps - v1.18", "ngId": "jubrain mni152 v18 left", - "auxillaryMeshIndices": [ - 65535 - ], "hasAdditionalViewMode": [ "connectivity" ], @@ -41068,9 +43108,6 @@ { "@id": "juelich/iav/atlas/v1.0.0/5", "ngId": "fibre bundle long", - "auxillaryMeshIndices": [ - 65535 - ], "type": "parcellation", "surfaceParcellation": true, "ngData": null, @@ -44326,9 +46363,6 @@ ], "@id": "juelich/iav/atlas/v1.0.0/6", "ngId": "fibre bundle short", - "auxillaryMeshIndices": [ - 65535 - ], "type": "parcellation", "surfaceParcellation": true, "ngData": null, @@ -44347,9 +46381,6 @@ "name": "DiFuMo Atlas (64 dimensions)", "ngId": "DiFuMo Atlas (64 dimensions)", "@id": "minds/core/parcellationatlas/v1.0.0/d80fbab2-ce7f-4901-a3a2-3c8ef8a3b721", - "auxillaryMeshIndices": [ - 65535 - ], "originDatasets": [ { "kgSchema": "minds/core/dataset/v1.0.0", @@ -45515,9 +47546,6 @@ "name": "DiFuMo Atlas (128 dimensions)", "ngId": "DiFuMo Atlas (128 dimensions)", "@id": "minds/core/parcellationatlas/v1.0.0/73f41e04-b7ee-4301-a828-4b298ad05ab8", - "auxillaryMeshIndices": [ - 65535 - ], "originDatasets": [ { "kgSchema": "minds/core/dataset/v1.0.0", @@ -47835,9 +49863,6 @@ "name": "DiFuMo Atlas (256 dimensions)", "ngId": "DiFuMo Atlas (256 dimensions)", "@id": "minds/core/parcellationatlas/v1.0.0/141d510f-0342-4f94-ace7-c97d5f160235", - "auxillaryMeshIndices": [ - 65535 - ], "originDatasets": [ { "kgSchema": "minds/core/dataset/v1.0.0", @@ -52459,9 +54484,6 @@ "name": "DiFuMo Atlas (512 dimensions)", "ngId": "DiFuMo Atlas (512 dimensions)", "@id": "minds/core/parcellationatlas/v1.0.0/63b5794f-79a4-4464-8dc1-b32e170f3d16", - "auxillaryMeshIndices": [ - 65535 - ], "originDatasets": [ { "kgSchema": "minds/core/dataset/v1.0.0", @@ -61691,9 +63713,6 @@ "name": "DiFuMo Atlas (1024 dimensions)", "ngId": "DiFuMo Atlas (1024 dimensions)", "@id": "minds/core/parcellationatlas/v1.0.0/12fca5c5-b02c-46ce-ab9f-f12babf4c7e1", - "auxillaryMeshIndices": [ - 65535 - ], "originDatasets": [ { "kgSchema": "minds/core/dataset/v1.0.0", diff --git a/src/res/ext/MNI152NehubaConfig.json b/src/res/ext/MNI152NehubaConfig.json index a19a6ba72d7a8e02e32f1326b7bd080ef89401cf..a1f6f3e44abf8d865abe3bc9878b121604b07e0e 100644 --- a/src/res/ext/MNI152NehubaConfig.json +++ b/src/res/ext/MNI152NehubaConfig.json @@ -93,6 +93,37 @@ ] ] }, + "auxMesh": { + "type": "segmentation", + "visible": true, + "source": "precompmesh://https://neuroglancer.humanbrainproject.eu/precomputed/icbm152_2009c_nonlin_asym", + "transform": [ + [ + 1, + 0, + 0, + -96500000 + ], + [ + 0, + 1, + 0, + -132500000 + ], + [ + 0, + 0, + 1, + -78500000 + ], + [ + 0, + 0, + 0, + 1 + ] + ] + }, "jubrain mni152 v18 left": { "type": "segmentation", "visible": false, @@ -220,7 +251,7 @@ "MNI152_V25_RIGHT_NG_SPLIT_HEMISPHERE": { "type": "segmentation", "visible": true, - "source": "precomputed://https://neuroglancer.humanbrainproject.eu/precomputed/data-repo/20201204_JulichBrainV3_0_hemisphereSplit/precomputed/JuBrain_Map_icbm_v30_r", + "source": "precomputed://https://neuroglancer-dev.humanbrainproject.eu/precomputed/data-repo-ng-bot/JulichBrainV2_5_3/precomputed/JulichBrain_MPMAtlas_r_N10_nlin2Stdicbm152asym2009c_publicDOI_453c4c95827e38dcce5372b200065cba", "transform": [ [ 1, @@ -251,7 +282,7 @@ "MNI152_V25_LEFT_NG_SPLIT_HEMISPHERE": { "type": "segmentation", "visible": true, - "source": "precomputed://https://neuroglancer.humanbrainproject.eu/precomputed/data-repo/20201204_JulichBrainV3_0_hemisphereSplit/precomputed/JuBrain_Map_icbm_v30_l", + "source": "precomputed://https://neuroglancer-dev.humanbrainproject.eu//precomputed/data-repo-ng-bot/JulichBrainV2_5_3/precomputed/JulichBrain_MPMAtlas_l_N10_nlin2Stdicbm152asym2009c_publicDOI_3f5ec6016bc2242769c41befdbc1b2e0", "transform": [ [ 1, diff --git a/src/res/ext/allenMouse.json b/src/res/ext/allenMouse.json index d8ae3d5a9f14014796c79e453aaec4a4a937269e..67432c0726200b55204b591dfb83c2b1798134de 100644 --- a/src/res/ext/allenMouse.json +++ b/src/res/ext/allenMouse.json @@ -9,6 +9,15 @@ "nissl" ], "useTheme": "dark", + "auxMeshes": [{ + "name": "Allen CCF v3 whole brain", + "displayName": "Whole brain", + "@id": "allen_ccf_v3_wholebrain", + "ngId": "auxMesh", + "labelIndicies": [ 997 ], + "rgb": [255, 255, 255], + "visible": true + }], "nehubaConfigURL": "nehubaConfig/allenMouseNehubaConfig", "parcellations": [ { diff --git a/src/res/ext/allenMouseNehubaConfig.json b/src/res/ext/allenMouseNehubaConfig.json index e6ed7be2d1fe8d5f47ae27253be7375bc75ba5d1..817703930fa97632f3f25963dcae7134bbb4fc8d 100644 --- a/src/res/ext/allenMouseNehubaConfig.json +++ b/src/res/ext/allenMouseNehubaConfig.json @@ -142,6 +142,36 @@ 1 ] ] + }, + "auxMesh": { + "type": "segmentation", + "source": "precompmesh://https://neuroglancer.humanbrainproject.eu/precomputed/AMBA/parcellations/v3_2017_mesh", + "transform": [ + [ + 0, + 0, + -1, + 5670000 + ], + [ + -1, + 0, + 0, + 6570000 + ], + [ + 0, + -1, + 0, + 3970000 + ], + [ + 0, + 0, + 0, + 1 + ] + ] } }, "navigation": { diff --git a/src/res/ext/atlas/atlas_multiLevelHuman.json b/src/res/ext/atlas/atlas_multiLevelHuman.json index 9eb2e035cb96cf9643689065f67c873be0bf5c0a..8bff76f3ec6d19cd1c975824bad57841f8bae5d4 100644 --- a/src/res/ext/atlas/atlas_multiLevelHuman.json +++ b/src/res/ext/atlas/atlas_multiLevelHuman.json @@ -51,20 +51,6 @@ } ] }, - { - "@id": "minds/core/referencespace/v1.0.0/7f39f7be-445b-47c0-9791-e971c0b6d992", - "name": "MNI Colin 27", - "availableIn": [ - { - "@id": "minds/core/parcellationatlas/v1.0.0/94c1125b-b87e-45e4-901c-00daee7f2579-25", - "name": "Cytoarchitectonic maps - v2.5" - }, - { - "@id": "juelich/iav/atlas/v1.0.0/8", - "name": "Cytoarchitectonic Maps - v1.18" - } - ] - }, { "@id": "minds/core/referencespace/v1.0.0/a1655b99-82f1-420f-a3c2-fe80fd4c8588", "name": "Big Brain (Histology)", @@ -111,13 +97,6 @@ "originalDatasetFormats": [{ "name": "probability map" }] - }, - { - "@id": "minds/core/referencespace/v1.0.0/7f39f7be-445b-47c0-9791-e971c0b6d992", - "name": "MNI Colin 27", - "originalDatasetFormats": [{ - "name": "probability map" - }] } ] }, @@ -145,7 +124,7 @@ "@version": { "@next": null, "@this": "minds/core/parcellationatlas/v1.0.0/94c1125b-b87e-45e4-901c-00daee7f2579-25", - "name": "v2.5", + "name": "v2.6", "@previous": "juelich/iav/atlas/v1.0.0/8" }, "availableIn": [ @@ -155,13 +134,6 @@ "originalDatasetFormats": [{ "name": "probability map" }] - }, - { - "@id": "minds/core/referencespace/v1.0.0/7f39f7be-445b-47c0-9791-e971c0b6d992", - "name": "MNI Colin 27", - "originalDatasetFormats": [{ - "name": "probability map" - }] } ] }, diff --git a/src/res/ext/bigbrain.json b/src/res/ext/bigbrain.json index 85d502866ec6af1f5f8efc425b82ff33940781d9..0dec98a241ece1f0d9c5a427e265346e050d688f 100644 --- a/src/res/ext/bigbrain.json +++ b/src/res/ext/bigbrain.json @@ -852,36 +852,6 @@ "ngId": "v3v", "status": "fully mapped", "labelIndex": 1, - "position": [], - "rgb": [ - 83, - 179, - 155 - ], - "children": [], - "fullId": { - "kg": { - "kgSchema": "minds/core/parcellationregion/v1.0.0", - "kgId": "04674a3c-bb3a-495e-a466-206355e630bd" - } - }, - "relatedAreas": [], - "originDatasets":[ - { - "kgSchema": "minds/core/dataset/v1.0.0", - "kgId": "f746514d-b79a-48e2-9c07-39f7c62459cf", - "format": { - "name": "Full 3D map" - } - } - ] - }, - { - "name": "Area hOc3v (LingG)", - "ngId": "v3v", - "status": "fully mapped", - "labelIndex": 1, - "position": [], "rgb": [ 83, 179, @@ -937,7 +907,6 @@ "ngId": "v5", "status": "fully mapped", "labelIndex": 1, - "position": [], "rgb": [ 255, 0, @@ -991,7 +960,6 @@ "ngId": "LGB-lam1", "status": "fully mapped", "labelIndex": 1, - "position": [], "rgb": [ 255, 255, @@ -1020,7 +988,6 @@ "ngId": "LGB-lam2", "status": "fully mapped", "labelIndex": 1, - "position": [], "rgb": [ 222, 74, @@ -1049,7 +1016,6 @@ "ngId": "LGB-lam3", "status": "fully mapped", "labelIndex": 1, - "position": [], "rgb": [ 132, 90, @@ -1078,7 +1044,6 @@ "ngId": "LGB-lam4", "status": "fully mapped", "labelIndex": 1, - "position": [], "rgb": [ 41, 123, @@ -1107,7 +1072,6 @@ "ngId": "LGB-lam5", "status": "fully mapped", "labelIndex": 1, - "position": [], "rgb": [ 82, 214, @@ -1136,7 +1100,6 @@ "ngId": "LGB-lam6", "status": "fully mapped", "labelIndex": 1, - "position": [], "rgb": [ 99, 231, @@ -1170,7 +1133,6 @@ "ngId": "v5", "status": "fully mapped", "labelIndex": 1, - "position": [], "rgb": [ 255, 0, @@ -1215,7 +1177,6 @@ "ngId": "LGB-lam1", "status": "fully mapped", "labelIndex": 1, - "position": [], "rgb": [ 255, 255, @@ -1235,7 +1196,6 @@ "ngId": "LGB-lam2", "status": "fully mapped", "labelIndex": 1, - "position": [], "rgb": [ 222, 74, @@ -1255,7 +1215,6 @@ "ngId": "LGB-lam3", "status": "fully mapped", "labelIndex": 1, - "position": [], "rgb": [ 132, 90, @@ -1275,7 +1234,6 @@ "ngId": "LGB-lam4", "status": "fully mapped", "labelIndex": 1, - "position": [], "rgb": [ 41, 123, @@ -1295,7 +1253,6 @@ "ngId": "LGB-lam5", "status": "fully mapped", "labelIndex": 1, - "position": [], "rgb": [ 82, 214, @@ -1315,7 +1272,6 @@ "ngId": "LGB-lam6", "status": "fully mapped", "labelIndex": 1, - "position": [], "rgb": [ 99, 231, @@ -1511,6 +1467,23 @@ "type": "parcellation", "ngData": null, "ngId": " tissue type: ", + "auxMeshes": [{ + "name": "Big Brain - white matter", + "displayName": "White matter", + "@id": "bigbrain_whitematter", + "ngId": "auxMesh", + "labelIndicies": [ 200 ], + "rgb": [255, 255, 255], + "visible": false + },{ + "name": "Big Brain - grey matter", + "displayName": "Grey matter", + "@id": "bigbrain_greymatter", + "ngId": "auxMesh", + "labelIndicies": [ 100 ], + "rgb": [255, 255, 255], + "visible": true + }], "regions": [ { "name": "Isocortex", diff --git a/src/res/ext/bigbrainNehubaConfig.json b/src/res/ext/bigbrainNehubaConfig.json index 941fd3fb2a8767a1052ea7cdec20aca6613152c4..2c858a69e4756bdd706387d325e2f0244d85bb46 100644 --- a/src/res/ext/bigbrainNehubaConfig.json +++ b/src/res/ext/bigbrainNehubaConfig.json @@ -93,6 +93,37 @@ ] ] }, + "auxMesh": { + "type": "segmentation", + "visible": false, + "source": "precompmesh://https://neuroglancer.humanbrainproject.org/precomputed/BigBrainRelease.2015/classif_mesh", + "transform": [ + [ + 1, + 0, + 0, + -70666600 + ], + [ + 0, + 1, + 0, + -72910000 + ], + [ + 0, + 0, + 1, + -58777700 + ], + [ + 0, + 0, + 0, + 1 + ] + ] + }, "v1": { "type": "segmentation", "source": "precomputed://https://neuroglancer.humanbrainproject.org/precomputed/BigBrainRelease.2015/2019_05_01_v1", diff --git a/src/res/ext/colin.json b/src/res/ext/colin.json index 932ccb8a54b4caa2e0306a81f27941dfa5547911..2c1d0cd2639a41c661fb6e45c8f695e84299ee33 100644 --- a/src/res/ext/colin.json +++ b/src/res/ext/colin.json @@ -22,7 +22,7 @@ "originDatasets": [ { "kgSchema": "minds/core/dataset/v1.0.0", - "kgId": "ef48c5e9-6b3c-4d5a-a9a9-e678fe10bdf6" + "kgId": "2eaa3dc6-a21b-41c1-b703-bf06f82adf25" } ], "properties": { diff --git a/src/ui/ui.module.ts b/src/ui/ui.module.ts index 708649fd9aad63c7814d30eeea689076d68821a2..7145621bc27bf7ae34fd0d85dde3d3d43a7dc14e 100644 --- a/src/ui/ui.module.ts +++ b/src/ui/ui.module.ts @@ -3,7 +3,6 @@ import { ComponentsModule } from "src/components/components.module"; import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { LayoutModule } from "src/layouts/layout.module"; -// import { NehubaContainer } from "./nehubaContainer/nehubaContainer.component"; import { FilterRegionDataEntries } from "src/util/pipes/filterRegionDataEntries.pipe"; import { GroupDatasetByRegion } from "src/util/pipes/groupDataEntriesByRegion.pipe"; @@ -28,7 +27,6 @@ import { DatabrowserModule } from "../atlasComponents/databrowserModule/databrow import { LogoContainer } from "./logoContainer/logoContainer.component"; import { MobileOverlay } from "./nehubaContainer/mobileOverlay/mobileOverlay.component"; import { MobileControlNubStylePipe } from "./nehubaContainer/pipes/mobileControlNubStyle.pipe"; -// import { StatusCardComponent } from "./nehubaContainer/statusCard/statusCard.component"; import { HumanReadableFileSizePipe } from "src/util/pipes/humanReadableFileSize.pipe"; import { KgSearchBtnColorPipe } from "src/util/pipes/kgSearchBtnColor.pipe"; @@ -73,14 +71,11 @@ import { AtlasCmptConnModule } from "src/atlasComponents/connectivity"; AtlasCmptConnModule, ], declarations : [ - // NehubaContainer, CitationsContainer, LogoContainer, MobileOverlay, - // StatusCardComponent, - ActionDialog, /* pipes */ diff --git a/src/util/fn.spec.ts b/src/util/fn.spec.ts index f17d211b79c3b363eb7da40c9e517817a66db4a5..be7d8b7dd660ec877b5fc640883eaae03712d2f5 100644 --- a/src/util/fn.spec.ts +++ b/src/util/fn.spec.ts @@ -1,9 +1,13 @@ +import { fakeAsync, tick } from '@angular/core/testing' import {} from 'jasmine' -import { isSame, getGetRegionFromLabelIndexId } from './fn' +import { cold, hot } from 'jasmine-marbles' +import { of } from 'rxjs' +import { switchMap } from 'rxjs/operators' +import { isSame, getGetRegionFromLabelIndexId, switchMapWaitFor } from './fn' -describe(`util/fn.ts`, () => { +describe(`> util/fn.ts`, () => { - describe('getGetRegionFromLabelIndexId', () => { + describe('> #getGetRegionFromLabelIndexId', () => { const colinsJson = require('!json-loader!../res/ext/colin.json') const COLIN_JULICHBRAIN_LAYER_NAME = `COLIN_V25_LEFT_NG_SPLIT_HEMISPHERE` @@ -23,7 +27,7 @@ describe(`util/fn.ts`, () => { }) }) - describe(`#isSame`, () => { + describe(`> #isSame`, () => { it('should return true with null, null', () => { expect(isSame(null, null)).toBe(true) }) @@ -49,4 +53,29 @@ describe(`util/fn.ts`, () => { expect(obj).not.toEqual(obj2) }) }) + + describe('> #switchMapWaitFor', () => { + const val = 'hello world' + describe('> if condition is true to begin', () => { + const conditionFn = jasmine.createSpy() + beforeEach(() => { + conditionFn.and.returnValue(true) + }) + afterEach(() => { + conditionFn.calls.reset() + }) + it('> should wait for 16 ms then emit', fakeAsync(() => { + const obs$ = of(val).pipe( + switchMap(switchMapWaitFor({ + condition: conditionFn + })) + ) + obs$.subscribe(ex => { + expect(conditionFn).toHaveBeenCalled() + expect(ex).toEqual(val) + }) + tick(200) + })) + }) + }) }) diff --git a/src/util/fn.ts b/src/util/fn.ts index f8f65694eae2e8623f73a7f1b5ceaf0fe38ec425..4f673a08e5b2ace779f13d8994d68965687688af 100644 --- a/src/util/fn.ts +++ b/src/util/fn.ts @@ -1,4 +1,6 @@ import { deserialiseParcRegionId } from 'common/util' +import { interval } from 'rxjs' +import { filter, mapTo, take } from 'rxjs/operators' export function isSame(o, n) { if (!o) { return !n } @@ -69,3 +71,15 @@ const include = <T extends TPrimitive>(el: T, arr: T[]) => arr.indexOf(el) >= 0 export const arrayOfPrimitiveEqual = <T extends TPrimitive>(o: T[], n: T[]) => o.every(el => include(el, n)) && n.every(el => include(el, o)) + +interface ISwitchMapWaitFor { + interval?: number + condition: () => boolean +} +export function switchMapWaitFor(opts: ISwitchMapWaitFor){ + return (arg: unknown) => interval(opts.interval || 16).pipe( + filter(() => opts.condition()), + take(1), + mapTo(arg) + ) +} diff --git a/src/viewerModule/nehuba/actions.ts b/src/viewerModule/nehuba/actions.ts deleted file mode 100644 index 979a485f1694ed7586d2326a5a286703d4610522..0000000000000000000000000000000000000000 --- a/src/viewerModule/nehuba/actions.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { createAction, props } from "@ngrx/store"; -import { INgLayerInterface } from "src/services/state/ngViewerState.store"; -import { NEHUBA_VIEWER_FEATURE_KEY } from "./constants"; - -export const actionAddNgLayer = createAction( - `[${NEHUBA_VIEWER_FEATURE_KEY}] [addNgLayer]`, - props<{ - layers: INgLayerInterface[] - }>() -) \ No newline at end of file diff --git a/src/viewerModule/nehuba/constants.ts b/src/viewerModule/nehuba/constants.ts index 81b4f89cf14e6ecdc98431ea1f4fe35ab902f575..9428b63efb8eed35e8d634de1ddd82667e77107b 100644 --- a/src/viewerModule/nehuba/constants.ts +++ b/src/viewerModule/nehuba/constants.ts @@ -15,7 +15,13 @@ export interface INgLayerInterface { transform?: any } -export function getMultiNgIdsRegionsLabelIndexMap(parcellation: any = {}, inheritAttrsOpt: any = { ngId: 'root' }): Map<string, Map<number, any>> { +export interface IRegion { + [key: string]: any + ngId: string + rgb?: [number, number, number] +} + +export function getMultiNgIdsRegionsLabelIndexMap(parcellation: any = {}, inheritAttrsOpt: any = { ngId: 'root' }): Map<string, Map<number, IRegion>> { const map: Map<string, Map<number, any>> = new Map() const inheritAttrs = Object.keys(inheritAttrsOpt) diff --git a/src/viewerModule/nehuba/layerCtrl.service/index.ts b/src/viewerModule/nehuba/layerCtrl.service/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..61975bcfe1e269f45f4774e535089977b02bf1ea --- /dev/null +++ b/src/viewerModule/nehuba/layerCtrl.service/index.ts @@ -0,0 +1,10 @@ +export { + NehubaLayerControlService +} from './layerCtrl.service' + +export { + IColorMap, + SET_COLORMAP_OBS, + SET_LAYER_VISIBILITY, + getRgb, +} from './layerCtrl.util' diff --git a/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.spec.ts b/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..cb0e151e25db43987e08f28862d77be36a52b112 --- /dev/null +++ b/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.spec.ts @@ -0,0 +1,271 @@ +import { TestBed } from "@angular/core/testing" +import { MockStore, provideMockStore } from "@ngrx/store/testing" +import { viewerStateSelectedParcellationSelector, viewerStateSelectedTemplateSelector } from "src/services/state/viewerState/selectors" +import { NehubaLayerControlService } from "./layerCtrl.service" +import * as layerCtrlUtil from '../constants' +import { hot } from "jasmine-marbles" + + +describe('> layerctrl.service.ts', () => { + describe('> NehubaLayerControlService', () => { + let mockStore: MockStore + let getMultiNgIdsRegionsLabelIndexMapSpy: jasmine.Spy + let getMultiNgIdsRegionsLabelIndexMapReturnVal: Map<string, Map<number, layerCtrlUtil.IRegion>> + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + NehubaLayerControlService, + provideMockStore() + ] + }) + + mockStore = TestBed.inject(MockStore) + getMultiNgIdsRegionsLabelIndexMapReturnVal = new Map() + getMultiNgIdsRegionsLabelIndexMapSpy = spyOnProperty( + layerCtrlUtil, + 'getMultiNgIdsRegionsLabelIndexMap' + ).and.returnValue(() => getMultiNgIdsRegionsLabelIndexMapReturnVal) + }) + + it('> can be init', () => { + const service = TestBed.inject(NehubaLayerControlService) + expect(service).toBeTruthy() + }) + + describe('> setColorMap$', () => { + describe('> overwriteColorMap$ not firing', () => { + describe('> template/parc has no aux meshes', () => { + beforeEach(() => { + mockStore.overrideSelector(viewerStateSelectedTemplateSelector, {}) + mockStore.overrideSelector(viewerStateSelectedParcellationSelector, {}) + }) + + it('> calls getMultiNgIdsRegionsLabelIndexMapReturn', () => { + const service = TestBed.inject(NehubaLayerControlService) + service.setColorMap$.subscribe() + expect(getMultiNgIdsRegionsLabelIndexMapSpy).toHaveBeenCalled() + }) + + it('> emitted value is as expected', () => { + const map = new Map<number, layerCtrlUtil.IRegion>() + getMultiNgIdsRegionsLabelIndexMapReturnVal.set( + 'foo-bar', + map + ) + map.set(1, { + ngId: 'foo-bar', + rgb: [100, 200, 255] + }) + map.set(2, { + ngId: 'foo-bar', + rgb: [15, 15, 15] + }) + + const service = TestBed.inject(NehubaLayerControlService) + expect( + service.setColorMap$ + ).toBeObservable( + hot('a', { + a: { + 'foo-bar': { + 1: { red: 100, green: 200, blue: 255 }, + 2: { red: 15, green: 15, blue: 15} + } + } + }) + ) + }) + + }) + + describe('> template/parc has aux meshes', () => { + let tmplAuxMeshes = [{ + name: 'foo-bar', + ngId: 'bazz', + labelIndicies: [1,2,3], + rgb: [100, 100, 100] + }, { + name: 'hello-world', + ngId: 'hello-world', + labelIndicies: [4,5,6], + rgb: [200, 200, 200] + }] + let parcAuxMeshes = [{ + name: 'hello-world', + ngId: 'hello-world', + labelIndicies: [10,11,12], + rgb: [255, 255, 255] + }] + beforeEach(() => { + mockStore.overrideSelector(viewerStateSelectedTemplateSelector, { + auxMeshes: tmplAuxMeshes + }) + mockStore.overrideSelector(viewerStateSelectedParcellationSelector, { + auxMeshes: parcAuxMeshes + }) + }) + + it('> should inherit values from tmpl and parc', () => { + + const service = TestBed.inject(NehubaLayerControlService) + expect( + service.setColorMap$ + ).toBeObservable( + hot('a', { + a: { + 'bazz': { + 1: { red: 100, green: 100, blue: 100 }, + 2: { red: 100, green: 100, blue: 100 }, + 3: { red: 100, green: 100, blue: 100 }, + }, + 'hello-world': { + 4: { red: 200, green: 200, blue: 200 }, + 5: { red: 200, green: 200, blue: 200 }, + 6: { red: 200, green: 200, blue: 200 }, + 10: { red: 255, green: 255, blue: 255 }, + 11: { red: 255, green: 255, blue: 255 }, + 12: { red: 255, green: 255, blue: 255 }, + } + } + }) + ) + }) + + it('> should overwrite any value if at all, from region', () => { + const map = new Map<number, layerCtrlUtil.IRegion>() + map.set(10, { + ngId: 'hello-world', + rgb: [0, 0, 0] + }) + map.set(15, { + ngId: 'hello-world', + rgb: [0, 0, 0] + }) + getMultiNgIdsRegionsLabelIndexMapReturnVal.set('hello-world', map) + + const service = TestBed.inject(NehubaLayerControlService) + expect( + service.setColorMap$ + ).toBeObservable( + hot('a', { + a: { + 'bazz': { + 1: { red: 100, green: 100, blue: 100 }, + 2: { red: 100, green: 100, blue: 100 }, + 3: { red: 100, green: 100, blue: 100 }, + }, + 'hello-world': { + 4: { red: 200, green: 200, blue: 200 }, + 5: { red: 200, green: 200, blue: 200 }, + 6: { red: 200, green: 200, blue: 200 }, + 10: { red: 255, green: 255, blue: 255 }, + 11: { red: 255, green: 255, blue: 255 }, + 12: { red: 255, green: 255, blue: 255 }, + 15: { red: 0, green: 0, blue: 0 }, + } + } + }) + ) + }) + }) + }) + + describe('> overwriteColorMap$ firing', () => { + beforeEach(() => { + mockStore.overrideSelector(viewerStateSelectedTemplateSelector, {}) + mockStore.overrideSelector(viewerStateSelectedParcellationSelector, {}) + const map = new Map<number, layerCtrlUtil.IRegion>() + getMultiNgIdsRegionsLabelIndexMapReturnVal.set( + 'foo-bar', + map + ) + map.set(1, { + ngId: 'foo-bar', + rgb: [100, 200, 255] + }) + map.set(2, { + ngId: 'foo-bar', + rgb: [15, 15, 15] + }) + }) + + it('> should overwrite existing colormap', () => { + const service = TestBed.inject(NehubaLayerControlService) + service.overwriteColorMap$.next({ + 'foo-bar': { + 2: { + red: 255, + green: 255, + blue: 255, + } + } + }) + + expect(service.setColorMap$).toBeObservable( + hot('(ab)', { + a: { + 'foo-bar': { + 1: { red: 100, green: 200, blue: 255 }, + 2: { red: 15, green: 15, blue: 15 }, + } + }, + b: { + 'foo-bar': { + 2: { red: 255, green: 255, blue: 255 }, + } + } + }) + ) + }) + }) + }) + + + describe('> visibleLayer$', () => { + beforeEach(() => { + mockStore.overrideSelector(viewerStateSelectedTemplateSelector, { + ngId: 'tmplNgId', + auxMeshes: [{ + ngId: 'tmplAuxId1', + labelIndicies: [1,2,3] + },{ + ngId: 'tmplAuxId2', + labelIndicies: [1,2,3] + }] + }) + + mockStore.overrideSelector(viewerStateSelectedParcellationSelector, { + auxMeshes: [{ + ngId: 'parcAuxId1', + labelIndicies: [1,2,3], + },{ + ngId: 'parcAuxId2', + labelIndicies: [1,2,3] + }] + }) + + getMultiNgIdsRegionsLabelIndexMapReturnVal.set( + 'regionsNgId1', null + ) + + getMultiNgIdsRegionsLabelIndexMapReturnVal.set( + 'regionsNgId2', null + ) + }) + it('> combines ngId of template, aux mesh and regions', () => { + const service = TestBed.inject(NehubaLayerControlService) + expect(service.visibleLayer$).toBeObservable(hot('a', { + a: [ + 'tmplNgId', + 'tmplAuxId1', + 'tmplAuxId2', + 'parcAuxId1', + 'parcAuxId2', + 'regionsNgId1', + 'regionsNgId2', + ] + })) + }) + }) + }) +}) diff --git a/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.ts b/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..7a338c72e24a09592fdc718d5064687e7d67a6db --- /dev/null +++ b/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.ts @@ -0,0 +1,139 @@ +import { Injectable } from "@angular/core"; +import { select, Store } from "@ngrx/store"; +import { BehaviorSubject, combineLatest, merge, Observable, Subject } from "rxjs"; +import { filter, map, shareReplay, tap } from "rxjs/operators"; +import { viewerStateSelectedParcellationSelector, viewerStateSelectedTemplateSelector } from "src/services/state/viewerState/selectors"; +import { getRgb, IColorMap } from "./layerCtrl.util"; +import { getMultiNgIdsRegionsLabelIndexMap } from "../constants"; +import { IAuxMesh } from '../store' + +export function getAuxMeshesAndReturnIColor(auxMeshes: IAuxMesh[]): IColorMap{ + const returnVal: IColorMap = {} + for (const auxMesh of auxMeshes as IAuxMesh[]) { + const { ngId, labelIndicies, rgb } = auxMesh + const auxMeshColorMap = returnVal[ngId] || {} + for (const lblIdx of labelIndicies) { + auxMeshColorMap[lblIdx as number] = { + red: rgb[0] as number, + green: rgb[1] as number, + blue: rgb[2] as number, + } + } + returnVal[ngId] = auxMeshColorMap + } + return returnVal +} + +@Injectable() +export class NehubaLayerControlService { + + private selectedParcellation$ = this.store$.pipe( + select(viewerStateSelectedParcellationSelector) + ) + + private selectedTemplateSelector$ = this.store$.pipe( + select(viewerStateSelectedTemplateSelector) + ) + + private selParcNgIdMap$ = this.selectedParcellation$.pipe( + map(parc => getMultiNgIdsRegionsLabelIndexMap(parc)), + shareReplay(1), + ) + + private activeColorMap$: Observable<IColorMap> = combineLatest([ + this.selParcNgIdMap$.pipe( + map(map => { + const returnVal: IColorMap = {} + for (const [ key, val ] of map.entries()) { + returnVal[key] = {} + for (const [ lblIdx, region ] of val.entries()) { + const rgb = getRgb(lblIdx, region) + returnVal[key][lblIdx] = rgb + } + } + return returnVal + }) + ), + this.selectedTemplateSelector$.pipe( + map(template => { + const { auxMeshes = [] } = template + return getAuxMeshesAndReturnIColor(auxMeshes) + }) + ), + this.selectedParcellation$.pipe( + map(parc => { + const { auxMeshes = [] } = parc + return getAuxMeshesAndReturnIColor(auxMeshes) + }) + ), + ]).pipe( + map(([ regions, ...auxMeshesArr ]) => { + + const returnVal: IColorMap = {} + + for (const key in regions) { + returnVal[key] = regions[key] + } + + for (const auxMeshes of auxMeshesArr) { + for (const key in auxMeshes) { + const existingObj = returnVal[key] || {} + returnVal[key] = { + ...existingObj, + ...auxMeshes[key], + } + } + } + this.activeColorMap = returnVal + return returnVal + }) + ) + + private auxMeshes$: Observable<IAuxMesh[]> = combineLatest([ + this.selectedTemplateSelector$, + this.selectedParcellation$, + ]).pipe( + map(([ tmpl, parc ]) => { + const { auxMeshes: tmplAuxMeshes = [] as IAuxMesh[] } = tmpl + const { auxMeshes: parclAuxMeshes = [] as IAuxMesh[] } = parc + return [...tmplAuxMeshes, ...parclAuxMeshes] + }) + ) + + constructor( + private store$: Store<any>, + ){ + + } + + public activeColorMap: IColorMap + + public overwriteColorMap$ = new BehaviorSubject<IColorMap>(null) + + public setColorMap$: Observable<IColorMap> = merge( + this.activeColorMap$, + this.overwriteColorMap$.pipe( + filter(v => !!v) + ) + ) + + public visibleLayer$: Observable<string[]> = combineLatest([ + this.selectedTemplateSelector$, + this.auxMeshes$, + this.selParcNgIdMap$ + ]).pipe( + map(([ tmpl, auxMeshes, parcNgIdMap ]) => { + const ngIdSet = new Set<string>() + const { ngId } = tmpl + ngIdSet.add(ngId) + for (const auxMesh of auxMeshes) { + const { ngId } = auxMesh + ngIdSet.add(ngId as string) + } + for (const ngId of parcNgIdMap.keys()) { + ngIdSet.add(ngId) + } + return Array.from(ngIdSet) + }) + ) +} diff --git a/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.util.spec.ts b/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.util.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..62aa8819cf104fcd966663ed3b39d3b860ea6f63 --- /dev/null +++ b/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.util.spec.ts @@ -0,0 +1,70 @@ +import * as util from 'common/util' +import { getRgb } from './layerCtrl.util' + +describe('> layerCtrl.util.ts', () => { + describe('> #getRgb', () => { + let strToRgbSpy: jasmine.Spy + let strToRgbValue: [number, number, number] + beforeEach(() => { + strToRgbSpy = spyOn(util, 'strToRgb') + strToRgbValue = [1,2,3] + strToRgbSpy.and.returnValue(strToRgbValue) + }) + + describe('> region has rgb defined', () => { + const labelIndex = 1020 + const region = { + ngId: 'foo-bar', + rgb: [100, 200, 255] as [number, number, number] + } + it('> should return region rgb', () => { + expect( + getRgb(labelIndex, region) + ).toEqual({ + red: 100, + green: 200, + blue: 255 + }) + }) + }) + + describe('> if region does not have rgb defined', () => { + describe('> if labelIndex > 65500', () => { + const region = { + ngId: 'foo-bar', + } + const labelIndex = 65535 + it('> should return white', () => { + expect( + getRgb(labelIndex, region) + ).toEqual({ + red: 255, + green: 255, + blue: 255 + }) + }) + }) + + describe('> otherwise', () => { + const region = { + ngId: 'foo-bar', + } + const labelIndex = 12 + it('> should call strToRgb', () => { + getRgb(labelIndex, region) + expect(strToRgbSpy).toHaveBeenCalledWith(`${region.ngId}${labelIndex}`) + }) + + it('> returns what strToRgb returns', () => { + expect( + getRgb(labelIndex, region) + ).toEqual({ + red: 1, + green: 2, + blue: 3 + }) + }) + }) + }) + }) +}) \ No newline at end of file diff --git a/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.util.ts b/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.util.ts new file mode 100644 index 0000000000000000000000000000000000000000..9ad22f97de5527b7620985ae1ad72f6d0ad4947c --- /dev/null +++ b/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.util.ts @@ -0,0 +1,40 @@ +import { InjectionToken } from '@angular/core' +import { strToRgb } from 'common/util' +import { Observable } from 'rxjs' + +export interface IColorMap { + [key: string]: { + [key: number]: { + red: number + green: number + blue: number + } + } +} + +export function getRgb(labelIndex: number, region: { rgb?: [number, number, number], ngId: string }): {red: number, green: number, blue: number} { + const { rgb, ngId } = region + if (typeof rgb === 'undefined' || rgb === null) { + if (labelIndex > 65500) { + return { + red: 255, + green: 255, + blue: 255 + } + } + const arr = strToRgb(`${ngId}${labelIndex}`) + return { + red : arr[0], + green: arr[1], + blue : arr[2], + } + } + return { + red : rgb[0], + green: rgb[1], + blue : rgb[2], + } +} + +export const SET_COLORMAP_OBS = new InjectionToken<Observable<IColorMap>>('SET_COLORMAP_OBS') +export const SET_LAYER_VISIBILITY = new InjectionToken<Observable<string[]>>('SET_LAYER_VISIBILITY') diff --git a/src/viewerModule/nehuba/mesh.service/index.ts b/src/viewerModule/nehuba/mesh.service/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..eba47eb2549b4fa67a698e4a002e9c570fe10a8a --- /dev/null +++ b/src/viewerModule/nehuba/mesh.service/index.ts @@ -0,0 +1,3 @@ +export { + NehubaMeshService +} from './mesh.service' diff --git a/src/viewerModule/nehuba/mesh.service.spec.ts b/src/viewerModule/nehuba/mesh.service/mesh.service.spec.ts similarity index 83% rename from src/viewerModule/nehuba/mesh.service.spec.ts rename to src/viewerModule/nehuba/mesh.service/mesh.service.spec.ts index fa5d5002bdaa17613a897d65cdff68221d3228a0..967762e46acb61182a31dfc625772c14da8a2dca 100644 --- a/src/viewerModule/nehuba/mesh.service.spec.ts +++ b/src/viewerModule/nehuba/mesh.service/mesh.service.spec.ts @@ -1,7 +1,8 @@ import { TestBed } from "@angular/core/testing" import { MockStore, provideMockStore } from "@ngrx/store/testing" import { hot } from "jasmine-marbles" -import { viewerStateSelectedParcellationSelector, viewerStateSelectedRegionsSelector } from "src/services/state/viewerState/selectors" +import { viewerStateSelectedParcellationSelector, viewerStateSelectedRegionsSelector, viewerStateSelectedTemplateSelector } from "src/services/state/viewerState/selectors" +import { selectorAuxMeshes } from "../store" import { getLayerNameIndiciesFromParcRs, collateLayerNameIndicies, findFirstChildrenWithLabelIndex, NehubaMeshService } from "./mesh.service" @@ -125,6 +126,9 @@ describe('> mesh.server.ts', () => { NehubaMeshService, ] }) + const mockStore = TestBed.inject(MockStore) + mockStore.overrideSelector(viewerStateSelectedParcellationSelector, {}) + mockStore.overrideSelector(viewerStateSelectedTemplateSelector, {}) }) it('> can be init', () => { @@ -134,20 +138,34 @@ describe('> mesh.server.ts', () => { it('> mixes in auxillaryMeshIndices', () => { const mockStore = TestBed.inject(MockStore) - mockStore.overrideSelector(viewerStateSelectedParcellationSelector, { - auxillaryMeshIndices: [11, 22] - }) mockStore.overrideSelector(viewerStateSelectedRegionsSelector, [ fits1 ]) + + mockStore.overrideSelector(selectorAuxMeshes, [{ + ngId: fits2.ngId, + labelIndicies: [11, 22], + "@id": '', + name: '', + rgb: [100, 100, 100], + visible: true, + displayName: '' + }]) + const service = TestBed.inject(NehubaMeshService) expect( service.loadMeshes$ ).toBeObservable( - hot('a', { + hot('(ab)', { a: { layer: { name: fits1.ngId }, - labelIndicies: [ fits1.labelIndex, 11, 22 ] + labelIndicies: [ fits1.labelIndex ] + }, + b: { + layer: { + name: fits2.ngId, + }, + labelIndicies: [11, 22] } }) ) diff --git a/src/viewerModule/nehuba/mesh.service.ts b/src/viewerModule/nehuba/mesh.service/mesh.service.ts similarity index 62% rename from src/viewerModule/nehuba/mesh.service.ts rename to src/viewerModule/nehuba/mesh.service/mesh.service.ts index 007aedaa559a035306d1e73ed71f34a580a19d28..d991aff9e9bafc856dcd6d00cd058681f8d66eac 100644 --- a/src/viewerModule/nehuba/mesh.service.ts +++ b/src/viewerModule/nehuba/mesh.service/mesh.service.ts @@ -2,9 +2,10 @@ import { Injectable, OnDestroy } from "@angular/core"; import { select, Store } from "@ngrx/store"; import { combineLatest, Observable, of } from "rxjs"; import { switchMap } from "rxjs/operators"; -import { viewerStateSelectedParcellationSelector, viewerStateSelectedRegionsSelector } from "src/services/state/viewerState/selectors"; -import { IMeshesToLoad } from './constants' +import { viewerStateSelectedParcellationSelector, viewerStateSelectedRegionsSelector, viewerStateSelectedTemplateSelector } from "src/services/state/viewerState/selectors"; +import { IMeshesToLoad } from '../constants' import { flattenReducer } from 'common/util' +import { IAuxMesh, selectorAuxMeshes, actionSetAuxMeshes } from "../store"; interface IRegion { ngId?: string @@ -63,13 +64,29 @@ export class NehubaMeshService implements OnDestroy { constructor( private store$: Store<any> ){ - + const auxMeshSub = combineLatest([ + this.selectedTemplate$, + this.selectedParc$ + ]).subscribe(([ tmpl, parc ]) => { + const { auxMeshes: tmplAuxMeshes = [] as IAuxMesh[] } = tmpl || {} + const { auxMeshes: parcAuxMeshes = [] as IAuxMesh[]} = parc || {} + this.store$.dispatch( + actionSetAuxMeshes({ + payload: [...tmplAuxMeshes, ...parcAuxMeshes] + }) + ) + }) + this.onDestroyCb.push(() => auxMeshSub.unsubscribe()) } ngOnDestroy(){ while(this.onDestroyCb.length > 0) this.onDestroyCb.pop()() } + private selectedTemplate$ = this.store$.pipe( + select(viewerStateSelectedTemplateSelector) + ) + private selectedRegions$ = this.store$.pipe( select(viewerStateSelectedRegionsSelector) ) @@ -78,11 +95,16 @@ export class NehubaMeshService implements OnDestroy { select(viewerStateSelectedParcellationSelector) ) + private auxMeshes$ = this.store$.pipe( + select(selectorAuxMeshes), + ) + public loadMeshes$: Observable<IMeshesToLoad> = combineLatest([ + this.auxMeshes$, this.selectedParc$, this.selectedRegions$, ]).pipe( - switchMap(([parc, selRegions]) => { + switchMap(([auxMeshes, parc, selRegions]) => { const obj = getLayerNameIndiciesFromParcRs(parc, selRegions) const { auxillaryMeshIndices = [] } = parc const arr: IMeshesToLoad[] = [] @@ -95,6 +117,29 @@ export class NehubaMeshService implements OnDestroy { labelIndicies }) } + + const auxLayers: { + [key: string]: number[] + } = {} + + for (const auxMesh of auxMeshes) { + const { name, ngId, labelIndicies } = auxMesh + if (!auxLayers[ngId]) { + auxLayers[ngId] = [] + } + if (auxMesh.visible) { + auxLayers[ngId].push(...labelIndicies) + } + } + for (const key in auxLayers) { + arr.push({ + layer: { + name: key + }, + labelIndicies: auxLayers[key] + }) + } + return of(...arr) }), ) diff --git a/src/viewerModule/nehuba/module.ts b/src/viewerModule/nehuba/module.ts index b0bdeec6eef7d448804954174d8d7e9f65866447..e4a6808a53f84691b01e8f8bd5ff1489fa3dc4a3 100644 --- a/src/viewerModule/nehuba/module.ts +++ b/src/viewerModule/nehuba/module.ts @@ -23,6 +23,7 @@ import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { BehaviorSubject } from "rxjs"; import { StateModule } from "src/state"; import { AuthModule } from "src/auth"; +import { ViewerCtrlModule } from "./viewerCtrl"; @NgModule({ imports: [ @@ -36,6 +37,7 @@ import { AuthModule } from "src/auth"; ComponentsModule, MouseoverModule, ShareModule, + ViewerCtrlModule, /** * should probably break this into its own... diff --git a/src/viewerModule/nehuba/navigation.service/index.ts b/src/viewerModule/nehuba/navigation.service/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..ac47740ee69a641d7ef23ed05e27eeb80a945824 --- /dev/null +++ b/src/viewerModule/nehuba/navigation.service/index.ts @@ -0,0 +1,7 @@ +export { + NehubaNavigationService +} from './navigation.service' + +export { + INavObj +} from './navigation.util' diff --git a/src/viewerModule/nehuba/navigation.service.spec.ts b/src/viewerModule/nehuba/navigation.service/navigation.service.spec.ts similarity index 97% rename from src/viewerModule/nehuba/navigation.service.spec.ts rename to src/viewerModule/nehuba/navigation.service/navigation.service.spec.ts index 34c97ad1252f633d96fee18955e203f07876ebab..9fdde1ebbab0cd2c3a8d71c01d935d9b175b897c 100644 --- a/src/viewerModule/nehuba/navigation.service.spec.ts +++ b/src/viewerModule/nehuba/navigation.service/navigation.service.spec.ts @@ -4,8 +4,8 @@ import { BehaviorSubject, of, Subject } from 'rxjs' import { selectViewerConfigAnimationFlag } from 'src/services/state/viewerConfig/selectors' import { viewerStateSelectorNavigation } from 'src/services/state/viewerState/selectors' import * as NavUtil from './navigation.util' -import { NehubaViewerUnit } from './nehubaViewer/nehubaViewer.component' -import { NEHUBA_INSTANCE_INJTKN } from './util' +import { NehubaViewerUnit } from '../nehubaViewer/nehubaViewer.component' +import { NEHUBA_INSTANCE_INJTKN } from '../util' import { NehubaNavigationService } from './navigation.service' const nav1 = { diff --git a/src/viewerModule/nehuba/navigation.service.ts b/src/viewerModule/nehuba/navigation.service/navigation.service.ts similarity index 97% rename from src/viewerModule/nehuba/navigation.service.ts rename to src/viewerModule/nehuba/navigation.service/navigation.service.ts index 4664a9255d1314f69221a9dcb09b6a7ca1dbbe9c..6d6e16b83ad5201ffe61770f93ce3db6806f7e73 100644 --- a/src/viewerModule/nehuba/navigation.service.ts +++ b/src/viewerModule/nehuba/navigation.service/navigation.service.ts @@ -5,8 +5,8 @@ import { debounceTime } from "rxjs/operators"; import { selectViewerConfigAnimationFlag } from "src/services/state/viewerConfig/selectors"; import { viewerStateChangeNavigation } from "src/services/state/viewerState/actions"; import { viewerStateSelectorNavigation } from "src/services/state/viewerState/selectors"; -import { NehubaViewerUnit } from "./nehubaViewer/nehubaViewer.component"; -import { NEHUBA_INSTANCE_INJTKN } from "./util"; +import { NehubaViewerUnit } from "../nehubaViewer/nehubaViewer.component"; +import { NEHUBA_INSTANCE_INJTKN } from "../util"; import { timedValues } from 'src/util/generator' import { INavObj, navAdd, navMul, navObjEqual } from './navigation.util' diff --git a/src/viewerModule/nehuba/navigation.util.spec.ts b/src/viewerModule/nehuba/navigation.service/navigation.util.spec.ts similarity index 100% rename from src/viewerModule/nehuba/navigation.util.spec.ts rename to src/viewerModule/nehuba/navigation.service/navigation.util.spec.ts diff --git a/src/viewerModule/nehuba/navigation.util.ts b/src/viewerModule/nehuba/navigation.service/navigation.util.ts similarity index 100% rename from src/viewerModule/nehuba/navigation.util.ts rename to src/viewerModule/nehuba/navigation.service/navigation.util.ts diff --git a/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.spec.ts b/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.spec.ts index 451dcbdd7af2a58560cdb978096f3b636f3ec9a3..7faa79281c19f9f82c5d0a0910ec9b856aede274 100644 --- a/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.spec.ts +++ b/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.spec.ts @@ -1,17 +1,89 @@ -import { TestBed, async, fakeAsync, tick } from "@angular/core/testing" +import { TestBed, async, fakeAsync, tick, ComponentFixture } from "@angular/core/testing" import { CommonModule, DOCUMENT } from "@angular/common" -import { NehubaViewerUnit, IMPORT_NEHUBA_INJECT_TOKEN } from "./nehubaViewer.component" +import { NehubaViewerUnit, IMPORT_NEHUBA_INJECT_TOKEN, scanFn } from "./nehubaViewer.component" import { importNehubaFactory } from "../util" import { AtlasWorkerService } from "src/atlasViewer/atlasViewer.workerService.service" -import { LoggingModule } from "src/logging" +import { LoggingModule, LoggingService } from "src/logging" import { APPEND_SCRIPT_TOKEN, appendScriptFactory } from "src/util/constants" import { IMeshesToLoad, SET_MESHES_TO_LOAD } from "../constants" -import { Subject } from "rxjs" +import { ReplaySubject, Subject } from "rxjs" +import { IColorMap, SET_COLORMAP_OBS, SET_LAYER_VISIBILITY } from "../layerCtrl.service" -describe('nehubaViewer.component,ts', () => { - describe('NehubaViewerUnit', () => { - let provideSetMeshToLoadCtrl = false +describe('> nehubaViewer.component.ts', () => { + describe('> #scanFn', () => { + + const curr = { + layer: { + name: 'foo-bar' + }, + labelIndicies: [1,2,3] + } + + describe('> insert OP', () => { + describe('> if incoming is empty arr', () => { + const acc = [] + it('> should insert', () => { + expect( + scanFn(acc, curr) + ).toEqual([curr]) + }) + }) + + describe('> if incoming has other key', () => { + it('> should insert', () => { + const acc = [{ + layer: { + name: 'hello-world' + }, + labelIndicies: [4,5,6] + }] + expect( + scanFn(acc, curr) + ).toEqual([ + ...acc, + curr + ]) + }) + }) + }) + + describe('> update OP', () => { + const acc = [{ + layer: { + name: 'hello-world' + }, + labelIndicies: [4,5,6] + }, { + layer: { + name: 'foo-bar', + }, + labelIndicies: [1] + }] + it('> should update with same key', () => { + expect( + scanFn(acc, curr) + ).toEqual([{ + layer: { + name: 'hello-world' + }, + labelIndicies: [4,5,6] + }, { + layer: { + name: 'foo-bar', + }, + labelIndicies: [1,2,3] + }]) + }) + }) + }) + + describe('> NehubaViewerUnit', () => { + let provideSetMeshToLoadCtrl = true + let provideLayerVisibility = true + let provideSetColorObs = true const setMeshToLoadCtl$ = new Subject<IMeshesToLoad>() + let setLayerVisibility$: Subject<string[]> + let setcolorMap$: Subject<IColorMap> beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ @@ -38,7 +110,26 @@ describe('nehubaViewer.component,ts', () => { ? setMeshToLoadCtl$ : null }, + { + provide: SET_LAYER_VISIBILITY, + useFactory: () => { + setLayerVisibility$ = provideLayerVisibility + ? new ReplaySubject(1) + : null + return setLayerVisibility$ + } + }, + { + provide: SET_COLORMAP_OBS, + useFactory: () => { + setcolorMap$ = provideSetColorObs + ? new ReplaySubject(1) + : null + return setcolorMap$ + } + }, AtlasWorkerService, + LoggingService, ] }).compileComponents() })) @@ -48,28 +139,6 @@ describe('nehubaViewer.component,ts', () => { expect(fixture.componentInstance).toBeTruthy() }) - describe('> getters', () => { - it('> showLayersName is a combination of multiNgIdsLabelIndexMap key values and overrideShowLayers', () => { - const fixture = TestBed.createComponent(NehubaViewerUnit) - const overrideShowLayers = [ - `test-1`, - `test-2` - ] - fixture.componentInstance.overrideShowLayers = overrideShowLayers - fixture.componentInstance.multiNgIdsLabelIndexMap = new Map([ - ['test-3', new Map()] - ]) - - fixture.detectChanges() - - expect(fixture.componentInstance.showLayersName).toEqual([ - `test-1`, - `test-2`, - `test-3` - ]) - }) - }) - describe('> on create', () => { it('> calls onInit lifecycle param properly', () => { const onInitSpy = jasmine.createSpy('onInit') @@ -98,7 +167,12 @@ describe('nehubaViewer.component,ts', () => { } fixture.detectChanges() - fixture.componentInstance['loadMeshes']([1,2,3], { name: 'foo-bar' }) + fixture.componentInstance['loadMeshes$'].next({ + layer: { + name: 'foo-bar' + }, + labelIndicies: [1,2,3] + }) tick(1000) expect(fixture.componentInstance.nehubaViewer.setMeshesToLoad).toHaveBeenCalledWith([1,2,3], { name: 'foo-bar' }) })) @@ -117,7 +191,12 @@ describe('nehubaViewer.component,ts', () => { } fixture.detectChanges() - fixture.componentInstance['loadMeshes']([1,2,3], { name: 'foo-bar' }) + fixture.componentInstance['loadMeshes$'].next({ + layer: { + name: 'foo-bar' + }, + labelIndicies: [1,2,3] + }) tick(1000) expect(fixture.componentInstance.nehubaViewer.setMeshesToLoad).not.toHaveBeenCalledWith([1,2,3], { name: 'foo-bar' }) })) @@ -142,5 +221,196 @@ describe('nehubaViewer.component,ts', () => { })) }) }) + + describe('> layer visibility', () => { + let nehubaViewerSpy: any + let managedLayersSpy: jasmine.Spy + let getLayerByNameSpy: jasmine.Spy + let managedLayer = { + setVisible: jasmine.createSpy() + } + let layerManager = { + get managedLayers() { + return [] + }, + getLayerByName(layerName: string){ + + } + } + + afterEach(() => { + managedLayer.setVisible.calls.reset() + }) + beforeEach(() => { + managedLayersSpy = spyOnProperty(layerManager, 'managedLayers') + managedLayersSpy.and.returnValue([ managedLayer ]) + getLayerByNameSpy = spyOn(layerManager, 'getLayerByName') + getLayerByNameSpy.and.callThrough() + + nehubaViewerSpy = { + ngviewer: { + layerManager + }, + dispose: () => {} + } + + provideLayerVisibility = true + }) + + it('> if provided obs does not emit, does not call manage layers', fakeAsync(() => { + const fixture = TestBed.createComponent(NehubaViewerUnit) + fixture.componentInstance.nehubaViewer = nehubaViewerSpy + fixture.detectChanges() + tick(320) + expect(managedLayersSpy).not.toHaveBeenCalled() + })) + + describe('> if provided obs does emit', () => { + + const setup = (emit = []) => { + const fixture = TestBed.createComponent(NehubaViewerUnit) + setLayerVisibility$.next(emit) + fixture.componentInstance.nehubaViewer = nehubaViewerSpy + fixture.detectChanges() + tick(640) + } + describe('> emits []', () => { + it('> call manage layers', fakeAsync(() => { + setup() + expect(managedLayersSpy).toHaveBeenCalled() + })) + it('> layers have visibility set off', fakeAsync(() => { + setup() + expect(managedLayer.setVisible).toHaveBeenCalledWith(false) + })) + }) + + describe('> emits ["something"]', () => { + it('> calls getLayerByname',fakeAsync(() => { + setup(['something']) + expect(layerManager.getLayerByName).toHaveBeenCalledWith('something') + })) + + it('> if returns layer, expects setVisible to be called', fakeAsync(() => { + const layer = { + setVisible: jasmine.createSpy() + } + getLayerByNameSpy.and.returnValue(layer) + setup(['something']) + expect(layer.setVisible).toHaveBeenCalledWith(true) + })) + }) + }) + }) + + describe('> colorMap obs', () => { + + let prvSetCMSpy: jasmine.Spy + const setup = () => { + + const fixture = TestBed.createComponent(NehubaViewerUnit) + fixture.detectChanges() + prvSetCMSpy = spyOn<any>(fixture.componentInstance, 'setColorMap').and.callFake(() => {}) + } + + beforeEach(() => { + provideSetColorObs = true + }) + it('> if obs does not emit, does not call setcolormap', fakeAsync(() => { + setup() + tick(320) + expect(prvSetCMSpy).not.toHaveBeenCalled() + })) + + describe('> if obs does emit', () => { + it('> setcolormap gets called', fakeAsync(() => { + setup() + setcolorMap$.next({ + 'foo-bar': { + 1: { red: 100, green: 100, blue: 100 }, + 2: { red: 200, green: 200, blue: 200 }, + }, + 'hello-world': { + 1: { red: 10, green: 10, blue: 10 }, + 2: { red: 20, green: 20, blue: 20 }, + } + }) + tick(320) + expect(prvSetCMSpy).toHaveBeenCalled() + })) + + it('> call arg is as expected', fakeAsync(() => { + setup() + setcolorMap$.next({ + 'foo-bar': { + 1: { red: 100, green: 100, blue: 100 }, + 2: { red: 200, green: 200, blue: 200 }, + }, + 'hello-world': { + 1: { red: 10, green: 10, blue: 10 }, + 2: { red: 20, green: 20, blue: 20 }, + } + }) + tick(320) + const map = new Map([ + ['foo-bar', new Map([ + ['1', { red: 100, green: 100, blue: 100 }], + ['2', { red: 200, green: 200, blue: 200 }], + ])], + ['hello-world', new Map([ + ['1', { red: 10, green: 10, blue: 10 }], + ['2', { red: 20, green: 20, blue: 20 }], + ])] + ]) + + expect(prvSetCMSpy).toHaveBeenCalledWith(map) + })) + }) + }) + + describe('> # setColorMap', () => { + let nehubaViewerSpy: any + beforeEach(() => { + nehubaViewerSpy = { + batchAddAndUpdateSegmentColors: jasmine.createSpy(), + dispose(){ + + } + } + }) + it('> calls nehubaViewer.batchAddAndUpdateSegmentColors', () => { + const fixture = TestBed.createComponent(NehubaViewerUnit) + fixture.componentInstance.nehubaViewer = nehubaViewerSpy + fixture.detectChanges() + + const mainMap = new Map<string, Map<number, { red: number, green: number, blue: number }>>() + const fooBarMap = new Map() + fooBarMap.set(1, {red: 100, green: 100, blue: 100}) + fooBarMap.set(2, {red: 200, green: 200, blue: 200}) + mainMap.set('foo-bar', fooBarMap) + + const helloWorldMap = new Map() + helloWorldMap.set(1, {red: 10, green: 10, blue: 10}) + helloWorldMap.set(2, {red: 20, green: 20, blue: 20}) + mainMap.set('hello-world', helloWorldMap) + + fixture.componentInstance['setColorMap'](mainMap) + + expect( + nehubaViewerSpy.batchAddAndUpdateSegmentColors + ).toHaveBeenCalledTimes(2) + + expect(nehubaViewerSpy.batchAddAndUpdateSegmentColors).toHaveBeenCalledWith( + fooBarMap, + { name: 'foo-bar' } + ) + + expect(nehubaViewerSpy.batchAddAndUpdateSegmentColors).toHaveBeenCalledWith( + helloWorldMap, + { name: 'hello-world' } + ) + }) + }) + }) }) diff --git a/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts b/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts index e6b84b64cfbbfa06f4b9ac2a381b67f85406a268..bf63d48d516ee607455f70beb4639910184fa00e 100644 --- a/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts +++ b/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts @@ -3,15 +3,15 @@ import { fromEvent, Subscription, ReplaySubject, BehaviorSubject, Observable, ra import { debounceTime, filter, map, scan, startWith, mapTo, switchMap, take, skip, tap } from "rxjs/operators"; import { AtlasWorkerService } from "src/atlasViewer/atlasViewer.workerService.service"; import { StateInterface as ViewerConfiguration } from "src/services/state/viewerConfig.store"; - import { LoggingService } from "src/logging"; -import { getExportNehuba, getViewer, setNehubaViewer } from "src/util/fn"; +import { getExportNehuba, getViewer, setNehubaViewer, switchMapWaitFor } from "src/util/fn"; +import { NEHUBA_INSTANCE_INJTKN, scanSliceViewRenderFn } from "../util"; +import { deserialiseParcRegionId } from 'common/util' +import { IMeshesToLoad, SET_MESHES_TO_LOAD } from "../constants"; +import { IColorMap, SET_COLORMAP_OBS, SET_LAYER_VISIBILITY } from "../layerCtrl.service"; import '!!file-loader?context=third_party&name=main.bundle.js!export-nehuba/dist/min/main.bundle.js' import '!!file-loader?context=third_party&name=chunk_worker.bundle.js!export-nehuba/dist/min/chunk_worker.bundle.js' -import { NEHUBA_INSTANCE_INJTKN, scanSliceViewRenderFn } from "../util"; -import { strToRgb, deserialiseParcRegionId } from 'common/util' -import { IMeshesToLoad, SET_MESHES_TO_LOAD } from "../constants"; const NG_LANDMARK_LAYER_NAME = 'spatial landmark layer' const NG_USER_LANDMARK_LAYER_NAME = 'user landmark layer' @@ -38,17 +38,18 @@ export interface INehubaLifecycleHook{ onInit?: () => void } -const scanFn: (acc: LayerLabelIndex[], curr: LayerLabelIndex) => LayerLabelIndex[] = (acc: LayerLabelIndex[], curr: LayerLabelIndex) => { - const { layer } = curr - const { name } = layer - const foundIndex = acc.findIndex(({ layer }) => layer.name === name) - if (foundIndex < 0) { return acc.concat(curr) } else { return acc.map((item, idx) => idx === foundIndex - ? { - ...item, - labelIndicies: [...new Set([...item.labelIndicies, ...curr.labelIndicies])], - } - : item) +export const scanFn = (acc: LayerLabelIndex[], curr: LayerLabelIndex) => { + const found = acc.find(layerLabelIndex => { + return layerLabelIndex.layer.name === curr.layer.name + }) + if (!found) { + return [ ...acc, curr ] } + return acc.map(layerLabelIndex => { + return layerLabelIndex.layer.name === curr.layer.name + ? curr + : layerLabelIndex + }) } /** @@ -66,12 +67,6 @@ export class NehubaViewerUnit implements OnInit, OnDestroy { private sliceviewLoading$: Observable<boolean> public overrideShowLayers: string[] = [] - get showLayersName() { - return [ - ...this.overrideShowLayers, - ...Array.from(this.multiNgIdsLabelIndexMap.keys()) - ] - } public lifecycle: INehubaLifecycleHook @@ -81,7 +76,6 @@ export class NehubaViewerUnit implements OnInit, OnDestroy { public mousePosInReal$ = new BehaviorSubject(null) private exportNehuba: any - private viewer: any private subscriptions: Subscription[] = [] @@ -119,7 +113,6 @@ export class NehubaViewerUnit implements OnInit, OnDestroy { : [1.5e9, 1.5e9, 1.5e9] } - public _s1$: any = null public _s2$: any = null public _s3$: any = null public _s4$: any = null @@ -127,10 +120,8 @@ export class NehubaViewerUnit implements OnInit, OnDestroy { public _s6$: any = null public _s7$: any = null public _s8$: any = null - public _s9$: any = null public _s$: any[] = [ - this._s1$, this._s2$, this._s3$, this._s4$, @@ -138,7 +129,6 @@ export class NehubaViewerUnit implements OnInit, OnDestroy { this._s6$, this._s7$, this._s8$, - this._s9$, ] public ondestroySubscriptions: Subscription[] = [] @@ -150,6 +140,8 @@ export class NehubaViewerUnit implements OnInit, OnDestroy { public nehubaLoaded: boolean = false + public landmarksLoaded: boolean = false + constructor( public elementRef: ElementRef, private workerService: AtlasWorkerService, @@ -157,6 +149,8 @@ export class NehubaViewerUnit implements OnInit, OnDestroy { @Inject(IMPORT_NEHUBA_INJECT_TOKEN) getImportNehubaPr: () => Promise<any>, @Optional() @Inject(NEHUBA_INSTANCE_INJTKN) private nehubaViewer$: Subject<NehubaViewerUnit>, @Optional() @Inject(SET_MESHES_TO_LOAD) private injSetMeshesToLoad$: Observable<IMeshesToLoad>, + @Optional() @Inject(SET_COLORMAP_OBS) private setColormap$: Observable<IColorMap>, + @Optional() @Inject(SET_LAYER_VISIBILITY) private layerVis$: Observable<string[]>, ) { if (this.nehubaViewer$) { @@ -185,6 +179,9 @@ export class NehubaViewerUnit implements OnInit, OnDestroy { }) .catch(e => this.errorEmitter.emit(e)) + /** + * TODO move to layerCtrl.service + */ this.ondestroySubscriptions.push( fromEvent(this.workerService.worker, 'message').pipe( filter((message: any) => { @@ -222,6 +219,9 @@ export class NehubaViewerUnit implements OnInit, OnDestroy { }), ) + /** + * TODO move to layerCtrl.service + */ this.ondestroySubscriptions.push( fromEvent(this.workerService.worker, 'message').pipe( filter((message: any) => { @@ -251,6 +251,7 @@ export class NehubaViewerUnit implements OnInit, OnDestroy { debounceTime(100), map(e => e.data.url), ).subscribe(url => { + this.landmarksLoaded = !!url this.removeuserLandmarks() /** @@ -260,13 +261,7 @@ export class NehubaViewerUnit implements OnInit, OnDestroy { /** * remove transparency from meshes in current layer(s) */ - for (const layerKey of this.multiNgIdsLabelIndexMap.keys()) { - const layer = this.nehubaViewer.ngviewer.layerManager.getLayerByName(layerKey) - if (layer) { - layer.layer.displayState.objectAlpha.restoreState(1.0) - } - } - + this.setMeshTransparency(false) return } const _ = {} @@ -280,18 +275,55 @@ export class NehubaViewerUnit implements OnInit, OnDestroy { /** * adding transparency to meshes in current layer(s) */ - for (const layerKey of this.multiNgIdsLabelIndexMap.keys()) { - const layer = this.nehubaViewer.ngviewer.layerManager.getLayerByName(layerKey) - if (layer) { - layer.layer.displayState.objectAlpha.restoreState(0.2) - } - } + this.setMeshTransparency(true) }), ) - } + + if (this.setColormap$) { + this.ondestroySubscriptions.push( + this.setColormap$.pipe( + debounceTime(160), + ).subscribe(v => { + const map = new Map() + for (const key in v) { + const m = new Map() + map.set(key, m) + for (const lblIdx in v[key]) { + m.set(lblIdx, v[key][lblIdx]) + } + } + this.setColorMap(map) + }) + ) + } else { + this.log.error(`SET_COLORMAP_OBS not provided`) + } - private _baseUrlToParcellationIdMap: Map<string, string> = new Map() - private _baseUrls: string[] = [] + if (this.layerVis$) { + this.ondestroySubscriptions.push( + this.layerVis$.pipe( + switchMap(switchMapWaitFor({ condition: () => !!(this.nehubaViewer?.ngviewer) })), + tap(() => { + const managedLayers = this.nehubaViewer.ngviewer.layerManager.managedLayers + managedLayers.forEach(layer => layer.setVisible(false)) + }), + debounceTime(160), + ).subscribe((layerNames: string[]) => { + + for (const layerName of layerNames) { + const layer = this.nehubaViewer.ngviewer.layerManager.getLayerByName(layerName) + if (layer) { + layer.setVisible(true) + } else { + this.log.log('layer unavailable', layerName) + } + } + }) + ) + } else { + this.log.error(`SET_LAYER_VISIBILITY not provided`) + } + } public numMeshesToBeLoaded: number = 0 @@ -313,25 +345,6 @@ export class NehubaViewerUnit implements OnInit, OnDestroy { this._templateId = id } - /** compatible with multiple parcellation id selection */ - private _ngIds: string[] = [] - get ngIds() { - return this._ngIds - } - - set ngIds(val: string[]) { - this.createNehubaPromise - .then(() => { - this._ngIds.forEach(id => { - const oldlayer = this.nehubaViewer.ngviewer.layerManager.getLayerByName(id) - if (oldlayer) {oldlayer.setVisible(false) } else { this.log.warn('could not find old layer', id) } - }) - this._ngIds = val - this.loadNewParcellation() - this.showAllSeg() - }) - } - public spatialLandmarkSelectionChanged(labels: number[]) { const getCondition = (label: number) => `if(label > ${label - 0.1} && label < ${label + 0.1} ){${FRAGMENT_EMIT_RED}}` const newShader = `void main(){ ${labels.map(getCondition).join('else ')}else {${FRAGMENT_EMIT_WHITE}} }` @@ -351,6 +364,8 @@ export class NehubaViewerUnit implements OnInit, OnDestroy { } } + // TODO move region management to another service + public multiNgIdsLabelIndexMap: Map<string, Map<number, any>> = new Map() public navPosReal: [number, number, number] = [0, 0, 0] @@ -399,13 +414,6 @@ export class NehubaViewerUnit implements OnInit, OnDestroy { * Hide all layers except the base layer (template) * Then show the layers referenced in multiNgIdLabelIndexMap */ - const managedLayers = this.nehubaViewer.ngviewer.layerManager.managedLayers - managedLayers.slice(1).forEach(layer => layer.setVisible(false)) - - for (const layerName of this.showLayersName) { - const layer = this.nehubaViewer.ngviewer.layerManager.getLayerByName(layerName) - if (layer) { layer.setVisible(true) } else { this.log.log('layer unavailable', layerName) } - } this.redraw() @@ -771,23 +779,36 @@ export class NehubaViewerUnit implements OnInit, OnDestroy { this.nehubaViewer.ngviewer.navigationState.pose.rotateRelative(this.vec3([0, 0, 1]), amount / 4.0 * Math.PI / 180.0) } - /** - * - * @param arrayIdx label indices of the shown segment(s) - * @param ngId segmentation layer name - */ - private updateColorMap(arrayIdx: number[], ngId: string) { - const set = new Set(arrayIdx) - const newColorMap = new Map( - Array.from(this.multiNgIdColorMap.get(ngId).entries()) - .map(v => set.has(v[0]) || set.size === 0 ? - v : - [v[0], {red: 255, green: 255, blue: 255}]) as any, - ) + public toggleOctantRemoval(flag?: boolean) { + const ctrl = this.nehubaViewer?.ngviewer?.showPerspectiveSliceViews + if (!ctrl) { + this.log.error(`toggleOctantRemoval failed. this.nehubaViewer.ngviewer?.showPerspectiveSliceViews returns falsy`) + return + } + const newVal = typeof flag === 'undefined' + ? !ctrl.value + : flag + ctrl.restoreState(newVal) - this.nehubaViewer.batchAddAndUpdateSegmentColors(newColorMap, { - name: ngId, - }) + if (this.landmarksLoaded) { + /** + * showPerspectSliceView -> ! meshTransparency + */ + this.setMeshTransparency(!newVal) + } + } + + public setMeshTransparency(flag: boolean){ + + /** + * remove transparency from meshes in current layer(s) + */ + for (const layerKey of this.multiNgIdsLabelIndexMap.keys()) { + const layer = this.nehubaViewer.ngviewer.layerManager.getLayerByName(layerKey) + if (layer) { + layer.layer.displayState.objectAlpha.restoreState(flag ? 0.2 : 1.0) + } + } } private newViewerInit() { @@ -913,113 +934,22 @@ export class NehubaViewerUnit implements OnInit, OnDestroy { private loadNewParcellation() { - /* show correct segmentation layer */ - this._baseUrls = [] - - this.ngIds.map(id => { - const newlayer = this.nehubaViewer.ngviewer.layerManager.getLayerByName(id) - if (newlayer) {newlayer.setVisible(true) } else { this.log.warn('could not find new layer', id) } - - const regex = /^(\S.*?):\/\/(.*?)$/.exec(newlayer.sourceUrl) - - if (!regex || !regex[2]) { - this.log.error('could not parse baseUrl') - return - } - if (regex[1] !== 'precomputed') { - this.log.error('sourceUrl is not precomputed') - return - } - - const baseUrl = regex[2] - this._baseUrls.push(baseUrl) - this._baseUrlToParcellationIdMap.set(baseUrl, id) - - const indicies = [ - ...Array.from(this.multiNgIdsLabelIndexMap.get(id).keys()), - ...this.auxilaryMeshIndices, - ] - if (!this.injSetMeshesToLoad$) { - this.loadMeshes(indicies, { name: id }) - } - }) - - const obj = Array.from(this.multiNgIdsLabelIndexMap.keys()).map(ngId => { - return [ - ngId, - new Map(Array.from( - [ - // set aux mesh first - // as sometimes, existing rgb can overwrite the rgb prop of aux mesh - ...this.auxilaryMeshIndices.map(val => { - return [val, {}] - }), - ...this.multiNgIdsLabelIndexMap.get(ngId).entries(), - ], - ).map((val: [number, any]) => ([val[0], this.getRgb(val[0], { ngId, rgb: val[1].rgb})])) as any), - ] - }) as Array<[string, Map<number, {red: number, green: number, blue: number}>]> - - const multiNgIdColorMap = new Map(obj) - - /* load colour maps */ - - this.setColorMap(multiNgIdColorMap) - this._s$.forEach(_s$ => { if (_s$) { _s$.unsubscribe() } }) - if (this._s1$) {this._s1$.unsubscribe() } - if (this._s9$) {this._s9$.unsubscribe() } - - const arr = Array.from(this.multiNgIdsLabelIndexMap.keys()).map(ngId => { - return this.nehubaViewer.getShownSegmentsObservable({ - name: ngId, - }).subscribe(arrayIdx => this.updateColorMap(arrayIdx, ngId)) - }) - - this._s9$ = { - unsubscribe: () => { - while (arr.length > 0) { - arr.pop().unsubscribe() - } - }, - } } - public setColorMap(map: Map<string, Map<number, {red: number, green: number, blue: number}>>) { + private setColorMap(map: Map<string, Map<number, {red: number, green: number, blue: number}>>) { this.multiNgIdColorMap = map - - Array.from(map.entries()).forEach(([ngId, map]) => { - + for (const [ ngId, cMap ] of map.entries()) { + const nMap = new Map() + for (const [ key, cm ] of cMap.entries()) { + nMap.set(Number(key), cm) + } this.nehubaViewer.batchAddAndUpdateSegmentColors( - map, + nMap, { name : ngId }) - }) - } - - private getRgb(labelIndex: number, region: { rgb: number[], ngId: string }): {red: number, green: number, blue: number} { - const { rgb, ngId } = region - if (typeof rgb === 'undefined' || rgb === null) { - if (labelIndex > 65500) { - return { - red: 255, - green: 255, - blue: 255 - } - } - const arr = strToRgb(`${ngId}${labelIndex}`) - return { - red : arr[0], - green: arr[1], - blue : arr[2], - } - } - return { - red : rgb[0], - green: rgb[1], - blue : rgb[2], } } } diff --git a/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.ts b/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.ts index af1bbefe8592dc18f515a9606a74461e7264404b..004f45f50516bcc6dc5ea1d55a575ac750be0781 100644 --- a/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.ts +++ b/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.ts @@ -1,26 +1,28 @@ import { Component, ElementRef, EventEmitter, Inject, Input, OnChanges, OnDestroy, Optional, Output, SimpleChanges, ViewChild } from "@angular/core"; import { select, Store } from "@ngrx/store"; -import { asyncScheduler, combineLatest, fromEvent, interval, merge, Observable, of, Subject, timer } from "rxjs"; -import { ngViewerActionAddNgLayer, ngViewerActionRemoveNgLayer, ngViewerActionSetPerspOctantRemoval, ngViewerActionToggleMax } from "src/services/state/ngViewerState/actions"; +import { asyncScheduler, combineLatest, fromEvent, merge, Observable, of, Subject } from "rxjs"; +import { ngViewerActionAddNgLayer, ngViewerActionRemoveNgLayer, ngViewerActionToggleMax } from "src/services/state/ngViewerState/actions"; import { ClickInterceptor, CLICK_INTERCEPTOR_INJECTOR } from "src/util"; import { uiStateMouseOverSegmentsSelector } from "src/services/state/uiState/selectors"; -import { debounceTime, distinctUntilChanged, filter, map, mapTo, scan, shareReplay, startWith, switchMap, switchMapTo, take, tap, throttleTime, withLatestFrom } from "rxjs/operators"; +import { debounceTime, distinctUntilChanged, filter, map, mapTo, scan, shareReplay, startWith, switchMap, switchMapTo, take, tap, throttleTime } from "rxjs/operators"; import { viewerStateAddUserLandmarks, viewerStateChangeNavigation, viewerStateMouseOverCustomLandmark, viewerStateSelectRegionWithIdDeprecated, viewerStateSetSelectedRegions, viewreStateRemoveUserLandmarks } from "src/services/state/viewerState/actions"; -import { ngViewerSelectorLayers, ngViewerSelectorClearView, ngViewerSelectorPanelOrder, ngViewerSelectorOctantRemoval, ngViewerSelectorPanelMode } from "src/services/state/ngViewerState/selectors"; +import { ngViewerSelectorLayers, ngViewerSelectorClearView, ngViewerSelectorPanelOrder, ngViewerSelectorPanelMode } from "src/services/state/ngViewerState/selectors"; import { viewerStateCustomLandmarkSelector, viewerStateNavigationStateSelector, viewerStateSelectedRegionsSelector } from "src/services/state/viewerState/selectors"; import { serialiseParcellationRegion } from 'common/util' import { ARIA_LABELS, IDS } from 'common/constants' import { PANELS } from "src/services/state/ngViewerState/constants"; import { LoggingService } from "src/logging"; -import { getNgIds, getMultiNgIdsRegionsLabelIndexMap, SET_MESHES_TO_LOAD } from "../constants"; +import { getMultiNgIdsRegionsLabelIndexMap, SET_MESHES_TO_LOAD } from "../constants"; import { IViewer, TViewerEvent } from "../../viewer.interface"; import { NehubaViewerUnit } from "../nehubaViewer/nehubaViewer.component"; import { NehubaViewerContainerDirective } from "../nehubaViewerInterface/nehubaViewerInterface.directive"; -import { cvtNavigationObjToNehubaConfig, getFourPanel, getHorizontalOneThree, getSinglePanel, getVerticalOneThree, NEHUBA_INSTANCE_INJTKN, scanSliceViewRenderFn, takeOnePipe } from "../util"; +import { cvtNavigationObjToNehubaConfig, getFourPanel, getHorizontalOneThree, getSinglePanel, getVerticalOneThree, scanSliceViewRenderFn, takeOnePipe } from "../util"; import { API_SERVICE_SET_VIEWER_HANDLE_TOKEN, TSetViewerHandle } from "src/atlasViewer/atlasViewer.apiService.service"; import { MouseHoverDirective } from "src/mouseoverModule"; import { NehubaMeshService } from "../mesh.service"; +import { NehubaLayerControlService, IColorMap, SET_COLORMAP_OBS, SET_LAYER_VISIBILITY } from "../layerCtrl.service"; +import { switchMapWaitFor } from "src/util/fn"; interface INgLayerInterface { name: string // displayName @@ -46,7 +48,18 @@ interface INgLayerInterface { useFactory: (meshService: NehubaMeshService) => meshService.loadMeshes$, deps: [ NehubaMeshService ] }, - NehubaMeshService + NehubaMeshService, + { + provide: SET_COLORMAP_OBS, + useFactory: (layerCtrl: NehubaLayerControlService) => layerCtrl.setColorMap$, + deps: [ NehubaLayerControlService ] + }, + { + provide: SET_LAYER_VISIBILITY, + useFactory: (layerCtrl: NehubaLayerControlService) => layerCtrl.visibleLayer$, + deps: [ NehubaLayerControlService ] + }, + NehubaLayerControlService ] }) @@ -101,31 +114,6 @@ export class NehubaGlueCmp implements IViewer, OnChanges, OnDestroy{ }))), ) - private forceUI$ = this.customLandmarks$.pipe( - map(lm => { - if (lm.length > 0) { - return { - target: 'perspective:octantRemoval', - mode: false, - message: `octant control disabled: showing landmarks.` - } - } else { - return { - target: 'perspective:octantRemoval', - mode: null - } - } - }) - ) - - public disableOctantRemovalCtrl$ = this.forceUI$.pipe( - filter(({ target }) => target === 'perspective:octantRemoval'), - ) - - public nehubaViewerPerspectiveOctantRemoval$ = this.store$.pipe( - select(ngViewerSelectorOctantRemoval), - ) - public panelOrder$ = this.store$.pipe( select(ngViewerSelectorPanelOrder), distinctUntilChanged(), @@ -164,21 +152,11 @@ export class NehubaGlueCmp implements IViewer, OnChanges, OnDestroy{ return } - /** - * first, get all all the ngIds, including parent id from parcellation (if defined) - */ - const ngIds = getNgIds(parcellation.regions).concat( parcellation.ngId ? parcellation.ngId : []) - this.multiNgIdsRegionsLabelIndexMap = getMultiNgIdsRegionsLabelIndexMap(parcellation) this.viewerUnit.multiNgIdsLabelIndexMap = this.multiNgIdsRegionsLabelIndexMap this.viewerUnit.auxilaryMeshIndices = parcellation.auxillaryMeshIndices || [] - /* TODO replace with proper KG id */ - /** - * need to set unique array of ngIds, or else workers will be overworked - */ - this.viewerUnit.ngIds = Array.from(new Set(ngIds)) } private unloadTmpl(tmpl: any) { @@ -282,6 +260,7 @@ export class NehubaGlueCmp implements IViewer, OnChanges, OnDestroy{ private log: LoggingService, @Optional() @Inject(CLICK_INTERCEPTOR_INJECTOR) clickInterceptor: ClickInterceptor, @Optional() @Inject(API_SERVICE_SET_VIEWER_HANDLE_TOKEN) setViewerHandle: TSetViewerHandle, + @Optional() private layerCtrlService: NehubaLayerControlService, ){ this.viewerEvent.emit({ type: 'MOUSEOVER_ANNOTATION', @@ -473,19 +452,6 @@ export class NehubaGlueCmp implements IViewer, OnChanges, OnDestroy{ }) this.onDestroyCb.push(() => perspectiveRenderEvSub.unsubscribe()) - const perspOctCtrlSub = this.customLandmarks$.pipe( - withLatestFrom( - this.nehubaViewerPerspectiveOctantRemoval$ - ), - switchMap(this.waitForNehuba.bind(this)) - ).subscribe(([ landmarks, flag ]) => { - this.nehubaContainerDirective.toggleOctantRemoval( - landmarks.length > 0 ? false : flag - ) - this.nehubaContainerDirective.nehubaViewerInstance.updateUserLandmarks(landmarks) - }) - this.onDestroyCb.push(() => perspOctCtrlSub.unsubscribe()) - this.sliceRenderEvent$ = fromEvent<CustomEvent>(this.el.nativeElement, 'sliceRenderEvent') this.sliceViewLoadingMain$ = this.sliceRenderEvent$.pipe( scan(scanSliceViewRenderFn, [null, null, null]), @@ -648,25 +614,37 @@ export class NehubaGlueCmp implements IViewer, OnChanges, OnDestroy{ selectRegionIds: [] })) }, - segmentColourMap : new Map(), getLayersSegmentColourMap: () => { + if (!this.layerCtrlService) { + throw new Error(`layerCtrlService not injected. Cannot call getLayersSegmentColourMap`) + } const newMainMap = new Map() - for (const [key, colormap] of this.nehubaContainerDirective.nehubaViewerInstance.multiNgIdColorMap.entries()) { - const newColormap = new Map() - newMainMap.set(key, newColormap) - - for (const [lableIndex, entry] of colormap.entries()) { - newColormap.set(lableIndex, JSON.parse(JSON.stringify(entry))) + for (const key in this.layerCtrlService.activeColorMap) { + const obj = this.layerCtrlService.activeColorMap[key] + const m = new Map() + newMainMap.set(key, m) + for (const labelIndex in obj) { + m.set(Number(labelIndex), obj[labelIndex]) } } return newMainMap }, - applyColourMap : (_map) => { - throw new Error(`apply color map has been deprecated. use applyLayersColourMap instead`) - }, applyLayersColourMap: (map) => { - this.nehubaContainerDirective.nehubaViewerInstance.setColorMap(map) + if (!this.layerCtrlService) { + throw new Error(`layerCtrlService not injected. Cannot call getLayersSegmentColourMap`) + } + const obj: IColorMap = {} + for (const [ key, value ] of map.entries()) { + const cmap = obj[key] = {} + for (const [ labelIdx, rgb ] of value.entries()) { + cmap[Number(labelIdx)] = rgb + } + } + this.layerCtrlService.overwriteColorMap$.next(obj) }, + /** + * TODO go via layerCtrl.service + */ loadLayer : (layerObj) => this.nehubaContainerDirective.nehubaViewerInstance.loadLayer(layerObj), removeLayer : (condition) => this.nehubaContainerDirective.nehubaViewerInstance.removeLayer(condition), setLayerVisibility : (condition, visible) => this.nehubaContainerDirective.nehubaViewerInstance.setLayerVisibility(condition, visible), @@ -680,9 +658,14 @@ export class NehubaGlueCmp implements IViewer, OnChanges, OnDestroy{ /** * neuroglancer prevents propagation, so use capture instead */ - Observable.create(observer => { - this.el.nativeElement.addEventListener('mousedown', event => observer.next({eventName: 'mousedown', event}), true) - }) as Observable<{eventName: string, event: MouseEvent}>, + fromEvent(this.el.nativeElement, 'mousedown', { capture: true }).pipe( + map((event: MouseEvent) => { + return { + eventName: 'mousedown', + event + } + }) + ), fromEvent(this.el.nativeElement, 'mouseup').pipe( map((ev: MouseEvent) => ({eventName : 'mouseup', event: ev})), ), @@ -717,7 +700,7 @@ export class NehubaGlueCmp implements IViewer, OnChanges, OnDestroy{ this.viewerLoaded = flag } - private selectHoveredRegion(ev: any, next: Function){ + private selectHoveredRegion(_ev: any, next: Function){ /** * If label indicies are not defined by the ontology, it will be a string in the format of `{ngId}#{labelIndex}` */ @@ -731,21 +714,9 @@ export class NehubaGlueCmp implements IViewer, OnChanges, OnDestroy{ next() } - private waitForNehuba(arg: unknown) { - return interval(16).pipe( - filter(() => !!(this.nehubaContainerDirective?.isReady())), - take(1), - mapTo(arg), - ) - } - - public setOctantRemoval(octantRemovalFlag: boolean) { - this.store$.dispatch( - ngViewerActionSetPerspOctantRemoval({ - octantRemovalFlag - }) - ) - } + private waitForNehuba = switchMapWaitFor({ + condition: () => !!(this.nehubaContainerDirective?.isReady()) + }) public toggleMaximiseMinimise(index: number) { this.store$.dispatch(ngViewerActionToggleMax({ diff --git a/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.template.html b/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.template.html index 65057b2b5f6b841514f2619dc063b96fe136afe7..d5f86d163f05dcb062d6883476a76670d9e132f0 100644 --- a/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.template.html +++ b/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.template.html @@ -115,12 +115,12 @@ <!-- perspective specific control --> <ng-container *ngIf="panelIndex === 3"> - <ng-container *ngTemplateOutlet="perspectiveOctantRemovalTmpl; context: { - state: (nehubaViewerPerspectiveOctantRemoval$ | async), - disableOctantRemovalCtrl: disableOctantRemovalCtrl$ | async - }"> - </ng-container> + <button mat-icon-button color="primary" + [matMenuTriggerFor]="viewerCtrlMenu"> + <i class="fas fa-cog"></i> + </button> + </ng-container> <!-- factor < 1.0 === zoom in --> @@ -145,28 +145,12 @@ </ng-template> -<!-- tmpl for toggling perspective frontal octant --> -<ng-template #perspectiveOctantRemovalTmpl - let-state="state" - let-disableOctantRemovalCtrl="disableOctantRemovalCtrl"> - <div class="d-inline-block" - [matTooltip]="disableOctantRemovalCtrl?.mode !== null ? disableOctantRemovalCtrl.message : null"> - <button - (click)="setOctantRemoval(!state)" - mat-icon-button - [disabled]="disableOctantRemovalCtrl?.mode !== null" - [attr.aria-label]="ARIA_LABELS.TOGGLE_FRONTAL_OCTANT" - color="primary"> - - <!-- octant removal is true --> - <ng-template [ngIf]="disableOctantRemovalCtrl?.mode !== null ? disableOctantRemovalCtrl.mode : state" [ngIfElse]="octantRemovalOffTmpl"> - <i class="fas fa-eye-slash"></i> - </ng-template> - - <!-- octant removal is false --> - <ng-template #octantRemovalOffTmpl> - <i class="fas fa-eye"></i> - </ng-template> - </button> - </div> -</ng-template> \ No newline at end of file +<!-- viewer ctrl --> +<mat-menu #viewerCtrlMenu> + <!-- NB must not lazy load. key listener needs to work even when component is not yet rendered --> + <!-- stop propagation is needed, or else click will result in dismiss of menu --> + <viewer-ctrl-component class="d-block m-2 ml-3 mr-3" + #viewerCtrlCmp="viewerCtrlCmp" + (click)="$event.stopPropagation()"> + </viewer-ctrl-component> +</mat-menu> diff --git a/src/viewerModule/nehuba/nehubaViewerInterface/nehubaViewerInterface.directive.spec.ts b/src/viewerModule/nehuba/nehubaViewerInterface/nehubaViewerInterface.directive.spec.ts index a061c392141ee2c259157fc7df55dc75feb7d287..42c350441b7aba57d1a3d15eece54a238e25b2a7 100644 --- a/src/viewerModule/nehuba/nehubaViewerInterface/nehubaViewerInterface.directive.spec.ts +++ b/src/viewerModule/nehuba/nehubaViewerInterface/nehubaViewerInterface.directive.spec.ts @@ -88,7 +88,8 @@ describe('> nehubaViewerInterface.directive.ts', () => { mouseoverUserlandmarkEmitter: new Subject(), elementRef: { nativeElement: {} - } + }, + toggleOctantRemoval: jasmine.createSpy() } const spyComRef = { destroy: jasmine.createSpy('destroy') diff --git a/src/viewerModule/nehuba/nehubaViewerInterface/nehubaViewerInterface.directive.ts b/src/viewerModule/nehuba/nehubaViewerInterface/nehubaViewerInterface.directive.ts index cdb000a9cfa40f0c34ba86f7dc6e697a7ea6267a..33891485ba4928a4a4f5a8f0e817fda7acd67dcd 100644 --- a/src/viewerModule/nehuba/nehubaViewerInterface/nehubaViewerInterface.directive.ts +++ b/src/viewerModule/nehuba/nehubaViewerInterface/nehubaViewerInterface.directive.ts @@ -290,11 +290,11 @@ export class NehubaViewerContainerDirective implements OnInit, OnDestroy{ } public toggleOctantRemoval(flag: boolean){ - const showPerspectiveSliceViews = this.nehubaViewerInstance?.nehubaViewer?.ngviewer?.showPerspectiveSliceViews - if (showPerspectiveSliceViews) showPerspectiveSliceViews.restoreState(flag) - else { - this.log && this.log.warn(`showPerspectiveSliceViews not defined`) + if (!this.nehubaViewerInstance) { + this.log.error(`this.nehubaViewerInstance is not yet available`) + return } + this.nehubaViewerInstance.toggleOctantRemoval(flag) } createNehubaInstance(template: any, lifeCycle: INehubaLifecycleHook = {}){ @@ -309,7 +309,7 @@ export class NehubaViewerContainerDirective implements OnInit, OnDestroy{ } } - const { nehubaConfig } = template + const { nehubaConfig, name } = template /** * apply viewer config such as gpu limit diff --git a/src/viewerModule/nehuba/store.ts b/src/viewerModule/nehuba/store.ts deleted file mode 100644 index f00a217031ac76ef8bb50ba0a7e30b0e47963e22..0000000000000000000000000000000000000000 --- a/src/viewerModule/nehuba/store.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { createReducer } from "@ngrx/store"; -import { INgLayerInterface } from "src/services/state/ngViewerState.store"; - - -/** - * TODO port from global store to feature store - */ - -enum EnumPanelMode { - FOUR_PANEL = 'FOUR_PANEL', - V_ONE_THREE = 'V_ONE_THREE', - H_ONE_THREE = 'H_ONE_THREE', - SINGLE_PANEL = 'SINGLE_PANEL', -} - -interface INehubaFeature { - layers: INgLayerInterface[] - panelMode: string - panelOrder: string - octantRemoval: boolean - clearViewQueue: { - [key: string]: boolean - } -} - -const defaultState: INehubaFeature = { - layers: [], - panelMode: EnumPanelMode.FOUR_PANEL, - panelOrder: '0123', - octantRemoval: true, - clearViewQueue: {} -} - -export const reducer = createReducer( - defaultState -) \ No newline at end of file diff --git a/src/viewerModule/nehuba/store/actions.ts b/src/viewerModule/nehuba/store/actions.ts new file mode 100644 index 0000000000000000000000000000000000000000..38c6572e1259651318bede3684278e71179f3daa --- /dev/null +++ b/src/viewerModule/nehuba/store/actions.ts @@ -0,0 +1,36 @@ +import { createAction, props } from "@ngrx/store"; +import { INgLayerInterface } from "src/services/state/ngViewerState.store"; +import { NEHUBA_VIEWER_FEATURE_KEY } from "../constants"; +import { IAuxMesh } from "./type"; + +export const actionAddNgLayer = createAction( + `[${NEHUBA_VIEWER_FEATURE_KEY}] [addNgLayer]`, + props<{ + layers: INgLayerInterface[] + }>() +) + +export const actionSetAuxMesh = createAction( + `[${NEHUBA_VIEWER_FEATURE_KEY}] [setAuxMesh]`, + props<{ + payload: IAuxMesh + }>() +) + +export const actionRemoveAuxMesh = createAction( + `[${NEHUBA_VIEWER_FEATURE_KEY}] [rmAuxMesh]`, + props<{ + payload: { "@id": string } + }>() +) + +export const actionSetAuxMeshes = createAction( + `[${NEHUBA_VIEWER_FEATURE_KEY}] [setAuxMeshes]`, + props<{ + payload: IAuxMesh[] + }>() +) + +export const actionClearAuxMeshes = createAction( + `[${NEHUBA_VIEWER_FEATURE_KEY}] [clearAuxMeshes]` +) diff --git a/src/viewerModule/nehuba/store/index.ts b/src/viewerModule/nehuba/store/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..a384638d8bf82bd1b38296d9a061405b552cd7f1 --- /dev/null +++ b/src/viewerModule/nehuba/store/index.ts @@ -0,0 +1,18 @@ +export { + actionAddNgLayer, + actionRemoveAuxMesh, + actionSetAuxMesh, + actionClearAuxMeshes, + actionSetAuxMeshes, +} from './actions' +export { + selectorAuxMeshes +} from './selectors' +export { + reducer +} from './store' +export { + IAuxMesh, + INehubaFeature, + INgLayerInterface +} from './type' diff --git a/src/viewerModule/nehuba/store/selectors.ts b/src/viewerModule/nehuba/store/selectors.ts new file mode 100644 index 0000000000000000000000000000000000000000..528d54d7d49dc53dde74f5c59b280efb87b4db0b --- /dev/null +++ b/src/viewerModule/nehuba/store/selectors.ts @@ -0,0 +1,8 @@ +import { createSelector } from "@ngrx/store"; +import { NEHUBA_VIEWER_FEATURE_KEY } from '../constants' +import { INehubaFeature, IAuxMesh } from "./type"; + +export const selectorAuxMeshes = createSelector<any, INehubaFeature, IAuxMesh[]>( + state => state[NEHUBA_VIEWER_FEATURE_KEY], + nehubaFeatureStore => nehubaFeatureStore['auxMeshes'] +) diff --git a/src/viewerModule/nehuba/store/store.ts b/src/viewerModule/nehuba/store/store.ts new file mode 100644 index 0000000000000000000000000000000000000000..6782fa77c723fe8457f268df1d74f63535556b58 --- /dev/null +++ b/src/viewerModule/nehuba/store/store.ts @@ -0,0 +1,54 @@ +import { createReducer, on } from "@ngrx/store"; +import { actionRemoveAuxMesh, actionSetAuxMesh, actionSetAuxMeshes } from "./actions"; +import { INehubaFeature } from "./type"; + + +/** + * TODO port from global store to feature store + */ + +enum EnumPanelMode { + FOUR_PANEL = 'FOUR_PANEL', + V_ONE_THREE = 'V_ONE_THREE', + H_ONE_THREE = 'H_ONE_THREE', + SINGLE_PANEL = 'SINGLE_PANEL', +} + +const defaultState: INehubaFeature = { + layers: [], + panelMode: EnumPanelMode.FOUR_PANEL, + panelOrder: '0123', + octantRemoval: true, + clearViewQueue: {}, + auxMeshes: [] +} + +export const reducer = createReducer( + defaultState, + on(actionSetAuxMeshes, (state, { payload }) => { + return { + ...state, + auxMeshes: payload + } + }), + on(actionSetAuxMesh, (state, { payload }) => { + return { + ...state, + auxMeshes: state.auxMeshes.map(v => v['@id'] === payload['@id'] + ? payload + : v) + } + }), + on(actionRemoveAuxMesh, (state, {payload}) => { + return { + ...state, + auxMeshes: state.auxMeshes.filter(v => v['@id'] !== payload['@id']) + } + }), + on(actionRemoveAuxMesh, state => { + return { + ...state, + auxMeshes: [] + } + }) +) diff --git a/src/viewerModule/nehuba/store/type.ts b/src/viewerModule/nehuba/store/type.ts new file mode 100644 index 0000000000000000000000000000000000000000..4b1d4d3d69ab657aa67edbd18512397cda07d495 --- /dev/null +++ b/src/viewerModule/nehuba/store/type.ts @@ -0,0 +1,31 @@ +export interface IAuxMesh { + ['@id']: string + name: string + displayName?: string + ngId: string + labelIndicies: number[] + rgb: [number, number, number] + visible: boolean +} + +export interface INgLayerInterface { + name: string // displayName + source: string + mixability: string // base | mixable | nonmixable + annotation?: string // + id?: string // unique identifier + visible?: boolean + shader?: string + transform?: any +} + +export interface INehubaFeature { + layers: INgLayerInterface[] + panelMode: string + panelOrder: string + octantRemoval: boolean + clearViewQueue: { + [key: string]: boolean + } + auxMeshes: IAuxMesh[] +} diff --git a/src/viewerModule/nehuba/viewerCtrl/index.ts b/src/viewerModule/nehuba/viewerCtrl/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..6f3447caf89d780f37adf4a2ff01403e9468440a --- /dev/null +++ b/src/viewerModule/nehuba/viewerCtrl/index.ts @@ -0,0 +1 @@ +export { ViewerCtrlModule } from './module' diff --git a/src/viewerModule/nehuba/viewerCtrl/module.ts b/src/viewerModule/nehuba/viewerCtrl/module.ts new file mode 100644 index 0000000000000000000000000000000000000000..e3f1623f13f128fbc5df4ba9bd88606048bda0ae --- /dev/null +++ b/src/viewerModule/nehuba/viewerCtrl/module.ts @@ -0,0 +1,26 @@ +import { CommonModule } from "@angular/common"; +import { NgModule } from "@angular/core"; +import { FormsModule, ReactiveFormsModule } from "@angular/forms"; +import { ComponentsModule } from "src/components"; +import { AngularMaterialModule } from "src/ui/sharedModules/angularMaterial.module"; +import { UtilModule } from "src/util"; +import { ViewerCtrlCmp } from "./viewerCtrlCmp/viewerCtrlCmp.component"; + +@NgModule({ + imports: [ + CommonModule, + AngularMaterialModule, + UtilModule, + FormsModule, + ReactiveFormsModule, + ComponentsModule, + ], + declarations: [ + ViewerCtrlCmp, + ], + exports: [ + ViewerCtrlCmp + ] +}) + +export class ViewerCtrlModule{} diff --git a/src/viewerModule/nehuba/viewerCtrl/viewerCtrlCmp/viewerCtrlCmp.component.spec.ts b/src/viewerModule/nehuba/viewerCtrl/viewerCtrlCmp/viewerCtrlCmp.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..3a3e81dc4cb133762ca00310d7e839904776fcd8 --- /dev/null +++ b/src/viewerModule/nehuba/viewerCtrl/viewerCtrlCmp/viewerCtrlCmp.component.spec.ts @@ -0,0 +1,211 @@ +import { CommonModule } from "@angular/common" +import { ComponentFixture, TestBed } from "@angular/core/testing" +import { FormsModule, ReactiveFormsModule } from "@angular/forms" +import { MockStore, provideMockStore } from "@ngrx/store/testing" +import { BehaviorSubject, of } from "rxjs" +import { ComponentsModule } from "src/components" +import { ngViewerSelectorOctantRemoval } from "src/services/state/ngViewerState.store.helper" +import { viewerStateCustomLandmarkSelector, viewerStateSelectedTemplatePureSelector } from "src/services/state/viewerState/selectors" +import { AngularMaterialModule } from "src/ui/sharedModules/angularMaterial.module" +import { UtilModule } from "src/util" +import { actionSetAuxMeshes, selectorAuxMeshes } from "../../store" +import { NEHUBA_INSTANCE_INJTKN } from "../../util" +import { ViewerCtrlCmp } from "./viewerCtrlCmp.component" +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed' +import { HarnessLoader } from "@angular/cdk/testing" +import { MatSlideToggleHarness } from '@angular/material/slide-toggle/testing' + +describe('> viewerCtrlCmp.component.ts', () => { + describe('> ViewerCtrlCmp', () => { + let fixture: ComponentFixture<ViewerCtrlCmp> + let loader: HarnessLoader + let mockStore: MockStore + let mockNehubaViewer = { + updateUserLandmarks: jasmine.createSpy() + } + + afterEach(() => { + mockNehubaViewer.updateUserLandmarks.calls.reset() + }) + + beforeEach( async () => { + await TestBed.configureTestingModule({ + imports: [ + CommonModule, + AngularMaterialModule, + FormsModule, + ReactiveFormsModule, + ComponentsModule, + UtilModule, + ], + declarations: [ ViewerCtrlCmp ], + providers: [ + provideMockStore(), + { + provide: NEHUBA_INSTANCE_INJTKN, + useValue: new BehaviorSubject(mockNehubaViewer) + } + ] + }).compileComponents() + + }) + beforeEach(() => { + mockStore = TestBed.inject(MockStore) + mockStore.overrideSelector(viewerStateSelectedTemplatePureSelector, {}) + mockStore.overrideSelector(ngViewerSelectorOctantRemoval, true) + mockStore.overrideSelector(viewerStateCustomLandmarkSelector, []) + }) + + describe('> can be init', () => { + + beforeEach(() => { + mockStore.overrideSelector(selectorAuxMeshes, []) + fixture = TestBed.createComponent(ViewerCtrlCmp) + fixture.detectChanges() + loader = TestbedHarnessEnvironment.loader(fixture) + }) + + it('> can be inst', () => { + expect(fixture).toBeTruthy() + }) + }) + + describe('> UI', () => { + + beforeEach(() => { + mockStore.overrideSelector(selectorAuxMeshes, []) + fixture = TestBed.createComponent(ViewerCtrlCmp) + fixture.detectChanges() + loader = TestbedHarnessEnvironment.loader(fixture) + }) + + describe('> octant removal', () => { + const toggleName = 'remove-frontal-octant' + let setOctantRemovalSpy: jasmine.Spy + beforeEach(() => { + setOctantRemovalSpy = spyOn(fixture.componentInstance, 'setOctantRemoval') + }) + afterEach(() => { + setOctantRemovalSpy.calls.reset() + }) + + it('> toggleslider should exist', async () => { + const slideToggle = await loader.getAllHarnesses( + MatSlideToggleHarness.with({ + name: toggleName, + }) + ) + expect(slideToggle.length).toBe(1) + }) + + it('> toggling it should result in setOctantRemoval to be called', async () => { + const slideToggle = await loader.getAllHarnesses( + MatSlideToggleHarness.with({ + name: toggleName, + }) + ) + const wasChecked = await slideToggle[0].isChecked() + await slideToggle[0].toggle() + expect( + setOctantRemovalSpy + ).toHaveBeenCalledWith(!wasChecked) + }) + }) + + describe('> toggle delineation', () => { + + let toggleDelination: jasmine.Spy + const toggleName = 'toggle-delineation' + beforeEach(() => { + toggleDelination = spyOn<any>(fixture.componentInstance, 'toggleParcVsbl') + }) + afterEach(() => { + toggleDelination.calls.reset() + }) + + it('> toggleslider should exist', async () => { + const slideToggle = await loader.getAllHarnesses( + MatSlideToggleHarness.with({ + name: toggleName, + }) + ) + expect(slideToggle.length).toBe(1) + }) + + it('> toggling it should result in setOctantRemoval to be called', async () => { + const slideToggle = await loader.getAllHarnesses( + MatSlideToggleHarness.with({ + name: toggleName, + }) + ) + await slideToggle[0].toggle() + expect( + toggleDelination + ).toHaveBeenCalled() + }) + }) + }) + + describe('> UI aux meshes', () => { + const id = 'test-1-id' + const name = `toggle-aux-mesh-${id}` + const auxMesh = { + '@id': id, + labelIndicies: [1,2,3], + name: 'test-1-name', + ngId: 'test-1-ng-id', + rgb: [255, 255, 255] as [number, number, number] , + visible: true, + } + const auxMesh2 = { + '@id': 'foo-bar', + labelIndicies: [3,4,5], + name: 'test-2-name', + ngId: 'test-2-ng-id', + rgb: [100, 100, 100] as [number, number, number] , + visible: true, + } + beforeEach(() => { + mockStore.overrideSelector(selectorAuxMeshes, [ + auxMesh, + auxMesh2 + ]) + fixture = TestBed.createComponent(ViewerCtrlCmp) + fixture.detectChanges() + loader = TestbedHarnessEnvironment.loader(fixture) + }) + it('> toggleslider should exist', async () => { + const slideToggle = await loader.getAllHarnesses( + MatSlideToggleHarness.with({ + name + }) + ) + expect(slideToggle.length).toBe(1) + }) + + it('> toggling it should call dispatch', async () => { + const dispatchSpy = spyOn(mockStore, 'dispatch') + + const slideToggle = await loader.getAllHarnesses( + MatSlideToggleHarness.with({ + name + }) + ) + await slideToggle[0].toggle() + expect( + dispatchSpy + ).toHaveBeenCalledWith( + actionSetAuxMeshes({ + payload: [ + { + ...auxMesh, + visible: !auxMesh.visible + }, + auxMesh2 + ] + }) + ) + }) + }) + }) +}) diff --git a/src/viewerModule/nehuba/viewerCtrl/viewerCtrlCmp/viewerCtrlCmp.component.ts b/src/viewerModule/nehuba/viewerCtrl/viewerCtrlCmp/viewerCtrlCmp.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..cbe0380a6c5a06350b7ec29287072094343a25c2 --- /dev/null +++ b/src/viewerModule/nehuba/viewerCtrl/viewerCtrlCmp/viewerCtrlCmp.component.ts @@ -0,0 +1,192 @@ +import { Component, HostBinding, Inject, Optional } from "@angular/core"; +import { select, Store } from "@ngrx/store"; +import { combineLatest, merge, Observable, of, Subscription } from "rxjs"; +import { filter, map, pairwise, withLatestFrom } from "rxjs/operators"; +import { ngViewerActionSetPerspOctantRemoval } from "src/services/state/ngViewerState/actions"; +import { ngViewerSelectorOctantRemoval } from "src/services/state/ngViewerState/selectors"; +import { viewerStateCustomLandmarkSelector, viewerStateSelectedTemplatePureSelector } from "src/services/state/viewerState/selectors"; +import { NehubaViewerUnit } from "src/viewerModule/nehuba"; +import { NEHUBA_INSTANCE_INJTKN } from "src/viewerModule/nehuba/util"; +import { ARIA_LABELS } from 'common/constants' +import { actionSetAuxMeshes, selectorAuxMeshes } from "../../store"; +import { FormBuilder, FormControl, FormGroup } from "@angular/forms"; + +@Component({ + selector: 'viewer-ctrl-component', + templateUrl: './viewerCtrlCmp.template.html', + styleUrls: [ + './viewerCtrlCmp.style.css' + ], + exportAs: 'viewerCtrlCmp' +}) + +export class ViewerCtrlCmp{ + + public ARIA_LABELS = ARIA_LABELS + + @HostBinding('attr.darktheme') + darktheme = false + + private _flagDelin = true + get flagDelin(){ + return this._flagDelin + } + set flagDelin(flag){ + this._flagDelin = flag + this.toggleParcVsbl() + } + + private sub: Subscription[] = [] + private hiddenLayerNames: string[] = [] + + private _removeOctantFlag: boolean + get removeOctantFlag(){ + return this._removeOctantFlag + } + set removeOctantFlag(val){ + this._removeOctantFlag = val + this.setOctantRemoval(this._removeOctantFlag) + } + + public nehubaViewerPerspectiveOctantRemoval$ = this.store$.pipe( + select(ngViewerSelectorOctantRemoval), + ) + + public customLandmarks$: Observable<any> = this.store$.pipe( + select(viewerStateCustomLandmarkSelector), + map(lms => lms.map(lm => ({ + ...lm, + geometry: { + position: lm.position + } + }))), + ) + + public auxMeshFormGroup: FormGroup + private auxMeshesNamesSet: Set<string> = new Set() + public auxMeshes$ = this.store$.pipe( + select(selectorAuxMeshes), + ) + + constructor( + private store$: Store<any>, + formBuilder: FormBuilder, + @Optional() @Inject(NEHUBA_INSTANCE_INJTKN) private nehubaInst$: Observable<NehubaViewerUnit>, + ){ + + this.auxMeshFormGroup = formBuilder.group({}) + + + if (this.nehubaInst$) { + this.sub.push( + combineLatest([ + this.customLandmarks$, + this.nehubaInst$, + ]).pipe( + filter(([_, neubaInst]) => !!neubaInst), + ).subscribe(([landmarks, nehubainst]) => { + this.setOctantRemoval(landmarks.length === 0) + nehubainst.updateUserLandmarks(landmarks) + }) + ) + } else { + console.warn(`NEHUBA_INSTANCE_INJTKN not provided`) + } + + this.sub.push( + this.store$.pipe( + select(viewerStateSelectedTemplatePureSelector) + ).subscribe(tmpl => { + const { useTheme } = tmpl || {} + this.darktheme = useTheme === 'dark' + }), + + this.nehubaViewerPerspectiveOctantRemoval$.subscribe( + flag => this.removeOctantFlag = flag + ), + + merge( + of(null), + this.auxMeshes$, + ).pipe( + pairwise() + ).subscribe(([oldMeshes, meshes]) => { + if (!!oldMeshes) { + for (const mesh of oldMeshes) { + this.auxMeshFormGroup.removeControl(mesh['@id']) + } + } + if (meshes === null) { + return + } + this.auxMeshesNamesSet.clear() + for (const mesh of meshes) { + this.auxMeshesNamesSet.add(mesh.ngId) + this.auxMeshFormGroup.addControl(mesh['@id'], new FormControl(mesh.visible)) + } + }), + + this.auxMeshFormGroup.valueChanges.pipe( + withLatestFrom(this.auxMeshes$) + ).subscribe(([v, auxMeshes]) => { + if (!auxMeshes) return + + let changed = false + const auxMeshesCopy = JSON.parse(JSON.stringify(auxMeshes)) + for (const key in v) { + const found = auxMeshesCopy.find(mesh => mesh['@id'] === key) + if (found && found.visible !== v[key]) { + changed = true + found.visible = v[key] + } + } + + if (changed) { + this.store$.dispatch( + actionSetAuxMeshes({ + payload: auxMeshesCopy + }) + ) + } + }) + ) + } + + private toggleParcVsbl(){ + const visibleParcLayers = ((window as any).viewer.layerManager.managedLayers) + .slice(1) + .filter(({ visible }) => visible) + .filter(layer => !this.auxMeshesNamesSet.has(layer.name)) + + if (this.flagDelin) { + for (const name of this.hiddenLayerNames) { + const l = (window as any).viewer.layerManager.getLayerByName(name) + l && l.setVisible(true) + } + this.hiddenLayerNames = [] + } else { + this.hiddenLayerNames = [] + for (const { name } of visibleParcLayers) { + const l = (window as any).viewer.layerManager.getLayerByName(name) + l && l.setVisible(false) + this.hiddenLayerNames.push( name ) + } + } + + setTimeout(() => { + (window as any).viewer.display.scheduleRedraw() + }) + } + + public setOctantRemoval(octantRemovalFlag: boolean) { + this.store$.dispatch( + ngViewerActionSetPerspOctantRemoval({ + octantRemovalFlag + }) + ) + } + + public trackByAtId(_idx: number, obj: { ['@id']: string }) { + return obj['@id'] + } +} diff --git a/src/viewerModule/nehuba/viewerCtrl/viewerCtrlCmp/viewerCtrlCmp.style.css b/src/viewerModule/nehuba/viewerCtrl/viewerCtrlCmp/viewerCtrlCmp.style.css new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/viewerModule/nehuba/viewerCtrl/viewerCtrlCmp/viewerCtrlCmp.template.html b/src/viewerModule/nehuba/viewerCtrl/viewerCtrlCmp/viewerCtrlCmp.template.html new file mode 100644 index 0000000000000000000000000000000000000000..a1a1507eedbdcf739c18c24f77642fb397d6df84 --- /dev/null +++ b/src/viewerModule/nehuba/viewerCtrl/viewerCtrlCmp/viewerCtrlCmp.template.html @@ -0,0 +1,43 @@ +<h3 class="iv-custom-comp text mat-h3"> + Volumes +</h3> + +<mat-slide-toggle [(ngModel)]="flagDelin" + #delinToggle="matSlideToggle" + [iav-key-listener]="[{ type: 'keydown', key: 'q', target: 'document', capture: true }]" + (iav-key-event)="delinToggle.toggle()" + name="toggle-delineation"> + + <markdown-dom class="d-inline-block iv-custom-comp text"> + Show delineations `[q]` + </markdown-dom> +</mat-slide-toggle> + +<mat-divider class="mt-2 mb-2"></mat-divider> + +<h3 class="iv-custom-comp text mat-h3"> + Perspective View +</h3> + +<mat-slide-toggle [(ngModel)]="removeOctantFlag" + [aria-label]="ARIA_LABELS.TOGGLE_FRONTAL_OCTANT" + name="remove-frontal-octant"> + <span class="iv-custom-comp text"> + Remove frontal octant + </span> +</mat-slide-toggle> + +<ng-container *ngIf="auxMeshes$ | async as auxMeshes"> + <mat-divider class="mt-1 mb-1"></mat-divider> + <form [formGroup]="auxMeshFormGroup"> + <mat-slide-toggle *ngFor="let auxMesh of auxMeshes; trackBy: trackByAtId" + [formControlName]="auxMesh['@id']" + class="d-block" + [name]="'toggle-aux-mesh-' + auxMesh['@id']"> + <span class="iv-custom-comp text"> + {{ auxMesh.displayName || auxMesh.name }} + </span> + </mat-slide-toggle> + </form> +</ng-container> +