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 algorithms description framework. May still need tweaking. #15

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@ yarn-debug.log*
yarn-error.log*
yarn.lock
node_modules

.vercel
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
"@types/react-dom": "^17.0.0",
"@types/react-rangeslider": "^2.2.3",
"@types/react-router-dom": "^5.1.7",
"@types/react-router-hash-link": "^2.4.0",
"@types/react-scrollspy": "^3.3.3",
"d3": "6.7.0",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.6",
Expand All @@ -25,7 +27,9 @@
"react-markdown": "^6.0.2",
"react-rangeslider": "^2.2.0",
"react-router-dom": "^5.2.0",
"react-router-hash-link": "^2.4.3",
"react-scripts": "4.0.3",
"react-scrollspy": "^3.4.3",
"rehype-katex": "^5.0.0",
"remark-gfm": "^1.0.0",
"remark-math": "^4.0.0",
Expand Down
106 changes: 66 additions & 40 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,58 +1,84 @@
import React from "react"
import { Card, Container } from "react-bootstrap"
import { BrowserRouter } from "react-router-dom"
import "./App.css"
import ConfigPanelWrapper from "./components/ConfigPanelWrapper"
import Algorithms, { AlgorithmEntry } from "./components/Algorithms/Algorithms"
// import ConfigPanelWrapper from "./components/ConfigPanelWrapper"
import ExpandingHeatmapTable from "./components/ExpandingHeatmapTable"
import MetricsDescription from "./components/MetricsDescription/MetricsDescription"
import Preloader from "./components/Shared/Preloader"
// import MetricsDescription from "./components/MetricsDescription/MetricsDescription"
import "./index.css"
import algosJson from "./sampleData/algos.json"
import {
expandingHeatmapTableSampleHeader as header,
expandingHeatmapTableSampleRows as tableRows
expandingHeatmapTableSampleHeader as header,
expandingHeatmapTableSampleRows as tableRows
} from "./sampleData/expandingHeatmapTableTestData"

// import { basicConfig } from "./sampleData/HeatmapConfigTestData"

function App() {
// const columnConfig = {...basicConfig, useColumnFormat: true}
// const cpuConfig = {...basicConfig, format: 'cpu' as FormatType, showCPU: true }
return (
<div className="wrapper">
<div className="page__body page__body--alert">
<div style={{ padding: 25 }}>
<BrowserRouter>
<ExpandingHeatmapTable
header={header}
rows={tableRows}
onCellSelected={(cell) => {
alert(`Selected cell ${cell.id}`)
}}
/>
</BrowserRouter>
<React.Fragment>
<div className="wrapper">
<div className="page__body page__body--alert">
<div style={{ padding: 25 }}>
<BrowserRouter>
<ExpandingHeatmapTable
header={header}
rows={tableRows}
onCellSelected={(cell) => {
alert(`Selected cell ${cell.id}`)
}}
/>
</BrowserRouter>
</div>
<div>learn react or the default test will be sad at you</div>
</div>
</div>
<div>
<hr />
<p>Whole Thing</p>
<ConfigPanelWrapper />
<div className="wrapper">
<hr />
{/* <div>
<hr />
<ConfigPanelWrapper />
<hr />
</div> */}
<BrowserRouter>
<div>
<p>This is what a fetch failure should look like:</p>
<div className="page__body">
<Container className="container__heatmap">
<Card>
<Card.Body>
<Preloader fetchFailure={true} />
</Card.Body>
</Card>
</Container>
</div>
</div>
<hr />
<p>This is the Algorithms section:</p>
<Algorithms algorithms={algosJson.algorithms as AlgorithmEntry[]} />
</BrowserRouter>
{/* <div>
<hr />
<p>Row configuration</p>
<ConfigurationPanel {...basicConfig}/>
</div>
<div>
<hr />
<p>CPU Row config</p>
<ConfigurationPanel {...cpuConfig}/>
</div>
<div>
<hr />
<p>Column config</p>
<ConfigurationPanel {...columnConfig}/>
</div> */}
{/* <MetricsDescription /> */}
</div>
{/* <div>
<hr />
<p>Row configuration</p>
<ConfigurationPanel {...basicConfig}/>
</div>
<div>
<hr />
<p>CPU Row config</p>
<ConfigurationPanel {...cpuConfig}/>
</div>
<div>
<hr />
<p>Column config</p>
<ConfigurationPanel {...columnConfig}/>
</div> */}
<div>learn react or the default test will be sad at you</div>
</div>
<hr />
<MetricsDescription />
</div>
</React.Fragment>
)
}

