Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a new forcing data table and remove datasets from specifier tables #96

Merged
merged 21 commits into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 17 additions & 11 deletions app/src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,15 +137,21 @@ setTimeout(() => {
</Provider>
)
})
}, 100)

setTimeout(() => {
// scroll to anchor or position once everthing is settled
if (anchor) {
anchor.scrollIntoView()
}

// remove the cover div
const cover = document.getElementsByClassName('cover')[0]
cover.remove()
}, 200)
setTimeout(() => {
// scroll to anchor or position once everthing is settled
if (anchor) {
anchor.scrollIntoView()
}

// set the main height to auto
const main = document.getElementsByTagName('main')[0]
main.style.height = 'auto'

setTimeout(() => {
// remove the cover div
const cover = document.getElementsByClassName('cover')[0]
cover.remove()
}, 100)
}, 200)
}, 100)
30 changes: 26 additions & 4 deletions app/src/components/Config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import { actions } from '../store'


const Config = ({ definitions, config, actions }) => {
const dev_note = 'Currently in development.'
const group3_note = 'Ready for Group III simulations.'
const group3_dev_note = 'Data still under construction (see Table 3.1), but models' +
' not needing those data may already start.'

return (
<div className="config">
<div className="mb-3">
Expand Down Expand Up @@ -42,16 +47,33 @@ const Config = ({ definitions, config, actions }) => {
value={row.specifier}
checked={config.sectors.includes(row.specifier)}
onChange={(event) => actions.changeSector(event.target.value)} />
<label className="form-check-label" htmlFor={id}>{row.title} {row.dev && <span>🚧</span>}</label>
<label className="form-check-label" htmlFor={id}>
{row.title}
{row.dev && <span className="ml-1" title={dev_note}>🚧</span>}
{
row.group3 && (
<span className="badge badge-info ml-1" title={group3_note}>III</span>
)
}
{
row.group3_dev && <span className="badge badge-warning ml-1" title={group3_dev_note}>III</span>
}
</label>
</div>
)
})
}
</div>
</div>
<div className="text-muted">
Sectors marked with the 🚧 sign are currently in development and the protocol will not contain all nessesary information, yet.
</div>
<p className="text-muted mb-1">
🚧: {dev_note}
</p>
<p className="text-muted mb-1">
<span className="badge badge-info">III</span>: {group3_note}
</p>
<p className="text-muted mb-1">
<span className="badge badge-warning">III</span>: {group3_dev_note}
</p>
</div>
)
}
Expand Down
16 changes: 12 additions & 4 deletions app/src/components/Table.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ import { actions } from '../store'

import BiasAdjustmentTable from './tables/BiasAdjustmentTable'
import ClimateForcingTable from './tables/ClimateForcingTable'
import InputDatasetTable from './tables/InputDatasetTable'
import InputVariableTable from './tables/InputVariableTable'
import CropTable from './tables/CropTable'
import ForestStandTable from './tables/ForestStandTable'
import ExperimentsTable from './tables/ExperimentsTable'
import ForcingDataTable from './tables/ForcingDataTable'
import ForestStandTable from './tables/ForestStandTable'
import Group3RankingTable from './tables/Group3RankingTable'
import Group3RequirementsTable from './tables/Group3RequirementsTable'
import HarmonizationTable from './tables/HarmonizationTable'
import InputDatasetTable from './tables/InputDatasetTable'
import InputVariableTable from './tables/InputVariableTable'
import IrrigationTable from './tables/IrrigationTable'
import LakeSiteTable from './tables/LakeSiteTable'
import OceanRegionTable from './tables/OceanRegionTable'
Expand All @@ -21,7 +24,6 @@ import ScenarioTable from './tables/ScenarioTable'
import SpeciesTable from './tables/SpeciesTable'
import VariableTable from './tables/VariableTable'


