Skip to content
Snippets Groups Projects
refseq.vue 7.24 KiB
Newer Older
<script setup lang="ts">
import * as Plot from "@observablehq/plot";
import PlotFigure from "~/components/PlotFigure";
import { useDisplay } from "vuetify";
Remi  PLANEL's avatar
Remi PLANEL committed
import JsonCSV from 'vue-json-csv';
Remi  PLANEL's avatar
Remi PLANEL committed
import { useFacetsStore, type Facets } from '~~/stores/facets'
const runtimeConfig = useRuntimeConfig();
Remi  PLANEL's avatar
Remi PLANEL committed
const facetStore = useFacetsStore()
Remi  PLANEL's avatar
Remi PLANEL committed
const { width, height } = useDisplay();
const minTableHeight = ref(400)
Remi  PLANEL's avatar
Remi PLANEL committed
const computedTableHeight = computed(() => {
  const computedHeight = height.value - 500
  return computedHeight > minTableHeight.value ? computedHeight : minTableHeight.value
Remi  PLANEL's avatar
Remi PLANEL committed
})
Remi  PLANEL's avatar
Remi PLANEL committed

// SORTING
const sortBy: Ref<{ key: string, order: string }[]> = ref([{ key: 'type', order: "asc" }])
const msSortBy = computed(() => {
  if (sortBy.value.length > 0) {
    return sortBy.value.map((curr) => {
      if (curr?.key && curr?.order) {
        return `${curr.key}:${curr.order}`
      }
      else { return "" }
    })
  } else { return [""] }
})



Remi  PLANEL's avatar
Remi PLANEL committed

const availableTaxo: Ref<string[]> = ref(["species", "genus", "family", "order", "phylum", "Superkingdom"]);
const selectedTaxoRank = ref("phylum");
Remi  PLANEL's avatar
Remi PLANEL committed


const computedWidth = computed(() => {
  return Math.max(width.value, 550);
Remi  PLANEL's avatar
Remi PLANEL committed
const plotHeight = computed(() => {
  return computedWidth.value / 4;
Remi  PLANEL's avatar
Remi PLANEL committed
// const filterError = ref(null)
const search: Ref<string> = ref("");
Remi  PLANEL's avatar
Remi PLANEL committed
const filter: Ref<string> = ref('')
const hitsPerPage: Ref<number> = ref(25)
const limit = ref(1000)
const itemValue = ref("id");
Remi  PLANEL's avatar
Remi PLANEL committed
const facets = ref([
  "type",
  "Superkingdom",
  "phylum",
  "order",
  "family",
  "genus",
  "species",
])
Remi  PLANEL's avatar
Remi PLANEL committed
const page = ref(1)
const prependHeaders = ref([
  { title: "Replicon", key: "replicon" },
  {
    title: "System",
    key: "type",
  },
  {
    title: "Subtype",
    key: "subtype",
  },
]);
const appendHeaders = ref([
  {
    title: "Accessions",
    key: "accession_in_sys"
function capitalize([first, ...rest]) {
  return first.toUpperCase() + rest.join('').toLowerCase();
}
Remi  PLANEL's avatar
Remi PLANEL committed
const {
  hits: items,
  pending,
  totalHits: itemsLength,
  filterError,
  facetDistribution }
  = useFetchMsDocument(
    "refseq",
    search,
    filter,
    limit,
    hitsPerPage,
    page,
Remi  PLANEL's avatar
Remi PLANEL committed
    facets,
Remi  PLANEL's avatar
Remi PLANEL committed
    msSortBy
  )
Remi  PLANEL's avatar
Remi PLANEL committed
watch(facetDistribution, (facetDistri) => {
Remi  PLANEL's avatar
Remi PLANEL committed
  facetStore.setFacets({ facetDistribution: facetDistri, facetStat: undefined })
})
const computedSystemDistribution = computed(() => {
  if (facetDistribution.value?.type) {
    return Object.entries(facetDistribution.value.type).map(([key, value]) => {
      return { type: key, count: value }
    }).sort()
  } else { return [] }

})

const computedTaxonomyDistribution = computed(() => {
  if (facetDistribution.value?.[selectedTaxoRank.value]) {
    return Object.entries(facetDistribution.value[selectedTaxoRank.value]).map(([key, value]) => {
      return { [selectedTaxoRank.value]: key, count: value }
    }).sort()
  } else { return [] }

})


const computedHeaders = computed(() => {
  return [...prependHeaders.value, ...availableTaxo.value.map(taxo => {
    return {
      title: capitalize(taxo),
      key: taxo
  }), ...appendHeaders.value]
})


function itemToFilter(item, key) {
  const value = item[key]
  const filterToAdd = /\s/g.test(value) ? `${key}="${value}"` : `${key}=${value}`
Remi  PLANEL's avatar
Remi PLANEL committed
  return filter.value === '' ? filterToAdd : `${filter.value} AND ${filterToAdd}`

const itemFilterKeys = computed(() => {
  return [...availableTaxo.value, 'type', 'subtype']
})
Remi  PLANEL's avatar
Remi PLANEL committed
const defaultBarPlotOptions = computed(() => {
  return {
Remi  PLANEL's avatar
Remi PLANEL committed
    x: { label: null, tickRotate: 70 },
Remi  PLANEL's avatar
Remi PLANEL committed
    y: { nice: true, grid: true },
    color: { legend: true },
    width: computedWidth.value,
Remi  PLANEL's avatar
Remi PLANEL committed
    height: plotHeight.value,
Remi  PLANEL's avatar
Remi PLANEL committed
  }
})
const computedDistriSystemOptions = computed(() => {
  return {
    ...defaultBarPlotOptions.value,
    marginBottom: 120,
    marks: [
Remi  PLANEL's avatar
Remi PLANEL committed
      // Plot.frame(),
Remi  PLANEL's avatar
Remi PLANEL committed
      Plot.barY(
Remi  PLANEL's avatar
Remi PLANEL committed
        toValue(computedSystemDistribution),
        {
          y: "count", x: 'type', tip: true,
          fill: "#6750a4",
          sort: { x: "-y" },
        },

const computedDistriTaxoOptions = computed(() => {
  return {
Remi  PLANEL's avatar
Remi PLANEL committed
    ...defaultBarPlotOptions.value,
    marginBottom: 200,
    marks: [
Remi  PLANEL's avatar
Remi PLANEL committed
      Plot.barY(
Remi  PLANEL's avatar
Remi PLANEL committed
        toValue(computedTaxonomyDistribution),
        {
          y: "count",
          x: selectedTaxoRank.value,
          tip: true,
          fill: "#6750a4",
          sort: { x: "-y" },
        }
Remi  PLANEL's avatar
Remi PLANEL committed
// const datatable = ref(null)
const hasToGenerateDownload = ref(false)
let itemsToDownload = ref()

watch(hasToGenerateDownload, (val) => {
  console.log(val)
  if (val === true) {
    const { hits: items, pending, totalHits: itemsLength, filterError, facetDistribution } = useFetchMsDocument("refseq", search, filter, limit, hitsPerPage, page, facets)
Remi  PLANEL's avatar
Remi PLANEL committed
    itemsToDownload.value = items.value
  }
})
  <v-card flat>
    <v-toolbar color="primary" density="compact">
      <v-app-bar-nav-icon></v-app-bar-nav-icon>
Remi  PLANEL's avatar
Remi PLANEL committed
      <v-toolbar-title>RefSeq Entries ({{ itemsLength }})
      </v-toolbar-title>
Remi  PLANEL's avatar
Remi PLANEL committed
      <JsonCSV :data="itemsToDownload" name="refseq-defenes-system.csv">
        <v-btn icon @click="hasToGenerateDownload = true">
          <v-icon icon="md:download"></v-icon>
Remi  PLANEL's avatar
Remi PLANEL committed
          <v-tooltip activator="parent" location="bottom">Download {{ itemsLength }} entries</v-tooltip>
        </v-btn>
      </JsonCSV>
    </v-toolbar>
    <!-- </template> -->
Remi  PLANEL's avatar
Remi PLANEL committed
    <v-card-text>

      Tu peux mettre du texte ici

    </v-card-text>
    <v-col>
      <v-text-field v-model="search" prepend-inner-icon="mdi-magnify" label="Search for defense systems" hide-details
Remi  PLANEL's avatar
Remi PLANEL committed
        class="mx-2 mb-1" clearable></v-text-field>

    </v-col>
    <v-col class="pt-1">
      Examples: <v-chip color="primary" @click="search = 'RADAR'">RADAR</v-chip> <v-chip color="primary"
        @click="search = 'BREX'">BREX</v-chip>
    </v-col>
    <v-col cols="auto">
      <v-text-field v-model="filter" prepend-inner-icon="mdi-magnify" label="Filter" hide-details="auto" class="mx-2"
        clearable :error-messages="filterError"></v-text-field></v-col>
Remi  PLANEL's avatar
Remi PLANEL committed
    <v-data-table-server v-model:page="page" v-model:items-per-page="hitsPerPage" v-model:sortBy="sortBy" fixed-header
      :loading="pending" :headers="computedHeaders" :items="items" :items-length="itemsLength" :item-value="itemValue"
      multi-sort density="compact" :height="computedTableHeight" class="elevation-1 mt-2">
      <template #[`item.${key}`]="{ item }" v-for="key in itemFilterKeys" :key="key">
        <v-chip @click="filter = itemToFilter(item, key)">{{ item[key] }}</v-chip>
      </template>
      <template #[`item.accession_in_sys`]="{ item }">
Remi  PLANEL's avatar
Remi PLANEL committed
        <accession-chips :accessions="item.accession_in_sys" baseUrl="http://toto.pasteur.cloud"></accession-chips>
Remi  PLANEL's avatar
Remi PLANEL committed
      </template>
Remi  PLANEL's avatar
Remi PLANEL committed
    </v-data-table-server>
  </v-card>
  <v-card flat class="my-3" :loading="pending">
    <v-card-title> Systems Distribution</v-card-title>

    <v-card-text>
Remi  PLANEL's avatar
Remi PLANEL committed
      <PlotFigure :options="unref(computedDistriSystemOptions)" defer></PlotFigure>
    </v-card-text>
  </v-card>
  <v-card flat :loading="pending">
    <v-card-title> Taxonomic Distribution</v-card-title>
    <v-card-text>
Remi  PLANEL's avatar
Remi PLANEL committed
      <v-select v-model="selectedTaxoRank" :items="availableTaxo" density="compact"
        label="Select taxonomic rank"></v-select>
      <PlotFigure defer :options="unref(computedDistriTaxoOptions)"></PlotFigure>
    </v-card-text>
  </v-card>