Expand Down
75 changes: 75 additions & 0 deletions src/components/Algorithms/AlgorithmCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Replaces former ListCard

import { FunctionComponent } from "react"
import { Col } from "react-bootstrap"
import ReactMarkdown from 'react-markdown'
import { isEmpty } from "../util"
import { AlgorithmEntry } from "./Algorithms"

const parseDescription = (rawMarkdown: string) => {
// Assume markdown is a single string, with a name or something, followed
// by a heading ## Description, followed by some more markdown,
// ending in a ## References section we don't care about.
// Return only the part between the ## Description header and the start of the
// ## References header.
// This is brittle but works well enough for now.
const description = rawMarkdown.split("Description")[1]
const before_references = description.split("## References")[0]
return before_references
}

const AlgorithmCard: FunctionComponent<AlgorithmEntry> = (Props: AlgorithmEntry) => {
return (
<Col lg={12} sm={12} xl={12}>
<div className="finder" id={Props?.label || "undefined-algorithm"} />
<div className="listcard">
{isEmpty(Props) ? //TODO: is this still needed/possible?
<h3>...</h3> :
<div className="listcard-content">
<div className="listcard-section">
<div className="listcard-top">
<a href={Props.website}>
<p className="listcard-title">
{Props.label}
</p>
</a>
{/* Probably don't need the following check */}
{Props.dockerfile ? (
<a
className="listcard-env"
href={Props.dockerfile}
target="_blank"
rel="noreferrer noopener"
>
View Docker
</a>
) : (
<span className="listcard-env">
{Props.env_name} {/*SHOULD BE UNREACHABLE?*/}
</span>
)}
</div>
<p className="listcard-authors">
<span>By</span> {Props.authors}
</p>
</div>
<div className="listcard-section">
<div className="listcard-copy">
<ReactMarkdown children={parseDescription(Props.markdown)} linkTarget="_blank"/>
</div>
</div>
<div className="listcard-section__bottom">
<a className="listcard-env" href={Props.wrapper} target="_blank" rel="noreferrer noopener">
View Wrapper
</a>
<a className="listcard-env" href={Props.website} target="_blank" rel="noreferrer noopener">
View Algorithm Website
</a>
</div>
</div>}
</div>
</Col>
)
}

export default AlgorithmCard
20 changes: 20 additions & 0 deletions src/components/Algorithms/AlgorithmOverview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Generally speaking, a spike sorting algorithm takes in an unfiltered
multi-channel timeseries (aka, recording) and a dictionary of algorithm
parameters and outputs a list of firing times and associated integer
unit labels. This page lists the spike sorting codes we run, as well as
some that have yet to be incorporated. Most of the codes were developed
at other institutions; two of them are in-house.

SpikeForest uses Python wrappers to implement the algorithms. Links to those
may be found in the "Wrapper" links for each entry. For the non-MATLAB
sorters, we use Singularity containers (similar to Docker containers)
in order to ensure a reproducible compute environment. In those cases,
links to the Docker files (environment prescriptions) are provided. We
almost always use the default parameters of the wrappers, but some may
be overridden in the
[analysis configuration files](https://github.com/flatironinstitute/spikeforest/tree/master/working/main_analysis).

Wrappers were created in collaboration with the
[SpikeInterface](https://github.com/SpikeInterface/)
project. The goal is ultimately to merge these with the corresponding wrappers
in SpikeInterface/SpikeToolkit.
Loading