const Table = ({ definitions, config, identifier, caption, actions }) => {
const groups = definitions.group.filter(group => group.identifier == identifier)
const rows = definitions[identifier]
Expand All @@ -39,8 +41,14 @@ const Table = ({ definitions, config, identifier, caption, actions }) => {
return <CropTable config={config} caption={caption} rows={rows} groups={groups} actions={actions} />
case 'experiments':
return <ExperimentsTable definitions={definitions} config={config} caption={caption} rows={rows} actions={actions} />
case 'forcing_data':
return <ForcingDataTable definitions={definitions} config={config} caption={caption} rows={rows} groups={groups} actions={actions} />
case 'forest_stand':
return <ForestStandTable config={config} caption={caption} rows={rows} actions={actions} />
case 'group3_ranking':
return <Group3RankingTable config={config} caption={caption} rows={rows} groups={groups} actions={actions} />
case 'group3_requirements':
return <Group3RequirementsTable config={config} caption={caption} rows={rows} actions={actions} />
case 'geo_dataset':
return <InputDatasetTable config={config} caption={caption} rows={rows} groups={groups} actions={actions} />
case 'harmonization':
Expand Down
2 changes: 1 addition & 1 deletion app/src/components/tables/ExperimentsTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ const ExperimentsTable = function({ definitions, config, caption, rows, actions
{row.priority && <p><strong>{row.priority}</strong></p>}
<p>
<SimulationRounds config={config} simulationRounds={row.simulation_rounds} />
{row.group3 && <span className="badge badge-info">Group 3</span>}
{row.group3 && <span className="badge badge-info">Group III</span>}
<Sectors config={config} sectors={row.sectors} />
</p>
</td>
Expand Down
160 changes: 160 additions & 0 deletions app/src/components/tables/ForcingDataTable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import React, { Component} from 'react'
import ReactMarkdown from 'react-markdown'
import PropTypes from 'prop-types'

import Sectors from '../badges/Sectors'
import Status from '../badges/Status'
import { GroupToggleLink, filterGroups, filterField, toggleGroups } from '../../utils'


const ForcingTable = function({ config, caption, rows, groups, actions }) {
const filteredGroups = filterGroups(config, rows, groups, actions)
const empty = (filteredGroups.length == 0)
const allOpen = filteredGroups.every(group => !group.closed)
const allToggle = () => toggleGroups(filteredGroups, allOpen)

return (
<div className="w-100">
<table className="table table-bordered table-fixed">
<caption>
<ReactMarkdown components={{p: 'span'}} children={caption} />
</caption>
<thead className="thead-dark">
<tr>
<th style={{width: '30%'}}>Forcing</th>
<th style={{width: '70%'}}>
DOI / Path / Documentation
{!empty && <GroupToggleLink className="float-right" closed={!allOpen} toggle={allToggle} all={true} />}
</th>
</tr>
</thead>
<tbody>
{
filteredGroups.map(group => {
const header = [
<tr key="-1">
<td colSpan="6" className="table-secondary">
<GroupToggleLink className="float-right" closed={group.closed} toggle={group.toggle}/>
<strong>{group.title}</strong>
</td>
</tr>
]

if (group.closed) {
return header
} else {
return header.concat(
group.rows.map((row, index) => {
const dois = filterField(config, row.doi)
const path = filterField(config, row.path)

return (
<tr key={index}>
<td colSpan="1">
<p>{row.title}</p>
<Status status={row.status} />
</td>
<td>
<p>
{row.group3 && <span className="badge badge-info">Group III</span>}
<Sectors config={config} sectors={row.sectors} />
</p>
{
dois && (
Array.isArray(dois) ? (
dois.map((doi, index) => (
<p key={index}>
<a className="doi-link" href={doi}>{doi}</a>
</p>
))
) : (
<p>
<a className="doi-link" href={dois}>{dois}</a>
</p>
)
)
}
{
row.path && (
Array.isArray(path) ? (
<>
<p className="mb-0">Paths:</p>
<ul className="list-unstyled mb-1">
{
path.map((p, i) => <div className="mb-0" key={i}><code>{p}</code></div>)
}
</ul>
</>
) : (
<p>
Path: <code>{filterField(config, row.path)}</code>
{
row.path_comment && <>
{' ('}<ReactMarkdown children={row.path_comment} components={{p: React.Fragment}}/>{')'}
</>
}
</p>
)
)
}
{
row.noadapt && (
<p>
noadapt forcing:{' '}
{
Array.isArray(row.noadapt) ? (
row.noadapt.map((s, i) => <strong key={i}>{s}</strong>).reduce((agg, cur) => [agg, ', ', cur])
) : (
<ReactMarkdown children={row.noadapt} components={{p: React.Fragment}}/>
)
}
</p>
)
}
{
row.adapt && (
<p>
adapt forcing:{' '}
{
Array.isArray(row.adapt) ? (
row.adapt.map((s, i) => <strong key={i}>{s}</strong>).reduce((agg, cur) => [agg, ', ', cur])
) : (
<ReactMarkdown children={row.adapt} components={{p: React.Fragment}}/>
)
}
</p>
)
}
{
row.comment && <ReactMarkdown children={filterField(config, row.comment)} />
}
</td>
</tr>
)
})
)
}
})
}
{
empty && <tr>
<td colSpan="4">
No forcing data have been defined for this selection of simulation round and sectors, yet.
</td>
</tr>
}
</tbody>
</table>
</div>
)
}

ForcingTable.propTypes = {
config: PropTypes.object.isRequired,
caption: PropTypes.string.isRequired,
rows: PropTypes.array.isRequired,
groups: PropTypes.array.isRequired,
actions: PropTypes.object.isRequired
}

export default ForcingTable
98 changes: 98 additions & 0 deletions app/src/components/tables/Group3RankingTable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import React, { Component} from 'react'
import ReactMarkdown from 'react-markdown'
import PropTypes from 'prop-types'

import { filterGroups, filterRows, filterField, GroupToggleLink, toggleGroups } from '../../utils'

const Group3RankingTable = function({ config, caption, rows, groups, actions }) {

const filteredGroups = filterGroups(config, rows, groups, actions)
const allOpen = filteredGroups.every(group => !group.closed)
const allToggle = () => toggleGroups(filteredGroups, allOpen)

const backgroundColor = {
'tier1': '#cfc',
'tier2': '#f9f',
'tier3': '#faf',
'tier4': '#fbf',
'tier5': '#fcf',
'tier6': '#fdf',
'tier7': '#fef',
'tier8': 'white'
}

const sortRows = (rows) => {
return (
rows.toSorted((a, b) => {
if (a.priority > b.priority) {
return 1
} else if (a.priority < b.priority) {
return -1
} else {
return 0
}
})
)
}

return (
<table className="table table-bordered table-fixed w-70">
<caption>
<ReactMarkdown components={{p: 'span'}} children={caption} />
</caption>
<thead className="thead-dark">
<tr>
<th style={{width: '10%'}}>Priority</th>
<th style={{width: '25%'}}>Climate forcing</th>
<th style={{width: '25%'}}>LU model</th>
<th style={{width: '40%'}}>
Direct human forcing
<GroupToggleLink className="float-right" closed={!allOpen} toggle={allToggle} all={true} label="tiers" />
</th>
</tr>
</thead>
<tbody>
{
filteredGroups.map(group => {
const header = [
<tr key="-1">
<td colSpan="5" className="table-secondary">
<GroupToggleLink className="float-right" closed={group.closed} toggle={group.toggle} label="tier"/>
<strong>{group.title}</strong>
</td>
</tr>
]

if (group.closed) {
return header
} else {
return header.concat(
sortRows(group.rows).map((row, index) => {
return (
<tr key={index}>
<td style={{ backgroundColor: backgroundColor[row.group] }}>
{row.priority}
</td>
<td>{row.gcm}</td>
<td>{row.lu_model}</td>
<td><strong>{row.soc_scenario}</strong></td>
</tr>
)
})
)
}
})
}
</tbody>
</table>
)
}

Group3RankingTable.propTypes = {
config: PropTypes.object.isRequired,
caption: PropTypes.string.isRequired,
rows: PropTypes.array.isRequired,
actions: PropTypes.object.isRequired
}

export default Group3RankingTable
Loading