diff --git a/Dockerfile b/Dockerfile index d4a3d17e..0ad89263 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,6 +32,9 @@ RUN npm install --global yarn RUN npm install --global yalc RUN python install.py ${BUILD_ARGS} --geppetto ${GEPPETTO_VERSION} +# Temp fixes for eeg plots +RUN wget -P `pip show LFPykit | grep "Location:" | awk '{print $2"/lfpykit"}'` https://www.parralab.org/nyhead/sa_nyhead.mat + WORKDIR ${INSTALLATION_FOLDER} RUN pip install -r requirements-test.txt diff --git a/netpyne_ui/netpyne_geppetto.py b/netpyne_ui/netpyne_geppetto.py index c70190e8..a58f3f7a 100644 --- a/netpyne_ui/netpyne_geppetto.py +++ b/netpyne_ui/netpyne_geppetto.py @@ -824,7 +824,7 @@ def getAvailableCellTypes(self): def getAvailableRxDSections(self, selectedRegion): sections = set([]) sections.add('all') - if self.netParams.rxdParams.regions[selectedRegion].get('cells'): + if selectedRegion in self.netParams.rxdParams.regions and self.netParams.rxdParams.regions[selectedRegion].get('cells'): if 'all' in self.netParams.rxdParams.regions[selectedRegion]['cells']: for cellRule in self.netParams.cellParams: for cellSect in self.netParams.cellParams[cellRule]['secs']: diff --git a/requirements.txt b/requirements.txt index 6b24bda8..733a41ce 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,6 +15,7 @@ defusedxml==0.6.0 Deprecated==1.2.10 entrypoints==0.3 future==0.18.2 +h5py==3.7.0 idna==2.9 ipython-genutils==0.2.0 ipywidgets==7.5.1 diff --git a/webapp/components/experiments/ExperimentEdit.js b/webapp/components/experiments/ExperimentEdit.js index 2341b7cf..5530fc62 100644 --- a/webapp/components/experiments/ExperimentEdit.js +++ b/webapp/components/experiments/ExperimentEdit.js @@ -480,8 +480,9 @@ const ExperimentEdit = (props) => { }; const setExperimentNameInfo = (val) => { - validateExperimentName(val); - setExperimentName(val); + const name = val.replace(' ', '_'); + validateExperimentName(name); + setExperimentName(name); }; return ( diff --git a/webapp/components/general/List.js b/webapp/components/general/List.js index 8cc08327..136ef083 100644 --- a/webapp/components/general/List.js +++ b/webapp/components/general/List.js @@ -293,12 +293,14 @@ class ListComponent extends Component { ({ }, '& .MuiTabs-scroller': { borderBottom: `0.0625rem solid ${navShadow}`, - } + }, }, button: { @@ -276,6 +276,7 @@ class Rxd extends React.Component { ); } else if (value === 1) { @@ -324,6 +325,7 @@ class Rxd extends React.Component { tabPanelContent = ( ); diff --git a/webapp/components/rxd/RxdConstants.js b/webapp/components/rxd/RxdConstants.js index 4a60a9ef..aa47ad70 100644 --- a/webapp/components/rxd/RxdConstants.js +++ b/webapp/components/rxd/RxdConstants.js @@ -16,19 +16,6 @@ import AddIcon from '@material-ui/icons/Add'; import FontIcon from '@material-ui/core/Icon'; import Utils from '../../Utils'; import { - bgDarkest, - bgLight, - bgRegular, - secondaryColor, - fontColor, - radius, - primaryColor, - experimentInputColor, - experimentFieldColor, - experimentSvgColor, - experimentLabelColor, - experimentAutocompleteBorder, - errorFieldBorder, tabsTextColor, } from '../../theme'; diff --git a/webapp/components/rxd/RxdExtracellular.js b/webapp/components/rxd/RxdExtracellular.js deleted file mode 100644 index 0acd3dda..00000000 --- a/webapp/components/rxd/RxdExtracellular.js +++ /dev/null @@ -1,107 +0,0 @@ -import React from 'react'; -import { makeStyles } from '@material-ui/core/styles'; -import { - NetPyNEField, - NetPyNETextField, -} from 'netpyne/components'; -import RxdNoData from './RxdNoData'; - -const useStyles = makeStyles((theme) => ({ - root: { - overflow: 'hidden', - display: 'flex', - alignItems: 'stretch', - }, -})); - -const RxdExtracellular = (props) => { - const classes = useStyles(); - const baseTag = `netParams.rxdParams['extracellular']['${props.id}']`; - - return ( - <> - { !props.id && ( - <> - - - )} - { props.id && ( -
-
- - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
-
- )} - - ); -}; - -export default RxdExtracellular; diff --git a/webapp/components/rxd/RxdExtracellulars.js b/webapp/components/rxd/RxdExtracellulars.js index b6c7e653..c31464b4 100644 --- a/webapp/components/rxd/RxdExtracellulars.js +++ b/webapp/components/rxd/RxdExtracellulars.js @@ -1,13 +1,13 @@ import React, { useState } from 'react'; -import FontIcon from '@material-ui/core/Icon'; import { - Box, - Tabs, - Tab, - Chip, -} from '@material-ui/core'; + NetPyNEField, + ListComponent, + NetPyNECheckbox, + NetPyNETextField, +} from 'netpyne/components'; +import { makeStyles } from '@material-ui/core/styles'; +import RxdNoData from './RxdNoData'; import Utils from '../../Utils'; -import RxdExtracellular from './RxdExtracellular'; function a11yProps (index) { return { @@ -16,88 +16,118 @@ function a11yProps (index) { }; } -const RxdExtracellulars = (props) => { - const [tab, setTab] = React.useState(0); - const [extraCounter, setExtraCounter] = useState(0); +const useStyles = makeStyles((theme) => ({ + root: { + overflow: 'hidden', + display: 'flex', + alignItems: 'stretch', + }, +})); - const addSingleExtra = () => { - const newCounter = extraCounter + 1; - const newExtra = `extracellular${extraCounter}`; - if (!props.extracellular) { - Utils.execPythonMessage( - "netpyne_geppetto.netParams.rxdParams['extracellular'] = {}", - ); - } - Utils.execPythonMessage( - `netpyne_geppetto.netParams.rxdParams['extracellular']['${newExtra}'] = {}`, - ); - setExtraCounter(newCounter); - props.onAddExtracellular(newExtra); - }; +const RxdExtracellulars = (props) => { + const classes = useStyles(); + const baseTag = "netParams.rxdParams['extracellular']"; - let extras = []; - if (props.extracellular) { - extras = Object.keys(props.extracellular); + let regions = []; + if (props.regions) { + regions = Object.keys(props.regions); } return ( <> - { extras.length > 0 + { regions.length > 0 ? ( - - setTab(newTabValue)} - scrollButtons="auto" - indicatorColor="primary" - > - { - extras.map((region, index) => ( - } - onClick={(event) => { - const clickedRegion = event.currentTarget.parentElement.id; - const regionIndex = extras.indexOf(clickedRegion); - if (tab !== regionIndex) { - setTab(regionIndex); - } - }} - onDelete={(event) => { - Utils.execPythonMessage( - `del netpyne_geppetto.netParams.rxdParams['extracellular']['${event.currentTarget.parentElement.id}']`, - ); - const newRegions = Object.keys(props.extracellular).filter((item) => item !== event.currentTarget.parentElement.id); - if (newRegions.length > 0) { - setTab(newRegions.length - 1); - } else { - props.onAddExtracellular(event.currentTarget.parentElement.id); - } - }} - /> - )} - {...a11yProps(index)} - /> - )) - } - - +
+
+ + { console.log('test'); }} + /> + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + +
+
) - : <> } - - <> - - + : ( + <> + + + )} ); }; + export default RxdExtracellulars; diff --git a/webapp/components/rxd/RxdNoData.js b/webapp/components/rxd/RxdNoData.js index d2877b16..affbbdcb 100644 --- a/webapp/components/rxd/RxdNoData.js +++ b/webapp/components/rxd/RxdNoData.js @@ -37,9 +37,13 @@ const RxdNoData = (props) => { {message} - + {callback && callbackText + ? ( + + ) + : (<>)} ); }; diff --git a/webapp/components/rxd/RxdRegion.js b/webapp/components/rxd/RxdRegion.js index 88aa109b..58e6d427 100644 --- a/webapp/components/rxd/RxdRegion.js +++ b/webapp/components/rxd/RxdRegion.js @@ -1,14 +1,28 @@ -import React from 'react'; +import React, { useState } from 'react'; import { makeStyles } from '@material-ui/core/styles'; +import { + Chip, + Button, + MenuItem, + TextField, +} from '@material-ui/core'; +import AddIcon from '@material-ui/icons/Add'; +import FontIcon from '@material-ui/core/Icon'; import { NetPyNEField, NetPyNETextField, SelectField, + ListComponent, NetPyNECheckbox, NetPyNESelectField, } from 'netpyne/components'; -import MenuItem from '@material-ui/core/MenuItem'; +import Select from 'netpyne/components/general/Select'; import RxdNoData from './RxdNoData'; +import Utils from '../../Utils'; +import { geometryClasses, geometryStrings } from '../../constants'; +import { + tabsTextColor, +} from '../../theme'; const useStyles = makeStyles((theme) => ({ root: { @@ -20,7 +34,19 @@ const useStyles = makeStyles((theme) => ({ const RxdRegion = (props) => { const classes = useStyles(); + const [variable, setVariable] = useState(''); + const [parameter, setParameter] = useState(''); const baseTag = `netParams.rxdParams['regions']['${props.id}']`; + const extracellularTag = "netParams.rxdParams['extracellular']"; + let updateDone = true; + let dxField = ( + + ); + let geometryExtras = (<>); const postProcessPops = (pythonData) => { let results = []; @@ -56,6 +82,151 @@ const RxdRegion = (props) => { return results; }; + const activateExtracellular = () => { + if (!props?.extracellular?.extracellular) { + Utils.execPythonMessage( + `netpyne_geppetto.netParams.rxdParams['regions']['${props.id}']['dx'] = ''`, + ); + } else { + Utils.execPythonMessage( + `netpyne_geppetto.netParams.rxdParams['regions']['${props.id}']['dx'] = list()`, + ); + } + }; + + if (props?.extracellular?.extracellular === true) { + dxField = ( + + ); + } + + const addGeometryArgs = (item) => { + if (!props?.controlledRegion?.geometry?.args) { + Utils.execPythonMessage( + `netpyne_geppetto.netParams.rxdParams['regions']['${props.id}']['geometry']['args'] = {}`, + ); + } + Utils.execPythonMessage( + `netpyne_geppetto.netParams.rxdParams['regions']['${props.id}']['geometry']['args']['${parameter}'] = '${variable}'`, + ); + setVariable(''); + setParameter(''); + }; + + const handleGeometry = (value) => { + if (geometryClasses.includes(value.target.value)) { + if (props?.controlledRegion?.geometry?.class === undefined) { + Utils.execPythonMessage( + `netpyne_geppetto.netParams.rxdParams['regions']['${props.id}']['geometry'] = { 'class': '${value.target.value}'}`, + ); + } else if (value.target.value !== props.controlledRegion.geometry.class) { + Utils.execPythonMessage( + `netpyne_geppetto.netParams.rxdParams['regions']['${props.id}']['geometry']['class'] = '${value.target.value}'`, + ); + } + } else if (geometryStrings.includes(value.target.value)) { + if (value.target.value !== props.controlledRegion.geometry) { + Utils.execPythonMessage( + `netpyne_geppetto.netParams.rxdParams['regions']['${props.id}']['geometry'] = '${value.target.value}'`, + ); + } + geometryExtras = (<>); + } + }; + + if (typeof props.controlledRegion?.geometry === 'string' || props.controlledRegion?.geometry instanceof String) { + handleGeometry({ target: { value: props.controlledRegion?.geometry } }); + } else if (typeof props.controlledRegion?.geometry?.class === 'string' || props.controlledRegion?.geometry?.class instanceof String) { + handleGeometry({ target: { value: props.controlledRegion?.geometry.class } }); + geometryExtras = ( + <> +
+
+ setParameter(e.target.value)} + value={parameter} + /> +
+
+ setVariable(e.target.value)} + value={variable} + /> +
+
+ +
+
+ {Object?.keys(props?.controlledRegion?.geometry?.args || {}).map((item) => ( +
+
+ +
+
+ +
+
+ } + onClick={(event) => { + Utils.execPythonMessage( + `del netpyne_geppetto.netParams.rxdParams['regions']['${props.id}']['geometry']['args']['${event.currentTarget.parentElement.id}']`, + ); + }} + onDelete={(event) => { + Utils.execPythonMessage( + `del netpyne_geppetto.netParams.rxdParams['regions']['${props.id}']['geometry']['args']['${event.currentTarget.parentElement.id}']`, + ); + }} + /> +
+
+ ))} + ); + } + + return ( <> { !props.id && ( @@ -86,83 +257,100 @@ const RxdRegion = (props) => { - - - - - + {dxField} + + + + + {geometryExtras} + +
+ + - + - + -
-
- + - + - + - + - + - + - - -
)} diff --git a/webapp/components/rxd/RxdRegions.js b/webapp/components/rxd/RxdRegions.js index 862bd783..4c465f67 100644 --- a/webapp/components/rxd/RxdRegions.js +++ b/webapp/components/rxd/RxdRegions.js @@ -29,6 +29,9 @@ const RxdRegions = (props) => { Utils.execPythonMessage( "netpyne_geppetto.netParams.rxdParams['regions'] = {}", ); + Utils.execPythonMessage( + "netpyne_geppetto.netParams.rxdParams['extracellular'] = {}", + ); } Utils.execPythonMessage( `netpyne_geppetto.netParams.rxdParams['regions']['${newRegion}'] = {}`, @@ -100,6 +103,7 @@ const RxdRegions = (props) => { id={props?.regions ? regions[tab] : undefined} onAddRegion={props.onAddRegion} controlledRegion={props?.regions ? props.regions[regions[tab]] : undefined} + extracellular={props?.extracellular ? props?.extracellular : undefined} /> diff --git a/webapp/constants.js b/webapp/constants.js index a742f353..d549edcb 100644 --- a/webapp/constants.js +++ b/webapp/constants.js @@ -683,3 +683,16 @@ export const LAUNCH_MODAL = { defaultResource: 'Local Machine', errorText: 'Please check the input', }; + +export const geometryClasses = [ + 'DistributedBoundary', + 'FractionalVolume', + 'FixedCrossSection', + 'ScalableBorder', + 'Shell', +]; + +export const geometryStrings = [ + 'inside', + 'membrane', +];