Skip to content
Merged
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
12 changes: 6 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,15 @@ FROM frodriguez4600/jupyter-neuron:v7.8.0
ARG INSTALLATION_FOLDER=/home/jovyan/work/NetPyNE-UI
ARG NETPYNE_VERSION=development
ARG WORKSPACE_VERSION=nov2020
ARG JUPYTER_GEPPETTO_VERSION=development
ARG PYGEPPETTO_VERSION=development
ARG GEPPETTO_VERSION=development
ARG BUILD_ARGS=""

USER $NB_USER

ENV INSTALLATION_FOLDER=$INSTALLATION_FOLDER
ENV NETPYNE_VERSION=$NETPYNE_VERSION
ENV WORKSPACE_VERSION=$WORKSPACE_VERSION
ENV JUPYTER_GEPPETTO_VERSION=$JUPYTER_GEPPETTO_VERSION
ENV PYGEPPETTO_VERSION=$PYGEPPETTO_VERSION
ENV GEPPETTO_VERSION=$GEPPETTO_VERSION
ENV BUILD_ARGS=$BUILD_ARGS

# Install openmpi for parallel simulations
Expand All @@ -30,10 +28,12 @@ RUN pip install -r requirements.txt
COPY --chown=1000:1000 . .
WORKDIR ${INSTALLATION_FOLDER}/utilities

RUN python install.py ${BUILD_ARGS}
RUN npm install --global yarn
RUN npm install --global yalc
RUN python install.py ${BUILD_ARGS} --geppetto ${GEPPETTO_VERSION}

WORKDIR ${INSTALLATION_FOLDER}

