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

Cell distri

parent df6ef38b
No related branches found
No related tags found
1 merge request!153Cell distri
...@@ -38,7 +38,9 @@ function onScroll() { ...@@ -38,7 +38,9 @@ function onScroll() {
<v-row justify="center"> <v-row justify="center">
<v-col cols="auto"> <v-col cols="auto">
<v-card flat color="transparent" :min-width="mobile ? undefined : 900" :max-width="fluid ? undefined : 1500"> <v-card flat color="transparent" :min-width="mobile ? undefined : 900" :max-width="fluid ? undefined : 1500">
<slot /> <v-card-text>
<slot />
</v-card-text>
<EditGitlab v-if="edit" /> <EditGitlab v-if="edit" />
<NavPrevNext v-if="edit" /> <NavPrevNext v-if="edit" />
</v-card> </v-card>
......
...@@ -13,23 +13,23 @@ import { useDisplay, useTheme } from "vuetify"; ...@@ -13,23 +13,23 @@ import { useDisplay, useTheme } from "vuetify";
const { navigation, page } = useContent(); const { navigation, page } = useContent();
// const drawer = ref(true); // const drawer = ref(true);
// const computedNavigation = computed(() => { const computedNavigation = computed(() => {
// return navigation.value return navigation.value
// .filter((item: { layout: string }) => { .filter((item: { layout: string }) => {
// if (item?.layout === "db") { if (item?.layout === "db") {
// console.log(item) console.log(item)
// return false return false
// } }
// return true return true
// // return item?.layout !== "db" // return item?.layout !== "db"
// }) })
// }); });
</script> </script>
<template> <template>
<v-navigation-drawer :model-value="drawer" :border="1" color="background"> <v-navigation-drawer :model-value="drawer" :border="1" color="background">
<v-list nav density="compact" :lines="false"> <v-list nav density="compact" :lines="false">
<NavNavigation :navigation="navigation" /> <NavNavigation :navigation="computedNavigation" />
</v-list> </v-list>
</v-navigation-drawer> </v-navigation-drawer>
</template> </template>
\ No newline at end of file
...@@ -2,9 +2,10 @@ ...@@ -2,9 +2,10 @@
// import type { FacetDistribution } from "meilisearch"; // import type { FacetDistribution } from "meilisearch";
import { useSlots } from 'vue' import { useSlots } from 'vue'
import { useDisplay } from "vuetify"; import { useDisplay } from "vuetify";
import { useFacetsStore } from '~~/stores/facets' import * as Plot from "@observablehq/plot";
import PlotFigure from "~/components/PlotFigure";
import * as d3 from "d3";
import { useThrottleFn } from '@vueuse/core'
import { useMeiliSearch } from "#imports" import { useMeiliSearch } from "#imports"
export interface SortItem { export interface SortItem {
key: string, key: string,
...@@ -36,17 +37,15 @@ const props = withDefaults(defineProps<Props>(), { ...@@ -36,17 +37,15 @@ const props = withDefaults(defineProps<Props>(), {
console.log(props.dataTableServerProps)
const slots = useSlots() const slots = useSlots()
const sortByRef = toRef(props.sortBy) const sortByRef = toRef(props.sortBy)
const facetsRef = toRef(props.facets) const facetsRef = toRef(props.facets)
const emit = defineEmits(["refresh:search"])
const { search: msSearch, result: msResult } = useMeiliSearch(props.db) const { search: msSearch, result: msResult } = useMeiliSearch(props.db)
const facetStore = useFacetsStore()
const search: Ref<string> = ref(""); const search: Ref<string> = ref("");
const filterOrSearch: Ref<FilterItem[] | null> = ref(null) const filterOrSearch: Ref<FilterItem[] | null> = ref(null)
const hitsPerPage: Ref<number> = ref(25) const hitsPerPage: Ref<number> = ref(25)
const itemsPerPage: Ref<number[]> = ref([25, 50, 100])
const filterError: Ref<string | null> = ref(null) const filterError: Ref<string | null> = ref(null)
const msFilter: Ref<string | undefined> = ref(undefined) const msFilter: Ref<string | undefined> = ref(undefined)
const page = ref(1) const page = ref(1)
...@@ -58,6 +57,7 @@ const computedTableHeight = computed(() => { ...@@ -58,6 +57,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 { pending: pendingDownloadData, downloadCsv } = useCsvDownload(props.db, `df-${props.db}`) // const { pending: pendingDownloadData, downloadCsv } = useCsvDownload(props.db, `df-${props.db}`)
...@@ -126,7 +126,40 @@ watch([paginationParams, msSortBy, page], ([newParams, newSort, newPage]) => { ...@@ -126,7 +126,40 @@ watch([paginationParams, msSortBy, page], ([newParams, newSort, newPage]) => {
onMounted(async () => { onMounted(async () => {
searchOrFilter() searchOrFilter()
}) })
const hasPlddt = computed(() => props.db === 'structure')
// Fetch results // Fetch results
const plddtFilter = computed(() => {
const plddtRangeValue = plddtRange.value
if (hasPlddt.value && plddtRangeValue?.length === 2) {
return `plddts ${plddtRangeValue[0]} TO ${plddtRangeValue[1]}`
} else {
return undefined
}
})
const computedFilter = computed(() => {
if (toValue(msFilter)) {
if (toValue(plddtFilter)) {
return `${toValue(msFilter)} AND ${toValue(plddtFilter)}`
}
else {
return toValue(msFilter)
}
} else {
if (toValue(plddtFilter)) {
return `${toValue(plddtFilter)}`
}
else {
return undefined
}
}
})
const msError = computed(() => { const msError = computed(() => {
if (filterError.value?.type && filterError.value?.message) { if (filterError.value?.type && filterError.value?.message) {
...@@ -134,16 +167,26 @@ const msError = computed(() => { ...@@ -134,16 +167,26 @@ const msError = computed(() => {
} else { return false } } else { return false }
}) })
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
try { try {
loading.value = true loading.value = true
// const q = queryInputValue.value === null ? "" : queryInputValue.value // const q = queryInputValue.value === null ? "" : queryInputValue.value
const q = search.value const q = search.value
emit("refresh:search", {
index: props.db,
query: q,
params: { ...notPaginatedParams.value, filter: toValue(computedFilter), sort: msSortBy.value }
})
if (pagination) { if (pagination) {
await msSearch(q, { ...paginationParams.value, filter: msFilter.value, sort: msSortBy.value }) await msSearch(q, { ...paginationParams.value, filter: toValue(computedFilter), sort: msSortBy.value })
} }
else { else {
await msSearch(q, { ...notPaginatedParams.value, filter: msFilter.value, sort: msSortBy.value }) await msSearch(q, { ...notPaginatedParams.value, filter: toValue(computedFilter), sort: msSortBy.value })
} }
} catch (error: any) { } catch (error: any) {
...@@ -153,9 +196,11 @@ async function searchOrFilter(pagination = true) { ...@@ -153,9 +196,11 @@ async function searchOrFilter(pagination = true) {
finally { finally {
loading.value = false loading.value = false
} }
} }
function clearFilterOrSearch() { function clearFilterOrSearch() {
filterOrSearch.value = null filterOrSearch.value = null
searchOrFilter() searchOrFilter()
...@@ -167,11 +212,6 @@ watch(msFilter, async (fos) => { ...@@ -167,11 +212,6 @@ watch(msFilter, async (fos) => {
}) })
watch(msResult, (newRes) => {
facetStore.setFacets({ facetDistribution: newRes.facetDistribution, facetStat: newRes.facetStat })
}, { deep: true })
const totalHits = computed(() => { const totalHits = computed(() => {
return toValue(msResult)?.totalHits ?? toValue(msResult)?.estimatedTotalHits ?? 0 return toValue(msResult)?.totalHits ?? toValue(msResult)?.estimatedTotalHits ?? 0
...@@ -195,7 +235,7 @@ watch(filterInputValues, (newSoF) => { ...@@ -195,7 +235,7 @@ watch(filterInputValues, (newSoF) => {
}) })
watch(search, () => { searchOrFilter() }) watch(search, () => { searchOrFilter() })
// watch(plddtRange, () => { searchOrFilter() })
const filterStep = computed(() => { const filterStep = computed(() => {
return filterInputValues.value !== null && filterInputValues.value.length > 0 ? filterInputValues.value?.length % 3 : null return filterInputValues.value !== null && filterInputValues.value.length > 0 ? filterInputValues.value?.length % 3 : null
}) })
...@@ -239,7 +279,7 @@ const autocompleteItems = computed(() => { ...@@ -239,7 +279,7 @@ const autocompleteItems = computed(() => {
const { type, value } = filterOrSearch.value?.slice(-2, -1)[0] const { type, value } = filterOrSearch.value?.slice(-2, -1)[0]
const sanitizedValue = value.split("-")[0] const sanitizedValue = value.split("-")[0]
// console.log("compute new facets") // console.log("compute new facets")
const facetDistri = facetStore.facets?.facetDistribution const facetDistri = msResult.value?.facetDistribution
// console.log(facetDistri) // console.log(facetDistri)
return facetDistri?.[sanitizedValue] ? Object.entries(facetDistri[sanitizedValue]).map(([key, val]) => { return facetDistri?.[sanitizedValue] ? Object.entries(facetDistri[sanitizedValue]).map(([key, val]) => {
return { return {
...@@ -276,32 +316,19 @@ function clearSearch() { ...@@ -276,32 +316,19 @@ function clearSearch() {
// function runTextSearch() {
// if (canAddTextSearch) {
// const item: FilterItem = reactive({
// type: 'text', title: search.value, value: search.value, deletable: true, props: { type: "text", deletable: true, }
// })
// if (Array.isArray(filterOrSearch.value)) {
// filterOrSearch.value = [
// ...filterOrSearch.value, item
// ] // const groupSortDomain = computed(() => {
// } else { // console.log(msResult.value)
// filterOrSearch.value = [item] // return msResult.value ? d3.groupSort(msResult.value?.hits?.filter((d) => d.phylum), (g) => d3.median(g, (d) => d.phylum), (d) => d.type) : []
// } // })
// search.value = ""
// searchOrFilter()
// }
// }
// function downloadData() {
// downloadCsv(search, msFilter, msSortBy, notPaginatedParams)
// }
</script> </script>
<template> <template>
<v-card flat color="transparent"> <v-card flat color="transparent">
<v-card-text>
</v-card-text>
<v-card-text> <v-card-text>
<v-row> <v-row>
<v-col cols="5"> <v-col cols="5">
...@@ -327,23 +354,28 @@ function clearSearch() { ...@@ -327,23 +354,28 @@ function clearSearch() {
</v-autocomplete> </v-autocomplete>
</v-col> </v-col>
</v-row> </v-row>
<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"
@update:modelValue="throttleSearch()">
<template v-slot:prepend>
<span hide-details single-line type="number" variant="outlined" density="compact"
style="width: 70px">{{ plddtRange[0] }}</span>
</template>
<template v-slot:append>
<span hide-details single-line type="number" variant="outlined" style="width: 70px"
density="compact">{{ plddtRange[1] }}</span>
</template>
</v-range-slider>
</v-col>
</v-row>
</v-card-text> </v-card-text>
<v-data-table-server v-if="!msError" v-model:page="page" color="primary" v-bind="dataTableServerProps" <v-data-table-server v-if="!msError" v-model:page="page" color="primary" v-bind="dataTableServerProps"
v-model:items-per-page="hitsPerPage" v-model:sortBy="sortByRef" v-model:expanded="expanded" fixed-header v-model:items-per-page="hitsPerPage" v-model:sortBy="sortByRef" v-model:expanded="expanded" fixed-header
:loading="loading" :items="msResult?.hits ?? []" :items-length="totalHits" density="compact" :loading="loading" :items="msResult?.hits ?? []" :items-length="totalHits" density="compact"
:height="computedTableHeight" class="elevation-1 mt-2"> :items-per-page-options="itemsPerPage" :height="computedTableHeight" class="elevation-1 mt-2">
<template #top>
<v-toolbar><v-toolbar-title class="text-capitalize">
{{ props.db }}
</v-toolbar-title><v-spacer></v-spacer>
<!-- <v-btn :loading="pendingDownloadData" :disabled="totalHits > 10000" @click="downloadData" icon
variant="text" class="text-none mr-15">
<v-badge :content="totalHits" color="info" floating>
<v-icon>md:download</v-icon></v-badge></v-btn> -->
</v-toolbar>
</template>
<template v-for="(slot, index) of Object.keys(slots)" :key="index" v-slot:[slot]="data"> <template v-for="(slot, index) of Object.keys(slots)" :key="index" v-slot:[slot]="data">
<slot :name="slot" v-bind="data"></slot> <slot :name="slot" v-bind="data"></slot>
</template> </template>
......
...@@ -196,7 +196,7 @@ const moleculeFormat: Ref<string> = ref("pdb") ...@@ -196,7 +196,7 @@ const moleculeFormat: Ref<string> = ref("pdb")
<template> <template>
<span class="d-flex flex-wrap align-center justify-center"> <span class="d-flex flex-wrap align-center justify-center">
<v-col> <v-col>
<v-btn v-if="uniq" size="x-small" variant="tonal" icon="mdi-molecule" @click="setSelectedPdbToFirst()"></v-btn> <v-btn v-if="uniq" size="x-small" variant="tonal" icon="md:visibility" @click="setSelectedPdbToFirst()"></v-btn>
<v-select v-else v-model="selectedPdb" label="Select PDB" :items="refinedDataUrls" hide-details="auto"> <v-select v-else v-model="selectedPdb" label="Select PDB" :items="refinedDataUrls" hide-details="auto">
</v-select> </v-select>
</v-col> </v-col>
......
<script setup lang="ts"> <script setup lang="ts">
import { useFacetsStore } from '~~/stores/facets'
import * as Plot from "@observablehq/plot"; import * as Plot from "@observablehq/plot";
import PlotFigure from "~/components/PlotFigure"; import PlotFigure from "~/components/PlotFigure";
import { useDisplay } from "vuetify"; import { useDisplay } from "vuetify";
import type { SortItem } from "@/components/ServerDbTable.vue" import type { SortItem } from "@/components/ServerDbTable.vue"
import { ServerDbTable } from "#components" import { ServerDbTable } from "#components"
const facetStore = useFacetsStore()
const sortBy: Ref<SortItem[]> = ref([{ key: 'type', order: "asc" }]) const sortBy: Ref<SortItem[]> = ref([{ key: 'type', order: "asc" }])
const itemValue = ref("id"); const itemValue = ref("id");
const { width } = useDisplay(); const { width } = useDisplay();
const distriTool: Ref<string[]> = ref([]) const scaleTransform: Ref<string[]> = ref([])
const facets = ref([ const facets = ref([
"replicon", "replicon",
...@@ -50,11 +48,9 @@ const headers = ref([ ...@@ -50,11 +48,9 @@ const headers = ref([
sortable: false sortable: false
} }
]) ])
const logTransform = computed(() => {
return distriTool.value.includes('log')
})
const fullWidth = computed(() => { const fullWidth = computed(() => {
return distriTool.value.includes('fullwidth') return layoutPlot.value === 'fullwidth'
}) })
const computedHeaders = computed(() => { const computedHeaders = computed(() => {
return [...headers.value, ...availableTaxo.value.map(taxo => { return [...headers.value, ...availableTaxo.value.map(taxo => {
...@@ -64,12 +60,38 @@ const computedHeaders = computed(() => { ...@@ -64,12 +60,38 @@ const computedHeaders = computed(() => {
} }
})] })]
}) })
const { result: msResult } = useMeiliSearch('refseq')
const computedWidth = computed(() => { const computedWidth = computed(() => {
const currentWidth = fullWidth.value ? width.value : width.value / 2 const currentWidth = fullWidth.value ? width.value : width.value / 2
return Math.max(currentWidth, 550); return Math.max(currentWidth, 550);
}); });
const allHits = ref([])
onMounted(async () => {
const params = {
facets: ["*"],
filter: [],
sort: ["type:asc"],
limit: 500000
}
await getAllHits({ index: "refseq", params, query: "" })
})
async function getAllHits(params) {
console.log("refresh hits")
console.log(params)
console.log(params.index)
if (params.index === 'refseq') {
console.log(params.index)
const { data, error } = await useAsyncMeiliSearch(params)
console.log(error.value)
console.log(data.value)
allHits.value = data.value
}
}
const plotHeight = computed(() => { const plotHeight = computed(() => {
return computedWidth.value / 3; return computedWidth.value / 3;
// return 500 // return 500
...@@ -87,11 +109,10 @@ const dataTableServerProps = computed(() => { ...@@ -87,11 +109,10 @@ const dataTableServerProps = computed(() => {
} }
}) })
const defaultBarPlotOptions = computed(() => { const defaultBarPlotOptions = computed(() => {
const y = logTransform.value ? { nice: true, grid: true, type: 'symlog' } : { nice: true, grid: true, type: "linear" }
// const y = { nice: true, grid: true }
return { return {
x: { label: null, tickRotate: 45, ticks: 10 }, x: { label: null, tickRotate: 45, ticks: 10 },
y, y: { grid: true, type: scaleType.value },
color: { legend: true }, color: { legend: true },
width: computedWidth.value, width: computedWidth.value,
height: plotHeight.value + 100, height: plotHeight.value + 100,
...@@ -99,11 +120,10 @@ const defaultBarPlotOptions = computed(() => { ...@@ -99,11 +120,10 @@ const defaultBarPlotOptions = computed(() => {
}) })
const computedSystemDistribution = computed(() => { const computedSystemDistribution = computed(() => {
if (facetStore.facets?.facetDistribution?.type) { if (toValue(msResult)?.facetDistribution?.type) {
return Object.entries(facetStore.facets.facetDistribution.type).map(([key, value]) => { return Object.entries(toValue(msResult).facetDistribution.type).map(([key, value]) => {
return { return {
type: key, type: key,
// count: logTransform.value ? Math.log(value) : value
count: value count: value
} }
}).sort() }).sort()
...@@ -129,8 +149,8 @@ const computedDistriSystemOptions = computed(() => { ...@@ -129,8 +149,8 @@ const computedDistriSystemOptions = computed(() => {
}; };
}); });
const computedTaxonomyDistribution = computed(() => { const computedTaxonomyDistribution = computed(() => {
if (facetStore.facets?.facetDistribution?.[selectedTaxoRank.value]) { if (toValue(msResult)?.facetDistribution?.[selectedTaxoRank.value]) {
return Object.entries(facetStore.facets.facetDistribution[selectedTaxoRank.value]).map(([key, value]) => { return Object.entries(toValue(msResult).facetDistribution[selectedTaxoRank.value]).map(([key, value]) => {
return { return {
[selectedTaxoRank.value]: key, [selectedTaxoRank.value]: key,
count: value count: value
...@@ -172,71 +192,125 @@ function namesToAccessionChips(names: string[]) { ...@@ -172,71 +192,125 @@ function namesToAccessionChips(names: string[]) {
return { ...it, href: new URL(it.title, "http://toto.pasteur.cloud").toString() } return { ...it, href: new URL(it.title, "http://toto.pasteur.cloud").toString() }
}) })
} }
const taxoPanel: Ref<number> = ref(0) const systemPanel: Ref<number> = ref(["table"])
const systemPanel: Ref<number> = ref(0) const layoutPlot: Ref<string[]> = ref("grid")
const binPlotOptions = ref({
marginLeft: 150,
marginBottom: 200,
padding: 0,
width: 1920,
grid: true,
x: { tickRotate: 90, tip: true, },
color: { scheme: "turbo", legend: true },
})
const binPlotDataOptions = computed(() => {
return allHits.value?.hits?.length > 0 ? {
...binPlotOptions.value,
color: {
...binPlotOptions.value.color,
type: scaleType.value
},
// fy: { domain: groupSortDomain.value },
marks: [
Plot.cell(allHits.value?.hits ?? [], Plot.group({ fill: "count" }, { x: "type", y: selectedTaxoRank.value, tip: true, inset: 0.5, sort: { y: "fill" } })),
]
} : null
})
const scaleType = ref("linear")
</script> </script>
<template> <template>
<v-card flat class="mb-2" color="transparent"> <v-card flat class="mb-2" color="transparent">
<v-toolbar density="compact"> <v-toolbar>
<v-toolbar-title>Distributions</v-toolbar-title> <!-- <v-toolbar-title>Plots</v-toolbar-title> -->
<v-btn-toggle v-model="distriTool" multiple density="compact" rounded="false" variant="text" color="primary" <v-btn-toggle v-model="layoutPlot" density="compact" rounded="false" variant="text" color="primary" mandatory
class="mx-2"> class="mx-2">
<v-btn icon="md:fullscreen" value="fullwidth"></v-btn> <v-btn icon="md:grid_view" value="grid"></v-btn>
<v-btn icon="mdi-math-log" value="log"></v-btn> <v-btn icon="md:view_agenda" value="fullwidth"></v-btn>
</v-btn-toggle> </v-btn-toggle>
<v-spacer></v-spacer>
<v-select v-model="selectedTaxoRank" :items="availableTaxo" density="compact" label="Select taxonomic rank"
hide-details="auto" class="mx-2"></v-select>
<!-- <v-btn-toggle v-model="scaleTransform" density="compact" mandatory rounded="false" variant="text"
color="primary" class="mx-2">
<v-btn icon="mdi-math-log" value="linear">linear</v-btn>
<v-btn value="pow">pow</v-btn>
<v-btn icon="mdi-math-log" value="sqrt">sqrt</v-btn>
<v-btn icon="mdi-math-log" value="symlog">symlog</v-btn>
<v-btn icon="mdi-math-log" value="log">log</v-btn>
</v-btn-toggle> -->
<v-select v-model="scaleType" class="mx-2" density="compact" :items="['linear', 'sqrt', 'symlog']"
label="Scale Type" hide-details="auto"></v-select>
</v-toolbar> </v-toolbar>
<v-row align="start" class="my-2">
<v-col :cols="fullWidth ? 12 : 6"> <v-card color="transparent" flat>
<v-expansion-panels v-model="systemPanel" class="my-2" density="compact" multiple>
<v-card color="transparent" flat> <v-expansion-panel elevation="3" value="barplot">
<v-expansion-panels v-model="systemPanel"> <v-expansion-panel-title color="grey-lighten-4"><v-icon color="primary"
<v-expansion-panel elevation="3"> class="mr-2">mdi-chart-bar</v-icon>Systems - Taxonomic</v-expansion-panel-title>
<v-expansion-panel-title color="grey-lighten-4">Systems</v-expansion-panel-title> <v-expansion-panel-text>
<v-expansion-panel-text> <v-card flat color="transparent">
<PlotFigure :options="unref(computedDistriSystemOptions)" defer></PlotFigure>
</v-expansion-panel-text> <v-row align="start">
</v-expansion-panel> <v-col :cols="fullWidth ? 12 : 6">
</v-expansion-panels> <PlotFigure :options="unref(computedDistriSystemOptions)" defer></PlotFigure>
</v-card>
</v-col> </v-col>
<v-col :cols="fullWidth ? 12 : 6"> <v-col :cols="fullWidth ? 12 : 6">
<v-card flat color="transparent">
<v-expansion-panels v-model="taxoPanel"> <PlotFigure defer :options="unref(computedDistriTaxoOptions)"></PlotFigure>
<v-expansion-panel elevation="3" :value="true">
<v-expansion-panel-title color="grey-lighten-4"> </v-col>
Taxonomic </v-row>
</v-card>
</v-expansion-panel-title> </v-expansion-panel-text>
<v-expansion-panel-text> </v-expansion-panel>
<v-select v-model="selectedTaxoRank" :items="availableTaxo" density="compact" <v-expansion-panel elevation="3" value="matrix">
label="Select taxonomic rank"></v-select> <v-expansion-panel-title color="grey-lighten-4"><v-icon color="primary"
class="mr-2">mdi-data-matrix</v-icon>Matrix</v-expansion-panel-title>
<v-expansion-panel-text>
<PlotFigure defer :options="unref(computedDistriTaxoOptions)"></PlotFigure> <v-card flat color="transparent">
<PlotFigure v-if="toValue(binPlotDataOptions) !== null" :options="unref(binPlotDataOptions)"
</v-expansion-panel-text> defer>
</v-expansion-panel> </PlotFigure>
</v-expansion-panels> </v-card>
</v-card> </v-expansion-panel-text>
</v-col> </v-expansion-panel>
</v-row> <v-expansion-panel elevation="3" value="table">
<v-expansion-panel-title color="grey-lighten-4"><v-icon color="primary"
class="mr-2">mdi-table</v-icon>Table</v-expansion-panel-title>
<v-expansion-panel-text>
<ServerDbTable title="RefSeq" db="refseq" :sortBy="sortBy" :facets="facets"
:data-table-server-props="dataTableServerProps" @refresh:search="getAllHits">
<template #top>
<v-toolbar><v-toolbar-title class="text-capitalize">
RefSeq
</v-toolbar-title><v-spacer></v-spacer>
</v-toolbar>
</template>
<template #[`item.accession_in_sys`]="{ item }">
<CollapsibleChips :items="namesToAccessionChips(item.accession_in_sys)">
</CollapsibleChips>
</template>
</ServerDbTable>
</v-expansion-panel-text>
</v-expansion-panel>
</v-expansion-panels>
</v-card>
</v-card> </v-card>
<ServerDbTable title="RefSeq" db="refseq" :sortBy="sortBy" :facets="facets"
:data-table-server-props="dataTableServerProps">
<template #top>
<v-toolbar><v-toolbar-title class="text-capitalize">
RefSeq
</v-toolbar-title><v-spacer></v-spacer>
</v-toolbar>
</template>
<template #[`item.accession_in_sys`]="{ item }">
<CollapsibleChips :items="namesToAccessionChips(item.accession_in_sys)"></CollapsibleChips>
</template>
</ServerDbTable>
</template> </template>
\ No newline at end of file
<script setup lang="ts"> <script setup lang="ts">
import * as Plot from "@observablehq/plot";
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");
const facets: Ref<string[]> = ref(["system", "completed"]) const facets: Ref<string[]> = ref(["system", "completed"])
const headers: Ref<Object[]> = ref([ const headers: Ref<Object[]> = ref([
{ title: 'Structure', key: 'structure', sortable: false, removable: false },
{ title: "System", key: "system", removable: false }, { title: "System", key: "system", removable: false },
// { title: "pdb file", key: "pdb" }, // { title: "pdb file", key: "pdb" },
// { title: "fasta", key: "fasta_file" }, // { title: "fasta", key: "fasta_file" },
...@@ -19,12 +22,12 @@ const headers: Ref<Object[]> = ref([ ...@@ -19,12 +22,12 @@ const headers: Ref<Object[]> = ref([
{ title: "iptm+ptm", key: "iptm+ptm", removable: true }, { title: "iptm+ptm", key: "iptm+ptm", removable: true },
{ title: "pDockQ", key: "pDockQ", removable: true }, { title: "pDockQ", key: "pDockQ", removable: true },
{ title: "Type", key: "type", removable: true }, { title: "Type", key: "type", removable: true },
{ title: 'Structure', key: 'structure', sortable: false, removable: false },
]) ])
const { search: msSearch, result: msResult } = useMeiliSearch('structure')
const defaultDataTableServerProps = ref({ const defaultDataTableServerProps = ref({
showExpand: true showExpand: false
}) })
const dataTableServerProps = computed(() => { const dataTableServerProps = computed(() => {
...@@ -35,6 +38,9 @@ const dataTableServerProps = computed(() => { ...@@ -35,6 +38,9 @@ const dataTableServerProps = computed(() => {
} }
}) })
function namesToCollapsibleChips(names: string[], file: string | null = null) { function namesToCollapsibleChips(names: string[], file: string | null = null) {
if (file === null) { if (file === null) {
return names.filter((it) => it !== "").map(it => ({ title: it.split("__").pop() })) return names.filter((it) => it !== "").map(it => ({ title: it.split("__").pop() }))
...@@ -54,6 +60,13 @@ function toSystemName(rawName: string) { ...@@ -54,6 +60,13 @@ function toSystemName(rawName: string) {
} }
const plddtDistribution = computed(() => {
if (toValue(msResult)?.facetDistribution?.plddts) {
return Object.entries(toValue(msResult).facetDistribution.plddts).map(([key, value]) => { })
}
})
function remove(key) { function remove(key) {
headers.value = headers.value.filter(header => header.key !== key) headers.value = headers.value.filter(header => header.key !== key)
} }
......
...@@ -5,6 +5,19 @@ navigation: true ...@@ -5,6 +5,19 @@ navigation: true
--- ---
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Cras lobortis nulla ac mauris aliquet lacinia.
Praesent viverra turpis orci, eget blandit ligula placerat nec.
Mauris a libero dui. Aenean sit amet quam at enim molestie tristique nec consequat libero.
Vestibulum rutrum tellus nec dui ornare, sit amet euismod velit faucibus. Aenean lectus mauris, convallis non dolor tincidunt, laoreet pulvinar diam. Maecenas at dignissim massa. Curabitur felis felis, maximus vitae mi non, condimentum rutrum urna. Phasellus consectetur libero sit amet iaculis dapibus.
Sed varius eget metus sed congue. Donec ut sodales lectus. Integer auctor maximus quam nec porta. Nulla urna magna, congue in sodales non, blandit eu lorem. Maecenas id massa sit amet libero elementum lobortis ut vel nibh. Integer sed ante eu tellus iaculis porttitor id at ante. Fusce at venenatis ante, et faucibus magna. Integer ut egestas diam. In vel blandit urna. Mauris nec tellus ut orci blandit consectetur. Nulla cursus tellus velit, vitae finibus lacus efficitur ut.
::refseq-db ::refseq-db
:: ::
...@@ -5,5 +5,9 @@ navigation: true ...@@ -5,5 +5,9 @@ navigation: true
--- ---
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras lobortis nulla ac mauris aliquet lacinia. Praesent viverra turpis orci, eget blandit ligula placerat nec. Mauris a libero dui. Aenean sit amet quam at enim molestie tristique nec consequat libero. Vestibulum rutrum tellus nec dui ornare, sit amet euismod velit faucibus. Aenean lectus mauris, convallis non dolor tincidunt, laoreet pulvinar diam. Maecenas at dignissim massa. Curabitur felis felis, maximus vitae mi non, condimentum rutrum urna. Phasellus consectetur libero sit amet iaculis dapibus.
Sed varius eget metus sed congue. Donec ut sodales lectus. Integer auctor maximus quam nec porta. Nulla urna magna, congue in sodales non, blandit eu lorem. Maecenas id massa sit amet libero elementum lobortis ut vel nibh. Integer sed ante eu tellus iaculis porttitor id at ante. Fusce at venenatis ante, et faucibus magna. Integer ut egestas diam. In vel blandit urna. Mauris nec tellus ut orci blandit consectetur. Nulla cursus tellus velit, vitae finibus lacus efficitur ut.
::structure-db ::structure-db
:: ::
\ No newline at end of file
import { defineStore } from 'pinia'
import type { FacetDistribution, FacetStat } from 'meilisearch';
export interface Facets {
facetDistribution: FacetDistribution | undefined;
facetStats: FacetStat | undefined;
}
export const useFacetsStore = defineStore('facets', () => {
const facets: Ref<Facets> = ref({ facetDistribution: undefined, facetStats: undefined })
function setFacets(newFacets: Facets) {
// console.log("start set facets")
// console.log(newFacets)
facets.value = newFacets
// console.log("end set facets")
}
return { facets, setFacets }
})
\ 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