Skip to content

Commit

Permalink
Merge pull request #287 from RENCI/489-metrics-additions-changes-for-…
Browse files Browse the repository at this point in the history
…study-data

489 metrics additions changes for study data
  • Loading branch information
hyi authored Nov 2, 2022
2 parents 9bd0c13 + 60f4d74 commit 9f12940
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 26 deletions.
4 changes: 2 additions & 2 deletions api/templates/study-sites-template.csv
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
Proposal ID,Principal Investigator,Site Number,Site ID,CTSA ID,Site Name, Date Protocol Sent (mm-dd-yyyy),Date Contract Sent (mm-dd-yyyy),Date of IRB Submission (mm-dd-yyyy),Date of IRB Approval (mm-dd-yyyy),Date of Contract Execution (mm-dd-yyyy),Last Patient First Visit (mm-dd-yyyy),Date of Site Activation (mm-dd-yyyy),First Patient First Visit (mm-dd-yyyy),Number of Patients Consented,Number of Patients Enrolled,Number of Patients Withdrawn,Number of Patients Expected,Queries per total data elements,Number of Protocol Deviations,data Element,lost To FollowUp
ProposalID,principalInvestigator,siteNumber,siteId,ctsaId,siteName,dateRegPacketSent,dateContractSent,dateIrbSubmission,dateIrbApproval,dateContractExecution,lpfv,dateSiteActivated,fpfv,patientsConsentedCount,patientsEnrolledCount,patientsWithdrawnCount,patientsExpectedCount,queriesCount,protocolDeviationsCount,dataElement,lostToFollowUp
Proposal ID,Principal Investigator,Site Number,Site ID,CTSA ID,Site Name, Date Protocol Sent (mm-dd-yyyy),Date Contract Sent (mm-dd-yyyy),Date of IRB Submission (mm-dd-yyyy),Date of IRB Approval (mm-dd-yyyy),Date of Contract Execution (mm-dd-yyyy),Last Patient First Visit (mm-dd-yyyy),Date of Site Activation (mm-dd-yyyy),First Patient First Visit (mm-dd-yyyy),Number of Patients Consented,Number of Patients Enrolled,Number of Patients Withdrawn,Number of Patients Expected,Number of Queries,Number of Protocol Deviations,lost To FollowUp
ProposalID,principalInvestigator,siteNumber,siteId,ctsaId,siteName,dateRegPacketSent,dateContractSent,dateIrbSubmission,dateIrbApproval,dateContractExecution,lpfv,dateSiteActivated,fpfv,patientsConsentedCount,patientsEnrolledCount,patientsWithdrawnCount,patientsExpectedCount,queriesCount,protocolDeviationsCount,lostToFollowUp
,,,,,,,,,,,,,,,,,,,,,
19 changes: 14 additions & 5 deletions frontend/src/components/Tables/DetailPanels/SiteDetailPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,42 @@ import { DetailPanel } from './DetailPanel'
import { StarBullet } from '../../Bullets'
import { formatDate } from '../../../utils/DateFormat'

const invalidDisplay = 'N/A'

export const dayCount = (startDate, endDate) => {
if (startDate && endDate) {
const num = Math.round((new Date(endDate) - new Date(startDate)) / (1000 * 60 * 60 * 24))
return `${ num } day${ num === 1 ? '' : 's' }`
} else {
return 'N/A'
return invalidDisplay
}
}

export const displayRatio = (a, b, precision = 2) => {
a = parseInt(a)
b = parseInt(b)
if ( !a || !b ) {
return 'N/A'
return invalidDisplay
}
if (a === 0) {
if (b === 0) return `N/A`
if (b === 0) return invalidDisplay
return `0% (${ a }/${ b })`
}
return b !== 0
? `${ (100 * a/b).toFixed(precision) }% (${ a }/${ b })`
: `N/A`
}

const displayRatioAsWholeNumberString = (a, b) => {
return b === 0 ? invalidDisplay : `${ Math.round(a / b) }${ a } / ${ b }`
}

