Skip to content
Snippets Groups Projects
Commit c044b822 authored by Remi  PLANEL's avatar Remi PLANEL
Browse files

slider for numerical

parent cc3b1fa7
No related branches found
No related tags found
1 merge request!168Multiple slider
Pipeline #119131 failed
<script setup lang="ts"> <script setup lang="ts">
// import type { FacetDistribution } from "meilisearch"; // import type { FacetDistribution } from "meilisearch";
import { useCsvDownload } from "@/composables/useCsvDownload" import { useCsvDownload } from "@/composables/useCsvDownload"
import { useNumericalFilter } from "@/composables/useNumericalfilter"
import { useSlots } from 'vue' import { useSlots } from 'vue'
import { useDisplay } from "vuetify"; import { useDisplay } from "vuetify";
import * as Plot from "@observablehq/plot"; import * as Plot from "@observablehq/plot";
import PlotFigure from "~/components/PlotFigure"; import PlotFigure from "~/components/PlotFigure";
import * as d3 from "d3";
import { useThrottleFn } from '@vueuse/core' import { useThrottleFn } from '@vueuse/core'
import * as d3 from "d3";
import { useMeiliSearch } from "#imports" import { useMeiliSearch } from "#imports"
// import { saveAs } from "file-saver"; // import { saveAs } from "file-saver";
import { useFileSystemAccess } from '@vueuse/core' import { useFileSystemAccess } from '@vueuse/core'
...@@ -15,13 +18,22 @@ export interface SortItem { ...@@ -15,13 +18,22 @@ export interface SortItem {
order: boolean | 'asc' | 'desc' order: boolean | 'asc' | 'desc'
} }
export interface NumericalFilter {
id: string
name: string
range: [number, number]
}
export interface NumericalFilterModel extends NumericalFilter {
model: [number, number]
}
export interface Props { export interface Props {
title?: string title?: string
db?: string db?: string
sortBy?: SortItem[] sortBy?: SortItem[]
facets: MaybeRef<string[]> facets: MaybeRef<string[]>
dataTableServerProps: Record<string, any> dataTableServerProps: Record<string, any>
columnsToDownload: MaybeRef<string[]> columnsToDownload?: MaybeRef<string[] | undefined>
} }
export interface FilterItem { export interface FilterItem {
...@@ -36,7 +48,9 @@ export interface FilterItem { ...@@ -36,7 +48,9 @@ export interface FilterItem {
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
title: '', title: '',
db: 'refseq', db: 'refseq',
columnsToDownload: undefined,
sortBy: () => [{ key: "type", order: "asc" }], sortBy: () => [{ key: "type", order: "asc" }],
}); });
...@@ -61,7 +75,7 @@ const computedTableHeight = computed(() => { ...@@ -61,7 +75,7 @@ const computedTableHeight = computed(() => {
const computedHeight = height.value - 350 const computedHeight = height.value - 350
return computedHeight > minTableHeight.value ? computedHeight : minTableHeight.value return computedHeight > minTableHeight.value ? computedHeight : minTableHeight.value
}) })
const plddtRange = ref([0, 100])
const pendingDownloadData = ref(false) const pendingDownloadData = ref(false)
const filterInputValues = computed(() => { const filterInputValues = computed(() => {
...@@ -111,39 +125,23 @@ onMounted(async () => { ...@@ -111,39 +125,23 @@ onMounted(async () => {
searchOrFilter() searchOrFilter()
}) })
const hasPlddt = computed(() => props.db === 'structure')
// Fetch results
const plddtFilter = computed(() => {
const plddtRangeValue = plddtRange.value
if (hasPlddt.value && plddtRangeValue?.length === 2 && (plddtRangeValue[0] !== 0 || plddtRangeValue[1] !== 100)) {
return `plddts ${plddtRangeValue[0]} TO ${plddtRangeValue[1]}`
} else {
return undefined
}
}) const { range: plddtsRange, stringifyFilter: plddtsFilter, reset: plddtsReset } = useNumericalFilter("plddts", 0, 100)
const { range: iptmRange, stringifyFilter: iptmFilter, reset: iptmReset } = useNumericalFilter("iptm+ptm", 0, 1)
const { range: pdockqRange, stringifyFilter: pdockqFilter, reset: pdockqReset } = useNumericalFilter("pDockQ", 0, 1)
const computedFilter = computed(() => { const computedFilter = computed(() => {
if (toValue(msFilter)) { return [toValue(msFilter), toValue(plddtsFilter), toValue(iptmFilter), toValue(pdockqFilter)].filter(f => f !== undefined).join(" AND ")
if (toValue(plddtFilter)) {
return `${toValue(msFilter)} AND ${toValue(plddtFilter)}`
}
else {
return toValue(msFilter)
}
} else {
if (toValue(plddtFilter)) {
return `${toValue(plddtFilter)}`
}
else {
return undefined
}
}
}) })
watch(computedFilter, () => {
searchOrFilter()
})
const msError = computed(() => { const msError = computed(() => {
if (filterError.value?.type && filterError.value?.message) { if (filterError.value?.type && filterError.value?.message) {
...@@ -151,8 +149,9 @@ const msError = computed(() => { ...@@ -151,8 +149,9 @@ const msError = computed(() => {
} else { return false } } else { return false }
}) })
const throttleSearch = useThrottleFn(async () => { searchOrFilter() }, 300) const throttleSearch = useThrottleFn(async () => {
searchOrFilter()
}, 300)
async function searchOrFilter(pagination = true) { async function searchOrFilter(pagination = true) {
// do something, it will be called at most 1 time per second // do something, it will be called at most 1 time per second
...@@ -276,13 +275,7 @@ const autocompleteItems = computed(() => { ...@@ -276,13 +275,7 @@ const autocompleteItems = computed(() => {
} }
}) })
// const canAddTextSearch = computed(() => {
// if (filterOrSearch.value !== null && filterOrSearch.value.length > 0) {
// const lastItem = filterOrSearch.value.slice(-1)[0]
// return lastItem?.props.type === 'value' || lastItem?.props.type === "text"
// }
// return true
// })
function selectItem(item) { function selectItem(item) {
filterOrSearch.value = Array.isArray(filterOrSearch.value) ? [...filterOrSearch.value, item] : [item] filterOrSearch.value = Array.isArray(filterOrSearch.value) ? [...filterOrSearch.value, item] : [item]
...@@ -319,19 +312,33 @@ async function downloadData() { ...@@ -319,19 +312,33 @@ async function downloadData() {
</v-card-text> </v-card-text>
<v-card-text> <v-card-text>
<v-row v-if="props.db === 'structure'"> <v-row v-if="props.db === 'structure'">
<v-col>
<v-range-slider v-model="plddtRange" density="compact" hide-details="auto" label="pLDDT" step="0.1" <v-col md="12" lg="4">
@update:modelValue="throttleSearch()"> <v-range-slider v-model="plddtsRange" strict density="compact" hide-details="auto" label="pLDDT"
<template v-slot:prepend> step="0.5" :min="0" :max="100" thumb-label="always" @update:modelValue="throttleSearch()">
<span hide-details single-line type="number" variant="outlined" density="compact" <template #append>
style="width: 70px">{{ plddtRange[0] }}</span> <v-btn variant="text" icon="md:restart_alt" @click="plddtsReset()"></v-btn>
</template> </template>
<template v-slot:append> </v-range-slider>
<span hide-details single-line type="number" variant="outlined" style="width: 70px" </v-col>
density="compact">{{ plddtRange[1] }}</span> <v-col md="12" lg="4">
<v-range-slider v-model="iptmRange" strict density="compact" hide-details="auto" label="iptm+ptm"
step="0.1" :min="0" :max="1" thumb-label="always" @update:modelValue="throttleSearch()">
<template #append>
<v-btn variant="text" icon="md:restart_alt" @click="iptmReset()"></v-btn>
</template> </template>
</v-range-slider>
</v-col>
<!-- pdockqReset -->
<v-col md="12" lg="4">
<v-range-slider v-model="pdockqRange" strict density="compact" hide-details="auto" label="pDockQ"
step="0.1" :min="0" :max="1" thumb-label="always" @update:modelValue="throttleSearch()">
<template #append>
<v-btn variant="text" icon="md:restart_alt" @click="pdockqReset()"></v-btn>
</template>
</v-range-slider> </v-range-slider>
</v-col> </v-col>
</v-row> </v-row>
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
import * as Plot from "@observablehq/plot"; import * as Plot from "@observablehq/plot";
import PlotFigure from "~/components/PlotFigure"; import PlotFigure from "~/components/PlotFigure";
import type { SortItem } from "@/components/ServerDbTable.vue" import type { SortItem } from "@/components/ServerDbTable.vue"
import { ServerDbTable } from "#components" import { ServerDbTable } from "#components"
const sortBy: Ref<SortItem[]> = ref([{ key: 'system', order: "asc" }]) const sortBy: Ref<SortItem[]> = ref([{ key: 'system', order: "asc" }])
const itemValue = ref("id"); const itemValue = ref("id");
...@@ -24,6 +25,7 @@ const headers: Ref<Object[]> = ref([ ...@@ -24,6 +25,7 @@ const headers: Ref<Object[]> = ref([
// { title: "Type", key: "type", removable: true }, // { title: "Type", key: "type", removable: true },
]) ])
const { search: msSearch, result: msResult } = useMeiliSearch('structure') const { search: msSearch, result: msResult } = useMeiliSearch('structure')
const defaultDataTableServerProps = ref({ const defaultDataTableServerProps = ref({
...@@ -74,6 +76,9 @@ const plddtDistribution = computed(() => { ...@@ -74,6 +76,9 @@ const plddtDistribution = computed(() => {
} }
}) })
function remove(key) { function remove(key) {
headers.value = headers.value.filter(header => header.key !== key) headers.value = headers.value.filter(header => header.key !== key)
} }
...@@ -83,14 +88,6 @@ function remove(key) { ...@@ -83,14 +88,6 @@ function remove(key) {
<ServerDbTable title="Predicted Structures" db="structure" :sortBy="sortBy" :facets="facets" <ServerDbTable title="Predicted Structures" db="structure" :sortBy="sortBy" :facets="facets"
:data-table-server-props="dataTableServerProps"> :data-table-server-props="dataTableServerProps">
<!-- <template #top>
<v-toolbar><v-toolbar-title class="text-capitalize">
Predicted Structures
</v-toolbar-title><v-spacer></v-spacer>
</v-toolbar>
</template> -->
<template #[`item.proteins_in_the_prediction`]="{ item }"> <template #[`item.proteins_in_the_prediction`]="{ item }">
<CollapsibleChips :items="namesToCollapsibleChips(item.proteins_in_the_prediction, item.fasta_file)"> <CollapsibleChips :items="namesToCollapsibleChips(item.proteins_in_the_prediction, item.fasta_file)">
</CollapsibleChips> </CollapsibleChips>
......
export function useNumericalFilter(
id: MaybeRef<string>,
min: MaybeRef<number>,
max: MaybeRef<number>,
) {
const range: Ref<[number, number]> = ref([toValue(min), toValue(max)])
const stringifyFilter: Ref<string | undefined> = ref(`${toValue(id)} ${toValue(min)} TO ${toValue(max)}`)
watchEffect(() => {
console.log("watch reange")
console.log(range.value)
if (range.value[0] === toValue(min) && range.value[1] === toValue(max)) {
stringifyFilter.value = undefined
} else {
stringifyFilter.value = `'${toValue(id)}' ${range.value[0]} TO ${range.value[1]}`
}
})
function reset() {
range.value = [toValue(min), toValue(max)]
}
// watch(() => range, () => {
// console.log("watch reange")
// console.log(range)
// if (range.value[0] === toValue(min) && range.value[1] === toValue(max)) {
// stringifyFilter.value = undefined
// } else {
// stringifyFilter.value = `${toValue(id)} ${toValue(min)} TO ${toValue(max)}`
// }
// }, { deep: true })
return { range, stringifyFilter, reset }
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment