Commit 02f8fa5a authored by Kenzo-Hugo Hillion's avatar Kenzo-Hugo Hillion
Browse files

Merge branch '71-eggnog-card' into 'dev'

Resolve "Create eggnog card"

Closes #71, #108, and #106

See merge request !56
parents a1173447 b9809ba2
Pipeline #32110 passed with stages
in 2 minutes and 58 seconds
from rest_framework import serializers
from metagenedb.apps.catalog.models import EggNOG, Function, KeggOrthology
from metagenedb.apps.catalog.models import (
EggNOG, EggNogFunctionalCategory, Function, KeggOrthology
)
from .asymetricslugrelatedfield import AsymetricSlugRelatedField
from .bulk_list import BulkListSerializer
......@@ -24,7 +27,21 @@ class EggNOGListSerializer(BulkListSerializer):
model = EggNOG
class EggNogFunctionalCategorySerializer(serializers.ModelSerializer):
class Meta:
model = EggNogFunctionalCategory
fields = ('category_id', 'name', 'group')
class EggNOGSerializer(serializers.ModelSerializer):
functional_categories = AsymetricSlugRelatedField.from_serializer(
EggNogFunctionalCategorySerializer,
queryset=EggNogFunctionalCategory.objects.all(),
slug_field='category_id',
many=True,
required=False,
)
class Meta:
model = EggNOG
......
frontend/public/img/logos/inserm.png

13.3 KB | W: | H:

frontend/public/img/logos/inserm.png

8.44 KB | W: | H:

frontend/public/img/logos/inserm.png
frontend/public/img/logos/inserm.png
frontend/public/img/logos/inserm.png
frontend/public/img/logos/inserm.png
  • 2-up
  • Swipe
  • Onion skin
frontend/public/img/logos/uniparis.png

18.1 KB | W: | H:

frontend/public/img/logos/uniparis.png

18.7 KB | W: | H:

