Skip to content

Commit 4f04375

Browse files
committed
netpyne-172 Add last missing components
1 parent 4a3abe9 commit 4f04375

2 files changed

Lines changed: 140 additions & 74 deletions

File tree

webapp/components/definition/populations/NetPyNEPopulation.js

Lines changed: 136 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,24 @@ import Box from '@material-ui/core/Box';
66
import Dialog from '@material-ui/core/Dialog/Dialog';
77
import Button from '@material-ui/core/Button';
88
import MenuItem from '@material-ui/core/MenuItem';
9+
import IconButton from '@material-ui/core/IconButton';
10+
import Icon from '@material-ui/core/Icon';
911

1012
import DialogActions from '@material-ui/core/DialogActions';
1113
import DialogContent from '@material-ui/core/DialogContent';
1214
import DialogContentText from '@material-ui/core/DialogContentText';
1315
import DialogTitle from '@material-ui/core/DialogTitle';
1416

17+
1518
import { withStyles } from '@material-ui/core/styles';
1619
import {
1720
Dimensions,
1821
NetPyNEField,
1922
NetPyNECoordsRange,
2023
NetPyNESelectField,
2124
NetPyNETextField,
25+
ListComponent,
26+
Tooltip,
2227
} from 'netpyne/components';
2328
import Utils from '../../../Utils';
2429
import Checkbox from '../../general/Checkbox';
@@ -35,9 +40,10 @@ const styles = ({ spacing }) => ({
3540

3641
const { textColor, primaryColor, experimentLabelColor } = vars;
3742
const newPulseObject = {
38-
start: null,
39-
end: null,
40-
noise: null,
43+
start: 0,
44+
end: 0,
45+
rate: 0,
46+
noise: 0,
4147
};
4248

4349
class 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'] = {}
207212
netpyne_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
</>

webapp/components/general/PythonControlledCapability.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ define((require) => {
376376
}
377377

378378
updatePythonValue (newValue) {
379+
const oldValue = this.state.value;
379380
this.setState({
380381
value: newValue,
381382
searchText: newValue,
@@ -384,6 +385,9 @@ define((require) => {
384385
if (this.syncValueWithPython) {
385386
this.syncValueWithPython(newValue);
386387
}
388+
if (this.postHandleChange !== undefined) {
389+
this.postHandleChange(newValue, oldValue)
390+
}
387391

388392
this.forceUpdate();
389393
}
@@ -396,9 +400,6 @@ define((require) => {
396400
}
397401
this.setState({ value: targetValue });
398402
this.updatePythonValue(targetValue);
399-
if (this.postHandleChange !== undefined) {
400-
this.postHandleChange(targetValue)
401-
}
402403
}
403404

404405
compareArrays (array1, array2) {

0 commit comments

Comments
 (0)