Skip to content

State Sharing

Jingpeng Wu edited this page Jul 13, 2018 · 2 revisions

Certain objects in the neuroglancer client complies with the trackable interface:

export class SomethingTrackable implements Trackable {
  get value()
  set value(newValue)
  changed = new Signal();
  toJSON()
  restoreState(json: any)
  reset()
};

These object can be registers so that every time there is a change on them, toJSON is called and the output updates the url and sent to the python state server. Or the opposite process, when the url changes or the python state server sends a new state restoreState is called.

In the neuroglancer code (src/neuroglancer/viewer.ts) you can find the objects being tracked.:

registerTrackable('layers', this.layerSpecification);
registerTrackable('navigation', this.navigationState);
registerTrackable('showAxisLines', this.showAxisLines);
registerTrackable('showScaleBar', this.showScaleBar);

registerTrackable('perspectiveOrientation', this.perspectiveNavigationState.pose.orientation);
registerTrackable('perspectiveZoom', this.perspectiveNavigationState.zoomFactor);
registerTrackable('showSlices', this.showPerspectiveSliceViews);
registerTrackable('layout', this.layoutName);
registerTrackable('stateURL', this.stateServer);

The actual sincronization between url(and state server) with the trackable is happening at (src/neuroglancer/url_hash_state.ts) which defines registerTrackable and schedules the update to every 0.2 seconds. It also implements the comunication to the state server:

  sock = new SockJS(url);
  sock.onopen = function() {
    let state = getCurrentState();
    sock.send(JSON.stringify(state))
  };
  sock.onmessage = function(e: any) {
    let state = JSON.parse(e.data);
    updateTrackedObjects(state);
  };
  sock.onclose = function() {
    console.log('closing socket connection');
  };

Similarly the server(state.py) communicates with the client by:

clients = set()
n_messages = 0
class Connection(SockJSConnection):
    def on_open(self, info):
        """
        info is an object which contains caller IP address, query string
        parameters and cookies associated with this request"""
        # When new client comes in, will add it to the clients list
        clients.add(self)
       
    def on_message(self, json_state):
        """
        This will call initialize_state or on_state_change depening on if it is
        the first message recieved.
        """
        state = json.JSONDecoder(object_pairs_hook=OrderedDict).decode(json_state)
        global n_messages

        if not n_messages: #first message ever
            new_state = self.initialize_state(state)
        else:
            new_state = self.on_state_change(state)

        n_messages += 1
        if new_state: #if you return a new state send it back
            self.broadcast(clients, json.dumps(new_state))
        
        
    def on_close(self):
        # If client disconnects, remove him from the clients list
        clients.remove(self)

    def initialize_state(self, state):
        """
        This is called once the connection is stablished.
        """
        pass

    def on_state_change(self, state):
        """
        This is called every time there is a new state available
        (except the very first time).
        """
        print(state)

Usage

  • start a python session (can be in a jupyter notebook or not)
  • import the controller module (e.g. import controller as C)
  • call the controller constructor function c = C.controller()
  • create a neuroglancer browser session with the layers you want to view
  • at the end of the url before the ending '}', add _'stateServer':'https://localhost:9999' (you can customize the port number in the controller module or constructor function call)
  • travel to your localhost port, and add a browser security exception for the controller
  • refresh your neuroglancer page, you should see state initialized in your python session -you should now be able to set the neuroglancer focus point, and display points using the c.set_pos and c.set_pts functions respectively -If your segmentation layer is called 'seg', you can also set which segments are selected using the c.set_segs function

Trouble Shooting

the aio-http package version is not matched

  • pip install sockjs-tornado

the parameter number of sockjs do not match

  • pip install tornado==4.5.2