frontend/public/img/logos/uniparis.png
frontend/public/img/logos/uniparis.png
frontend/public/img/logos/uniparis.png
frontend/public/img/logos/uniparis.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -2,7 +2,7 @@
<v-app>
<Navbar/>
<v-content class="ma-3">
<keep-alive :exclude="/gene-detail.*/">
<keep-alive include="compare,stats,genes">
<router-view></router-view>
</keep-alive>
......
<template>
<v-flex xs12 md6 lg4>
<v-card>
<v-toolbar class="kegg white--text" dense>
<v-icon class="white--text">fa-braille</v-icon>
<v-toolbar-title class="kegg white--text">
KEGG Function
</v-toolbar-title>
</v-toolbar>
<div class="text-xs-center" v-if="kegg_id == '' || request_done == false">
<v-progress-circular
indeterminate
color="kegg"
></v-progress-circular>
</div>
<div v-else-if="kegg_details.length == 0" class="text-xs-center">
<div class="nodata body-2 text-uppercase pa-3">No annotation for this entry</div>
</div>
<v-list v-else>
<!-- Basic information about the KEGG KO-->
<template v-for="(item, index) in kegg_details">
<v-divider
v-if="index > 0"
:key="index + '_details'"
></v-divider>
<v-list-tile :key="item.title">
<v-list-tile-content>
<v-list-tile-title v-html="item.title"></v-list-tile-title>
<v-list-tile-sub-title v-html="item.content"></v-list-tile-sub-title>
</v-list-tile-content>
<v-list-tile-action v-if="item.url">
<v-tooltip right>
<template v-slot:activator="{ on }">
<v-btn :href="item.url" flat icon class="kegg--text text--darken-1" target="_blank" v-on="on">
<v-icon>open_in_new</v-icon>
</v-btn>
</template>
<span>Open in KEGG</span>
</v-tooltip>
</v-list-tile-action>
</v-list-tile>
</template>
<!-- Expandable details (pathways and diseases) -->
<template v-for="(expanditem, expandindex) in kegg_expand_details">
<v-expansion-panel v-if="expanditem.content.length > 0" :key="expandindex">
<v-divider
:key="expanditem.title"
></v-divider>
<v-expansion-panel-content>
<template v-slot:header>
<div>{{ expanditem.title }}</div>
</template>
<v-card>
<v-list>
<template v-for="(item, index) in expanditem.content">
<v-divider
v-if="index > 0"
:key="index + '_expanded'"
></v-divider>
<v-list-tile :key="item.id" class="dropdown">
<v-list-tile-content>
<v-list-tile-title v-html="item.id"></v-list-tile-title>
<v-list-tile-sub-title v-html="item.name"></v-list-tile-sub-title>
</v-list-tile-content>
<v-list-tile-action>
<v-tooltip right>
<template v-slot:activator="{ on }">
<v-btn :href="item.url" flat icon class="kegg--text text--darken-1" target="_blank" v-on="on">
<v-icon>open_in_new</v-icon>
</v-btn>
</template>
<span>Open in KEGG</span>
</v-tooltip>
</v-list-tile-action>
</v-list-tile>
</template>
</v-list>
</v-card>
</v-expansion-panel-content>
</v-expansion-panel>
</template>
<!-- References -->
<v-expansion-panel v-if="kegg_references.length > 0">
<v-divider/>
<v-expansion-panel-content>
<template v-slot:header>
<div>References</div>
</template>
<v-card>
<v-list>
<template v-for="(item, index) in kegg_references">
<v-divider
v-if="index > 0"
:key="index + '_ref'"
></v-divider>
<v-list-tile :key="item.id" class="dropdown">
<v-list-tile-content>
<v-list-tile-title v-html="item.title"></v-list-tile-title>
<v-list-tile-sub-title v-html="item.authors"></v-list-tile-sub-title>
</v-list-tile-content>
<v-list-tile-action>
<v-tooltip right>
<template v-slot:activator="{ on }">
<v-btn :href="item.url" flat icon class="kegg--text text--darken-1" target="_blank" v-on="on">
<v-icon>open_in_new</v-icon>
</v-btn>
</template>
<span>Open in pubmed</span>
</v-tooltip>
</v-list-tile-action>
</v-list-tile>
</template>
</v-list>
</v-card>
</v-expansion-panel-content>
</v-expansion-panel>
</v-list>
</v-card>
</v-flex>
</template>
<script>
import axios from 'axios';
export default {
name: 'KeggCard',
props: {
kegg_id: String,
},
watch: {
kegg_id(val, oldVal) {
this.getKeggDetail();
},
},
data() {
return {
kegg_details: [],
kegg_expand_details: [],
kegg_references: [],
request_done: false,
};
},
methods: {
getKeggDetail() {
if (this.kegg_id == 'no_kegg') {
this.request_done = true;
return;
}
axios.get(`/api/catalog/v1/kegg-orthologies/${this.kegg_id}?detailed=true`, {
headers: {
Accept: 'application/json',
},
})
.then((response) => {
this.buildKeggDetails(response);
this.buildKeggExpandDetails(response);
this.buildReferences(response);
})
.catch((error) => {
console.log(error);
})
.finally(() => {
this.request_done = true;
});
},
buildKeggDetails(response) {
this.kegg_details = [
{
title: 'ID',
content: response.data.entry_id,
url: `https://www.genome.jp/dbget-bin/www_bget?ko:${response.data.entry_id}`,
},
{
title: 'Name',
content: response.data.name,
},
{
title: 'Definition',
content: response.data.definition,
},
];
},
buildKeggExpandDetails(response) {
this.kegg_expand_details = [
this.buildPathways(response),
this.buildDiseases(response),
];
},
buildPathways(response) {
const pathways = {
title: 'Pathways',
content: [],
};
Object.entries(response.data.pathways).forEach(([key, value]) => {
pathways.content.push(
{
id: key,
name: value,
url: `https://www.genome.jp/kegg-bin/show_pathway?${key}+${this.kegg_id}`,
},
);
});
return pathways;
},
buildDiseases(response) {
const diseases = {
title: 'Diseases',
content: [],
};
Object.entries(response.data.diseases).forEach(([key, value]) => {
diseases.content.push(
{
id: key,
name: value,
url: `https://www.genome.jp/dbget-bin/www_bget?ds:${key}`,
},
);
});
return diseases;
},
buildReferences(response) {
for (let i = 0; i < response.data.references.length; i++) {
this.kegg_references.push(
{
title: response.data.references[i].title,
authors: `${response.data.references[i].authors[0]} et al. ${response.data.references[i].journal}`,
url: `https://www.ncbi.nlm.nih.gov/pubmed/${response.data.references[i].pubmed}`,
},
);
}
},
},
};
</script>
<v-flex xs12 md6 lg4 xl3>
<v-card>
<v-toolbar class="eggnog white--text" dense>
<v-icon class="white--text">fa-braille</v-icon>
<v-toolbar-title class="eggnog white--text">
EggNOG {{displayVersion}}
</v-toolbar-title>
</v-toolbar>
<div class="text-xs-center" v-if="requestDone == false">
<v-progress-circular
indeterminate
color="eggnog"
></v-progress-circular>
</div>
<div v-else-if="eggnogDetails.length == 0" class="text-xs-center">
<div class="nodata body-2 text-uppercase pa-3">No annotation for this entry</div>
</div>
<!-- Simple information -->
<SimpleListing v-else :listData="eggnogDetails" :color="color"/>
<!-- Expanded information -->
<SimpleExpand :expandData="eggnogExpandDetails" :color="color"/>
</v-card>
</v-flex>
\ No newline at end of file
import axios from 'axios';
import SimpleExpand from '@/components/listing/simpleexpand/simpleexpand.vue';
import SimpleListing from '@/components/listing/simplelisting/simplelisting.vue';
export default {
components: {
SimpleExpand, SimpleListing,
},
name: 'EggNogCard',
props: {
eggnogId: String,
color: String,
},
mounted() {
this.getEggNogDetail();
},
data() {
return {
eggnogDetails: [],
eggnogExpandDetails: [],
eggnogReferences: [],
requestDone: false,
eggnogVersion: '',
};
},
computed: {
funcCatGroups() {
return {
'info_storage_processing': 'Information Storage and Processing',
'cellular_processes_signaling': 'Cellular Processes and Signaling',
'metabolism': 'Metabolism',
'poorly_characterized': 'Poorly Characterized',
}
},
displayVersion() {
if (this.eggnogVersion) {
return `v.${this.eggnogVersion}`;
}
return '';
},
},
methods: {
getEggNogDetail() {
if (this.eggnogId == 'no_eggnog') {
this.requestDone = true;
return;
}
axios.get(`/api/catalog/v1/eggnogs/${this.eggnogId}`, {
headers: {
Accept: 'application/json',
},
})
.then((response) => {
this.buildEggNogDetails(response);
this.buildEggNogExpandDetails(response);
})
.catch((error) => {
console.log(error);
})
.finally(() => {
this.requestDone = true;
});
},
buildEggNogDetails(response) {
this.eggnogVersion = response.data.version
this.eggnogDetails = [
{
title: 'ID',
content: response.data.function_id,
},
{
title: 'Name',
content: response.data.name,
},
];
},
buildEggNogExpandDetails(response) {
this.eggnogExpandDetails = [
this.buildFunctionalCategories(response),
];
},
buildFunctionalCategories(response) {
const funcCats = {
title: 'Functional Categories',
icon: 'fas fa-layer-group',
content: [],
};
Object.entries(response.data.functional_categories).forEach(([key, value]) => {
const name = `(${value.category_id}) ${value.name}`;
funcCats.content.push(
{
id: name,
name: this.funcCatGroups[value.group],
},
);
});
return funcCats;
},
},
};
\ No newline at end of file
<template src="./eggnogcard.html" lang="html"></template>
<script src="./eggnogcard.js" lang="js"></script>
\ No newline at end of file
<v-flex xs12 md6 lg4 xl3>
<v-card>
<v-toolbar class="kegg white--text" dense>
<v-icon class="white--text">fa-braille</v-icon>
<v-toolbar-title class="kegg white--text">
KEGG Orthology
</v-toolbar-title>
</v-toolbar>
<div class="text-xs-center" v-if="requestDone == false">
<v-progress-circular
indeterminate
color="kegg"
></v-progress-circular>
</div>
<div v-else-if="keggDetails.length == 0" class="text-xs-center">
<div class="nodata body-2 text-uppercase pa-3">No annotation for this entry</div>
</div>
<!-- Simple information -->
<SimpleListing v-else :listData="keggDetails" :color="color"/>
<!-- Expandable details (pathways, diseases, references...) -->
<SimpleExpand :expandData="keggExpandDetails" :color="color"/>
</v-card>
</v-flex>
\ No newline at end of file
import axios from 'axios';
import SimpleExpand from '@/components/listing/simpleexpand/simpleexpand.vue';
import SimpleListing from '@/components/listing/simplelisting/simplelisting.vue';
export default {
components: {
SimpleExpand, SimpleListing,
},
name: 'KeggCard',
props: {
keggId: String,
color: String,
},
mounted() {
this.getKeggDetail();
},
data() {
return {
keggDetails: [],
keggExpandDetails: [],
keggReferences: [],
requestDone: false,
};
},
methods: {
getKeggDetail() {
if (this.keggId == 'no_kegg') {
this.requestDone = true;
return;
}
axios.get(`/api/catalog/v1/kegg-orthologies/${this.keggId}?detailed=true`, {
headers: {
Accept: 'application/json',
},
})
.then((response) => {
this.buildKeggDetails(response);
this.buildKeggExpandDetails(response);
this.buildReferences(response);
})
.catch((error) => {
console.log(error);
})
.finally(() => {
this.requestDone = true;
});
},
buildKeggDetails(response) {
this.keggDetails = [
{
title: 'ID',
content: response.data.entry_id,
url: `https://www.genome.jp/dbget-bin/www_bget?ko:${response.data.entry_id}`,
url_label: 'Open in KEGG'
},
{
title: 'Name(s)',
content: response.data.name,
},
{
title: 'Definition',
content: response.data.definition,
},
];
},
buildKeggExpandDetails(response) {
this.keggExpandDetails = [
this.buildPathways(response),
this.buildDiseases(response),
this.buildModules(response),
this.buildReferences(response),
];
},
buildPathways(response) {
var pathways = {
title: 'Pathways',
icon: 'fas fa-bezier-curve',
content: [],
};
Object.entries(response.data.pathways).forEach(([key, value]) => {
pathways.content.push(
{
id: key,
name: value,
url: `https://www.genome.jp/kegg-bin/show_pathway?${key}+${this.keggId}`,
url_label: "Open in KEGG",
fetch: true,
},
);
});
return pathways;
},
buildModules(response) {
var modules = {
title: 'Modules',
icon: 'fas fa-bezier-curve',
content: [],
};
Object.entries(response.data.modules).forEach(([key, value]) => {
modules.content.push(
{
id: key,
name: value,
url: `https://www.genome.jp/kegg-bin/show_module?${key}+${this.keggId}`,
url_label: "Open in KEGG"
},
);
});
return modules;
},
buildDiseases(response) {
var diseases = {
title: 'Diseases',
icon: 'fas fa-laptop-medical',
content: [],
};
Object.entries(response.data.diseases).forEach(([key, value]) => {
diseases.content.push(
{
id: key,
name: value,
url: `https://www.genome.jp/dbget-bin/www_bget?ds:${key}`,
},
);
});
return diseases;
},
buildReferences(response) {
var references = {
title: 'References',
icon: 'fas fa-book-open',
content: [],
};
for (let i = 0; i < response.data.references.length; i++) {
references.content.push(
{
id: response.data.references[i].title,
name: `${response.data.references[i].authors[0]} et al. ${response.data.references[i].journal}`,
url: `https://www.ncbi.nlm.nih.gov/pubmed/${response.data.references[i].pubmed}`,
url_label: "Open in Pubmed"
},
);
};
return references;
},
},
};
\ No newline at end of file