RUN pip install -r requirements-test.txt
RUN pytest tests/backend
# RUN pytest tests/backend
CMD /bin/bash -c "jupyter notebook --NotebookApp.default_url=/geppetto --NotebookApp.token='' --library=netpyne_ui --NotebookApp.disable_check_xsrf=True"
7 changes: 6 additions & 1 deletion webapp/components/NetPyNE.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const styles = ({ zIndex }) => ({
},
topbar: {
position: 'relative',
zIndex: zIndex.drawer + 1,
zIndex: zIndex.drawer,
},
content: {
flexGrow: 1,
Expand All @@ -46,6 +46,11 @@ const TIMEOUT = 10000;
const EXPERIMENT_POLL_INTERVAL = 1000;

class NetPyNE extends React.Component {
constructor (props) {
super(props);
this.openPythonCallDialog = this.openPythonCallDialog.bind(this);
}

componentDidMount () {
GEPPETTO.on(GEPPETTO.Events.Error_while_exec_python_command, this.openPythonCallDialog, this);

Expand Down
50 changes: 32 additions & 18 deletions webapp/components/general/ControlPanelTreeItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import Shuffle from '@material-ui/icons/Shuffle';
import { ChromePicker } from 'react-color';
import { useDispatch, useSelector } from 'react-redux';
import { experimentLabelColor } from '../../theme';
import { changeInstanceColor } from '../../redux/actions/general';
import { changeInstanceColor, selectInstances } from '../../redux/actions/general';

const useStyles = makeStyles((theme) => ({
networkItem: {
Expand Down Expand Up @@ -62,26 +62,39 @@ const ControlPanelTreeItem = (props) => {
setColor(_color.rgb);
};

const getRandomColor = () => ({
r: parseFloat((Math.random() * 255).toFixed(2)),
g: parseFloat((Math.random() * 255).toFixed(2)),
b: parseFloat((Math.random() * 255).toFixed(2)),
a: 1,
});

const generateRandomColor = (event, nodeId) => {
const newInstances = instances.filter((instance) => !(instance.instancePath.startsWith(nodeId)));
const randomColor = {
r: parseFloat((Math.random() * 255).toFixed(2)),
g: parseFloat((Math.random() * 255).toFixed(2)),
b: parseFloat((Math.random() * 255).toFixed(2)),
a: 1,
};
const children = window.Instances.getInstance(nodeId).getChildren().map((instance) => instance.getInstancePath());
// const newInstances = instances.filter((instance) => !(instance.instancePath.startsWith(nodeId)));
const newInstances = instances.filter((instance) => {
let condition = true;
children.forEach((child) => {
if (instance.instancePath.startsWith(child)) {
condition = false;
}
});
return condition;
});

newInstances.push({
instancePath: nodeId,
color: {
r: randomColor.r / 255,
g: randomColor.g / 255,
b: randomColor.b / 255,
a: randomColor.a,
},
children.forEach((child) => {
const randomColor = getRandomColor();
newInstances.push({
instancePath: child,
color: {
r: randomColor.r / 255,
g: randomColor.g / 255,
b: randomColor.b / 255,
a: randomColor.a,
},
});
});
dispatch(changeInstanceColor(newInstances));
setColor(randomColor);
};

const changeVisibility = (event, nodeId) => {
Expand Down Expand Up @@ -126,6 +139,7 @@ const ControlPanelTreeItem = (props) => {
onNodeSelect,
onVisibilityClick,
children,
disableRandom,
...other
} = props;

Expand Down Expand Up @@ -153,7 +167,7 @@ const ControlPanelTreeItem = (props) => {
<IconButton onClick={(event) => changeVisibility(event, nodeId)}>
{ visibility ? <Visibility /> : <VisibilityOff /> }
</IconButton>
<IconButton onClick={(event) => generateRandomColor(event, nodeId)}><Shuffle /></IconButton>
<IconButton disabled={disableRandom} onClick={(event) => generateRandomColor(event, nodeId)}><Shuffle /></IconButton>
<IconButton onClick={() => setShowColorPicker(true)}><ColorLens /></IconButton>
{
showColorPicker
Expand Down
21 changes: 10 additions & 11 deletions webapp/components/general/ExperimentControlPanel.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
/* eslint-disable no-nested-ternary */
import * as React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { makeStyles } from '@material-ui/core/styles';
import Box from '@material-ui/core/Box';
import Typography from '@material-ui/core/Typography';
import TextField from '@material-ui/core/TextField';
import TreeView from '@material-ui/lab/TreeView';
import TreeItem from '@material-ui/lab/TreeItem';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import ChevronRightIcon from '@material-ui/icons/ChevronRight';
import ControlPanelTreeItem from './ControlPanelTreeItem';
import { experimentLabelColor } from '../../theme';

import { MODEL_STATE } from '../../constants';
import { selectInstances } from '../../redux/actions/general';

const useStyles = makeStyles(() => ({
header: {
Expand All @@ -24,9 +23,11 @@ const useStyles = makeStyles(() => ({

const ExperimentControlPanel = (props) => {
const classes = useStyles();
const dispatch = useDispatch();
const instances = useSelector((state) => state.general.instances);
const [filter, setFilter] = React.useState('');
const onNodeSelect = (nodeId) => {
console.log(`Node with id ${nodeId} clicked`);
dispatch(selectInstances(instances, [nodeId]));
};
const instancesMap = new Map();

Expand Down Expand Up @@ -71,7 +72,7 @@ const ExperimentControlPanel = (props) => {
};

const getTreeItemsFromData = (treeItems) => treeItems.map((treeItemData) => {
let children;
let children = [];
if (treeItemData.getChildren() && treeItemData.getChildren().length > 0) {
children = getTreeItemsFromData(treeItemData.getChildren());
}
Expand All @@ -84,6 +85,7 @@ const ExperimentControlPanel = (props) => {
type={treeItemData.getType().getId()}
onNodeSelect={onNodeSelect}
onVisibilityClick={onVisibilityClick}
disableRandom={children.length === 0}
>
{children}
</ControlPanelTreeItem>
Expand All @@ -110,12 +112,9 @@ const ExperimentControlPanel = (props) => {
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
>
<TreeItem nodeId="network" label="network_netpyne">
{filter === ''
? getTreeItemsFromData(window.Instances.network.getChildren())
: getFlatFilteredList(window.Instances.network.getChildren())
}
</TreeItem>
{filter === ''
? getTreeItemsFromData([window.Instances.getInstance('network')])
: getFlatFilteredList([window.Instances.getInstance('network')])}
</TreeView>
</Box>
)
Expand Down
4 changes: 2 additions & 2 deletions webapp/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { openBackendErrorDialog, closeBackendErrorDialog } from '../redux/action
import {
updateCards, editModel, simulateNetwork, createNetwork, closeDialog,
createAndSimulateNetwork, showNetwork, pythonCall, modelLoaded, deleteNetParamsObj, resetModel,
setDefaultWidgets, changeInstanceColor, openConfirmationDialog, closeConfirmationDialog,
setDefaultWidgets, changeInstanceColor, openConfirmationDialog, closeConfirmationDialog, selectInstances,
} from '../redux/actions/general';

import {
Expand Down Expand Up @@ -250,7 +250,7 @@ export const NetPyNEInstantiated = connect(
data: state.general.instances,
}),
(dispatch) => ({
selectInstances: (instances) => dispatch(changeInstanceColor(instances)),
selectInstances: (instances, selectedInstances) => dispatch(selectInstances(instances, selectedInstances)),
}),
)(_NetPyNEInstantiated);

Expand Down
44 changes: 8 additions & 36 deletions webapp/components/instantiation/NetPyNEInstantiated.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const SELECTION_COLOR = {
r: 0, g: 0.8, b: 0.8, a: 1,
};
const DEFAULT_COLOR = {
g: 0.50, b: 0.60, r: 1, a: 0.80,
g: 0.50, b: 0.60, r: 1, a: 1,
};

const styles = () => ({
Expand Down Expand Up @@ -50,13 +50,12 @@ class NetPyNEInstantiated extends React.Component {
this.canvasRef = React.createRef();

this.onSelection = this.onSelection.bind(this);
this.applySelection = this.applySelection.bind(this);
this.mapToCanvasData = this.mapToCanvasData.bind(this);
}

onSelection (selectedInstances) {
const { selectInstances, data } = this.props;
selectInstances(this.applySelection(data, selectedInstances));
selectInstances(data, selectedInstances);
}

updateBtnsWithTheme = (removeClass, addClass) => {
Expand All @@ -78,38 +77,6 @@ class NetPyNEInstantiated extends React.Component {
));
}

applySelection (data, selectedInstances) {
const smap = new Map(selectedInstances.map((i) => [i, true]));
const newData = data.map((item) => {
if (smap.get(item.instancePath)) {
return {
...item,
selected: !item.selected,
};
}
return { ...item };
});
const dmap = new Map(newData.map((i) => [i.instancePath, true]));

smap.forEach((value, key) => {
const item = dmap.get(key);
if (!item) {
newData.push({
instancePath: key,
color: undefined,
selected: true,
});
}
});
const canvasData = newData.filter((item) => {
if ((item?.selected !== undefined && item?.selected === false) && item?.color === undefined) {
return false;
}
return true;
});
return canvasData;
}

render () {
const { cameraOptions } = this.state;
const { data } = this.props;
Expand All @@ -135,8 +102,13 @@ class NetPyNEInstantiated extends React.Component {
ref={this.canvasRef}
key="CanvasContainer"
cameraOptions={camOptions}
backgroundColor={bgRegular}
backgroundColor={
this.props.theme === THEMES.BLACK
? canvasBgDark
: (this.props.theme === THEMES.LIGHT ? canvasBgLight : bgRegular)
}
onSelection={this.onSelection}
linesThreshold="10000"
/>
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion webapp/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const MODEL_STATE = {
};

export const DEFAULT_COLOR = {
g: 0.50, b: 0.60, r: 1, a: 0.80,
g: 0.50, b: 0.60, r: 1, a: 1,
};

export const NETPYNE_COMMANDS = {
Expand Down
14 changes: 14 additions & 0 deletions webapp/css/netpyne.less
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,20 @@ body {
.MuiTable-root {
border-collapse: separate;
}

.MuiBackdrop-root {
.MuiGrid-root {
display: block;
width: auto;
margin: 0;
flex: none;
text-align: center;

.MuiCircularProgress-root {
color: @textColor;
}
}
}
}

.instantiatedContainer {
Expand Down
9 changes: 9 additions & 0 deletions webapp/redux/actions/general.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const SET_THEME = 'SET_THEME';
export const ADD_CANVAS_INSTANCES = 'ADD_CANVAS_INSTANCES';
export const CHANGE_INSTANCE_COLOR = 'CHANGE_INSTANCE_COLOR';
export const REMOVE_CANVAS_INSTANCES = 'REMOVE_CANVAS_INSTANCES';
export const SELECT_INSTANCE = 'SELECT_INSTANCE';

// Actions
export const updateCards = { type: UPDATE_CARDS };
Expand Down Expand Up @@ -112,3 +113,11 @@ export const removeInstancesFromCanvas = (instances) => ({
type: REMOVE_CANVAS_INSTANCES,
instances,
});

export const selectInstances = (instance, selectedInstances) => ({
type: SELECT_INSTANCE,
data: {
instance,
selectedInstances,
},
});
31 changes: 31 additions & 0 deletions webapp/redux/reducers/general.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,33 @@ export const GENERAL_DEFAULT_STATE = {
instances: [],
};

const applySelection = (data, selectedInstances) => {
const smap = new Map(selectedInstances.map((i) => [i, true]));
const newData = data.map((item) => ({
...item,
selected: false,
}));
const dmap = new Map(newData.map((i) => [i.instancePath, true]));

smap.forEach((value, key) => {
const item = dmap.get(key);
if (!item) {
newData.push({
instancePath: key,
color: undefined,
selected: true,
});
}
});
const canvasData = newData.filter((item) => {
if ((item?.selected !== undefined && item?.selected === false) && item?.color === undefined) {
return false;
}
return true;
});
return canvasData;
};

// reducer function
export default function reduceGeneral (state = GENERAL_DEFAULT_STATE, action) {
switch (action.type) {
Expand Down Expand Up @@ -76,6 +103,10 @@ export default function reduceGeneral (state = GENERAL_DEFAULT_STATE, action) {
case Actions.REMOVE_CANVAS_INSTANCES: {
return { ...state };
}
case Actions.SELECT_INSTANCE: {
const newData = applySelection(action.data.instance, action.data.selectedInstances);
return { ...state, instances: [...newData] };
}
default: {
return state;
}
Expand Down