Skip to content

Commit

Permalink
Merge branch 'master' of github.com:PavlidisLab/GemBrow
Browse files Browse the repository at this point in the history
  • Loading branch information
Libby Natola committed Aug 16, 2023
2 parents 1979578 + 53484f5 commit 6cd6397
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 90 deletions.
78 changes: 30 additions & 48 deletions src/components/AnnotationSelector.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,31 @@
Annotations
</div>
<v-spacer></v-spacer>
<v-btn v-if="selectedValues.length > 0" @click="selectedValues = []" small text color="primary" :disabled="disabled">
<v-btn v-if="selectedValues.length > 0" @click="selectedValues = []" small text color="primary"
:disabled="disabled">
Clear Selection
</v-btn>
</div>
<v-progress-linear :active="loading" indeterminate/>
<v-treeview v-model="selectedValues" :items="rankedAnnotations" :disabled="disabled" item-key="id"
selectable
dense
class="hide-root-checkboxes"
:class="debug ? '' : 'hide-root-checkboxes'"
>
<template v-slot:label="{item}">
<i v-if="item.isCategory && isUncategorized(item)">Uncategorized</i>
<span v-else v-text="getTitle(item)" class="text-capitalize text-truncate"/>
<span v-else v-text="getTitle(item)" class="text-capitalize text-truncate"
:title="getTitle(item).length > 30 && getTitle(item)"/>
<span v-if="isTermLinkable(item)">&nbsp;<a v-if="debug" :href="getExternalUrl(item)" target="_blank"
class="mdi mdi-open-in-new"></a></span>
<div v-if="debug && getUri(item)">
<small>{{ getUri(item) }}</small>
<small :style="isExcluded(item) ? 'text-decoration: line-through;' : ''">{{ getUri(item) }}</small>
</div>
</template>
<template v-slot:append="{item}">
<span v-if="!item.isCategory"
:title="debug ? 'Entropy: ' + formatDecimal(entropy(item)) : undefined"
>
{{ formatNumber(item.numberOfExpressionExperiments) }}
</span>
<div v-if="!item.isCategory || debug" class="text-right">
{{ formatNumber(item.numberOfExpressionExperiments) }}<br>
</div>
</template>
</v-treeview>
<p v-show="annotations.length === 0 && !loading">
Expand All @@ -39,9 +39,9 @@
</template>

