Skip to content

End User

We refer to any component that requests results from Pyneal during a scan as an End User. For instance, a potential End User could be task presentation software that periodically makes requests for analysis results in order to update a neurofeedback display for the participant.

Sending requests

Sending a request to Pyneal for the results from a specific volume simply requires you to establish a connection to Pyneal and send the index value of the volume you'd like to request (0-based index). The volume index should be formatted as a 4-character string, with zero-padded as needed. For instance, to request the results from the 9th volume (i.e. index 8), the request would be formatted as 0008.

Here is an example, written in python for how you might send a request for the 9th volume:

import socket

# socket configs
host = '127.0.0.1'  # Pyneal address
port = 5556     # results server port number

# connect to the results server of Pyneal
clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientSocket.connect((host, port))

# format request for the 9th volume (index 8).
request = '0008'

# send the request
clientSocket.send(request.encode())

This approach can be incorporated into any End User application (e.g. an experimental task) to request specific results throughout a scan.

Parsing Responses

Continuing from the previous section, once the results server on Pyneal receives a request for volume index 0008, it will check to see if that volume has arrived and been analyzed yet.

  • If the volume has not arrived, the response will be a JSON message that contains a single key:value pair: "foundResults":False

  • If the volume has arrived, the response will be a JSON message that contains the key:value pair "foundResults":True as well all of the results key:value pairs for that volume. For instance, if the real-time analysis is set to compute the average activation with the selected mask, the response message for volume 0008 may look like {'foundResults': True, 'average':2432}. If you are using a custom analysis script that computes multiple results on each volume, all of those results will appear in the response message. For instance, if you have a custom analysis script that is computing the mean activation separately in 3 ROIs, the response message may look like {'foundResults': True, "roi1_average": 2149.81, "roi2_average": 2519.11, "roi3_average": 2543.61}

For reference, here is the code that the results server uses to send responses:

def sendResults(self, connection, results):
    """
    Format the results dict to a json string, and send results to the client.
    Message will be sent in 2 waves: first a header indicating the msg length,
    and then the message itself
    """
    # format as json string and then convert to bytes
    formattedMsg = '{}\n'.format(json.dumps(results)).encode()

    # send results as formatted message
    connection.sendall(formattedMsg)
    self.logger.debug('Sent result: {}'.format(formattedMsg))

Example Responses

Here are some example of what the JSON responses might look like using different analysis options.

  • Results were not found: The End User requested a volume that has not arrived or been analyzed yet:

    {'foundResults': False}

Pyneal Built-in Analysis Options

  • Average (from GUI): compute the average signal within the specified mask:

    {'foundResults': True, 'average':2432}

  • Weighted Average (from GUI): compute the weighted average within the specified mask, using mask voxels values as weights ("Weighted Mask?" is checked in GUI):

    {'foundResults': True, 'weightedAverage':2432}

  • Median (from GUI): compute the median signal within the specified mask:

    {'foundResults': True, 'median':2432}

  • Weighted Median (from GUI): compute the weighted median within the specified mask, using mask voxel values as weights ("Weighted Mask?" is checked in GUI):

    {'foundResults': True, 'weightedMedian':2432}

Using Custom Analyses

The JSON responses from custom analyses will vary based on your custom analysis script. At a minimum, all responses will contain the 'foundResults' entry.

For instance, if you have a custom analysis script that is computing the mean activation separately in 3 ROIs, the response message may look like:

  • {'foundResults': True, "roi1_average": 2149.81, "roi2_average": 2519.11, "roi3_average": 2543.61}