<script setup lang="ts"> import { useFacetsStore } from '~~/stores/facets' import * as Plot from "@observablehq/plot"; import PlotFigure from "~/components/PlotFigure"; import { useDisplay } from "vuetify"; import type { SortItem } from "@/components/ServerDbTable.vue" import { ServerDbTable } from "#components" const facetStore = useFacetsStore() const sortBy: Ref<SortItem[]> = ref([{ key: 'type', order: "asc" }]) const itemValue = ref("id"); const { width } = useDisplay(); const distriTool: Ref<string[]> = ref([]) const facets = ref([ "replicon", "type", "subtype", "Superkingdom", "phylum", "order", "family", "genus", "species", ]) const availableTaxo: Ref<string[]> = ref([ "species", "genus", "family", "order", "phylum", "Superkingdom" ]); const selectedTaxoRank = ref("phylum"); const headers = ref([ { title: "Replicon", key: "replicon" }, { title: "Type", key: "type", }, { title: "Subtype", key: "subtype", }, { title: "Accessions", key: "accession_in_sys", sortable: false } ]) const logTransform = computed(() => { return distriTool.value.includes('log') }) const fullWidth = computed(() => { return distriTool.value.includes('fullwidth') }) const computedHeaders = computed(() => { return [...headers.value, ...availableTaxo.value.map(taxo => { return { title: capitalize(taxo), key: taxo } })] }) const computedWidth = computed(() => { const currentWidth = fullWidth.value ? width.value : width.value / 2 return Math.max(currentWidth, 550); }); const plotHeight = computed(() => { return computedWidth.value / 3; // return 500 }); const defaultDataTableServerProps = ref({ showExpand: false }) const dataTableServerProps = computed(() => { return { ...defaultDataTableServerProps.value, headers: computedHeaders.value, itemValue: itemValue.value } }) 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 { x: { label: null, tickRotate: 45, ticks: 10 }, y, color: { legend: true }, width: computedWidth.value, height: plotHeight.value + 100, } }) const computedSystemDistribution = computed(() => { if (facetStore.facets?.facetDistribution?.type) { return Object.entries(facetStore.facets.facetDistribution.type).map(([key, value]) => { return { type: key, // count: logTransform.value ? Math.log(value) : value count: value } }).sort() } else { return [] } }) const computedDistriSystemOptions = computed(() => { return { ...defaultBarPlotOptions.value, marginBottom: 100, marks: [ // Plot.frame(), Plot.barY( toValue(computedSystemDistribution), { y: "count", x: 'type', tip: true, fill: "#6750a4", sort: { x: "-y" }, }, ), ], }; }); const computedTaxonomyDistribution = computed(() => { if (facetStore.facets?.facetDistribution?.[selectedTaxoRank.value]) { return Object.entries(facetStore.facets.facetDistribution[selectedTaxoRank.value]).map(([key, value]) => { return { [selectedTaxoRank.value]: key, count: value } }).sort() } else { return [] } }) const computedDistriTaxoOptions = computed(() => { return { ...defaultBarPlotOptions.value, marginBottom: 100, marks: [ Plot.barY( toValue(computedTaxonomyDistribution), { y: "count", x: selectedTaxoRank.value, tip: true, fill: "#6750a4", sort: { x: "-y" }, } ), ], }; }); function capitalize(name: string) { const [first, ...rest] = name return first.toUpperCase() + rest.join('').toLowerCase(); } function namesToCollapsibleChips(names: string[]) { return names.filter((it) => it !== "").map(it => ({ title: it })) } function namesToAccessionChips(names: string[]) { return namesToCollapsibleChips(names).map(it => { return { ...it, href: new URL(it.title, "http://toto.pasteur.cloud").toString() } }) } </script> <template> <v-card flat class="mb-2" color="transparent"> <v-toolbar density="compact"> <v-toolbar-title>Distributions</v-toolbar-title> <v-btn-toggle v-model="distriTool" multiple density="compact" rounded="false" variant="text" color="primary" class="mx-2"> <v-btn icon="md:fullscreen" value="fullwidth"></v-btn> <v-btn icon="mdi-math-log" value="log"></v-btn> </v-btn-toggle> </v-toolbar> <v-row align="start" class="my-2"> <v-col :cols="fullWidth ? 12 : 6"> <v-card color="transparent" flat> <v-expansion-panels> <v-expansion-panel elevation="3"> <v-expansion-panel-title color="grey-lighten-4">Systems</v-expansion-panel-title> <v-expansion-panel-text> <PlotFigure :options="unref(computedDistriSystemOptions)" defer></PlotFigure> </v-expansion-panel-text> </v-expansion-panel> </v-expansion-panels> </v-card> </v-col> <v-col :cols="fullWidth ? 12 : 6"> <v-card flat color="transparent"> <v-expansion-panels> <v-expansion-panel elevation="3"> <v-expansion-panel-title color="grey-lighten-4"> Taxonomic </v-expansion-panel-title> <v-expansion-panel-text> <PlotFigure defer :options="unref(computedDistriTaxoOptions)"></PlotFigure> </v-expansion-panel-text> </v-expansion-panel> </v-expansion-panels> </v-card> </v-col> </v-row> </v-card> <ServerDbTable title="RefSeq" db="refseq" :sortBy="sortBy" :facets="facets" :data-table-server-props="dataTableServerProps"> <template #[`item.accession_in_sys`]="{ item }"> <CollapsibleChips :items="namesToAccessionChips(item.accession_in_sys)"></CollapsibleChips> </template> </ServerDbTable> </template>