<script>
import { chain, isEqual, max, sum } from "lodash";
import { formatDecimal, formatNumber } from "@/utils";
import { annotationSelectorOrderArray, ontologySources } from "@/config/gemma";
import { chain, isEqual, max, sumBy } from "lodash";
import { formatDecimal, formatNumber, getCategoryId, getTermId } from "@/utils";
import { annotationSelectorOrderArray, excludedTerms, ontologySources } from "@/config/gemma";
import { mapState } from "vuex";
/**
Expand All @@ -67,12 +67,7 @@ export default {
/**
* If true, the checkboxes in the tree view are disabled.
*/
disabled: Boolean,
/**
* In order to rank annotations, we need to know how many datasets total are
* matched.
*/
totalNumberOfExpressionExperiments: Number
disabled: Boolean
},
data() {
return {
Expand Down Expand Up @@ -101,12 +96,8 @@ export default {
*/
rankedAnnotations() {
let selectedValues = new Set(this.selectedValues);
let byEntropy = (a, b) => {
// prioritize selected annotations
if (selectedValues.has(a.id) !== selectedValues.has(b.id)) {
return selectedValues.has(a.id) ? -1 : 1;
}
return this.entropy(b) - this.entropy(a);
let byNumberOfExpressionExperiments = (a, b) => {
return this.getNumberOfExpressionExperiments(b) - this.getNumberOfExpressionExperiments(a);
};
return this.annotations
.map(a => {
Expand All @@ -123,12 +114,12 @@ export default {
isCategory: false,
children: c.children && getChildren(c)
};
}).sort(byEntropy);
}).sort(byNumberOfExpressionExperiments);
}
return {
...a,
id: this.getCategoryId(a),
id: getCategoryId(a),
isCategory: true,
children: getChildren(a)
};
Expand All @@ -137,14 +128,14 @@ export default {
if (a.classUri && b.classUri) {
let aI = annotationSelectorOrderArray.indexOf(a.classUri);
let bI = annotationSelectorOrderArray.indexOf(b.classUri);
if(aI !== -1 && bI !== -1) {
if (aI !== -1 && bI !== -1) {
return aI - bI;
} else if (aI !== -1) {
return -1;
} else if (bI !== -1) {
return 1;
} else {
return 0;
return 0;
}
} else if (a.classUri) {
return -1;
Expand All @@ -160,31 +151,22 @@ export default {
})
},
methods: {
sumBy,
formatNumber,
formatDecimal,
/**
* @returns {*|string|null} an ID for the category or null if the term is uncategorized
*/
getCategoryId(term) {
return term.classUri || term.className?.toLowerCase() || null;
},
getId(term) {
return this.getCategoryId(term) + SEPARATOR + (term.termUri || term.termName?.toLowerCase());
return getCategoryId(term) + SEPARATOR + getTermId(term);
},
entropy(item) {
if (this.isUncategorized(item)) {
return 0;
}
getNumberOfExpressionExperiments(item) {
if (item.isCategory) {
// FIXME: because terms are not independent, we cannot sum their entropy
return max(item.children.map(c => this.entropy(c)));
// FIXME: because terms are not independent, we cannot sum their number of expression experiments
return max(item.children.map(c => this.getNumberOfExpressionExperiments(c))) || 0;
} else {
return item.numberOfExpressionExperiments;
}
const p = item.numberOfExpressionExperiments / this.totalNumberOfExpressionExperiments;
if (p === 0 || p === 1) {
return 0;
}
let distribution = [p, 1 - p];
return -sum(distribution.map(p => p * Math.log(p)));
},
isExcluded(item) {
return excludedTerms.includes(item.classUri) || excludedTerms.includes(item.termUri);
},
isUncategorized(item) {
return !item.className && !item.classUri;
Expand Down Expand Up @@ -218,7 +200,7 @@ export default {
* Selected annotations, grouped by category and excluding selected categories.
*/
computeSelectedAnnotations(newVal, selectedCategories) {
let sc = new Set(selectedCategories.map(sc => this.getCategoryId(sc)));
let sc = new Set(selectedCategories.map(sc => getCategoryId(sc)));
return newVal
// exclude annotations from selected categories
.filter(a => !sc.has(a.split(SEPARATOR, 2)[0]))
Expand Down
4 changes: 2 additions & 2 deletions src/components/DownloadButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import { axiosInst, baseUrl } from "@/config/gemma";
import { parse } from "json2csv";
import { chain } from "lodash";
import { compressFilter, downloadAs, formatNumber } from "@/utils";
import { compressFilter, downloadAs, formatNumber, getCategoryId } from "@/utils";
import axios from "axios";
const termsAndConditionsHeader = [
Expand Down Expand Up @@ -50,7 +50,7 @@ export default {
},
readableFilter() {
let annotationByCategoryId = chain(this.searchSettings.annotations)
.groupBy(t => t.classUri || t.className?.toLowerCase() || null)
.groupBy(getCategoryId)
.values()
.map(annotations => annotations.map(a => a.termName).join(", "))
.join("; ")
Expand Down
11 changes: 7 additions & 4 deletions src/components/SearchSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,32 +19,35 @@
outlined
clearable
hide-details
class="mb-3"
></v-text-field>
<TaxonSelector
v-model="searchSettings.taxon"
:taxon="taxon"
:disabled="taxonDisabled"
:loading="taxaLoading"/>
:loading="taxaLoading"
class="mb-1"/>
<TechnologyTypeSelector
v-if="searchSettings.resultTypes.indexOf(platformResultType) === -1"
v-model="searchSettings.platforms"
:platforms="platforms"
:selected-technology-types.sync="searchSettings.technologyTypes"
:disabled="platformDisabled"
:loading="platformLoading"/>
:loading="platformLoading"
class="mb-1"/>
<v-range-slider
v-model="searchSettings.quality"
min="0" max="3"
ticks="always"
:tick-labels="['trash', 'low', 'mid', 'high']"
label="Quality" title="Filter based on GEEQ scores or curation status"
v-show="false"/>
v-show="false"
class="mb-1"/>
<AnnotationSelector
v-model="searchSettings.annotations"
:annotations="annotations"
:loading="annotationLoading"
:disabled="annotationDisabled"
:total-number-of-expression-experiments="totalNumberOfExpressionExperiments"
:selectedCategories.sync="searchSettings.categories"/>
<div :class="debug ? '' : 'd-lg-none'">
<div style="margin-bottom: 59px;"></div>
Expand Down
58 changes: 33 additions & 25 deletions src/components/TaxonSelector.vue
Original file line number Diff line number Diff line change
@@ -1,28 +1,36 @@
<template>
<div>
<v-progress-linear :active="loading" indeterminate/>
<v-treeview
:items="treeItems"
item-key="id"
v-model="selectedTaxaIds"
selectable
dense
:disabled="disabled"
class="hide-root-checkboxes"
>
<template v-slot:label="{ item }">
<span v-text="item.label" class="text-truncate"> </span>
</template>
<template v-slot:append="{ item }">
<span v-if="item.type !== 'parent'"> {{ formatNumber(item.number) }} </span>
<span v-if="item.type === 'parent' && selectedTaxaIds.length > 0">
<v-btn @click="clearSelections" small text color="primary" :disabled="disabled">
Clear Selection
</v-btn>
</span>
</template>
</v-treeview>
</div>
<div>
<div class="d-flex align-baseline">
<div class="text--secondary">
Taxa
</div>
<v-progress-linear :active="loading" indeterminate/>
<v-spacer/>
<v-btn v-if="selectedTaxaIds.length > 0" @click="clearSelections" small text color="primary"
:disabled="disabled">
Clear Selection
</v-btn>
</div>
<v-treeview
:items="treeItems"
item-key="id"
v-model="selectedTaxaIds"
selectable
dense
:disabled="disabled"
class="hide-root-checkboxes"
>
<template v-slot:label="{ item }">
<span v-text="item.label" class="text-truncate"> </span>
</template>
<template v-slot:append="{ item }">
<div class="text-right">{{ formatNumber(item.number) }}</div>
</template>
</v-treeview>
<p v-show="treeItems.length === 0">
No taxa available
</p>
</div>
</template>

<script>
Expand Down Expand Up @@ -77,7 +85,7 @@ export default {
items[0].children.push(taxonItem);
}
return items;
return items[0].children;
},
selectedTaxa() {
if (!this.selectedTaxaIds) return [];
Expand Down
36 changes: 25 additions & 11 deletions src/components/TechnologyTypeSelector.vue
Original file line number Diff line number Diff line change
@@ -1,33 +1,40 @@
<template>
<div>
<v-progress-linear :active="loading" indeterminate/>
<div class="d-flex align-baseline">
<div class="text--secondary">Platforms</div>
<v-spacer></v-spacer>
<v-btn v-if="selectedValues.length > 0" @click="selectedValues = []" small text color="primary" :disabled="disabled">
<v-btn v-if="selectedValues.length > 0" @click="selectedValues = []" small text color="primary"
:disabled="disabled">
Clear Selection
</v-btn>
</div>
<v-progress-linear :active="loading" indeterminate/>
<v-treeview v-model="selectedValues"
:items="technologyTypes"
:disabled="disabled"
item-key="id"
item-text="name"
selectable dense
class="hide-root-checkboxes">
selectable dense class="hide-root-checkboxes">
<template v-slot:label="{item}">
{{ item.name }}
<span :title="item.name.length > 30 && item.name">{{ item.name }}</span>
</template>
<template v-slot:append="{item}">
{{ item.numberOfExpressionExperiments }}
<div v-if="item.numberOfExpressionExperiments" class="text-right">
{{ formatNumber(item.numberOfExpressionExperiments) }}
</div>
</template>
</v-treeview>
<p v-show="technologyTypes.length === 0">
No technology types available
</p>
</div>
</template>

<script>
import { isEqual, sumBy } from "lodash";
import { chain, isEqual } from "lodash";
import { formatNumber } from "@/utils";
import { mapState } from "vuex";
const MICROARRAY_TECHNOLOGY_TYPES = ["ONECOLOR", "TWOCOLOR", "DUALMODE"];
const OTHER_TECHNOLOGY_TYPES = ["SEQUENCING", "GENELIST", "OTHER"];
Expand Down Expand Up @@ -58,18 +65,25 @@ export default {
{
id: "RNASEQ",
name: "RNA-Seq",
numberOfExpressionExperiments: sumBy(rnaseqPlatforms, "numberOfExpressionExperiments")
numberOfExpressionExperiments: rnaseqPlatforms[0]?.numberOfExpressionExperimentsForTechnologyType || 0
},
{
id: "MICROARRAY",
name: "Microarray",
children: microarrayPlatforms,
numberOfExpressionExperiments: sumBy(microarrayPlatforms, "numberOfExpressionExperiments")
numberOfExpressionExperiments: chain(microarrayPlatforms)
.groupBy("technologyType")
.mapValues(v => v[0].numberOfExpressionExperimentsForTechnologyType)
.values()
.sum()
.value()
}
];
}
].filter(tt => tt.numberOfExpressionExperiments > 0);
},
...mapState(["debug"])
},
methods: {
formatNumber,
computeSelectedPlatforms(ids, st) {
return this.platforms
.filter(p => ids.has(p.id))
Expand Down

0 comments on commit 6cd6397

Please sign in to comment.