Skip to content

Commit

Permalink
Merge pull request #84 from glycojones/add_statistics_for_db
Browse files Browse the repository at this point in the history
Add New Stats Page
  • Loading branch information
Dialpuri authored Jan 19, 2024
2 parents 0d975a6 + f11f827 commit 4fef88a
Show file tree
Hide file tree
Showing 14 changed files with 816 additions and 4 deletions.
3 changes: 2 additions & 1 deletion webapp/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
2 changes: 2 additions & 0 deletions webapp/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -31,6 +32,7 @@ function App() {
/>
}
/>
<Route path="/statistics" element={<Statistics />} />
{/* <Route path="/api" element={<APIForwarding query={query} />} /> */}
</Routes>
</div>
Expand Down
5 changes: 5 additions & 0 deletions webapp/src/interfaces/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ export interface DatabaseHeaderProps {
pdbRedoResults: any;
}

export interface StatisticsHeaderProps {
resetApp: boolean;
setResetApp: Dispatch<SetStateAction<boolean>>;
}

export interface DatabaseResultProps {
pdbResults: any;
pdbRedoResults: any;
Expand Down
2 changes: 1 addition & 1 deletion webapp/src/layouts/BorderElement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ export default function BorderElement({
divStyle.backgroundImage = `linear-gradient(to top right, ${bottomColor}, ${bottomColor} 50%, ${topColor} 50%, ${topColor})`;
}

return <div style={divStyle}></div>;
return <div style={divStyle} className="w-full"></div>;
}
2 changes: 1 addition & 1 deletion webapp/src/layouts/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export default function Footer(): ReactElement {
<span className="text-sm text-primary text-center justify-center dark:text-gray-400">
Jordan Dialpuri, Haroldas Bagdonas and Jon Agirre
<br />
© 2023 University of York. All Rights Reserved.
© 2023-2024 University of York. All Rights Reserved.
<br />
Email: [email protected]
<br />
Expand Down
12 changes: 12 additions & 0 deletions webapp/src/layouts/NavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@ export default function NavBar({
</div>

<div className="flex">
<div className="h-12 w-12 mx-auto my-4 sm:w-12 sm:mt-12 sm:mr-6 flex items-center ">
<a id="statistics" href="/statistics">
<svg
className="w-6 h-6 text-gray-500 hover:scale-125 transition-all"
xmlns="http://www.w3.org/2000/svg"
height="1em"
viewBox="0 0 512 512"
>
<path d="M64 64c0-17.7-14.3-32-32-32S0 46.3 0 64V400c0 44.2 35.8 80 80 80H480c17.7 0 32-14.3 32-32s-14.3-32-32-32H80c-8.8 0-16-7.2-16-16V64zm406.6 86.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L320 210.7l-57.4-57.4c-12.5-12.5-32.8-12.5-45.3 0l-112 112c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L240 221.3l57.4 57.4c12.5 12.5 32.8 12.5 45.3 0l128-128z" />
</svg>
</a>
</div>
<div className="h-12 w-12 mx-auto my-4 sm:w-12 sm:mt-12 sm:mr-6 flex items-center ">
<a id="database" href="/database">
<svg
Expand Down
17 changes: 17 additions & 0 deletions webapp/src/layouts/StatisticsHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
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 (
<div className="bg-gray text-primary">
<NavBar setResetApp={props.setResetApp} />
<Graphs />
</div>
);
}
34 changes: 34 additions & 0 deletions webapp/src/pages/Statistics/Statistics.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
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';
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<boolean>(false);

const mainProps: StatisticsHeaderProps = {
resetApp,
setResetApp,
};
return (
<>
<StatisticsHeader {...mainProps} />
<BorderElement
topColor={'#D6D9E5'}
bottomColor={'#F4F9FF'}
reverse={false}
></BorderElement>
<Information />
<BorderElement
topColor={'#F4F9FF'}
bottomColor={'#D6D9E5'}
reverse={true}
></BorderElement>
<Footer></Footer>
</>
);
}
2 changes: 1 addition & 1 deletion webapp/src/shared/Loading/Loading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import ClipLoader from 'react-spinners/ClipLoader';
import React from 'react';
export default function Loading(props: { loadingText: string }) {
return (
<div className="flex flex-col items-center justify-center mx-auto px-12 m-12 h-64 w-64 border-2 border-gray-300 rounded-lg cursor-pointer bg-gray-50 dark:hover:bg-bray-800 dark:bg-gray-700 dark:border-gray-600">
<div className="flex flex-col items-center text-center justify-center mx-auto px-12 m-12 h-64 w-64 border-2 border-gray-300 rounded-lg cursor-pointer bg-gray-50 dark:hover:bg-bray-800 dark:bg-gray-700 dark:border-gray-600">
<h3 className="my-6">{props.loadingText}</h3>
<ClipLoader
loading={true}
Expand Down
42 changes: 42 additions & 0 deletions webapp/src/shared/PDBToggle/PDBToggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React, { type Dispatch, type SetStateAction } from 'react';

export default function toggleSwitch(props: {
checkState: boolean;
setCheckState: Dispatch<SetStateAction<boolean>>;
}) {
const handleCheckboxChange = () => {
props.setCheckState(!props.checkState);
};

return (
<div className="mt-4">
<label className="themeSwitcherTwo shadow-card relative inline-flex cursor-pointer select-none items-center justify-center rounded-md bg-white p-1">
<input
type="checkbox"
className="sr-only"
checked={props.checkState}
onChange={handleCheckboxChange}
/>
<span
className={`flex items-center space-x-[6px] rounded py-2 px-[18px] text-sm font-medium ${
!props.checkState
? 'text-primary bg-[#f4f7ff]'
: 'text-body-color'
}`}
>
PDB
</span>
<span
className={`flex items-center space-x-[6px] rounded py-2 px-[18px] text-sm font-medium ${
props.checkState
? 'text-primary bg-[#f4f7ff]'
: 'text-body-color'
}`}
>
{/* {pdbRedoSVG()} */}
PDB-REDO
</span>
</label>
</div>
);
}
184 changes: 184 additions & 0 deletions webapp/src/statistics/Graphs/ErrorsVsResolution.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
import React, { lazy, useEffect, useState } from 'react';
import Loading from '../../shared/Loading/Loading.tsx';
import Plot from 'react-plotly.js';

export default function ErrorsVsResolution(props: { database: string }) {
const [totalTrace, setTotalTrace] = useState();
const [errorTrace, setErrorTrace] = useState();
const [relativeTrace, setRelativeTrace] = useState();

// const [depositedTrace, setDepositedTrace] = useState();

const [data, setData] = useState<Record<
string,
Record<string, Record<string, number>>
> | 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<string, Record<string, number>>
>
);
})
.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 ? (
<Loading loadingText={'Crunching latest data...'} />
) : (
<Plot
data={[
totalTrace,
errorTrace,
// relativeTrace
]}
layout={{
autosize: true,
width,
height,
title: {
text: `Validation Errors in ${
props.database === 'pdbredo'
? 'PDB-REDO'
: 'the PDB'
} with resolution`,
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: {
title: {
text: 'Number',
},
tickformat: ',.0f',
linewidth: 2,
mirror: true,
automargin: true,
ticksuffix: ' ',
tickprefix: ' ',
range: [-50, 1600],
// type: 'log'
},
yaxis2: {
overlaying: 'y',
tickformat: ',.0f',
tickmode: 'auto',
// anchor: 'free',
side: 'right',
automargin: true,
tickprefix: ' ',
range: [0, 100],
},
xaxis: {
title: {
text: 'Resolution / Å',
},
linecolor: 'black',
linewidth: 2,
mirror: true,
tickmode: 'auto',
range: [0, 5],
},

legend: {
x: legendDown ? 0 : 1.15,
y: legendDown ? -0.6 : 0.5,
// bgcolor: '#FFFFFF',
},
}}
config = {{
toImageButtonOptions: {
format: 'svg',
filename: 'validationErrorsWithResolution',
height: 1000,
width: 1500,
scale: 1,

}}}
/>
)}
</>
);
}
Loading

0 comments on commit 4fef88a

Please sign in to comment.