From 2e4b8c940280e2df6ae3052bf4f3717489cf3869 Mon Sep 17 00:00:00 2001 From: Jordan Dialpuri <44945647+Dialpuri@users.noreply.github.com> Date: Tue, 16 Jan 2024 14:48:52 +0000 Subject: [PATCH 01/13] Add statistics page with glycans graph representation The commit introduces a new page for displaying various statistics related to glycans. It also adds a new plotly graph showing Glycosylation in the PDB over time. Modifications have been made to the navigation bar to link to this newly created statistics page and a new file for the statistics header was added. Code for fetching and processing the data for the graph has also been implemented. --- webapp/src/App.tsx | 8 + webapp/src/layouts/NavBar.tsx | 19 ++- webapp/src/layouts/StatisticsHeader.tsx | 15 ++ webapp/src/pages/Statistics/Statistics.tsx | 33 ++++ .../src/statistics/Graphs/GlycansVsYear.tsx | 149 ++++++++++++++++++ webapp/src/statistics/Graphs/Graphs.tsx | 14 ++ 6 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 webapp/src/layouts/StatisticsHeader.tsx create mode 100644 webapp/src/pages/Statistics/Statistics.tsx create mode 100644 webapp/src/statistics/Graphs/GlycansVsYear.tsx create mode 100644 webapp/src/statistics/Graphs/Graphs.tsx diff --git a/webapp/src/App.tsx b/webapp/src/App.tsx index 149b88ba..8014da0f 100644 --- a/webapp/src/App.tsx +++ b/webapp/src/App.tsx @@ -2,6 +2,7 @@ import React, { useMemo, Suspense } from 'react'; import './App.css'; import HomeSection from './pages/Home/HomeSection'; import DatabaseSection from './pages/DatabaseSection/DatabaseSection'; +import Statistics from './pages/Statistics/Statistics.tsx'; import PageLoad from './shared/Loading/PageLoad'; import { Routes, Route, useSearchParams, useLocation } from 'react-router-dom'; @@ -31,6 +32,13 @@ function App() { /> } /> + + } + /> {/* } /> */} diff --git a/webapp/src/layouts/NavBar.tsx b/webapp/src/layouts/NavBar.tsx index b55deea6..f2a5e61c 100644 --- a/webapp/src/layouts/NavBar.tsx +++ b/webapp/src/layouts/NavBar.tsx @@ -35,7 +35,20 @@ export default function NavBar({
+ +
+ + + + + + +
+ - +
@@ -74,7 +88,8 @@ export default function NavBar({ height="1em" viewBox="0 0 384 512" > - +
diff --git a/webapp/src/layouts/StatisticsHeader.tsx b/webapp/src/layouts/StatisticsHeader.tsx new file mode 100644 index 00000000..1ddad24c --- /dev/null +++ b/webapp/src/layouts/StatisticsHeader.tsx @@ -0,0 +1,15 @@ +import React, { lazy, type ReactElement, Suspense } from 'react'; +import { type StatisticsHeaderProps } from '../interfaces/types'; +import Graphs from "../statistics/Graphs/Graphs.tsx"; + +const Loading = lazy(async () => await import('../shared/Loading/Loading.tsx')); +const NavBar = lazy(async () => await import('./NavBar.tsx')); + +export default function StatisticsHeader(props: StatisticsHeaderProps): ReactElement { + return ( +
+ + +
+ ); +} diff --git a/webapp/src/pages/Statistics/Statistics.tsx b/webapp/src/pages/Statistics/Statistics.tsx new file mode 100644 index 00000000..2485ac7c --- /dev/null +++ b/webapp/src/pages/Statistics/Statistics.tsx @@ -0,0 +1,33 @@ +import React, { lazy, type ReactElement, useEffect, useState } from 'react'; +import { Information } from '../../shared/Information/Information.tsx'; +import {type StatisticsHeaderProps} from '../../interfaces/types'; +import StatisticsHeader from "../../layouts/StatisticsHeader.tsx" +const Footer = lazy(async () => await import('../../layouts/Footer.tsx')); +const BorderElement = lazy( + async () => await import('../../layouts/BorderElement.tsx') +); + +export default function DatabaseSection(): ReactElement { + const [resetApp, setResetApp] = useState(false); + + const mainProps: StatisticsHeaderProps = { + resetApp: resetApp, setResetApp: setResetApp + } + return ( + <> + + + + +
+ + ); +} diff --git a/webapp/src/statistics/Graphs/GlycansVsYear.tsx b/webapp/src/statistics/Graphs/GlycansVsYear.tsx new file mode 100644 index 00000000..68c9fba6 --- /dev/null +++ b/webapp/src/statistics/Graphs/GlycansVsYear.tsx @@ -0,0 +1,149 @@ +import {lazy, useEffect, useState} from "react"; +import {data} from "autoprefixer"; +import {Simulate} from "react-dom/test-utils"; +import error = Simulate.error; +import {binDB} from "../../data/Constants.tsx"; +const Plot = lazy(async () => await import('react-plotly.js')); + +export default function GlycansVsYear() { + + const [totalTrace, setTotalTrace] = useState() + const [nglycanTrace, setNGlycanTrace] = useState() + const [oglycanTrace, setOGlycanTrace] = useState() + const [cglycanTrace, setCGlycanTrace] = useState() + const [sglycanTrace, setSGlycanTrace] = useState() + const [ligandTrace, setLigandTrace] = useState() + const [depositedTrace, setDepositedTrace] = useState() + + const [data, setData] = useState(null) + useEffect(() => { + + const url = "https://raw.githubusercontent.com/Dialpuri/PrivateerDatabase/master/stats/glycosylation_per_year.json" + fetch(url) + .then(response => response.json()) + .then(data => { + setData(data); + }) + .catch(error => { + console.error('Error:', error); + }); + + }, []); + + useEffect(() => { + if (data === null) return + const newTotalTrace = { + x: Object.keys(data), + y: Object.values(data).map((e) => {return e.totalglyco }), + type: 'scatter', + mode: 'lines', + // marker: {color: 'red'}, + name: "Total Glycans" + }; + + setTotalTrace(newTotalTrace); + + const newNGlycanTrace = { + x: Object.keys(data), + y: Object.values(data).map((e) => {return e['n-glycosylation'] }), + type: 'scatter', + mode: 'lines', + // marker: {color: 'green'}, + name: "N-Glycans" + }; + + setNGlycanTrace(newNGlycanTrace); + + const newOGlycanTrace = { + x: Object.keys(data), + y: Object.values(data).map((e) => {return e['o-glycosylation'] }), + type: 'scatter', + mode: 'lines', + // marker: {color: 'blue'}, + name: "O-Glycans" + }; + + setOGlycanTrace(newOGlycanTrace); + + const newSGlycanTrace = { + x: Object.keys(data), + y: Object.values(data).map((e) => {return e['s-glycosylation'] }), + type: 'scatter', + mode: 'lines', + // marker: {color: 'blue'}, + name: "S-Glycans" + }; + + setSGlycanTrace(newSGlycanTrace); + + const newCGlycanTrace = { + x: Object.keys(data), + y: Object.values(data).map((e) => {return e['c-glycosylation'] }), + type: 'scatter', + mode: 'lines', + // marker: {color: 'blue'}, + name: "C-Glycans" + }; + + setCGlycanTrace(newCGlycanTrace); + + const newLigandTrace = { + x: Object.keys(data), + y: Object.values(data).map((e) => {return e.ligands }), + type: 'scatter', + mode: 'lines', + // marker: {color: 'blue'}, + name: "Ligands" + }; + + setLigandTrace(newLigandTrace); + + const newDepositedTrace = + { + x: Object.keys(data), + y: Object.values(data).map((e) => {return e.depositions }), + type: 'bar', + name: "Deposited", + yaxis: 'y2', + marker: { + color: 'rgb(158,202,225)', + opacity: 0.4, + + } + }; + + setDepositedTrace(newDepositedTrace) + + }, [data]); + + return ( + + ) +} \ No newline at end of file diff --git a/webapp/src/statistics/Graphs/Graphs.tsx b/webapp/src/statistics/Graphs/Graphs.tsx new file mode 100644 index 00000000..5130d148 --- /dev/null +++ b/webapp/src/statistics/Graphs/Graphs.tsx @@ -0,0 +1,14 @@ +import GlycansVsYear from "./GlycansVsYear.tsx"; + +export default function Graphs() { + + return ( + <> +
+

Statistics

+ + +
+ + ) +} \ No newline at end of file From ec2e70806f03b8545c72c4206b94d6e567f89f71 Mon Sep 17 00:00:00 2001 From: Jordan Dialpuri <44945647+Dialpuri@users.noreply.github.com> Date: Tue, 16 Jan 2024 14:52:20 +0000 Subject: [PATCH 02/13] Update Statistics-related components and improve readability Code readability and general appearance have been improved within several Statistics-related components. This includes changes such as reformatting in Statistics.tsx, Graphs/GlycansVsYear.tsx, Graphs.tsx and App.tsx. Minor modifications have also been applied to the NavBar.tsx SVG elements to enhance code understanding and presentation. --- webapp/src/App.tsx | 8 +- webapp/src/layouts/NavBar.tsx | 21 ++- webapp/src/layouts/StatisticsHeader.tsx | 8 +- webapp/src/pages/Statistics/Statistics.tsx | 11 +- .../src/statistics/Graphs/GlycansVsYear.tsx | 132 ++++++++++-------- webapp/src/statistics/Graphs/Graphs.tsx | 11 +- 6 files changed, 101 insertions(+), 90 deletions(-) diff --git a/webapp/src/App.tsx b/webapp/src/App.tsx index 8014da0f..14dcd426 100644 --- a/webapp/src/App.tsx +++ b/webapp/src/App.tsx @@ -32,13 +32,7 @@ function App() { /> } /> - - } - /> + } /> {/* } /> */} diff --git a/webapp/src/layouts/NavBar.tsx b/webapp/src/layouts/NavBar.tsx index f2a5e61c..953547f1 100644 --- a/webapp/src/layouts/NavBar.tsx +++ b/webapp/src/layouts/NavBar.tsx @@ -35,20 +35,19 @@ export default function NavBar({
- @@ -88,8 +86,7 @@ export default function NavBar({ height="1em" viewBox="0 0 384 512" > - +
diff --git a/webapp/src/layouts/StatisticsHeader.tsx b/webapp/src/layouts/StatisticsHeader.tsx index 1ddad24c..ed2eb8d0 100644 --- a/webapp/src/layouts/StatisticsHeader.tsx +++ b/webapp/src/layouts/StatisticsHeader.tsx @@ -1,15 +1,17 @@ import React, { lazy, type ReactElement, Suspense } from 'react'; import { type StatisticsHeaderProps } from '../interfaces/types'; -import Graphs from "../statistics/Graphs/Graphs.tsx"; +import Graphs from '../statistics/Graphs/Graphs.tsx'; const Loading = lazy(async () => await import('../shared/Loading/Loading.tsx')); const NavBar = lazy(async () => await import('./NavBar.tsx')); -export default function StatisticsHeader(props: StatisticsHeaderProps): ReactElement { +export default function StatisticsHeader( + props: StatisticsHeaderProps +): ReactElement { return (
- +
); } diff --git a/webapp/src/pages/Statistics/Statistics.tsx b/webapp/src/pages/Statistics/Statistics.tsx index 2485ac7c..b3ed5c09 100644 --- a/webapp/src/pages/Statistics/Statistics.tsx +++ b/webapp/src/pages/Statistics/Statistics.tsx @@ -1,7 +1,7 @@ -import React, { lazy, type ReactElement, useEffect, useState } from 'react'; +import React, { lazy, type ReactElement, useState } from 'react'; import { Information } from '../../shared/Information/Information.tsx'; -import {type StatisticsHeaderProps} from '../../interfaces/types'; -import StatisticsHeader from "../../layouts/StatisticsHeader.tsx" +import { type StatisticsHeaderProps } from '../../interfaces/types'; +import StatisticsHeader from '../../layouts/StatisticsHeader.tsx'; const Footer = lazy(async () => await import('../../layouts/Footer.tsx')); const BorderElement = lazy( async () => await import('../../layouts/BorderElement.tsx') @@ -11,8 +11,9 @@ export default function DatabaseSection(): ReactElement { const [resetApp, setResetApp] = useState(false); const mainProps: StatisticsHeaderProps = { - resetApp: resetApp, setResetApp: setResetApp - } + resetApp, + setResetApp, + }; return ( <> diff --git a/webapp/src/statistics/Graphs/GlycansVsYear.tsx b/webapp/src/statistics/Graphs/GlycansVsYear.tsx index 68c9fba6..b8e2cf74 100644 --- a/webapp/src/statistics/Graphs/GlycansVsYear.tsx +++ b/webapp/src/statistics/Graphs/GlycansVsYear.tsx @@ -1,124 +1,141 @@ -import {lazy, useEffect, useState} from "react"; -import {data} from "autoprefixer"; -import {Simulate} from "react-dom/test-utils"; -import error = Simulate.error; -import {binDB} from "../../data/Constants.tsx"; +import React, { lazy, useEffect, useState } from 'react'; const Plot = lazy(async () => await import('react-plotly.js')); export default function GlycansVsYear() { + const [totalTrace, setTotalTrace] = useState(); + const [nglycanTrace, setNGlycanTrace] = useState(); + const [oglycanTrace, setOGlycanTrace] = useState(); + const [cglycanTrace, setCGlycanTrace] = useState(); + const [sglycanTrace, setSGlycanTrace] = useState(); + const [ligandTrace, setLigandTrace] = useState(); + const [depositedTrace, setDepositedTrace] = useState(); + + const [data, setData] = useState + > | null>(null); - const [totalTrace, setTotalTrace] = useState() - const [nglycanTrace, setNGlycanTrace] = useState() - const [oglycanTrace, setOGlycanTrace] = useState() - const [cglycanTrace, setCGlycanTrace] = useState() - const [sglycanTrace, setSGlycanTrace] = useState() - const [ligandTrace, setLigandTrace] = useState() - const [depositedTrace, setDepositedTrace] = useState() - - const [data, setData] = useState(null) useEffect(() => { - - const url = "https://raw.githubusercontent.com/Dialpuri/PrivateerDatabase/master/stats/glycosylation_per_year.json" + const url = + 'https://raw.githubusercontent.com/Dialpuri/PrivateerDatabase/master/stats/glycosylation_per_year.json'; fetch(url) - .then(response => response.json()) - .then(data => { - setData(data); + .then(async (response) => await response.json()) + .then((data) => { + setData(data as Record>); }) - .catch(error => { + .catch((error) => { console.error('Error:', error); }); - }, []); useEffect(() => { - if (data === null) return + if (data === null) return; const newTotalTrace = { x: Object.keys(data), - y: Object.values(data).map((e) => {return e.totalglyco }), + y: Object.values(data).map((e) => { + return e.totalglyco; + }), type: 'scatter', mode: 'lines', // marker: {color: 'red'}, - name: "Total Glycans" + name: 'Total Glycans', }; setTotalTrace(newTotalTrace); const newNGlycanTrace = { x: Object.keys(data), - y: Object.values(data).map((e) => {return e['n-glycosylation'] }), + y: Object.values(data).map((e) => { + return e['n-glycosylation']; + }), type: 'scatter', mode: 'lines', // marker: {color: 'green'}, - name: "N-Glycans" + name: 'N-Glycans', }; setNGlycanTrace(newNGlycanTrace); const newOGlycanTrace = { x: Object.keys(data), - y: Object.values(data).map((e) => {return e['o-glycosylation'] }), + y: Object.values(data).map((e) => { + return e['o-glycosylation']; + }), type: 'scatter', mode: 'lines', // marker: {color: 'blue'}, - name: "O-Glycans" + name: 'O-Glycans', }; setOGlycanTrace(newOGlycanTrace); const newSGlycanTrace = { x: Object.keys(data), - y: Object.values(data).map((e) => {return e['s-glycosylation'] }), + y: Object.values(data).map((e) => { + return e['s-glycosylation']; + }), type: 'scatter', mode: 'lines', // marker: {color: 'blue'}, - name: "S-Glycans" + name: 'S-Glycans', }; setSGlycanTrace(newSGlycanTrace); const newCGlycanTrace = { x: Object.keys(data), - y: Object.values(data).map((e) => {return e['c-glycosylation'] }), + y: Object.values(data).map((e) => { + return e['c-glycosylation']; + }), type: 'scatter', mode: 'lines', // marker: {color: 'blue'}, - name: "C-Glycans" + name: 'C-Glycans', }; setCGlycanTrace(newCGlycanTrace); const newLigandTrace = { x: Object.keys(data), - y: Object.values(data).map((e) => {return e.ligands }), + y: Object.values(data).map((e) => { + return e.ligands; + }), type: 'scatter', mode: 'lines', // marker: {color: 'blue'}, - name: "Ligands" + name: 'Ligands', }; setLigandTrace(newLigandTrace); - const newDepositedTrace = - { - x: Object.keys(data), - y: Object.values(data).map((e) => {return e.depositions }), - type: 'bar', - name: "Deposited", - yaxis: 'y2', - marker: { - color: 'rgb(158,202,225)', - opacity: 0.4, - - } - }; - - setDepositedTrace(newDepositedTrace) + const newDepositedTrace = { + x: Object.keys(data), + y: Object.values(data).map((e) => { + return e.depositions; + }), + type: 'bar', + name: 'Deposited', + yaxis: 'y2', + marker: { + color: 'rgb(158,202,225)', + opacity: 0.4, + }, + }; + setDepositedTrace(newDepositedTrace); }, [data]); return ( - ) -} \ No newline at end of file + ); +} diff --git a/webapp/src/statistics/Graphs/Graphs.tsx b/webapp/src/statistics/Graphs/Graphs.tsx index 5130d148..794dbce1 100644 --- a/webapp/src/statistics/Graphs/Graphs.tsx +++ b/webapp/src/statistics/Graphs/Graphs.tsx @@ -1,14 +1,13 @@ -import GlycansVsYear from "./GlycansVsYear.tsx"; - +import GlycansVsYear from './GlycansVsYear.tsx'; +import React from 'react'; export default function Graphs() { - return ( <>

Statistics

- +
- ) -} \ No newline at end of file + ); +} From 07b805375be9b616011a4294c76e79ab272a3a28 Mon Sep 17 00:00:00 2001 From: Jordan Dialpuri <44945647+Dialpuri@users.noreply.github.com> Date: Tue, 16 Jan 2024 14:53:56 +0000 Subject: [PATCH 03/13] Add StatisticsHeaderProps interface A new interface, StatisticsHeaderProps, was added to types.ts. It includes resetApp and setResetApp properties, facilitating state management in the application. --- webapp/src/interfaces/types.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/webapp/src/interfaces/types.ts b/webapp/src/interfaces/types.ts index 90a7a107..dc1bb6ae 100644 --- a/webapp/src/interfaces/types.ts +++ b/webapp/src/interfaces/types.ts @@ -57,6 +57,11 @@ export interface DatabaseHeaderProps { pdbRedoResults: any; } +export interface StatisticsHeaderProps { + resetApp: boolean; + setResetApp: Dispatch>; +} + export interface DatabaseResultProps { pdbResults: any; pdbRedoResults: any; From ddc7076d6500e905e18a267faff78a4b3a42b2e9 Mon Sep 17 00:00:00 2001 From: Jordan Dialpuri <44945647+Dialpuri@users.noreply.github.com> Date: Tue, 16 Jan 2024 15:21:51 +0000 Subject: [PATCH 04/13] Refactor variable names in GlycansVsYear component The variable names related to different types of glycans and total depositions in the GlycansVsYear component have been refactored to ensure clarity and consistency. This change enhances code readability and maintains a consistent naming convention across the component. --- webapp/src/statistics/Graphs/GlycansVsYear.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/webapp/src/statistics/Graphs/GlycansVsYear.tsx b/webapp/src/statistics/Graphs/GlycansVsYear.tsx index b8e2cf74..a32859e8 100644 --- a/webapp/src/statistics/Graphs/GlycansVsYear.tsx +++ b/webapp/src/statistics/Graphs/GlycansVsYear.tsx @@ -33,7 +33,7 @@ export default function GlycansVsYear() { const newTotalTrace = { x: Object.keys(data), y: Object.values(data).map((e) => { - return e.totalglyco; + return e.totalGlycans; }), type: 'scatter', mode: 'lines', @@ -46,7 +46,7 @@ export default function GlycansVsYear() { const newNGlycanTrace = { x: Object.keys(data), y: Object.values(data).map((e) => { - return e['n-glycosylation']; + return e.nGlycans; }), type: 'scatter', mode: 'lines', @@ -59,7 +59,7 @@ export default function GlycansVsYear() { const newOGlycanTrace = { x: Object.keys(data), y: Object.values(data).map((e) => { - return e['o-glycosylation']; + return e.oGlycans; }), type: 'scatter', mode: 'lines', @@ -72,7 +72,7 @@ export default function GlycansVsYear() { const newSGlycanTrace = { x: Object.keys(data), y: Object.values(data).map((e) => { - return e['s-glycosylation']; + return e.sGlycans; }), type: 'scatter', mode: 'lines', @@ -85,7 +85,7 @@ export default function GlycansVsYear() { const newCGlycanTrace = { x: Object.keys(data), y: Object.values(data).map((e) => { - return e['c-glycosylation']; + return e.cGlycans; }), type: 'scatter', mode: 'lines', @@ -111,7 +111,7 @@ export default function GlycansVsYear() { const newDepositedTrace = { x: Object.keys(data), y: Object.values(data).map((e) => { - return e.depositions; + return e.totalDepositions; }), type: 'bar', name: 'Deposited', From 0fdc4bd4ecd758ad9c7eb3d3764be036f8190c17 Mon Sep 17 00:00:00 2001 From: Jordan Dialpuri <44945647+Dialpuri@users.noreply.github.com> Date: Tue, 16 Jan 2024 15:25:31 +0000 Subject: [PATCH 05/13] Update label name in GlycansVsYear graph The label for the bar in the GlycansVsYear graph has been updated from 'Deposited' to 'Total Deposited'. This change more accurately reflects the data being represented. Signed-off-by: Jordan Dialpuri <44945647+Dialpuri@users.noreply.github.com> --- webapp/src/statistics/Graphs/GlycansVsYear.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/src/statistics/Graphs/GlycansVsYear.tsx b/webapp/src/statistics/Graphs/GlycansVsYear.tsx index a32859e8..4890a85e 100644 --- a/webapp/src/statistics/Graphs/GlycansVsYear.tsx +++ b/webapp/src/statistics/Graphs/GlycansVsYear.tsx @@ -114,7 +114,7 @@ export default function GlycansVsYear() { return e.totalDepositions; }), type: 'bar', - name: 'Deposited', + name: 'Total Deposited', yaxis: 'y2', marker: { color: 'rgb(158,202,225)', From c7b886c4f6b22fe969cbc347eca89358780b90be Mon Sep 17 00:00:00 2001 From: Jordan Dialpuri <44945647+Dialpuri@users.noreply.github.com> Date: Tue, 16 Jan 2024 16:04:46 +0000 Subject: [PATCH 06/13] Refine graph title attributes and fetch last update date Graph's title attributes were adjusted further on GlycansVsYear graph for better visibility. Additionally, incorporated a function in Graphs.tsx to fetch and display the last updated date from the remote data source. This helps users have real-time updates of the Protein Data Bank statistics. Signed-off-by: Jordan Dialpuri <44945647+Dialpuri@users.noreply.github.com> --- .../src/statistics/Graphs/GlycansVsYear.tsx | 10 +++++++- webapp/src/statistics/Graphs/Graphs.tsx | 25 +++++++++++++++++-- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/webapp/src/statistics/Graphs/GlycansVsYear.tsx b/webapp/src/statistics/Graphs/GlycansVsYear.tsx index 4890a85e..9b378d97 100644 --- a/webapp/src/statistics/Graphs/GlycansVsYear.tsx +++ b/webapp/src/statistics/Graphs/GlycansVsYear.tsx @@ -137,7 +137,15 @@ export default function GlycansVsYear() { ligandTrace, ]} layout={{ - title: 'Glycosylation in the PDB over time', + title: { + text: 'Glycosylation in the PDB over time', + x: 0.5, + y: 1.1, + xanchor: 'auto', // or 'auto', which matches 'left' in this case + yanchor: 'bottom', + xref: 'paper', + yref: 'paper', + }, plot_bgcolor: '#FFFFFF', paper_bgcolor: '#D6D9E5', yaxis: { diff --git a/webapp/src/statistics/Graphs/Graphs.tsx b/webapp/src/statistics/Graphs/Graphs.tsx index 794dbce1..9b5fab07 100644 --- a/webapp/src/statistics/Graphs/Graphs.tsx +++ b/webapp/src/statistics/Graphs/Graphs.tsx @@ -1,10 +1,31 @@ import GlycansVsYear from './GlycansVsYear.tsx'; -import React from 'react'; +import React, { useEffect, useState } from 'react'; export default function Graphs() { + const [lastUpdated, setLastUpdated] = useState(); + + useEffect(() => { + const url = + 'https://raw.githubusercontent.com/Dialpuri/PrivateerDatabase/master/stats/last_updated.json'; + + fetch(url) + .then(async (response) => await response.json()) + .then((data) => { + setLastUpdated(data.date as string); + }) + .catch((error) => { + console.log('Error reading last updated date', error); + }); + }, []); + return ( <>
-

Statistics

+

+ Protein Data Bank Statistics +

+

+ Last Updated - {lastUpdated} +

From 49efb7faf32cae894a6db66d9d5f9bc195b109a3 Mon Sep 17 00:00:00 2001 From: Jordan Dialpuri <44945647+Dialpuri@users.noreply.github.com> Date: Tue, 16 Jan 2024 16:23:30 +0000 Subject: [PATCH 07/13] Update appearance settings of GlycansVsYear graph Updated y-axis, x-axis, and legend attributes to improve visibility in GlycansVsYear graph. For real-time updates and relevance, the graphical representation now includes the last updated date fetched from the data source. Signed-off-by: Jordan Dialpuri <44945647+Dialpuri@users.noreply.github.com> --- .../src/statistics/Graphs/GlycansVsYear.tsx | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/webapp/src/statistics/Graphs/GlycansVsYear.tsx b/webapp/src/statistics/Graphs/GlycansVsYear.tsx index 9b378d97..85a85da6 100644 --- a/webapp/src/statistics/Graphs/GlycansVsYear.tsx +++ b/webapp/src/statistics/Graphs/GlycansVsYear.tsx @@ -153,19 +153,36 @@ export default function GlycansVsYear() { text: 'Number of Depositions', }, tickformat: ',.0f', + linewidth: 2, + mirror: true, + automargin: true, + ticksuffix: " ", + tickprefix: " " + }, yaxis2: { - side: 'right', overlaying: 'y', tickformat: ',.0f', + tickmode: 'auto', + // anchor: 'free', + side: 'right', + automargin: true, + tickprefix: " ", + range: [0, 16000] }, xaxis: { title: { text: 'Year', }, + linecolor: 'black', + linewidth: 2, + mirror: true, + tickmode: 'auto', + }, + legend: { - x: 1.1, + x: 1.15, y: 0.5, // bgcolor: '#FFFFFF', }, From 813442074d4049801dbe3922e34b4cb4715ada8a Mon Sep 17 00:00:00 2001 From: Jordan Dialpuri <44945647+Dialpuri@users.noreply.github.com> Date: Tue, 16 Jan 2024 16:52:43 +0000 Subject: [PATCH 08/13] Update range parameters in GlycansVsYear graph Adjusted the range values in the tick settings for both the primary and secondary y-axis. These changes improve the graph's data range representation for more precise data visualization. Signed-off-by: Jordan Dialpuri <44945647+Dialpuri@users.noreply.github.com> --- webapp/src/statistics/Graphs/GlycansVsYear.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/webapp/src/statistics/Graphs/GlycansVsYear.tsx b/webapp/src/statistics/Graphs/GlycansVsYear.tsx index 85a85da6..ba6e0bc3 100644 --- a/webapp/src/statistics/Graphs/GlycansVsYear.tsx +++ b/webapp/src/statistics/Graphs/GlycansVsYear.tsx @@ -157,7 +157,8 @@ export default function GlycansVsYear() { mirror: true, automargin: true, ticksuffix: " ", - tickprefix: " " + tickprefix: " ", + range: [-50, 1600] }, yaxis2: { @@ -168,7 +169,7 @@ export default function GlycansVsYear() { side: 'right', automargin: true, tickprefix: " ", - range: [0, 16000] + range: [-500, 16000] }, xaxis: { title: { From bfaa738fb403bbf7be1403b2f8ae30f702bdfabc Mon Sep 17 00:00:00 2001 From: Jordan Dialpuri <44945647+Dialpuri@users.noreply.github.com> Date: Tue, 16 Jan 2024 17:05:53 +0000 Subject: [PATCH 09/13] Adjust text alignment and autosize Graph parameters Modified alignment of heading texts from left to center in 'Graphs.tsx' and autosized the graph container in 'GlycansVsYear.tsx' file to make it responsive. The width and height of the Graph have also been set to 100% to ensure full container coverage. Signed-off-by: Jordan Dialpuri <44945647+Dialpuri@users.noreply.github.com> --- webapp/src/statistics/Graphs/GlycansVsYear.tsx | 16 +++++++++------- webapp/src/statistics/Graphs/Graphs.tsx | 4 ++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/webapp/src/statistics/Graphs/GlycansVsYear.tsx b/webapp/src/statistics/Graphs/GlycansVsYear.tsx index ba6e0bc3..9a5b967e 100644 --- a/webapp/src/statistics/Graphs/GlycansVsYear.tsx +++ b/webapp/src/statistics/Graphs/GlycansVsYear.tsx @@ -137,6 +137,10 @@ export default function GlycansVsYear() { ligandTrace, ]} layout={{ + autosize: true, + // width: 1000, + width: '100%', + height: '100%', title: { text: 'Glycosylation in the PDB over time', x: 0.5, @@ -156,10 +160,9 @@ export default function GlycansVsYear() { linewidth: 2, mirror: true, automargin: true, - ticksuffix: " ", - tickprefix: " ", - range: [-50, 1600] - + ticksuffix: ' ', + tickprefix: ' ', + range: [-50, 1600], }, yaxis2: { overlaying: 'y', @@ -168,8 +171,8 @@ export default function GlycansVsYear() { // anchor: 'free', side: 'right', automargin: true, - tickprefix: " ", - range: [-500, 16000] + tickprefix: ' ', + range: [-500, 16000], }, xaxis: { title: { @@ -179,7 +182,6 @@ export default function GlycansVsYear() { linewidth: 2, mirror: true, tickmode: 'auto', - }, legend: { diff --git a/webapp/src/statistics/Graphs/Graphs.tsx b/webapp/src/statistics/Graphs/Graphs.tsx index 9b5fab07..261bc08b 100644 --- a/webapp/src/statistics/Graphs/Graphs.tsx +++ b/webapp/src/statistics/Graphs/Graphs.tsx @@ -20,10 +20,10 @@ export default function Graphs() { return ( <>
-

+

Protein Data Bank Statistics

-

+

Last Updated - {lastUpdated}

From c18745ba5f289b0a2adf6026c78290031da072b4 Mon Sep 17 00:00:00 2001 From: Jordan Dialpuri <44945647+Dialpuri@users.noreply.github.com> Date: Thu, 18 Jan 2024 17:27:00 +0000 Subject: [PATCH 10/13] Add two new graph components and update copyright year Introduced two new graphs (`ErrorsVsYear.tsx` and `ErrorsVsResolution.tsx`) to display error statistics. Updated the copyright year in the footer to extend to 2024, and improved existing components for better responsiveness and to include loading dispositions. Adjustments were also made to several files to optimize the graphical representation of data. Signed-off-by: Jordan Dialpuri <44945647+Dialpuri@users.noreply.github.com> --- webapp/src/layouts/Footer.tsx | 2 +- webapp/src/shared/Loading/Loading.tsx | 2 +- .../statistics/Graphs/ErrorsVsResolution.tsx | 175 ++++++++++++++++++ webapp/src/statistics/Graphs/ErrorsVsYear.tsx | 144 ++++++++++++++ .../src/statistics/Graphs/GlycansVsYear.tsx | 165 ++++++++++------- webapp/src/statistics/Graphs/Graphs.tsx | 82 +++++++- 6 files changed, 490 insertions(+), 80 deletions(-) create mode 100644 webapp/src/statistics/Graphs/ErrorsVsResolution.tsx create mode 100644 webapp/src/statistics/Graphs/ErrorsVsYear.tsx diff --git a/webapp/src/layouts/Footer.tsx b/webapp/src/layouts/Footer.tsx index d871316a..aef73485 100644 --- a/webapp/src/layouts/Footer.tsx +++ b/webapp/src/layouts/Footer.tsx @@ -6,7 +6,7 @@ export default function Footer(): ReactElement { Jordan Dialpuri, Haroldas Bagdonas and Jon Agirre
- © 2023 University of York. All Rights Reserved. + © 2023-2024 University of York. All Rights Reserved.
Email: support@privateer.york.ac.uk
diff --git a/webapp/src/shared/Loading/Loading.tsx b/webapp/src/shared/Loading/Loading.tsx index 065fd48b..d132d924 100644 --- a/webapp/src/shared/Loading/Loading.tsx +++ b/webapp/src/shared/Loading/Loading.tsx @@ -2,7 +2,7 @@ import ClipLoader from 'react-spinners/ClipLoader'; import React from 'react'; export default function Loading(props: { loadingText: string }) { return ( -
+

{props.loadingText}

> + > | null>(null); + + const [width, setWidth] = useState(1000); + const [height, setHeight] = useState(1000); + const [legendDown, setLegendDown] = useState(false); + + useEffect(() => { + const url = + 'https://raw.githubusercontent.com/Dialpuri/PrivateerDatabase/master/stats/validation_errors_per_resolution.json'; + + fetch(url) + .then(async (response) => await response.json()) + .then((data) => { + setData( + data as Record< + string, + Record> + > + ); + }) + .catch((error) => { + console.error('Error:', error); + }); + + function handleResize() { + const currentWidth = window.innerWidth; + + if (currentWidth < 1000) { + setWidth(0.75 * currentWidth); + setHeight(600); + setLegendDown(true); + } else { + setWidth(Math.max(0.75 * currentWidth, 1000)); + setHeight(0.5 * Math.max(0.75 * currentWidth, 1000)); + + setLegendDown(false); + } + } + + window.addEventListener('resize', handleResize); + handleResize(); + }, []); + + useEffect(() => { + if (data === null) return; + const newTotalTrace = { + x: Object.keys(data[props.database]), + y: Object.values(data[props.database]).map((e) => { + return e.totalGlycans; + }), + type: 'scatter', + mode: 'lines', + // marker: {color: 'red'}, + name: 'Total Glycosylated Models', + }; + + setTotalTrace(newTotalTrace); + + const newErrorTrace = { + x: Object.keys(data[props.database]), + y: Object.values(data[props.database]).map((e) => { + return e.totalErrors; + }), + type: 'scatter', + mode: 'lines', + // marker: {color: 'green'}, + name: 'Validation Errors', + }; + + setErrorTrace(newErrorTrace); + + const newRelativeTrace = { + x: Object.keys(data[props.database]), + y: Object.values(data[props.database]).map((e) => { + return (100 * e.totalErrors) / e.totalGlyco; + }), + type: 'scatter', + mode: 'lines', + // marker: {color: 'green'}, + yaxis: 'y2', + name: 'Validation Errors', + }; + + setRelativeTrace(newRelativeTrace); + }, [data, props.database]); + + return ( + <> + {data === null ? ( + + ) : ( + + )} + + ); +} diff --git a/webapp/src/statistics/Graphs/ErrorsVsYear.tsx b/webapp/src/statistics/Graphs/ErrorsVsYear.tsx new file mode 100644 index 00000000..f2861c13 --- /dev/null +++ b/webapp/src/statistics/Graphs/ErrorsVsYear.tsx @@ -0,0 +1,144 @@ +import React, { useEffect, useState } from 'react'; +import Loading from '../../shared/Loading/Loading.tsx'; +import Plot from 'react-plotly.js'; + +export default function ErrorsVsYear(props: { database: string }) { + const [totalTrace, setTotalTrace] = useState(); + const [errorTrace, setErrorTrace] = useState(); + + // const [depositedTrace, setDepositedTrace] = useState(); + + const [data, setData] = useState> + > | null>(null); + + const [width, setWidth] = useState(1000); + const [height, setHeight] = useState(1000); + const [legendDown, setLegendDown] = useState(false); + + useEffect(() => { + const url = + 'https://raw.githubusercontent.com/Dialpuri/PrivateerDatabase/master/stats/validation_errors_per_year.json'; + + fetch(url) + .then(async (response) => await response.json()) + .then((data) => { + setData( + data as Record< + string, + Record> + > + ); + }) + .catch((error) => { + console.error('Error:', error); + }); + + function handleResize() { + const currentWidth = window.innerWidth; + + if (currentWidth < 1000) { + setWidth(0.75 * currentWidth); + setHeight(600); + setLegendDown(true); + } else { + setWidth(Math.max(0.75 * currentWidth, 1000)); + setHeight(0.5 * Math.max(0.75 * currentWidth, 1000)); + + setLegendDown(false); + } + } + + window.addEventListener('resize', handleResize); + handleResize(); + }, []); + + useEffect(() => { + if (data === null) return; + const newTotalTrace = { + x: Object.keys(data[props.database]), + y: Object.values(data[props.database]).map((e) => { + return e.totalGlycans; + }), + type: 'scatter', + mode: 'lines', + // marker: {color: 'red'}, + name: 'Total Glycosylated Models', + }; + + setTotalTrace(newTotalTrace); + + const newErrorTrace = { + x: Object.keys(data[props.database]), + y: Object.values(data[props.database]).map((e) => { + return e.totalErrors; + }), + type: 'scatter', + mode: 'lines', + // marker: {color: 'green'}, + name: 'Validation Errors', + }; + + setErrorTrace(newErrorTrace); + }, [data, props.database]); + + return ( + <> + {data === null ? ( + + ) : ( + + )} + + ); +} diff --git a/webapp/src/statistics/Graphs/GlycansVsYear.tsx b/webapp/src/statistics/Graphs/GlycansVsYear.tsx index 9a5b967e..216c5161 100644 --- a/webapp/src/statistics/Graphs/GlycansVsYear.tsx +++ b/webapp/src/statistics/Graphs/GlycansVsYear.tsx @@ -1,5 +1,6 @@ -import React, { lazy, useEffect, useState } from 'react'; -const Plot = lazy(async () => await import('react-plotly.js')); +import React, { useEffect, useState } from 'react'; +import Loading from '../../shared/Loading/Loading.tsx'; +import Plot from 'react-plotly.js'; export default function GlycansVsYear() { const [totalTrace, setTotalTrace] = useState(); @@ -15,9 +16,14 @@ export default function GlycansVsYear() { Record > | null>(null); + const [width, setWidth] = useState(1000); + const [height, setHeight] = useState(1000); + const [legendDown, setLegendDown] = useState(false); + useEffect(() => { const url = 'https://raw.githubusercontent.com/Dialpuri/PrivateerDatabase/master/stats/glycosylation_per_year.json'; + fetch(url) .then(async (response) => await response.json()) .then((data) => { @@ -26,6 +32,24 @@ export default function GlycansVsYear() { .catch((error) => { console.error('Error:', error); }); + + function handleResize() { + const currentWidth = window.innerWidth; + + if (currentWidth < 1000) { + setWidth(0.75 * currentWidth); + setHeight(600); + setLegendDown(true); + } else { + setWidth(Math.max(0.75 * currentWidth, 1000)); + setHeight(0.5 * Math.max(0.75 * currentWidth, 1000)); + + setLegendDown(false); + } + } + + window.addEventListener('resize', handleResize); + handleResize(); }, []); useEffect(() => { @@ -38,7 +62,7 @@ export default function GlycansVsYear() { type: 'scatter', mode: 'lines', // marker: {color: 'red'}, - name: 'Total Glycans', + name: 'Total Carbohydrates', }; setTotalTrace(newTotalTrace); @@ -126,70 +150,75 @@ export default function GlycansVsYear() { }, [data]); return ( - + <> + {data === null ? ( + + ) : ( + + )} + ); } diff --git a/webapp/src/statistics/Graphs/Graphs.tsx b/webapp/src/statistics/Graphs/Graphs.tsx index 261bc08b..f3331faf 100644 --- a/webapp/src/statistics/Graphs/Graphs.tsx +++ b/webapp/src/statistics/Graphs/Graphs.tsx @@ -1,5 +1,8 @@ import GlycansVsYear from './GlycansVsYear.tsx'; -import React, { useEffect, useState } from 'react'; +import React, { Suspense, useEffect, useState } from 'react'; +import Loading from '../../shared/Loading/Loading.tsx'; +import ErrorsVsYear from './ErrorsVsYear.tsx'; +import ErrorsVsResolution from './ErrorsVsResolution.tsx'; export default function Graphs() { const [lastUpdated, setLastUpdated] = useState(); @@ -17,18 +20,77 @@ export default function Graphs() { }); }, []); + const [isChecked, setIsChecked] = useState(false); + + const handleCheckboxChange = () => { + setIsChecked(!isChecked); + }; + + function toggleSwitch(): React.ReactNode { + return ( +
+ +
+ ); + } + return ( <> -
-

- Protein Data Bank Statistics -

-

- Last Updated - {lastUpdated} -

+ } + > +
+

+ Protein Data Bank Statistics +

+

+ Last Updated - {lastUpdated} +

- -
+ +
+
+

+ Validation Statistics +

+

+ Last Updated - {lastUpdated} +

+
+
{toggleSwitch()}
+
+ + +
+ ); } From 44ebdee26c067da6cd4b370d1679f10095f77a40 Mon Sep 17 00:00:00 2001 From: Jordan Dialpuri <44945647+Dialpuri@users.noreply.github.com> Date: Thu, 18 Jan 2024 17:30:32 +0000 Subject: [PATCH 11/13] Update ESLint configuration Added "multiline-ternary" rule to the ESLint configuration file and set it to "off". This change aims to improve the readability of the code by allowing multiline ternary operators without triggering a lint warning. Signed-off-by: Jordan Dialpuri <44945647+Dialpuri@users.noreply.github.com> --- webapp/.eslintrc.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/webapp/.eslintrc.json b/webapp/.eslintrc.json index 422fd234..248d5ca8 100644 --- a/webapp/.eslintrc.json +++ b/webapp/.eslintrc.json @@ -25,6 +25,7 @@ } ], "@typescript-eslint/triple-slash-reference": "off", - "@typescript-eslint/no-misused-promises": "warn" + "@typescript-eslint/no-misused-promises": "warn", + "multiline-ternary": "off" } } From b32d800d190d6cabfbf4b91e9dffcf754baa86d4 Mon Sep 17 00:00:00 2001 From: Jordan Dialpuri <44945647+Dialpuri@users.noreply.github.com> Date: Fri, 19 Jan 2024 14:52:43 +0000 Subject: [PATCH 12/13] Improve border element styling and error graph functionality Updated the BorderElement styling to have full width and added a new 'Relative Validation Errors' trace in the ErrorsVsYear graph. Introduced a more efficient and reusable PDBToggle to switch between databases in Graphs component, replacing previous checkbox. Improved UI by changing paper_bgcolor and adding a yaxis2 in the ErrorsVsYear graph layout. Made the page layout cleaner and more easy to use. Signed-off-by: Jordan Dialpuri <44945647+Dialpuri@users.noreply.github.com> --- webapp/src/layouts/BorderElement.tsx | 2 +- webapp/src/shared/PDBToggle/PDBToggle.tsx | 42 +++++++++ webapp/src/statistics/Graphs/ErrorsVsYear.tsx | 33 ++++++- webapp/src/statistics/Graphs/Graphs.tsx | 92 ++++++++++--------- 4 files changed, 121 insertions(+), 48 deletions(-) create mode 100644 webapp/src/shared/PDBToggle/PDBToggle.tsx diff --git a/webapp/src/layouts/BorderElement.tsx b/webapp/src/layouts/BorderElement.tsx index 9f96d0a5..29b8a5e6 100644 --- a/webapp/src/layouts/BorderElement.tsx +++ b/webapp/src/layouts/BorderElement.tsx @@ -18,5 +18,5 @@ export default function BorderElement({ divStyle.backgroundImage = `linear-gradient(to top right, ${bottomColor}, ${bottomColor} 50%, ${topColor} 50%, ${topColor})`; } - return
; + return
; } diff --git a/webapp/src/shared/PDBToggle/PDBToggle.tsx b/webapp/src/shared/PDBToggle/PDBToggle.tsx new file mode 100644 index 00000000..373bbe4d --- /dev/null +++ b/webapp/src/shared/PDBToggle/PDBToggle.tsx @@ -0,0 +1,42 @@ +import React, { type Dispatch, type SetStateAction } from 'react'; + +export default function toggleSwitch(props: { + checkState: boolean; + setCheckState: Dispatch>; +}) { + const handleCheckboxChange = () => { + props.setCheckState(!props.checkState); + }; + + return ( +
+ +
+ ); +} diff --git a/webapp/src/statistics/Graphs/ErrorsVsYear.tsx b/webapp/src/statistics/Graphs/ErrorsVsYear.tsx index f2861c13..a47871f5 100644 --- a/webapp/src/statistics/Graphs/ErrorsVsYear.tsx +++ b/webapp/src/statistics/Graphs/ErrorsVsYear.tsx @@ -5,6 +5,7 @@ import Plot from 'react-plotly.js'; export default function ErrorsVsYear(props: { database: string }) { const [totalTrace, setTotalTrace] = useState(); const [errorTrace, setErrorTrace] = useState(); + const [relativeTrace, setRelativeTrace] = useState(); // const [depositedTrace, setDepositedTrace] = useState(); @@ -81,6 +82,20 @@ export default function ErrorsVsYear(props: { database: string }) { }; setErrorTrace(newErrorTrace); + + const newRelativeTrace = { + x: Object.keys(data[props.database]), + y: Object.values(data[props.database]).map((e) => { + return (100 * e.totalErrors) / e.totalGlycans; + }), + type: 'scatter', + mode: 'lines', + yaxis: 'y2', + // marker: {color: 'green'}, + name: 'Relative Validation Errors ', + }; + + setRelativeTrace(newRelativeTrace); }, [data, props.database]); return ( @@ -89,7 +104,11 @@ export default function ErrorsVsYear(props: { database: string }) { ) : ( (); @@ -20,45 +29,8 @@ export default function Graphs() { }); }, []); - const [isChecked, setIsChecked] = useState(false); - - const handleCheckboxChange = () => { - setIsChecked(!isChecked); - }; - - function toggleSwitch(): React.ReactNode { - return ( -
- -
- ); - } + const [errorVsYearDBSwitch, setErrorVsYearDBSwitch] = useState(false); + const [errorVsResDBSwitch, setErrorVsResDBSwitch] = useState(false); return ( <> @@ -74,20 +46,50 @@ export default function Graphs() { -
+ + + +
-

+

Validation Statistics

Last Updated - {lastUpdated}

-
{toggleSwitch()}
- + +
+
+ +
+ +
+ + + +
+ +
From f11f827dee61cfa7c95dd787eef2deeb1c326fc7 Mon Sep 17 00:00:00 2001 From: Jordan Dialpuri <44945647+Dialpuri@users.noreply.github.com> Date: Fri, 19 Jan 2024 15:13:12 +0000 Subject: [PATCH 13/13] Update error graphs and add image export option Enhancements were made in the error graphs to include a dynamic range for years and an export option was introduced allowing users to save the graphs as an SVG file. The export configuration includes settings for filename, dimensions, and format. This new functionality enables better data analysis and flexibility in terms of usage and distribution of the generated graphs. Signed-off-by: Jordan Dialpuri <44945647+Dialpuri@users.noreply.github.com> --- webapp/src/statistics/Graphs/ErrorsVsResolution.tsx | 9 +++++++++ webapp/src/statistics/Graphs/ErrorsVsYear.tsx | 11 +++++++++++ webapp/src/statistics/Graphs/GlycansVsYear.tsx | 11 ++++++++++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/webapp/src/statistics/Graphs/ErrorsVsResolution.tsx b/webapp/src/statistics/Graphs/ErrorsVsResolution.tsx index 33d21c5d..79f9138a 100644 --- a/webapp/src/statistics/Graphs/ErrorsVsResolution.tsx +++ b/webapp/src/statistics/Graphs/ErrorsVsResolution.tsx @@ -168,6 +168,15 @@ export default function ErrorsVsResolution(props: { database: string }) { // bgcolor: '#FFFFFF', }, }} + config = {{ + toImageButtonOptions: { + format: 'svg', + filename: 'validationErrorsWithResolution', + height: 1000, + width: 1500, + scale: 1, + + }}} /> )} diff --git a/webapp/src/statistics/Graphs/ErrorsVsYear.tsx b/webapp/src/statistics/Graphs/ErrorsVsYear.tsx index a47871f5..5e1bb36f 100644 --- a/webapp/src/statistics/Graphs/ErrorsVsYear.tsx +++ b/webapp/src/statistics/Graphs/ErrorsVsYear.tsx @@ -8,6 +8,7 @@ export default function ErrorsVsYear(props: { database: string }) { const [relativeTrace, setRelativeTrace] = useState(); // const [depositedTrace, setDepositedTrace] = useState(); + const d = new Date(); const [data, setData] = useState )} diff --git a/webapp/src/statistics/Graphs/GlycansVsYear.tsx b/webapp/src/statistics/Graphs/GlycansVsYear.tsx index 216c5161..f7da3820 100644 --- a/webapp/src/statistics/Graphs/GlycansVsYear.tsx +++ b/webapp/src/statistics/Graphs/GlycansVsYear.tsx @@ -215,8 +215,17 @@ export default function GlycansVsYear() { x: legendDown ? 0 : 1.15, y: legendDown ? -0.6 : 0.5, // bgcolor: '#FFFFFF', - }, + } }} + config = {{ + toImageButtonOptions: { + format: 'svg', + filename: 'glycosylationOverTime', + height: 1000, + width: 1500, + scale: 1, + + }}} /> )}