Skip to content

Commit

Permalink
chimeric facet
Browse files Browse the repository at this point in the history
  • Loading branch information
bioinsilico committed Nov 28, 2023
1 parent 71f159a commit 8f65b70
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 39 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

[Semantic Versioning](https://semver.org/)

## [6.0.2] - 2023-11-28
### Improvement
- `FacetMemberInterface.facetConfig` interface attribute to encode histogram data transformations and other configuration
- `facetTransform` can be used to transform Search API facets into other facets
- `bucketClickSearchQuery` can be used to overwrite bucket click events
- `mergeDomainMaxValue` has been moved from `FacetMemberInterface.chartConfig`
- `CHIMERIC_FACET` New facet histogram to display wild type vs chimeric protein group distribution

## [6.0.1] - 2023-11-27
### Improvement
- `MultipleEntryPropertyCollector` includes polymer entity prd ids
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@rcsb/rcsb-saguaro-app",
"version": "6.0.1",
"version": "6.0.2",
"description": "RCSB 1D Saguaro Web App",
"main": "build/app.js",
"files": [
Expand Down
4 changes: 2 additions & 2 deletions src/RcsbFvExamples/GroupHistogram.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import {buildGroup, buildGroupContent, buildGroupMembers} from "../RcsbGroupWeb/RcsbGroupBuilder";
import {GroupProvenanceId} from "@rcsb/rcsb-api-tools/build/RcsbDw/Types/DwEnums";

const groupId = "1534_30";
const groupId = "P00720";

buildGroupContent("select", GroupProvenanceId.ProvenanceSequenceIdentity, groupId);

buildGroupMembers("carousel", GroupProvenanceId.ProvenanceSequenceIdentity, groupId, 1, 1)

buildGroup("pfv", GroupProvenanceId.ProvenanceSequenceIdentity, groupId, undefined, ["ENTITY_NAME_FACET", "RELEASE_DATE_FACET", "METHODOLOGY_FACET"]).then((m)=>{
buildGroup("pfv", GroupProvenanceId.ProvenanceSequenceIdentity, groupId, undefined, ["CHIMERIC_FACET"]).then((m)=>{
});

buildGroup("pfv_2", GroupProvenanceId.ProvenanceSequenceIdentity, groupId, undefined, ["RESOLUTION_FACET","EXPERIMENTAL_METHOD_FACET"]).then((m)=>{
Expand Down
24 changes: 16 additions & 8 deletions src/RcsbGroupWeb/RcsbGroupView/RcsbGroupChart/GroupChartEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,17 @@ export namespace GroupChartEvents {
chart.chartConfig.barClickCallback = async (datum:ChartDataValueInterface<GroupChartMap.ChartObjectIdType>, data: ChartDataColumnInterface[], e?: React.MouseEvent) => {
if(datum.id === "excluded")
return;
let query: SearchQueryType = SQT.searchAttributeQuery(chart.attribute, datum.x, Operator.ExactMatch, Service.Text);
if(chart.filters)
chart.filters.forEach(f=>{
query = SQT.addNewNodeToAttributeSearchQuery(f.attribute, f.value, f.operator, query, f.service)
})
await clickEvent(e ?? {shiftKey: false}, chart, query, returnType);
if(chart.facetConfig?.bucketClickSearchQuery){
const query: SearchQueryType = chart.facetConfig?.bucketClickSearchQuery(datum, data, e);
await clickEvent(e ?? {shiftKey: false}, chart, query, returnType);
}else{
let query: SearchQueryType = SQT.searchAttributeQuery(chart.attribute, datum.x, Operator.ExactMatch, Service.Text);
if(chart.filters)
chart.filters.forEach(f=>{
query = SQT.addNewNodeToAttributeSearchQuery(f.attribute, f.value, f.operator, query, f.service)
})
await clickEvent(e ?? {shiftKey: false}, chart, query, returnType);
}
};
}

Expand All @@ -77,8 +82,11 @@ export namespace GroupChartEvents {
chart.chartConfig.barClickCallback = async (datum:ChartDataValueInterface, data: ChartDataColumnInterface[], e?: React.MouseEvent) => {
if(datum.id === "excluded")
return;
if(chart.chartConfig?.mergeDomainMaxValue && parseFloat(datum.x.toString()) >= chart.chartConfig.mergeDomainMaxValue) {
const query: SearchQueryType = SQT.searchAttributeQuery(chart.attribute, chart.chartConfig.mergeDomainMaxValue, Operator.GreaterOrEqual, Service.Text);
if(chart.facetConfig?.bucketClickSearchQuery){
const query: SearchQueryType = chart.facetConfig?.bucketClickSearchQuery(datum, data, e);
await clickEvent(e ?? {shiftKey: false}, chart, query, returnType);
} else if(chart.facetConfig?.mergeDomainMaxValue && parseFloat(datum.x.toString()) >= chart.facetConfig.mergeDomainMaxValue) {
const query: SearchQueryType = SQT.searchAttributeQuery(chart.attribute, chart.facetConfig.mergeDomainMaxValue, Operator.GreaterOrEqual, Service.Text);
await clickEvent(e ?? {shiftKey: false}, chart, query, returnType);
}else{
const range: Range|DateRange = formatRange(chart, datum);
Expand Down
17 changes: 15 additions & 2 deletions src/RcsbSeacrh/FacetStore/FacetMemberInterface.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@

import {ChartConfigInterface, ChartType} from "@rcsb/rcsb-charts/lib/RcsbChartComponent/ChartConfigInterface";
import {
AttributeFacetType,
AttributeFacetType, BucketDataType,
FilterFacetType
} from "@rcsb/rcsb-search-tools/lib/SearchParseTools/SearchFacetInterface";
import {RcsbSearchAttributeType} from "@rcsb/rcsb-api-tools/build/RcsbSearch/Types/SearchMetadata";
import {SearchQueryType} from "@rcsb/rcsb-search-tools/lib/SearchQueryTools/SearchQueryInterfaces";
import {
ChartDataColumnInterface,
ChartDataValueInterface
} from "@rcsb/rcsb-charts/lib/RcsbChartDataProvider/ChartDataProviderInterface";
import React from "react";

export type FacetType = AttributeFacetType | FilterFacetType;

Expand All @@ -14,7 +20,14 @@ export interface FacetMemberInterface {
attributeName: string;
attribute: RcsbSearchAttributeType;
chartType: ChartType;
chartConfig?: ChartConfigInterface & { mergeDomainMaxValue?:number; };
chartConfig?: ChartConfigInterface;
facetConfig?: FacetConfigInterface;
facet: FacetType;
contentType:"date"|"number"|"string";
}

export interface FacetConfigInterface {
mergeDomainMaxValue?: number;
facetTransform?: (d: BucketDataType[])=>BucketDataType[];
bucketClickSearchQuery?: (datum:ChartDataValueInterface, data: ChartDataColumnInterface[], e?: React.MouseEvent)=>SearchQueryType;
}
5 changes: 3 additions & 2 deletions src/RcsbSeacrh/FacetStore/SequenceGroupFacetStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
ECOD_FACET,
ENZYME_CLASS_FACET,
GO_FUNCTION_FACET, GO_PROCESS_FACET, GO_COMPONENT_FACET,
METHODOLOGY_FACET
METHODOLOGY_FACET, CHIMERIC_FACET
} from "./SingleFacets";
import {cloneDeep} from "lodash";

Expand All @@ -45,7 +45,8 @@ class SequenceGroupFacetStore implements FacetStoreInterface{
cloneDeep<FacetMemberInterface>(ENTITY_NAME_FACET),
cloneDeep<FacetMemberInterface>(GO_FUNCTION_FACET),
cloneDeep<FacetMemberInterface>(GO_PROCESS_FACET),
cloneDeep<FacetMemberInterface>(GO_COMPONENT_FACET)
cloneDeep<FacetMemberInterface>(GO_COMPONENT_FACET),
cloneDeep<FacetMemberInterface>(CHIMERIC_FACET)
];
private readonly nonPolymerFacet: FacetMemberInterface[] = [
cloneDeep<FacetMemberInterface>(CHEM_COMP_FACET)
Expand Down
73 changes: 70 additions & 3 deletions src/RcsbSeacrh/FacetStore/SingleFacets.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import {RcsbSearchMetadata} from "@rcsb/rcsb-api-tools/build/RcsbSearch/Types/SearchMetadata";
import {AggregationType, Service, Type} from "@rcsb/rcsb-api-tools/build/RcsbSearch/Types/SearchEnums";
import {AggregationType, Operator, Service, Type} from "@rcsb/rcsb-api-tools/build/RcsbSearch/Types/SearchEnums";
import {FacetMemberInterface} from "./FacetMemberInterface";
import {ChartType} from "@rcsb/rcsb-charts/lib/RcsbChartComponent/ChartConfigInterface";
import {ChartDataValueInterface} from "@rcsb/rcsb-charts/lib/RcsbChartDataProvider/ChartDataProviderInterface";
import {GroupChartMap} from "../../RcsbGroupWeb/RcsbGroupView/RcsbGroupChart/GroupChartTools";
import {BucketDataType} from "@rcsb/rcsb-search-tools/lib/SearchParseTools/SearchFacetInterface";
import {SearchQueryTools as SQT} from "../SearchQueryTools";


export const EXPERIMENTAL_METHOD_FACET: FacetMemberInterface = {
Expand Down Expand Up @@ -49,7 +51,6 @@ export const RESOLUTION_FACET: FacetMemberInterface = {
constHeight: 225
},
histogramBinIncrement: 0.5,
mergeDomainMaxValue: 5,
domainMinValue: 0,
domainMaxValue: 6,
axisLabel: "Angstroms",
Expand All @@ -59,6 +60,9 @@ export const RESOLUTION_FACET: FacetMemberInterface = {
return `Resolution ${d.x as number - 0.25} - ${d.x as number + 0.25}`;
}
},
facetConfig: {
mergeDomainMaxValue: 5
},
facet: {
name: "RESOLUTION_FACET",
aggregation_type: AggregationType.Histogram,
Expand Down Expand Up @@ -86,6 +90,68 @@ export const METHODOLOGY_FACET: FacetMemberInterface = {
}
};

export const CHIMERIC_FACET: FacetMemberInterface = {
id: "chimeric",
title: "Protein Sequence Composition",
attributeName: "CHIMERIC_FACET",
attribute: RcsbSearchMetadata.RcsbPolymerEntity.RcsbSourcePartCount.path,
chartType: ChartType.barplot,
contentType: "string",
facetConfig: {
facetTransform: (buckets)=>{
const out: BucketDataType[] = [];
const wt = buckets.find(b=>b.label == 1)
if(wt)
out.push({
label: "Wild Type",
population: wt.population
});
const synthetic = buckets.find(b=>b.label == 0)
if(synthetic)
out.push({
label: "Synthetic",
population: synthetic.population
});
const chimeric = buckets.filter(b=> parseInt(b.label.toString()) > 1);
if(chimeric?.length > 0)
out.push({
label: "Chimeric",
population: chimeric.reduce((c,p)=>c+p.population,0)
});
return out;
},
bucketClickSearchQuery: (datum, data, e) => {
if(datum.x == "Wild Type")
return SQT.searchAttributeQuery(
CHIMERIC_FACET.attribute,
1,
Operator.Equals,
Service.Text
);
else if(datum.x == "Synthetic")
return SQT.searchAttributeQuery(
CHIMERIC_FACET.attribute,
0,
Operator.Equals,
Service.Text
);
else
return SQT.searchAttributeQuery(
CHIMERIC_FACET.attribute,
1,
Operator.Greater,
Service.Text
);
}
},
facet: {
name: "CHIMERIC_FACET",
aggregation_type: AggregationType.Terms,
attribute: RcsbSearchMetadata.RcsbPolymerEntity.RcsbSourcePartCount.path,
min_interval_population: 1
}
};

export const RELEASE_DATE_FACET: FacetMemberInterface = {
id: "release_date",
title: undefined,
Expand Down Expand Up @@ -579,5 +645,6 @@ export const SearchFacets = {
GO_PROCESS_FACET,
GO_COMPONENT_FACET,
LIGAND_OF_INTEREST_FACET,
METHODOLOGY_FACET
METHODOLOGY_FACET,
CHIMERIC_FACET
};
5 changes: 3 additions & 2 deletions src/RcsbSeacrh/FacetStore/UniprotGroupFacetStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
ECOD_FACET,
ENZYME_CLASS_FACET,
GO_FUNCTION_FACET, GO_PROCESS_FACET, GO_COMPONENT_FACET,
METHODOLOGY_FACET
METHODOLOGY_FACET, CHIMERIC_FACET
} from "./SingleFacets";
import {cloneDeep} from "lodash";

Expand All @@ -45,7 +45,8 @@ class UniprotGroupFacetStore implements FacetStoreInterface{
cloneDeep<FacetMemberInterface>(ENTITY_NAME_FACET),
cloneDeep<FacetMemberInterface>(GO_FUNCTION_FACET),
cloneDeep<FacetMemberInterface>(GO_PROCESS_FACET),
cloneDeep<FacetMemberInterface>(GO_COMPONENT_FACET)
cloneDeep<FacetMemberInterface>(GO_COMPONENT_FACET),
cloneDeep<FacetMemberInterface>(CHIMERIC_FACET)
];
private readonly nonPolymerFacet: FacetMemberInterface[] = [
cloneDeep<FacetMemberInterface>(CHEM_COMP_FACET)
Expand Down
32 changes: 13 additions & 19 deletions src/RcsbSeacrh/FacetTools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import {
} from "@rcsb/rcsb-api-tools/build/RcsbSearch/Types/SearchQueryInterface";
import {Service} from "@rcsb/rcsb-api-tools/build/RcsbSearch/Types/SearchEnums";
import {
ChartConfigInterface, ChartDisplayConfigInterface,
ChartObjectInterface, ChartType,
ChartDisplayConfigInterface,
ChartObjectInterface,
} from "@rcsb/rcsb-charts/lib/RcsbChartComponent/ChartConfigInterface";
import {RcsbSearchAttributeType} from "@rcsb/rcsb-api-tools/build/RcsbSearch/Types/SearchMetadata";
import {
Expand All @@ -19,16 +19,10 @@ import {
import {getBucketsFromFacets} from "@rcsb/rcsb-search-tools/lib/SearchParseTools/SearchFacetTools";

export type SearchFilter = {attribute:RcsbSearchAttributeType;value:AttributeTextQueryParameters['value'];operator:AttributeTextQueryParameters["operator"];service:Service.Text|Service.TextChem};
export interface RcsbChartInterface<T=any> {
chartType: ChartType;
export interface RcsbChartInterface<T=any> extends Omit<FacetMemberInterface, "id"|"facet">{
labelList?: string[];
attribute: RcsbSearchAttributeType;
attributeName: string;
chartConfig?: FacetMemberInterface["chartConfig"],
title?: string,
data: ChartObjectInterface<T>[];
filters?:SearchFilter[];
contentType:FacetMemberInterface['contentType'];
}

export class FacetTools {
Expand All @@ -40,15 +34,13 @@ export class FacetTools {
const facet = FacetTools.getFacetFromName(facetMembers,bucket.name);
if(!facet)
return;
const chart: {chartType: ChartType; chartConfig?: ChartConfigInterface; title?: string;} = FacetTools.getFacetChartTypeFromAttribute(facetMembers, bucket.name);
const chart= FacetTools.getFacetChartTypeFromAttribute(facetMembers, bucket.name);
out.push({
chartType: chart.chartType,
chartConfig: chart.chartConfig,
...chart,
labelList: [],
attributeName: bucket.name,
attribute: facet.attribute,
title: chart.title,
data: applyChartConfigToData(bucket.data, facet?.chartConfig),
data: applyChartConfigToData(bucket.data, facet?.facetConfig),
filters: FacetTools.getFacetFiltersFromName(facetMembers, bucket.name),
contentType: facet.contentType
});
Expand Down Expand Up @@ -100,11 +92,11 @@ export class FacetTools {
});
}

private static getFacetChartTypeFromAttribute(facetMembers: FacetMemberInterface[], attribute: string): {chartType: ChartType, chartConfig?: ChartConfigInterface, title?: string} {
private static getFacetChartTypeFromAttribute(facetMembers: FacetMemberInterface[], attribute: string):FacetMemberInterface {
const facet: FacetMemberInterface | undefined = facetMembers.find((facet)=>(facet.attributeName === attribute));
if(!facet)
throw `Unknown facet attribute ${attribute}`;
return {chartType: facet.chartType, chartConfig:facet.chartConfig, title: facet.title};
return facet;
}

private static getFacetFiltersFromName(facetMembers: FacetMemberInterface[], attribute: string): SearchFilter[] {
Expand Down Expand Up @@ -133,9 +125,11 @@ export class FacetTools {
}
}

function applyChartConfigToData(data: BucketDataType[], chartConfig?: FacetMemberInterface["chartConfig"]): BucketDataType[] {
if(chartConfig?.mergeDomainMaxValue)
return mergeDomainMaxValue(data, chartConfig.mergeDomainMaxValue)
function applyChartConfigToData(data: BucketDataType[], facetConfig?: FacetMemberInterface["facetConfig"]): BucketDataType[] {
if(facetConfig?.mergeDomainMaxValue)
return mergeDomainMaxValue(data, facetConfig.mergeDomainMaxValue)
if(facetConfig?.facetTransform)
return facetConfig.facetTransform(data)
return data;
}

Expand Down

0 comments on commit 8f65b70

Please sign in to comment.