Skip to content

Commit

Permalink
Merge pull request #71 from tsdataclinic/about-methodology-pages
Browse files Browse the repository at this point in the history
Add about and methodology pages
  • Loading branch information
indraneel committed Mar 1, 2024
2 parents 389c3ee + 30f6032 commit 1c9bba9
Show file tree
Hide file tree
Showing 8 changed files with 370 additions and 1 deletion.
2 changes: 2 additions & 0 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
"@fortawesome/fontawesome-svg-core": "^6.2.1",
"@fortawesome/free-solid-svg-icons": "^6.2.1",
"@fortawesome/react-fontawesome": "^0.2.0",
"@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-dialog": "^1.0.2",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-select": "^1.1.2",
"@radix-ui/react-slider": "^1.1.0",
"@tanstack/react-query": "^4.14.5",
Expand Down
6 changes: 5 additions & 1 deletion app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { Routes, Route } from "react-router-dom";
import { useState, useEffect } from 'react';
import Header from "./components/Header";
import MainPage from "./components/MainPage";
import Methods from "./components/Methods";
import About from "./components/About";
import AboutPageNew from "./components/AboutNew";

function App() {
const [width, setWidth] = useState(window.innerWidth);
Expand All @@ -25,7 +27,9 @@ function App() {
<Header isMobile={isMobile} />
<Routes>
<Route path="/" element={<MainPage />} />
<Route path="/about" element={<About />} />
<Route path="/about" element={<About />} />
<Route path="/about-new" element={<AboutPageNew />} />
<Route path="/methods" element={<Methods />} />
</Routes>
</div>
);
Expand Down
102 changes: 102 additions & 0 deletions app/src/components/AboutNew.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import React from 'react';
// import AccordionComponent from './ui/Accordion/Accordion';
import InfoPage from './InfoPage';

const AboutPageNew = () => {
return <InfoPage title={'About'} menuItems={['TREC', 'About Data Clinic']}>
<div className="mb-36" id="TREC">
<div>
In the fall of 2022, Data Clinic took part in{' '}
<a
target="_blank"
rel="noreferrer"
href="https://opportunity.census.gov/"
>
The Opportunity Project
</a>
, a semi-annual sprint organized by the U.S. Census in partnership
with federal agencies to demonstrate the value of open data, as part
of the{' '}
<a
target="_blank"
rel="noreferrer"
href="https://opportunity.census.gov/sprints/"
>
Building Climate Change Resilience Through Public Transit
</a>{' '}
sprint sponsored by the U.S. Department of Transportation.
</div>
<div>
Across our many conversations with transit officials, researchers,
and community organizers from across the country about the
climate-related challenges and opportunities transportation systems
face, a recurring theme was the desire to enable a better
understanding of climate's intersectional impact on both transit and
communities.
</div>
<div>
In other words, a flooded bus stop doesn't just mean that the bus
and passengers can't access the stop, but it may also impede access
to a hospital or community support, or to a large amount of
essential jobs. How can we share that insight more effectively?
</div>
<div>
In response, we built Transit Resilience for Essential Commuting
(TREC), an open source tool that allows users to efficiently assess
the climate risk for transit stations within the context of the
access it provides to vital services and regions. Initially focused
on flooding, the most prevalent climate event facing transit
officials across the country, and access to hospital and jobs, TREC
allows users to explore our open data-derived, station-specific risk
and access ratings, and easily filter those with the highest climate
risk and highest importance for access.
</div>
<div>
Our hope is that this human-centered and geospatial approach to the
intersectional impact of climate change on transit and communities
will give transit planners a more holistic picture to inform their
infrastructure improvement decision-making. Further, we hope that
making localized climate resilience tools like this open source,
user-friendly, and publicly available, will empower community
organizations to advocate for their underserved constituents.
</div>
<div>
The climate crisis we face requires collective intelligence and
creative problem solving, and democratizing access to these kinds of
tools will be crucial in making progress.
</div>
</div>

<div className="mb-36" id="About Data Clinic">
<div>
Data Clinic is the data and tech-for-good arm of Two Sigma, a
financial sciences company headquartered in NYC.
</div>
<div>
Since Data Clinic was founded in 2014, we have provided pro bono
data science and engineering support to mission-driven organizations
around the world via close partnerships that pair Two Sigma’s talent
and way of thinking with our partner’s rich content-area expertise.
</div>
<div>
To scale the solutions and insights we have gathered over the years,
and to contribute to the democratization of data, we also engage in
the development of open source tooling and data products.
</div>

<div>
To learn more visit{' '}
<a
target="_blank"
rel="noreferrer"
href="https://dataclinic.twosigma.com"
>
dataclinic.twosigma.com
</a>{' '}
and connect with us via{' '}
<a href="mailto:[email protected]">[email protected]</a>
</div>
</div>
</InfoPage>
};
export default AboutPageNew;
2 changes: 2 additions & 0 deletions app/src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ function Header(props: { isMobile: boolean; }) {
isDropdownMenuOpen ?
<div>
<ButtonLink url="/about">About</ButtonLink>
<ButtonLink url="/methods">Methods</ButtonLink>
<ModalLink modalContents={<LegalContents />}>Legal</ModalLink>
</div>
:
Expand All @@ -422,6 +423,7 @@ function Header(props: { isMobile: boolean; }) {
<div className="flex">
<div className='hidden sm:block'>
<ButtonLink url="/about">About</ButtonLink>
<ButtonLink url="/methods">Methods</ButtonLink>
<ModalLink modalContents={<LegalContents />}>Legal</ModalLink>
</div>
<div className='block sm:hidden'>
Expand Down
51 changes: 51 additions & 0 deletions app/src/components/InfoPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React, { useState } from 'react';
import { ArrowLeftIcon, HamburgerMenuIcon } from '@radix-ui/react-icons';

export type InfoPageProps = {
title: string;
menuItems: any[];
children: any;
}

const InfoPage = ({ title, menuItems, children} : InfoPageProps) => {
const [activeSection, setActiveSection] = useState('');
const [isSectionMenuOpen, setIsSectionMenuOpen] = useState(true);

return <div className='flex flex-col px-4 md:p-24 md:container md:mx-auto'>
{/* mobile menu */}
<div className={`sm:hidden sticky top-0 flex flex-col ${isSectionMenuOpen ? 'bg-cyan-500' : 'bg-white'}`}>
<div className={`flex flex-row justify-between`}>
<a className="flex items-center text-white" href="/"><ArrowLeftIcon /> Back</a>
<span className="flex items-center">{title}
<HamburgerMenuIcon className='ml-2' onClick={() => setIsSectionMenuOpen(!isSectionMenuOpen)} />
</span>
</div>
{
isSectionMenuOpen &&
<ul className="list-none text-right text-white">
{menuItems.map((menuItem) => {
return <li><a className="text-white" href={`#${menuItem}`}>{menuItem}</a></li>
})}
</ul>
}
</div>

{/* end mobile menu */}

<a className="hidden sm:flex items-center" href="/"><ArrowLeftIcon /> <span>Back</span></a>
<div className='hidden sm:block sm:text-7xl w-full mb-10'>{title}</div>
<div className='flex w-full'>
<div className='hidden sm:block'>
<li className="list-none text-2xl leading-10 whitespace-nowrap sticky top-0">
{menuItems.map((menuItem) => {
return <li><a className="text-black" href={`#${menuItem}`}>{menuItem}</a></li>
})}
</li>
</div>
<div className="grow md:ml-48">
{children}
</div>
</div>
</div>
};
export default InfoPage;
94 changes: 94 additions & 0 deletions app/src/components/Methods.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import React from 'react';
import AccordionComponent from './ui/Accordion/Accordion';
import InfoPage from './InfoPage';

const MethodsPage = () => {
return <InfoPage title="Methodology" menuItems={['Methodology', 'Climate Data']}>
<section id="Methodology">
<div className="">
<p>
All data other than floodplain polygons were processed into a
stop level file. We describe the methods we used to create this
file below.
</p>
<div className="grid sm:grid-cols-2">
<p>
<p><b>Stops</b></p>
The GTFS feed data (refer Data Sources) was processed
into a file containing the stop IDs, transit type (e.g. bus,
light rail), name, the list of routes servicing the stop,
and a latitude/longitude point geometry.
</p>
<p>
<p><b>Flood Risk</b></p>
First Street Foundation's aggregated flood risk
data categorizes census tracts according to the number of
buildings at minor, moderate, major, severe, and extreme
flood risk. First Street Foundation's risk categories were
quantized from 1-10, and an aggregated risk score calculated
for each census tract. For a city, risk scores were cut
into tertiles and stops within these tracts categorized
as High, Medium, and Low flood risk respectively.

Note: Flood risk at Transit stops within a city are relative
to other locations within that city. For example: While overall
flood risk is higher in New Orleans compared to New York City,
there are transit locations categorized a "Low" flood risk in New Orleans
as they have lower chance of flooding compared to other areas of New Orleans.
</p>
<p>
<p><b>Hospital Access</b></p>
We calculated 10 and 20 minute walk sheds
(using walk graphs from OSM and assumptions on average
walking pace ) centered on each hospital in the GNIS
Database and intersected these polygons with the transit
stop points. We considered stops within a 10 minute walking
distance as providing high access and between 10-20 minutes
as providing medium access. All stops not within a walkshed
were categorized as providing low access to hospitals.
</p>
<p>
<p><b>Jobs</b></p>
The Census LODES dataset contains origin-destination
employment statistics for all workers within each state
which we use to derive the total number of people working in
each block. To estimate the total number of workers within
walking distance from each transit stop, we first create 15
minute walk sheds (using walk graphs from OSM ) around each
stop. These polygons do not conform with the census block
boundaries, so we use areal interpolation to estimate the
jobs within each walkshed. The final count is computed by
subtracting the number of people who both live and work in
each walkshed from this total to exclude workers who are
unlikely to rely on transit to get to their jobs. The
high/medium/low categories correspond to the first, second,
and third tertiles of these counts.
</p>
<p>
<p><b>Vulnerable workers</b></p>
We used a similar method to estimate the
vulnerability of workers in the area of a transit stop.
Instead of aggregating the LODES data to the census block,
we matched the origin-destination blocks to their
corresponding census tracts, and linked the origin tracts to
the SVI dataset . We again used an areal interpolation
process to estimate the vulnerability of workers working
within the 15 minute stop walksheds based on the census
tract in which they live. As with the jobs, we divided the
stops into high/medium/low using tertiles.
</p>
</div>
</div>
</section>
<section id="Climate Data">
<AccordionComponent title={'CITIES'}>
<li>City: </li>
<li>City: </li>
<li>City: </li>
<li>City: </li>
</AccordionComponent>
</section>
</InfoPage>

};
export default MethodsPage;
47 changes: 47 additions & 0 deletions app/src/components/ui/Accordion/Accordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';
import * as Accordion from '@radix-ui/react-accordion';
import classNames from 'classnames';
import { PlusIcon } from '@radix-ui/react-icons';
import './AccordionStyles.css';


const AccordionTrigger = React.forwardRef<HTMLButtonElement | null, Accordion.AccordionTriggerProps>(({ children, className, ...props } : Accordion.AccordionTriggerProps, forwardedRef: React.ForwardedRef<HTMLButtonElement | null>) => (
<Accordion.Header className="AccordionHeader flex flex-col">
<Accordion.Trigger
className={classNames('AccordionTrigger', className)}
{...props}
ref={forwardedRef}
>
{children}
<PlusIcon className="AccordionChevron" aria-hidden />
</Accordion.Trigger>
</Accordion.Header>
));

const AccordionContent = React.forwardRef<HTMLDivElement | null, Accordion.AccordionContentProps>(({ children, className, ...props } : Accordion.AccordionContentProps, forwardedRef: React.ForwardedRef<HTMLDivElement | null>) => (
<Accordion.Content
className={classNames('AccordionContent', className)}
{...props}
ref={forwardedRef}
>
<div className="AccordionContentText">{children}</div>
</Accordion.Content>
));

export type AccordionComponentProps = {
title: string;
children: any;
}

const AccordionComponent = ({ title, children } : AccordionComponentProps) => (
<Accordion.Root className="AccordionRoot border-y-10" type="single" defaultValue="item-1" collapsible>
<Accordion.Item className="AccordionItem" value="item-1">
<AccordionTrigger>{title}</AccordionTrigger>
<AccordionContent>
{children}
</AccordionContent>
</Accordion.Item>
</Accordion.Root>
);

export default AccordionComponent;
Loading

0 comments on commit 1c9bba9

Please sign in to comment.