diff --git a/src/app/core/models/open-genes-api/studies.model.ts b/src/app/core/models/open-genes-api/studies.model.ts index 8fa4e674..b4dc41a9 100644 --- a/src/app/core/models/open-genes-api/studies.model.ts +++ b/src/app/core/models/open-genes-api/studies.model.ts @@ -180,6 +180,8 @@ export interface PinkTable extends Research { ethnicity: string | null; studyType: string | null; location?: string | null; // TODO: Will be added according to OG-809 + significance?: string | null; + pValue?: string | null; } // gray form diff --git a/src/app/core/services/csv-export-service.ts b/src/app/core/services/csv-export-service.ts index 16c29267..c0f4e8af 100644 --- a/src/app/core/services/csv-export-service.ts +++ b/src/app/core/services/csv-export-service.ts @@ -1,8 +1,9 @@ import { Injectable } from '@angular/core'; import { AdditionalInterventionResolver } from '../utils/additional-intervention-resolver'; -import { PurpleTable } from '../models/open-genes-api/studies.model'; +import { BlueTable, GreenTable, PinkTable, PurpleTable, YellowTable } from '../models/open-genes-api/studies.model'; import { environment } from '../../../environments/environment'; + @Injectable({ providedIn: 'root', }) @@ -19,6 +20,7 @@ export class CsvExportService extends AdditionalInterventionResolver { super(); } + // Basic service functionality static wait(delay) { return new Promise((resolve) => setTimeout(resolve, delay)); } @@ -82,6 +84,21 @@ export class CsvExportService extends AdditionalInterventionResolver { return null; } + // eslint-disable-next-line @typescript-eslint/ban-types + public async fetchStudyFromEndpoint(url: string, fn: Function): Promise { + const response: Response = await CsvExportService.FetchData( + url, + 0, + 1, + {} + ); + if (response) { + const resJson = await response.json(); + fn(resJson.items) + } + } + + // Other datasets public async generateGenesDiseasesTable() { return await this.generateSimplePairCsv(["hgnc", "diseases"], 'diseases'); } @@ -177,7 +194,73 @@ export class CsvExportService extends AdditionalInterventionResolver { return null; } - public async generatePinkTable() { + public async generateGeneEvolutionTable() { + let items = []; + let resultingString = ''; + const fetchedItems = await CsvExportService.FetchData( + `${this.apiUrl}/api/gene/search?pageSize=${this.maxPageSize}`, + 0, + 1, + {} + ); + const resItems = await fetchedItems.json(); + items = resItems.items; + const csvHeader = this.makeRow(['hgnc', 'gene_origin', 'gene_family_origin', 'conservative_in']); + resultingString = resultingString + csvHeader; + + if (items.length !== 0) { + for (const gene of items) { + const origin = this.checkBlankValues(gene.origin?.phylum); + const familyOrigin = this.checkBlankValues(gene.familyOrigin?.phylum); + const conservativeIn = this.checkBlankValues(gene.homologueTaxon); + const arrRow = this.makeRow([gene.symbol, origin, familyOrigin, conservativeIn]); + resultingString = resultingString + arrRow; + } + return resultingString; + } + return null; + } + + // Studies + // - Fetch data + + public async fetchPinkTable(): Promise { + await this.fetchStudyFromEndpoint( + `${this.apiUrl}/api/research/associations-with-lifespan?pageSize=${this.maxPageSize}`, + this.generatePinkTable.bind(CsvExportService) + ); + } + + public async fetchPurpleTable(): Promise { + await this.fetchStudyFromEndpoint( + `${this.apiUrl}/api/research/lifespan-change?pageSize=${this.maxPageSize}`, + this.generatePurpleTable.bind(CsvExportService) + ); + } + + public async fetchGreenTable(): Promise { + await this.fetchStudyFromEndpoint( + `${this.apiUrl}/api/research/gene-activity-change-impact?pageSize=${this.maxPageSize}`, + this.generateGreenTable.bind(CsvExportService) + ); + } + + public async fetchBlueTable(): Promise { + await this.fetchStudyFromEndpoint( + `${this.apiUrl}/api/research/age-related-changes?pageSize=${this.maxPageSize}`, + this.generateBlueTable.bind(CsvExportService) + ); + } + + public async fetchYellowTable(): Promise { + await this.fetchStudyFromEndpoint( + `${this.apiUrl}/api/research/gene-regulation?pageSize=${this.maxPageSize}`, + this.generateYellowTable.bind(CsvExportService) + ); + } + + // - Generate datasets + public generatePinkTable(studies: PinkTable[]) { let resultingString = ''; const csvHeader = this.makeRow([ 'hgnc', @@ -212,17 +295,8 @@ export class CsvExportService extends AdditionalInterventionResolver { ]); resultingString = resultingString + csvHeader; - const response = await CsvExportService.FetchData( - `${this.apiUrl}/api/research/associations-with-lifespan?pageSize=${this.maxPageSize}`, - 0, - 1, - {} - ); - if (response) { - const resJson = await response.json(); - const researches = resJson.items; - if (researches) { - for (const form of researches) { + if (studies) { + for (const form of studies) { if (typeof form !== undefined) { let comment = this.sanitize(form?.comment); comment = this.checkBlankValues(comment); @@ -291,11 +365,11 @@ export class CsvExportService extends AdditionalInterventionResolver { } return resultingString; } - } + return null; } - public async generateYellowTable() { + public generateYellowTable(studies: YellowTable[]) { let resultingString = ''; const csvHeader = this.makeRow([ 'hgnc', @@ -308,17 +382,8 @@ export class CsvExportService extends AdditionalInterventionResolver { ]); resultingString = resultingString + csvHeader; - const response = await CsvExportService.FetchData( - `${this.apiUrl}/api/research/gene-regulation?pageSize=${this.maxPageSize}`, - 0, - 1, - {} - ); - if (response) { - const resJson = await response.json(); - const researches = resJson.items; - if (researches) { - for (const form of researches) { + if (studies) { + for (const form of studies) { if (typeof form !== undefined) { let comment = this.sanitize(form?.comment); comment = this.checkBlankValues(comment); @@ -335,11 +400,11 @@ export class CsvExportService extends AdditionalInterventionResolver { } return resultingString; } - } + return null; } - public async generatePurpleTable() { + public generatePurpleTable(studies: PurpleTable[]) { let resultingString = ''; const csvHeader = this.makeRow([ 'hgnc', @@ -388,18 +453,8 @@ export class CsvExportService extends AdditionalInterventionResolver { ]); resultingString = resultingString + csvHeader; - // TODO: OG-811 - const response = await CsvExportService.FetchData( - `${this.apiUrl}/api/research/lifespan-change?pageSize=${this.maxPageSize}`, - 0, - 1, - {} - ); - if (response) { - const resJson = await response.json(); - const researches: PurpleTable[] = resJson.items; - if (researches) { - for (const form of researches) { + if (studies) { + for (const form of studies) { if (typeof form !== undefined) { const isNoAdditionalIntervention = this.resolveAdditionalIntervention(form); @@ -553,16 +608,18 @@ export class CsvExportService extends AdditionalInterventionResolver { pmid, ]); resultingString = resultingString + csvRow; + } else { + resultingString = 'All experiments contain additional interventions. Generation of datasets with additional interventions is not yet implemented.' } } } return resultingString; } - } + return null; } - public async generateGreenTable() { + public generateGreenTable(studies: GreenTable[]) { let resultingString = ''; const csvHeader = this.makeRow([ 'hgnc', @@ -582,17 +639,8 @@ export class CsvExportService extends AdditionalInterventionResolver { ]); resultingString = resultingString + csvHeader; - const response = await CsvExportService.FetchData( - `${this.apiUrl}/api/research/gene-activity-change-impact?pageSize=${this.maxPageSize}`, - 0, - 1, - {} - ); - if (response) { - const resJson = await response.json(); - const researches = resJson.items; - if (researches) { - for (const form of researches) { + if (studies) { + for (const form of studies) { if (typeof form !== undefined) { const geneSymbol = this.sanitize(form?.geneSymbol); let comment = this.sanitize(form?.comment); @@ -647,11 +695,11 @@ export class CsvExportService extends AdditionalInterventionResolver { } return resultingString; } - } + return null; } - public async generateBlueTable() { + public generateBlueTable(studies: BlueTable[]) { let resultingString = ''; const csvHeader = this.makeRow([ 'hgnc', @@ -680,17 +728,8 @@ export class CsvExportService extends AdditionalInterventionResolver { ]); resultingString = resultingString + csvHeader; - const response = await CsvExportService.FetchData( - `${this.apiUrl}/api/research/age-related-changes?pageSize=${this.maxPageSize}`, - 0, - 1, - {} - ); - if (response) { - const resJson = await response.json(); - const researches = resJson.items; - if (researches) { - for (const form of researches) { + if (studies) { + for (const form of studies) { if (typeof form !== undefined) { const geneSymbol = this.sanitize(form?.geneSymbol); let comment = this.sanitize(form?.comment); @@ -746,7 +785,7 @@ export class CsvExportService extends AdditionalInterventionResolver { } return resultingString; } - } + return null; } @@ -943,31 +982,4 @@ export class CsvExportService extends AdditionalInterventionResolver { } return null; } - - public async generateGeneEvolutionTable() { - let items = []; - let resultingString = ''; - const fetchedItems = await CsvExportService.FetchData( - `${this.apiUrl}/api/gene/search?pageSize=${this.maxPageSize}`, - 0, - 1, - {} - ); - const resItems = await fetchedItems.json(); - items = resItems.items; - const csvHeader = this.makeRow(['hgnc', 'gene_origin', 'gene_family_origin', 'conservative_in']); - resultingString = resultingString + csvHeader; - - if (items.length !== 0) { - for (const gene of items) { - const origin = this.checkBlankValues(gene.origin?.phylum); - const familyOrigin = this.checkBlankValues(gene.familyOrigin?.phylum); - const conservativeIn = this.checkBlankValues(gene.homologueTaxon); - const arrRow = this.makeRow([gene.symbol, origin, familyOrigin, conservativeIn]); - resultingString = resultingString + arrRow; - } - return resultingString; - } - return null; - } } diff --git a/src/app/core/utils/datasets-download.ts b/src/app/core/utils/datasets-download.ts new file mode 100644 index 00000000..9458b2b0 --- /dev/null +++ b/src/app/core/utils/datasets-download.ts @@ -0,0 +1,75 @@ +import { SafeResourceUrl } from '@angular/platform-browser'; +import { MatDialog } from '@angular/material/dialog'; +import { CsvExportService } from '../services/csv-export-service'; +import { FileExportService } from '../services/browser/file-export.service'; +import { GoogleAnalyticsService } from 'ngx-google-analytics'; +import { Subject } from 'rxjs'; +import { TemplateRef } from '@angular/core'; + +export abstract class DatasetsDownload { + protected initialDownloadLinkVal = '#'; + protected initialDatasetName = 'export'; + protected subscription$ = new Subject(); + + public currentDownloadLink: + | string + | SafeResourceUrl = this.initialDownloadLinkVal; + public currentDatasetName = this.initialDatasetName; + public isProcessing = false; + + protected constructor( + protected matDialog: MatDialog, + protected csvExportService: CsvExportService, + protected fileExportService: FileExportService, + protected googleAnalyticsService: GoogleAnalyticsService + ) {} + + public async trackDownload(datasetName: string) { + try { + await this.googleAnalyticsService.event( + 'Download', + 'click', + datasetName + ); + } catch (error) { + console.error( + 'Error tracking download event:', + error + ); + } + } + + protected abstract openDownloadModal(template: any): void; + + protected abstract handleError(): void; + + public async downloadCsv( + datasetName: string, + generateFunction: () => unknown + ) { + try { + this.isProcessing = true; + let res; + if (generateFunction.constructor.name === 'AsyncFunction') { + res = await generateFunction(); + } else { + res = generateFunction(); + } + + if (res.length !== 0) { + this.currentDownloadLink = this.fileExportService.downloadCsv( + res + ); + this.currentDatasetName = datasetName; + await this.trackDownload(datasetName); + this.openDownloadModal( + this.getDownloadLinkTemplate() + ); + } + } catch { + this.handleError(); + } + } + + protected abstract getDownloadLinkTemplate(): TemplateRef; +} diff --git a/src/app/pages/download/download.component.ts b/src/app/pages/download/download.component.ts index e18e504b..7a190051 100644 --- a/src/app/pages/download/download.component.ts +++ b/src/app/pages/download/download.component.ts @@ -2,28 +2,20 @@ import { Component, TemplateRef, ViewChild } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { CsvExportService } from '../../core/services/csv-export-service'; import { FileExportService } from 'src/app/core/services/browser/file-export.service'; -import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'; +import { DomSanitizer } from '@angular/platform-browser'; import { Router } from '@angular/router'; import { CommonModalComponent } from 'src/app/components/ui-components/components/modals/common-modal/common-modal.component'; import { MatDialog } from '@angular/material/dialog'; -import { takeUntil } from 'rxjs/operators'; -import { Subject } from 'rxjs'; import { GoogleAnalyticsService } from 'ngx-google-analytics'; +import { DatasetsDownload } from '../../core/utils/datasets-download'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-download-page', templateUrl: './download.component.html', styleUrls: ['./download.component.scss'], }) -export class DownloadComponent { - private subscription$ = new Subject(); - private initialDownloadLinkVal = '#'; - private initialDatasetName = 'export'; - - public currentDownloadLink: string | SafeResourceUrl = this.initialDownloadLinkVal; - public currentDatasetName = this.initialDatasetName; - public isProcessing = false; - +export class DownloadComponent extends DatasetsDownload { @ViewChild('downLoadLinkTemplate') downLoadLinkTemplate: TemplateRef; @ViewChild('errorTemplate') errorTemplate: TemplateRef; @@ -31,14 +23,20 @@ export class DownloadComponent { public translate: TranslateService, private sanitizer: DomSanitizer, private router: Router, - private matDialog: MatDialog, - private csvExportService: CsvExportService, - private fileExportService: FileExportService, - private googleAnalyticsService: GoogleAnalyticsService - ) {} - - public openDownloadModal(template): void { - this.matDialog.open(CommonModalComponent, { + private _matDialog: MatDialog, + private _csvExportService: CsvExportService, + private _fileExportService: FileExportService, + private _googleAnalyticsService: GoogleAnalyticsService + ) { + super(_matDialog, _csvExportService, _fileExportService, _googleAnalyticsService); + } + + protected getDownloadLinkTemplate(): TemplateRef { + return this.downLoadLinkTemplate; + } + + protected openDownloadModal(template: any): void { + this._matDialog.open(CommonModalComponent, { data: { title: 'download', body: null, @@ -57,31 +55,8 @@ export class DownloadComponent { }); } - private async trackDownload(datasetName: string) { - try { - await this.googleAnalyticsService.event('Download', 'click', datasetName); - } catch (error) { - console.error('Error tracking download event:', error); - } - } - - private async downloadCsv(datasetName: string, generateFunction: () => Promise) { - try { - this.isProcessing = true; - const res = await generateFunction(); - if (res.length !== 0) { - this.currentDownloadLink = this.fileExportService.downloadCsv(res); - this.currentDatasetName = datasetName; - await this.trackDownload(datasetName); - this.openDownloadModal(this.downLoadLinkTemplate); - } - } catch { - this.openDownloadModal(this.errorTemplate); - } - } - - public async downloadGeneConfidenceLevel() { - await this.downloadCsv('gene-confidence-level', () => this.csvExportService.generateGenesConfidenceLevelTable()); + protected handleError(): void { + this.openDownloadModal(this.errorTemplate); } public async downloadDiseaseTsv() { @@ -101,23 +76,23 @@ export class DownloadComponent { } public async downloadYellowTablesTsv() { - await this.downloadCsv('gene-regulation', () => this.csvExportService.generateYellowTable()); + await this.downloadCsv('gene-regulation', () => this.csvExportService.fetchYellowTable()); } public async downloadPinkTablesTsv() { - await this.downloadCsv('associations-with-longevity', () => this.csvExportService.generatePinkTable()); + await this.downloadCsv('associations-with-longevity', () => this.csvExportService.fetchPinkTable()); } public async downloadPurpleTablesTsv() { - await this.downloadCsv('lifespan-change', () => this.csvExportService.generatePurpleTable()); + await this.downloadCsv('lifespan-change', () => this.csvExportService.fetchPurpleTable()); } public async downloadGreenTableTsv() { - await this.downloadCsv('age-related-processes-change', () => this.csvExportService.generateGreenTable()); + await this.downloadCsv('age-related-processes-change', () => this.csvExportService.fetchGreenTable()); } public async downloadBlueTableTsv() { - await this.downloadCsv('age-related-changes', () => this.csvExportService.generateBlueTable()); + await this.downloadCsv('age-related-changes', () => this.csvExportService.fetchBlueTable()); } public async downloadSummarizedResearchResultsTsv() { diff --git a/src/app/pages/gene/gene.component.html b/src/app/pages/gene/gene.component.html index 82476717..aef1b53a 100644 --- a/src/app/pages/gene/gene.component.html +++ b/src/app/pages/gene/gene.component.html @@ -278,8 +278,19 @@

{{ 'gene_page_title_research_data' | translate }}

- + We distinguished six types of studies in order to remain objective and precise while linking a particular gene to human aging. + Each study represented with a corresponding data table placed into the expandable panel. We did it as for some genes data can be + extensive. We also provided datasets for download. You can also download this experiment data for all genes in the database on a Download page. + Before analysing our data we highly recommend you to read the paper + Open Genes—a new comprehensive database of human genes associated with aging and longevity +

+ +
diff --git a/src/app/pages/gene/research-data/research-data.component.html b/src/app/pages/gene/research-data/research-data.component.html index 5f64a7aa..b968c231 100644 --- a/src/app/pages/gene/research-data/research-data.component.html +++ b/src/app/pages/gene/research-data/research-data.component.html @@ -1,7 +1,11 @@ +
+ +
+ @@ -9,6 +13,9 @@

{{ 'gene_page_research_data_lifespan' | translate }}

+ {{ studies.increaseLifespan.length }}
@@ -21,7 +28,7 @@

@@ -29,6 +36,9 @@

{{ 'gene_page_research_data_age_related_changes' | translate }}

+ {{ studies.ageRelatedChangesOfGene.length }}
@@ -41,7 +51,7 @@

@@ -49,6 +59,9 @@

{{ 'gene_page_intervention_moderates_aging' | translate }}

+ {{ studies.interventionToGeneImprovesVitalProcesses.length }}
@@ -61,7 +74,7 @@

@@ -69,6 +82,9 @@

{{ 'gene_page_research_data_longevity_effects' | translate }}

+ {{ studies.geneAssociatedWithLongevityEffects.length }}
@@ -81,7 +97,7 @@

@@ -101,7 +117,7 @@

@@ -109,6 +125,9 @@

{{ 'gene_page_research_data_protein_regulates_genes' | translate }}

+ {{ studies.proteinRegulatesOtherGenes.length }}
@@ -121,7 +140,7 @@

@@ -137,3 +156,31 @@

[showTitle]="false" [items]="studies.additionalEvidences"> + + +
+

+ {{ currentDatasetName }}.tsv +

+ {{ "download" | translate }} +
+
+ + + + + + + + \ No newline at end of file diff --git a/src/app/pages/gene/research-data/research-data.component.scss b/src/app/pages/gene/research-data/research-data.component.scss index f52b164c..fb6de8c1 100644 --- a/src/app/pages/gene/research-data/research-data.component.scss +++ b/src/app/pages/gene/research-data/research-data.component.scss @@ -14,11 +14,17 @@ min-width: 13px; width: 13px; height: 13px; - margin: 3px 8px 0 0; + margin: 2px 8px 0 0; @include study-type-mark-pseudo(); } } + .btn { + margin: 0 10px 0 0; + min-width: 80px; + font-size: 16px; + } + .counter { margin: 0; } @@ -32,4 +38,20 @@ .experiments-accordion + .experiments-accordion { margin-top: 10px; +} + +.file-download-sheet { + width: 100%; + box-sizing: border-box; + padding: 10px 0 30px 0; + font-family: sans-serif; + text-align: center; + + p { + color: $color-gray; + } + + .btn { + margin-top: 1em; + } } \ No newline at end of file diff --git a/src/app/pages/gene/research-data/research-data.component.ts b/src/app/pages/gene/research-data/research-data.component.ts index ef2b615e..646870b9 100644 --- a/src/app/pages/gene/research-data/research-data.component.ts +++ b/src/app/pages/gene/research-data/research-data.component.ts @@ -1,12 +1,22 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, Input, OnInit, TemplateRef, ViewChild } from '@angular/core'; import { Studies } from '../../../core/models/open-genes-api/studies.model'; +import { DatasetsDownload } from '../../../core/utils/datasets-download'; +import { CommonModalComponent } from '../../../components/ui-components/components/modals/common-modal/common-modal.component'; +import { takeUntil } from 'rxjs/operators'; +import { MatDialog } from '@angular/material/dialog'; +import { CsvExportService } from '../../../core/services/csv-export-service'; +import { FileExportService } from '../../../core/services/browser/file-export.service'; +import { GoogleAnalyticsService } from 'ngx-google-analytics'; @Component({ selector: 'app-research-data', templateUrl: './research-data.component.html', styleUrls: ['./research-data.component.scss'], }) -export class ResearchDataComponent implements OnInit { +export class ResearchDataComponent extends DatasetsDownload implements OnInit { + @ViewChild('downLoadLinkTemplate') downLoadLinkTemplate: TemplateRef; + @ViewChild('errorTemplate') errorTemplate: TemplateRef; + @Input() geneName: string; @Input() studies: Studies; @Input() slice = 20; @@ -18,6 +28,15 @@ export class ResearchDataComponent implements OnInit { public isGeneAssociatedWithLongevityEffects: boolean; public isAdditionalEvidences: boolean; + constructor( + private _matDialog: MatDialog, + private _csvExportService: CsvExportService, + private _fileExportService: FileExportService, + private _googleAnalyticsService: GoogleAnalyticsService + ) { + super(_matDialog, _csvExportService, _fileExportService, _googleAnalyticsService); + } + ngOnInit() { this.isIncreaseLifespan = this.studies?.increaseLifespan && @@ -46,4 +65,62 @@ export class ResearchDataComponent implements OnInit { this.isAdditionalEvidences = this.studies?.additionalEvidences && this.studies?.additionalEvidences.length !== 0; } + + protected getDownloadLinkTemplate(): TemplateRef { + return this.downLoadLinkTemplate; + } + + protected openDownloadModal(template: any): void { + this._matDialog.open(CommonModalComponent, { + data: { + title: 'download', + body: null, + template: template, + }, + panelClass: 'download-modal', + minWidth: '280px', + maxWidth: '280px', + autoFocus: false, + }); + this.isProcessing = false; + + this.matDialog.afterAllClosed.pipe(takeUntil(this.subscription$)).subscribe(() => { + this.currentDownloadLink = this.initialDownloadLinkVal; + this.currentDatasetName = this.initialDatasetName; + }); + } + + protected handleError(): void { + this.openDownloadModal(this.errorTemplate); + } + + public async downloadPurpleTablesTsv(event) { + event.stopPropagation(); + await this.downloadCsv(`${this.geneName.toLowerCase()}-lifespan-change`, + () => this.csvExportService.generatePurpleTable(this.studies.increaseLifespan)); + } + + public async downloadBlueTableTsv(event) { + event.stopPropagation(); + await this.downloadCsv(`${this.geneName.toLowerCase()}-age-related-changes`, + () => this.csvExportService.generateBlueTable(this.studies.ageRelatedChangesOfGene)); + } + + public async downloadGreenTableTsv(event) { + event.stopPropagation(); + await this.downloadCsv(`${this.geneName.toLowerCase()}-age-related-processes-change`, + () => this.csvExportService.generateGreenTable(this.studies.interventionToGeneImprovesVitalProcesses)); + } + + public async downloadPinkTablesTsv(event) { + event.stopPropagation(); + await this.downloadCsv(`${this.geneName.toLowerCase()}-associations-with-longevity`, + () => this.csvExportService.generatePinkTable(this.studies.geneAssociatedWithLongevityEffects)); + } + + public async downloadYellowTablesTsv(event) { + event.stopPropagation(); + await this.downloadCsv(`${this.geneName.toLowerCase()}-gene-regulation`, + () => this.csvExportService.generateYellowTable(this.studies.proteinRegulatesOtherGenes)); + } } diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 426a1b56..dca55edb 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -205,7 +205,7 @@ "gene_page_title_protein_description_og": "Gene description (Open Genes)", "gene_page_title_protein_description_uniprot": "Protein description (UniProt)", "gene_page_title_reference": "Reference", - "gene_page_title_research_data": "Experiments data on the association of a gene with aging", + "gene_page_title_research_data": "Experiment data on the association of a gene with aging", "gene_page_title_summary": "Summary", "gene_page_breadcrumb": "Gene page", "gene_page_gene_length_modal_title": "Gene length",