The gui_download function is used to download data from the application to the location selected by the user. Downloading data is quite straightforward in local mode, but because the same code should also work in deployed mode, some extra steps need to be taken. The workflow is as follows:

  1. The user clicks a button that triggers event downloadStart. In gui_init, you can call myButton.setEvent("downloadStart") to set this event for a specific button.
  2. Application-specific function gui_download is triggered. This function should define the file name and the data to return in the payload. This is described below.
  3. Simian GUI creates a file from the data specified by gui_download.
  4. The user selects the location to save the file.

The gui_download function should assign the download field of the payload. The download field is a dict/struct with the following fields:

  • fileContents: Base64 encoded version of the data to download. In Matlab, you can use the function to Base64-encode a bytestream representing the data you want to encode.
  • fileName: The name of the file to download. This includes an extension but excludes a path.
  • fileContentType: The content type. For example '*.zip'.

Multiple files can be downloaded at once using a zip-file. The following example illustrates how this could be achieved with gui_download:

import base64
import os.path
from pandas import DataFrame
import shutil
import tempfile

def gui_download(meta_data: dict, payload: dict) -> dict:
    """Download Example."""
    # Create a dummy table for the example.
    ones_table = DataFrame(
        [[1] * 4] * 3, columns=['A', 'B', 'C', 'D'], index=["Row 1", "Row 2", "Row 3"])

    # Create a temporary folder and create a csv and json file with the DataFrame in it.
    session_folder = utils.getSessionFolder(meta_data, create=True)
    temp_folder = tempfile.TemporaryDirectory(dir=session_folder)
    ones_table.to_csv(os.path.join(, 'ones_table.csv'))
    ones_table.to_json(os.path.join(, 'ones_table.json'))

    # Create a new temp folder to create the zip file in. (If you reuse the previous temp
    # folder, the zip file would contain a stub version of itself.)
    temp_zip_file = os.path.join(tempfile.TemporaryDirectory(dir=session_folder).name, 'Results')

    with open(shutil.make_archive(temp_zip_file, "zip",, 'rb') as file:
        # Open the zip file as a binary file, read its contents and base64 encode it.
        encoded = base64.b64encode(
        payload = {
            'download': {
                'fileContents': encoded.decode("utf-8"),
                'fileContentType': 'application/zip',
                'fileName': ""

    return payload
function payload = guiDownload(metaData, payload)
    % Save the data to multiple files.
    sessionFolder   = utils.getSessionFolder(metaData, "Create", true);
    csvFile         = fullfile(sessionFolder, "Measurements.csv");
    coeffFile       = fullfile(sessionFolder, "Coefficients.txt");
    writetable(myTable, csvFile)
    writematrix(myCoefficients, coeffFile)

    % Create a zip file.
    zipFileName     = "";
    zipFileNameFull = fullfile(sessionFolder, zipFileName);
    zip(zipFileNameFull, [csvFile, coeffFile]);

    % Base64-encode the zip file.
    fid             = fopen(zipFileNameFull, "r");
    fileContents    = fread(fid, "uint8=>uint8");
    fclose(fid);       =;    = "*.zip";           = zipFileName;

The code above uses utility function getSessionFolder. Its syntax is:

session_folder = utils.getSessionFolder(meta_data, create=True)
sessionFolder = utils.getSessionFolder(metaData, "Create", true);

The first input is the metadata. Optionally, specify whether to create the session folder if it does not exist yet.

When there are multiple different download options, each with their own button, they all have to trigger a downloadStart event. You can differentiate between them by looking at payload.key, which is the key of the button that was pushed.

Note: The session folder will be removed when the session is ended using the Close button. For files in other locations, it is the responsiblity of the developer to ensure they are cleaned up appropriately, for instance using gui_close.