@@ -6,19 +6,24 @@ import Box from '@material-ui/core/Box';
66import Dialog from '@material-ui/core/Dialog/Dialog' ;
77import Button from '@material-ui/core/Button' ;
88import MenuItem from '@material-ui/core/MenuItem' ;
9+ import IconButton from '@material-ui/core/IconButton' ;
10+ import Icon from '@material-ui/core/Icon' ;
911
1012import DialogActions from '@material-ui/core/DialogActions' ;
1113import DialogContent from '@material-ui/core/DialogContent' ;
1214import DialogContentText from '@material-ui/core/DialogContentText' ;
1315import DialogTitle from '@material-ui/core/DialogTitle' ;
1416
17+
1518import { withStyles } from '@material-ui/core/styles' ;
1619import {
1720 Dimensions ,
1821 NetPyNEField ,
1922 NetPyNECoordsRange ,
2023 NetPyNESelectField ,
2124 NetPyNETextField ,
25+ ListComponent ,
26+ Tooltip ,
2227} from 'netpyne/components' ;
2328import Utils from '../../../Utils' ;
2429import Checkbox from '../../general/Checkbox' ;
@@ -35,9 +40,10 @@ const styles = ({ spacing }) => ({
3540
3641const { textColor, primaryColor, experimentLabelColor } = vars ;
3742const newPulseObject = {
38- start : null ,
39- end : null ,
40- noise : null ,
43+ start : 0 ,
44+ end : 0 ,
45+ rate : 0 ,
46+ noise : 0 ,
4147} ;
4248
4349class NetPyNEPopulation extends React . Component {
@@ -49,13 +55,18 @@ class NetPyNEPopulation extends React.Component {
4955 sectionId : 'General' ,
5056 errorMessage : undefined ,
5157 errorDetails : undefined ,
52- pulses : [ {
53- ...newPulseObject ,
54- } ] ,
55- // cellModel: undefined,
56- cellModel : "VecStim" ,
57- patternType : undefined ,
58+ startParam : 'start' ,
59+ model : undefined
5860 } ;
61+
62+ this . updateModel ( )
63+ }
64+
65+ updateModel = async ( componentName ) => {
66+ const name = componentName ? componentName : this . props . name ;
67+ const command = `utils.convertToJS(netpyne_geppetto.netParams.popParams['${ name } '])`
68+ const response = await execPythonMessage ( command )
69+ this . setState ( { model : response } )
5970 }
6071
6172 UNSAFE_componentWillReceiveProps ( nextProps ) {
@@ -64,6 +75,7 @@ class NetPyNEPopulation extends React.Component {
6475 selectedIndex : 0 ,
6576 sectionId : 'General' ,
6677 } ) ;
78+ this . updateModel ( nextProps . name )
6779 }
6880
6981 shouldComponentUpdate ( nextProps , nextState ) {
@@ -73,6 +85,7 @@ class NetPyNEPopulation extends React.Component {
7385 || this . state . cellModelFields != nextState . cellModelFields
7486 || this . state . sectionId != nextState . sectionId
7587 || this . state . selectedIndex != nextState . selectedIndex
88+ || this . state . model != nextState . model
7689 ) ;
7790 }
7891
@@ -184,18 +197,10 @@ class NetPyNEPopulation extends React.Component {
184197 </ MenuItem >
185198 ) ) ;
186199 }
187- addAnotherPulse = ( ) => {
188- this . setState ( ( prevState ) => ( {
189- ...prevState , // Spread the current state to retain other properties
190- pulses : [ ...prevState . pulses , { ...newPulseObject } ] , // Push the new object into the 'pulses' array
191- } ) ) ;
192- } ;
200+
193201
194202 changeCellModel = ( newValue ) => {
195- this . setState ( ( prevState ) => ( {
196- ...prevState ,
197- cellModel : newValue
198- } ) )
203+ this . updateModel ( )
199204 }
200205
201206 changeCellPattern = ( newValue ) => {
@@ -206,10 +211,27 @@ class NetPyNEPopulation extends React.Component {
206211 execPythonMessage ( `netpyne_geppetto.netParams.popParams['${ this . props . name } ']['spikePattern'] = {}
207212netpyne_geppetto.netParams.popParams['${ this . props . name } ']['spikePattern']['type'] = '${ newValue } '` )
208213 }
209- this . setState ( ( prevState ) => ( {
210- ...prevState ,
211- patternType : newValue
212- } ) )
214+ this . updateModel ( )
215+ }
216+
217+ handleStartMaxChange = ( newValue ) => {
218+ const maxIsSet = ! ( ! newValue || newValue === '' )
219+ if ( maxIsSet ) {
220+ const command = `
221+ pattern = netpyne_geppetto.netParams.popParams['${ this . props . name } ']['spikePattern']
222+ pattern['start'], pattern['startMin'] = -1, pattern.get('start', '')`
223+ execPythonMessage ( command )
224+ } else {
225+ const command = `
226+ pattern = netpyne_geppetto.netParams.popParams['${ this . props . name } ']['spikePattern']
227+ pattern['start'] = pattern['startMin']
228+ del pattern['startMin']`
229+ execPythonMessage ( command )
230+ }
231+
232+ this . setState ( {
233+ startParam : maxIsSet ? "startMin" : "start"
234+ } )
213235 }
214236
215237 rhythmicLayout = ( ) => {
@@ -222,7 +244,7 @@ netpyne_geppetto.netParams.popParams['${this.props.name}']['spikePattern']['type
222244 < NetPyNETextField
223245 fullWidth
224246 variant = "filled"
225- model = { `netParams.popParams['${ this . props . name } ']['interval']` } // TODO
247+ model = { `netParams.popParams['${ this . props . name } ']['spikePattern'][' ${ this . state . startParam } ']` }
226248 />
227249 </ NetPyNEField >
228250 </ Grid >
@@ -231,7 +253,8 @@ netpyne_geppetto.netParams.popParams['${this.props.name}']['spikePattern']['type
231253 < NetPyNETextField
232254 fullWidth
233255 variant = "filled"
234- model = { `netParams.popParams['${ this . props . name } ']['interval']` } // TODO
256+ model = { `netParams.popParams['${ this . props . name } ']['spikePattern']['startMax']` }
257+ callback = { this . handleStartMaxChange }
235258 />
236259 </ NetPyNEField >
237260 </ Grid >
@@ -385,8 +408,84 @@ netpyne_geppetto.netParams.popParams['${this.props.name}']['spikePattern']['type
385408 return this [ patternKey ] ( )
386409 }
387410
411+ addAnotherPulse = ( ) => {
412+ const command = `
413+ pulse = {'start': 0, 'end': 0, 'rate': 0, 'noise': 0}
414+ netpyne_geppetto.netParams.popParams['${ this . props . name } '].setdefault('pulses', []).append(pulse)
415+ pulse`
416+ execPythonMessage ( command ) . then ( ( _ ) => {
417+ this . updateModel ( )
418+ } )
419+ } ;
420+
421+ removePulse = ( index ) => {
422+ const command = `
423+ netpyne_geppetto.netParams.popParams['${ this . props . name } ']['pulses'].pop(${ index } )`
424+ execPythonMessage ( command ) . then ( ( _ ) => {
425+ this . updateModel ( )
426+ } )
427+ }
428+
429+ displayPulses = ( ) => {
430+ if ( ! this . state . model || ! this . state . model . pulses ) {
431+ return < > </ >
432+ }
433+ return this . state . model . pulses . map ( ( pulse , index ) => (
434+ < Grid container alignItems = 'center' spacing = { 1 } key = { `pulse_${ index } ` } >
435+ < Tooltip title = "Delete pulse" placement = "top" >
436+ < IconButton size = "small" onClick = { ( ) => this . removePulse ( index ) } >
437+ < Icon fontSize = "inherit" style = { { color : primaryColor } } className = "fa fa-trash-o" />
438+ </ IconButton >
439+ </ Tooltip >
440+ < Grid item xs = { 3 } >
441+ < NetPyNEField mb = { 0 } id = "netParams.popParams.pulses.start" >
442+ < NetPyNETextField
443+ fullWidth
444+ variant = "filled"
445+ model = { `netParams.popParams['${ this . props . name } ']['pulses'][${ index } ]['start']` }
446+ />
447+ </ NetPyNEField >
448+ </ Grid >
449+ < Grid item xs = { 3 } >
450+ < NetPyNEField mb = { 0 } id = "netParams.popParams.pulses.end" >
451+ < NetPyNETextField
452+ fullWidth
453+ variant = "filled"
454+ model = { `netParams.popParams['${ this . props . name } ']['pulses'][${ index } ]['end']` }
455+ />
456+ </ NetPyNEField >
457+ </ Grid >
458+ < Grid item xs = { 2 } >
459+ < NetPyNEField mb = { 0 } id = "netParams.popParams.pulses.rate" >
460+ < NetPyNETextField
461+ fullWidth
462+ variant = "filled"
463+ model = { `netParams.popParams['${ this . props . name } ']['pulses'][${ index } ]['rate']` }
464+ />
465+ </ NetPyNEField >
466+ </ Grid >
467+ < Grid item xs = { 2 } >
468+ < NetPyNEField mb = { 0 } id = "netParams.popParams.pulses.noise" >
469+ < NetPyNETextField
470+ fullWidth
471+ variant = "filled"
472+ model = { `netParams.popParams['${ this . props . name } ']['pulses'][${ index } ]['noise']` }
473+ />
474+ </ NetPyNEField >
475+ </ Grid >
476+ { /* <Grid item xs={1}>
477+ <IconButton size="small" onClick={() => this.removePulse(index)} >
478+ <Icon fontSize="inherit" style={ { color: primaryColor } } className="fa fa-trash-o" />
479+ </IconButton>
480+ </Grid> */ }
481+ </ Grid > ) )
482+ }
483+
388484 cellStimulationLayout = ( ) => {
389- if ( ! [ "VecStim" , "NetStim" ] . includes ( this . state . cellModel ) ) {
485+ if ( ! this . state . model ) {
486+ return < > </ >
487+ }
488+ if ( ! [ "VecStim" , "NetStim" ] . includes ( this . state . model . cellModel ) ) {
390489 return < > </ >
391490 }
392491 return < >
@@ -397,46 +496,23 @@ netpyne_geppetto.netParams.popParams['${this.props.name}']['spikePattern']['type
397496 model = { `netParams.popParams['${ this . props . name } ']['seed']` }
398497 />
399498 </ NetPyNEField >
499+ < NetPyNEField
500+ id = "netParams.popParams.spkTimes"
501+ className = "listStyle"
502+ >
503+ < ListComponent
504+ model = { `netParams.popParams['${ this . props . name } ']['spkTimes']` }
505+ />
506+ </ NetPyNEField >
400507 < Box display = 'flex' alignItems = 'flex-start' style = { { gap : '1rem' } } >
401508 < Typography style = { {
402509 color : experimentLabelColor , flexShrink : 0 , padding : '18.5px 0 18.5px 10px' , fontSize : '0.875rem' , lineHeight : '130%' , fontWeight : 400
403510 } }
404511 >
405- Spiking Pulse / Rate
512+ Spiking Pulse
406513 </ Typography >
407514 < Box display = 'flex' flexDirection = 'column' style = { { gap : '0.5rem' } } >
408- { this . state . pulses . map ( ( pulse , index ) => ( < Grid container alignItems = 'center' spacing = { 1 } key = { `pulse_${ index } ` } >
409- < Grid item xs = { 4 } >
410- < TextField
411- variant = "filled"
412- fullWidth
413- onChange = { this . handleRenameChange }
414- value = { pulse . start }
415- disabled = { this . renaming }
416- label = "Start"
417- />
418- </ Grid >
419- < Grid item xs = { 4 } >
420- < TextField
421- variant = "filled"
422- fullWidth
423- onChange = { this . handleRenameChange }
424- value = { pulse . end }
425- disabled = { this . renaming }
426- label = "End"
427- />
428- </ Grid >
429- < Grid item xs = { 4 } >
430- < TextField
431- variant = "filled"
432- fullWidth
433- onChange = { this . handleRenameChange }
434- value = { pulse . noise }
435- disabled = { this . renaming }
436- label = "Noise"
437- />
438- </ Grid >
439- </ Grid > ) ) }
515+ { this . displayPulses ( ) }
440516 </ Box >
441517 </ Box >
442518
@@ -450,15 +526,6 @@ netpyne_geppetto.netParams.popParams['${this.props.name}']['spikePattern']['type
450526 > + add another pulse</ Button >
451527 </ Box >
452528
453- < TextField
454- variant = "filled"
455- fullWidth
456- onChange = { this . handleRenameChange }
457- value = { this . state . currentName }
458- disabled = { this . renaming }
459- label = "Spike intervals (ms)"
460- />
461-
462529 < NetPyNEField mb = { 0 } id = "netParams.popParams.interval" >
463530 < NetPyNETextField
464531 fullWidth
@@ -479,18 +546,16 @@ netpyne_geppetto.netParams.popParams['${this.props.name}']['spikePattern']['type
479546 < NetPyNEField mb = { 0 } id = "netParams.popParams.spikePattern" >
480547 < NetPyNESelectField
481548 style = { { mb : 0 } }
482- value = { this . state . patternType }
483549 method = "netpyne_geppetto.getAvailableStimulationPattern"
484550 model = {
485551 `netParams.popParams['${ this . props . name } ']['spikePattern']['type']`
486552 }
487- // pythonParams={[this.props.name]}
488553 postProcessItems = { this . postProcessMenuItems }
489554 postHandleChange = { this . changeCellPattern }
490555 />
491556 </ NetPyNEField >
492557
493- { this . changeStimulationPatternLayout ( this . state . patternType ) }
558+ { this . changeStimulationPatternLayout ( this . state . model ?. spikePattern ?. type ) }
494559
495560
496561</ >
0 commit comments