export const SiteDetailPanel = props => {
const {
siteName, dateRegPacketSent, dateContractSent, dateIrbSubmission, dateIrbApproval, dateContractExecution, dateSiteActivated, lpfv, fpfv, patientsConsentedCount, patientsEnrolledCount, patientsWithdrawnCount, patientsExpectedCount, queriesCount, protocolDeviationsCount, dataElement
siteName, dateRegPacketSent, dateContractSent, dateIrbSubmission, dateIrbApproval,
dateContractExecution, dateSiteActivated, lpfv, fpfv, patientsConsentedCount, patientsEnrolledCount,
patientsWithdrawnCount, patientsExpectedCount, queriesCount, protocolDeviationsCount, dataElement,
queriesPerConsentedPatient,
} = props

return (
Expand Down Expand Up @@ -87,7 +96,7 @@ export const SiteDetailPanel = props => {
</ListItem>
<ListItem>
<ListItemIcon><StarBullet /></ListItemIcon>
<ListItemText primary="Queries per data element:" secondary={ displayRatio(queriesCount, dataElement )} />
<ListItemText primary="Queries per patient:" secondary={ displayRatioAsWholeNumberString(queriesCount, patientsConsentedCount) } />
</ListItem>
</List>
</Grid>
Expand Down
19 changes: 14 additions & 5 deletions frontend/src/components/Tables/SitesTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ import { StoreContext } from '../../contexts/StoreContext'
import { SiteDetailPanel, dayCount, displayRatio } from './DetailPanels'
import { EnrollmentBar } from '../Widgets/EnrollmentBar'

const invalidDisplay = 'N/A'

const ratioAsWholeNumberString = (a, b) => {
return b === 0 ? invalidDisplay : Math.round(a / b)
}

export const SitesTable = props => {
let { title, sites } = props
const [store, ] = useContext(StoreContext)
Expand All @@ -28,7 +34,7 @@ export const SitesTable = props => {
site.actualToExpectedRandomizedPtRatio = displayRatio(site.patientsEnrolledCount, site.patientsExpectedCount)
site.ratioRandomizedPtsDropout = displayRatio(site.patientsWithdrawnCount, site.patientsEnrolledCount)
site.majorProtocolDeviationsPerRandomizedPt = displayRatio( site.protocolDeviationsCount, site.patientsEnrolledCount)
site.queriesPerDataElement = displayRatio(site.queriesCount, site.dataElement )
site.queriesPerConsentedPatient = ratioAsWholeNumberString(site.queriesCount, site.patientsConsentedCount )
})
}
}, [sites, store.proposals])
Expand Down Expand Up @@ -59,7 +65,7 @@ export const SitesTable = props => {

return (
<MaterialTable
title={ title || null }
title={ null }
components={{ }}
columns={
[
Expand All @@ -83,9 +89,7 @@ export const SitesTable = props => {
{ title: 'Patients Enrolled', field: 'patientsEnrolledCount', hidden: true, },
{ title: 'Patients Withdrawn', field: 'patientsWithdrawnCount', hidden: true, },
{ title: 'Patients Expected', field: 'patientsExpectedCount', hidden: true, },
{ title: 'Queries Count', field: 'queriesCount', hidden: true, },
{ title: 'Protocol Deviations', field: 'protocolDeviationsCount', hidden: true, },
{ title: 'Data Element', field: 'dataElement', hidden: true, },
{ title: 'Lost to Follow Up', field: 'lostToFollowUp', hidden: true, },
{ title: 'Protocol to FPFV', field: 'protocolToFpfv', hidden: true, },
{ title: 'Contract Execution Time', field: 'contractExecutionTime', hidden: true, },
Expand All @@ -96,7 +100,12 @@ export const SitesTable = props => {
{ title: 'Actual to expected randomized patient ratio', field: 'actualToExpectedRandomizedPtRatio', hidden: true, },
{ title: 'Ratio of randomized patients that dropout of the study', field: 'ratioRandomizedPtsDropout', hidden: true, },
{ title: 'Major Protocol deviations per randomized patient', field: 'majorProtocolDeviationsPerRandomizedPt', hidden: true, },
{ title: 'Queries per data element', field: 'queriesPerDataElement', hidden: true, }
{ title: 'Number of Queries', field: 'queriesCount', hidden: true, },
{
title: 'Queries per patient',
render: row => row.queriesPerConsentedPatient,
hidden: true,
},
]
}
data={ sites }
Expand Down
62 changes: 48 additions & 14 deletions frontend/src/views/Studies/CombinedMetrics.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,35 +42,69 @@ export const CombinedMetrics = ({ study, studyProfile, sites }) => {
return sites.reduce((sum, site) => sum + site[key], 0)
}

const ratioString = (a, b, precision = 2) => {
return b === 0 ? invalidDisplay : `${ (100 * a/b).toFixed(precision) }% (${ a }/${ b })`
const ratioAsPercentString = (a, b, precision = 2) => {
return b === 0 ? invalidDisplay : `${ (100 * a/b).toFixed(precision) }% ${ a } / ${ b }`
}

const item = (label, value) => (
const ratioAsWholeNumberString = (a, b) => {
return b === 0 ? invalidDisplay : `${ Math.round(a / b) }${ a } / ${ b }`
}

const Metric = React.useCallback(({ label, value }) => (
<ListItem>
<ListItemIcon><StarBullet /></ListItemIcon>
<ListItemText primary={ label + ":" } secondary={ value } />
</ListItem>
)
), [])

return (
<Grid container>
<Grid item xs={ 12 } md={ 6 }>
<List>
{ item('Activation (protocol to FPFV)', dayString(averageDays('dateRegPacketSent', 'fpfv'))) }
{ item('Contract execution time', dayString(averageDays('dateContractSent', 'dateContractExecution'))) }
{ item('sIRB approval time', dayString(averageDays('dateIrbSubmission', 'dateIrbApproval'))) }
{ item('Site open to FPFV', dayString(averageDays('dateSiteActivated', 'fpfv'))) }
{ item('Site open to LPFV', dayString(averageDays('dateSiteActivated', 'lpfv'))) }
<Metric
label="Activation (protocol to FPFV)"
value={ dayString(averageDays('dateRegPacketSent', 'fpfv')) }
/>
<Metric
label="Contract execution time"
value={ dayString(averageDays('dateContractSent', 'dateContractExecution')) }
/>
<Metric
label="sIRB approval time"
value={ dayString(averageDays('dateIrbSubmission', 'dateIrbApproval')) }
/>
<Metric
label="Site open to FPFV"
value={ dayString(averageDays('dateSiteActivated', 'fpfv')) }
/>
<Metric
label="Site open to LPFV"
value={ dayString(averageDays('dateSiteActivated', 'lpfv')) }
/>
</List>
</Grid>
<Grid item xs={ 12 } md={ 6 }>
<List>
{ item('Percent of consented patients randomized', ratioString(sum('patientsEnrolledCount'), sum('patientsConsentedCount'))) }
{ item('Actual to expected randomized patient ratio', ratioString(sum('patientsEnrolledCount'), sum('patientsExpectedCount'))) }
{ item('Ratio of randomized patients that dropped out of the study', ratioString(sum('patientsWithdrawnCount'), sum('patientsEnrolledCount'))) }
{ item('Major protocol deviations per randomized patients', ratioString(sum('protocolDeviationsCount'), sum('patientsEnrolledCount'))) }
{ item('Queries per data element', ratioString(sum('queriesCount'), sum('dataElement'))) }
<Metric
label="Percent of consented patients randomized"
value={ ratioAsPercentString(sum('patientsEnrolledCount'), sum('patientsConsentedCount')) }
/>
<Metric
label="Actual to expected randomized patient ratio"
value={ ratioAsPercentString(sum('patientsEnrolledCount'), sum('patientsExpectedCount')) }
/>
<Metric
label="Ratio of randomized patients that dropped out of the study"
value={ ratioAsPercentString(sum('patientsWithdrawnCount'), sum('patientsEnrolledCount')) }
/>
<Metric
label="Major protocol deviations per randomized patients"
value={ ratioAsPercentString(sum('protocolDeviationsCount'), sum('patientsEnrolledCount')) }
/>
<Metric
label="Queries per patient"
value={ ratioAsWholeNumberString(sum('queriesCount'), sum('patientsConsentedCount')) }
/>
</List>
</Grid>
</Grid>
Expand Down

0 comments on commit 9f12940

Please sign in to comment.