diff --git a/docs/releases/v2.11.3.md b/docs/releases/v2.11.3.md new file mode 100644 index 0000000000000000000000000000000000000000..834f0c7dd7677e5066e85cd999927a59c1aa3d20 --- /dev/null +++ b/docs/releases/v2.11.3.md @@ -0,0 +1,9 @@ +# v2.11.3 + +## Bugfixes + +- Fixed point assignment for maps that do not have statistical maps. Also fixed error messages. + +## Behind the scenes + +- Using hashed region name to encode selected region, rather than the archaic ngId & label index diff --git a/mkdocs.yml b/mkdocs.yml index fc88fe80be9e51f1591d52834ece4a8698b79ef5..9712d37e5f86c3d73a458b7085fb7711fdec7f9d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -33,6 +33,7 @@ nav: - Fetching datasets: 'advanced/datasets.md' - Display non-atlas volumes: 'advanced/otherVolumes.md' - Release notes: + - v2.11.3: 'releases/v2.11.3.md' - v2.11.2: 'releases/v2.11.2.md' - v2.11.1: 'releases/v2.11.1.md' - v2.11.0: 'releases/v2.11.0.md' diff --git a/package-lock.json b/package-lock.json index eaa6b864e66c3e6d3556f6482a0816e0eb9e5d0c..792fff775330a11e4a0c83b26158e1694e7836f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "siibra-explorer", - "version": "2.10.0", + "version": "2.11.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "siibra-explorer", - "version": "2.10.0", + "version": "2.11.2", "license": "apache-2.0", "dependencies": { "@angular/animations": "^14.2.12", diff --git a/package.json b/package.json index 4ea49304574b3072c6f16f5690b98a624b3558ba..be58cf38626de883cb9990f6b30614bc2f31bbae 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "siibra-explorer", - "version": "2.11.2", + "version": "2.11.3", "description": "siibra-explorer - explore brain atlases. Based on humanbrainproject/nehuba & google/neuroglancer. Built with angular", "scripts": { "lint": "eslint src --ext .ts", diff --git a/src/atlasComponents/sapi/schemaV3.ts b/src/atlasComponents/sapi/schemaV3.ts index e73a25736e182902ac13528a75848ee3a6f44e3c..3c10d79b9c849d9aa745879549de94cfe82b45fa 100644 --- a/src/atlasComponents/sapi/schemaV3.ts +++ b/src/atlasComponents/sapi/schemaV3.ts @@ -642,12 +642,6 @@ export interface components { */ ontologyIdentifier?: (string)[] } - /** - * ImageTypes - * @description An enumeration. - * @enum {unknown} - */ - ImageTypes: "BlockfaceVolumeOfInterest" | "CellBodyStainedVolumeOfInterest" | "CellbodyStainedSection" | "MRIVolumeOfInterest" | "PLIVolumeOfInterest" | "SegmentedVolumeOfInterest" | "XPCTVolumeOfInterest" /** LocationModel */ LocationModel: { /** @Type */ @@ -1237,12 +1231,6 @@ export interface components { /** Max */ max: number } - /** - * TabularTypes - * @description An enumeration. - * @enum {unknown} - */ - TabularTypes: "ReceptorDensityFingerprint" | "LayerwiseBigBrainIntensities" | "LayerwiseCellDensity" | "RegionalBOLD" /** ValidationError */ ValidationError: { /** Location */ @@ -1677,6 +1665,7 @@ export interface operations { parcellation_id: string space_id: string point: string + assignment_type?: string sigma_mm?: number } } @@ -1902,7 +1891,7 @@ export interface operations { query: { parcellation_id: string region_id: string - type?: components["schemas"]["TabularTypes"] + type?: string page?: number size?: number } @@ -1928,7 +1917,7 @@ export interface operations { query: { parcellation_id: string region_id: string - type?: components["schemas"]["TabularTypes"] + type?: string } path: { feature_id: string @@ -1955,7 +1944,7 @@ export interface operations { query: { space_id: string bbox?: string - type?: components["schemas"]["ImageTypes"] + type?: string page?: number size?: number } @@ -1980,7 +1969,7 @@ export interface operations { parameters: { query: { space_id: string - type?: components["schemas"]["ImageTypes"] + type?: string } path: { feature_id: string diff --git a/src/atlasComponents/sapiViews/volumes/point-assignment/point-assignment.component.html b/src/atlasComponents/sapiViews/volumes/point-assignment/point-assignment.component.html index 57a9cf3d5031587bc37f7ac36e115319b396f500..59694f74a9f84f067a93a56eb0f0d9988895d8e1 100644 --- a/src/atlasComponents/sapiViews/volumes/point-assignment/point-assignment.component.html +++ b/src/atlasComponents/sapiViews/volumes/point-assignment/point-assignment.component.html @@ -1,7 +1,13 @@ -<div class="sxplr-m-2" *ngIf="busy$ | async"> +<div class="sxplr-m-2" *ngIf="busy$ | async as busyMessage"> <spinner-cmp class="sxplr-d-inline-block"></spinner-cmp> <span> - Performing probabilistic assignment ... + {{ busyMessage }} + </span> +</div> + +<div class="sxplr-m-2" *ngIf="error$ | async"> + <span> + An error occurred when performing map assignment. </span> </div> diff --git a/src/atlasComponents/sapiViews/volumes/point-assignment/point-assignment.component.ts b/src/atlasComponents/sapiViews/volumes/point-assignment/point-assignment.component.ts index 45709ac786ae36a492d8c806003beb0398609a72..b12a4b3cc53426d0fe8c5a5e19d791a7b83e1a11 100644 --- a/src/atlasComponents/sapiViews/volumes/point-assignment/point-assignment.component.ts +++ b/src/atlasComponents/sapiViews/volumes/point-assignment/point-assignment.component.ts @@ -1,7 +1,7 @@ import { Component, Input, OnDestroy, Output, TemplateRef, EventEmitter } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { BehaviorSubject, EMPTY, Observable, Subscription, combineLatest, concat, of } from 'rxjs'; -import { map, shareReplay, switchMap, tap } from 'rxjs/operators'; +import { catchError, map, shareReplay, switchMap, tap } from 'rxjs/operators'; import { SAPI, EXPECTED_SIIBRA_API_VERSION } from 'src/atlasComponents/sapi/sapi.service'; import { SxplrParcellation, SxplrRegion, SxplrTemplate } from 'src/atlasComponents/sapi/sxplrTypes'; import { translateV3Entities } from 'src/atlasComponents/sapi/translateV3'; @@ -10,6 +10,9 @@ import { TSandsPoint } from 'src/util/types'; import { TZipFileConfig } from "src/zipFilesOutput/type" import { environment } from "src/environments/environment" +const DOING_PROB_ASGMT = "Performing probabilistic assignment ..." +const DOING_LABEL_ASGMT = "Probabilistic assignment failed. Performing labelled assignment ..." + @Component({ selector: 'sxplr-point-assignment', templateUrl: './point-assignment.component.html', @@ -22,9 +25,12 @@ export class PointAssignmentComponent implements OnDestroy { "map value", ] - #busy$ = new BehaviorSubject(false) + #busy$ = new BehaviorSubject<string>(null) busy$ = this.#busy$.asObservable() + #error$ = new BehaviorSubject<string>(null) + error$ = this.#error$.asObservable() + #point = new BehaviorSubject<TSandsPoint>(null) @Input() set point(val: TSandsPoint) { @@ -52,6 +58,9 @@ export class PointAssignmentComponent implements OnDestroy { this.#template, ]).pipe( switchMap(([ point, parcellation, template ]) => { + + this.#error$.next(null) + if (!point || !parcellation || !template) { return EMPTY } @@ -60,7 +69,7 @@ export class PointAssignmentComponent implements OnDestroy { console.warn(`point coordination space id ${ptSpaceId} is not the same as template id ${template.id}.`) return EMPTY } - this.#busy$.next(true) + this.#busy$.next(DOING_PROB_ASGMT) return concat( of(null), this.sapi.v3Get("/map/assign", { @@ -71,7 +80,24 @@ export class PointAssignmentComponent implements OnDestroy { sigma_mm: 0 } }).pipe( - tap(() => this.#busy$.next(false)), + catchError(() => { + this.#busy$.next(DOING_LABEL_ASGMT) + return this.sapi.v3Get("/map/assign", { + query: { + parcellation_id: parcellation.id, + point: point.coordinates.map(v => `${v.value/1e6}mm`).join(','), + space_id: template.id, + sigma_mm: 0, + assignment_type: "labelled" + } + }) + }), + catchError((err) => { + this.#busy$.next(null) + this.#error$.next(err.toString()) + return of(null) + }), + tap(() => this.#busy$.next(null)), ) ) }), diff --git a/src/routerModule/routeStateTransform.service.spec.ts b/src/routerModule/routeStateTransform.service.spec.ts index a341cdd6d405e275beedfd82a29c8f42ef3f36a5..2dee59c937f86923ca06f41c073aca2a22dcc0ba 100644 --- a/src/routerModule/routeStateTransform.service.spec.ts +++ b/src/routerModule/routeStateTransform.service.spec.ts @@ -6,6 +6,7 @@ import { DefaultUrlSerializer } from "@angular/router" import * as nehubaConfigService from "src/viewerModule/nehuba/config.service" import { atlasSelection, userInteraction } from "src/state" import { encodeNumber } from "./cipher" +import { QuickHash } from "src/util/fn" const serializer = new DefaultUrlSerializer() @@ -123,7 +124,7 @@ describe("> routeStateTransform.service.ts", () => { const altasObj = {"@id": 'foo-bar-a'} const templObj = {"@id": 'foo-bar-t'} const parcObj = {"@id": 'foo-bar-p'} - const regions = [{}] + const regions = [{'name': 'selected-region-1'}] const standAloneVolumes = [] const navigation = null @@ -181,9 +182,12 @@ describe("> routeStateTransform.service.ts", () => { const getRegionLabelIndicesSpy = sapi.getRegionLabelIndices as jasmine.Spy getRegionLabelIndicesSpy.and.resolveTo(labelIndex) - const s = await svc.cvtStateToRoute(state as any) - expect(s).toContain(`r:${ngId}::${encodeNumber(labelIndex, { float: false })}`) + + expect(getParcNgId).not.toHaveBeenCalled() + expect(getRegionLabelIndicesSpy).not.toHaveBeenCalled() + + expect(s).toContain(`rn:${QuickHash.GetHash(regions[0].name)}`) }) it('> ngId containing expected value', async () => { diff --git a/src/routerModule/routeStateTransform.service.ts b/src/routerModule/routeStateTransform.service.ts index 1032448ec67ea1c9bf80d3f18f82f901bf7c6057..b01ac54beb7085b01ea548ac2de69b4d0a103fff 100644 --- a/src/routerModule/routeStateTransform.service.ts +++ b/src/routerModule/routeStateTransform.service.ts @@ -9,6 +9,7 @@ import { getParcNgId } from "src/viewerModule/nehuba/config.service"; import { decodeToNumber, encodeNumber, encodeURIFull, separator } from "./cipher"; import { TUrlAtlas, TUrlPathObj, TUrlStandaloneVolume } from "./type"; import { decodePath, encodeId, decodeId, encodePath } from "./util"; +import { QuickHash } from "src/util/fn"; @Injectable() export class RouteStateTransformSvc { @@ -26,6 +27,7 @@ export class RouteStateTransformSvc { const selectedTemplateId = decodeId( RouteStateTransformSvc.GetOneAndOnlyOne(obj.t) ) const selectedParcellationId = decodeId( RouteStateTransformSvc.GetOneAndOnlyOne(obj.p) ) const selectedRegionIds = obj.r + const selectedRegionNames = obj.rn if (!selectedAtlasId || !selectedTemplateId || !selectedParcellationId) { return {} @@ -60,7 +62,11 @@ export class RouteStateTransformSvc { const userViewer = await this.sapi.useViewer(selectedTemplate).toPromise() const selectedRegions = await (async () => { - if (!selectedRegionIds) return [] + if (!selectedRegionIds && !selectedRegionNames) return [] + + if (selectedRegionNames && selectedRegionNames.length > 0) { + return allParcellationRegions.filter(region => selectedRegionNames.includes(QuickHash.GetHash(region.name))) + } /** * should account for @@ -268,16 +274,7 @@ export class RouteStateTransformSvc { } } - // encoding selected regions - let selectedRegionsString: string - if (selectedRegions.length === 1) { - const region = selectedRegions[0] - const labelIndex = await this.sapi.getRegionLabelIndices(selectedTemplate, selectedParcellation, region) - - const ngId = getParcNgId(selectedAtlas, selectedTemplate, selectedParcellation, region) - selectedRegionsString = `${ngId}::${encodeNumber(labelIndex, { float: false })}` - } - let routes: TUrlPathObj<string, TUrlAtlas<string>> | TUrlPathObj<string, TUrlStandaloneVolume<string>> + let routes: TUrlPathObj<string|string[], TUrlAtlas<string|string[]>> | TUrlPathObj<string, TUrlStandaloneVolume<string>> routes = { // for atlas @@ -287,7 +284,8 @@ export class RouteStateTransformSvc { // for parcellation p: selectedParcellation && encodeId(selectedParcellation.id), // for regions - r: selectedRegionsString && encodeURIFull(selectedRegionsString), + // r: selectedRegionsString && encodeURIFull(selectedRegionsString), + rn: selectedRegions[0] && selectedRegions.map(r => QuickHash.GetHash(r.name)), // nav ['@']: cNavString, // showing dataset diff --git a/src/routerModule/type.ts b/src/routerModule/type.ts index 13205ad3e09e0969a8c419a5d9803b2883bc2de3..284b5e7a9441fd52be9281ad3dec5c749e390993 100644 --- a/src/routerModule/type.ts +++ b/src/routerModule/type.ts @@ -7,6 +7,7 @@ export type TUrlAtlas<T> = { t: T // template p: T // parcellation r?: T // region selected + rn?: T } export type TUrlPlugin<T> = { diff --git a/src/util/fn.ts b/src/util/fn.ts index 9c1d188f7aea4e807406b45dfb82491f23d9543b..6457ccf78a80061da34734ae0c3b2e20b0ffe238 100644 --- a/src/util/fn.ts +++ b/src/util/fn.ts @@ -134,7 +134,7 @@ export const CachedFunction = (config?: TCacheFunctionArg) => { } } -// A quick, non security hash function +// A quick, non secure hash function export class QuickHash { private length = 6 constructor(opts?: any){