-
Notifications
You must be signed in to change notification settings - Fork 8
File Adapter Tutorial
A FileAdapter is a plugin that defines how NANSEN reads and writes a specific file format. FileAdapters let you load and save data from different formats using simple, consistent commands—nansen.load() and nansen.save()—no matter which file type you’re working with. An internal registry matches each file to the appropriate adapter automatically.
FileAdapters are easily extensible: users can add support for new formats and share them with others.
- Load built-in demo data using FileAdapters.
- Discover which adapters are available in your installation.
- Create your first custom FileAdapter that returns a consistent table from multiple file types.
- Extend an adapter to support additional extensions.
- Save data with
nansen.save.
% Load a supported file format using NANSEN
data = nansen.load('patients.mat');
% Check what's in the data
dataYou should see a MATLAB struct with fields like Gender, LastName, Age, etc.
data =
struct with fields:
Gender: {100×1 cell}
LastName: {100×1 cell}
Age: [100×1 double]
Weight: [100×1 double]
Smoker: [100×1 logical]
Systolic: [100×1 double]
Diastolic: [100×1 double]
Height: [100×1 double]
Location: {100×1 cell}
SelfAssessedHealthStatus: {100×1 cell}
Note
In this example, NANSEN uses a MatFile adapter that wraps MATLAB’s load to read .mat files. For other file formats, we can use existing file adapters or create new ones (see Creating your first file adapter)
Let's try to load another file format. The patients demo file is also available as an excel file:
% Load another supported file format
data = nansen.load('patients.xls');
% Inspect the returned data
dataYou should see a 100×10 table with the same variables.
data =
100×10 table
LastName Gender Age Location Height Weight Smoker Systolic Diastolic SelfAssessedHealthStatus
_____________ __________ ___ _____________________________ ______ ______ ______ ________ _________ ________________________
{'Smith' } {'Male' } 38 {'County General Hospital' } 71 176 true 124 93 {'Excellent'}
{'Johnson' } {'Male' } 43 {'VA Hospital' } 69 163 false 109 77 {'Fair' }
{'Williams' } {'Female'} 38 {'St. Mary's Medical Center'} 64 131 false 125 83 {'Good' }
{'Jones' } {'Female'} 40 {'VA Hospital' } 67 133 false 117 75 {'Fair' }
{'Brown' } {'Female'} 49 {'County General Hospital' } 64 119 false 122 80 {'Good' }
{'Davis' } {'Female'} 46 {'St. Mary's Medical Center'} 68 142 false 121 70 {'Good' }
{'Miller' } {'Female'} 33 {'VA Hospital' } 64 142 true 130 88 {'Good' }
: : : : : : : : : :
The core NANSEN toolbox supports a set of builtin file adapters. We can check out the list of available file adapters:
nansen.dataio.listFileAdapters()>>
FileAdapterName FunctionName SupportedFileTypes DataType IsDynamic
_______________________________ _____________________________________________________________________ ___________________________________ _________________________ _________
"ExcelFile" "nansen.module.general.core.fileadapter.ExcelFile" ".xls" "table" true
"MatFile" "nansen.module.general.core.fileadapter.MatFile" ".mat" "struct" true
"ChiatahDemoFile" "nansen.module.ophys.twophoton.fileadapter.ChiatahDemoFile" "h5" "ImageStack" false
"ImageStack" "nansen.module.general.core.fileadapter.ImageStack" "ini, raw, tif, tiff, avi, h5, tsm" "ImageStack" false
"Numpy2Mat" "nansen.module.general.core.fileadapter.Numpy2Mat" "npy" "struct" false
"RoiGroup" "nansen.module.ophys.twophoton.fileadapter.RoiGroup" "mat, npy" "RoiGroup" false
"RoiSignalArray" "nansen.module.ophys.twophoton.fileadapter.RoiSignalArray" "mat" "RoiSignalArray" false
"ScanImageMultiRoi2PSeries" "nansen.module.ophys.twophoton.fileadapter.ScanImageMultiRoi2PSeries" "tif, tiff" "ImageStack" false
"SciScanXYTSeries" "nansen.module.ophys.twophoton.fileadapter.SciScanXYTSeries" "raw" "ImageStack" false
Note
The list shows adapters currently registered in your environment (core + any installed modules). It may look different from this tutorial. That’s expected.
Now that you’ve seen how the built‑in adapters work, you may run into a format that isn’t supported—or simply want more control over how your data is read. When that happens, the next step is to create a custom FileAdapter.
Let's revisit the patients.mat demo file, and create a file adapter that reads the data into a nicely formatted table instead of a structure.
nansen.createFileAdapter(...
'Name', 'PatientsTable', ...
'SupportedFileTypes', '.mat', ...
'DataType', 'table', ...
'FileExpression', 'patients');Tip
It is also possible to create a FileAdapter interactively using nansen.interactive.createFileAdapter()
After registration, MATLAB automatically creates this folder:
+PatientsTable/
├── fileadapter.json % File adapter metadata
└── read.m % Read function; opened automatically in editor
Fill in the read.m function:
function data = read(filename)
%READ Read patients.mat file and output a table
%
% data = read(filename) reads a patients .mat file and returns a table
% where each row represents patient information.
S = load(filename);
T = struct2table(S); % Convert to table
% Convert text values to string
T.LastName = string(T.LastName);
T.Location = string(T.Location);
% Convert discrete text values to categorical
T.Gender = categorical(T.Gender);
T.SelfAssessedHealthStatus = categorical(T.SelfAssessedHealthStatus);
data = T; % Assign T to the data output
endNow we can use the new file adapter to load the same file:
data = nansen.load('patients.mat', 'FileAdapter', 'PatientsTable');
% Display the data
dataYou should see the same table as before but with better use of data types.
data =
100×10 table
Gender LastName Age Weight Smoker Systolic Diastolic Height Location SelfAssessedHealthStatus
______ ___________ ___ ______ ______ ________ _________ ______ ___________________________ ________________________
Male "Smith" 38 176 true 124 93 71 "County General Hospital" Excellent
Male "Johnson" 43 163 false 109 77 69 "VA Hospital" Fair
Female "Williams" 38 131 false 125 83 64 "St. Mary's Medical Center" Good
Female "Jones" 40 133 false 117 75 67 "VA Hospital" Fair
Female "Brown" 49 119 false 122 80 64 "County General Hospital" Good
: : : : : : : : : :
Male "Alexander" 25 171 true 128 99 69 "County General Hospital" Good
Male "Russell" 44 188 true 124 92 69 "VA Hospital" Good
Male "Griffin" 49 186 false 119 74 70 "County General Hospital" Fair
Male "Diaz" 45 172 true 136 93 68 "County General Hospital" Good
Male "Hayes" 48 177 false 114 86 66 "County General Hospital" Fair
Note
Specifying the name-value pair 'FileAdapter', 'PatientsTable' is optional here, but is shown for demonstration. The file adapter registry should match the new file adapter based on the combination of the filename and the filetype, but sometimes multiple file adapters could exist for a given file type.
We could also use our new file adapter to load the excel file. Let's edit the file adapter:
nansen.editFileAdapter('PatientsTable')This will change the current working directory in MATLAB into the folder where the file adapter definition is located.
- Add ".xls" to the SupportedFileTypes in
fileadapter.json
"SupportedFileTypes": [
".mat",
".xls"
],- Replace line 7-8 in read.m with this snippet
if endsWith(filename, '.mat')
S = load(filename);
T = struct2table(S); % Convert to table
elseif endsWith(filename, '.xls')
T = readtable(filename);
endNow we have a file adapter that can read both .mat and .xls files and present the data in the same way. Try it out:
data = nansen.load('patients.xls', 'FileAdapter', 'PatientsTable');
% Display the data
dataLet's create an adapter for files with this structure:
example_data.myformat
{
"metadata": {
"description": "Sample time series data",
"sampleRate": 1000,
"channels": ["voltage", "current"]
},
"data": [
[0.001, 1.2, 0.3],
[0.002, 1.1, 0.35],
[0.003, 0.9, 0.4]
]
}% Open the interactive registration dialog
nansen.interactive.createFileAdapter();This opens a dialog where you fill in:
- Name: MyFormat
- File Extensions: myformat
- Data Type: struct (MATLAB class of returned data)
- Description: JSON format with metadata and numeric data
After registration, MATLAB automatically creates this structure:
+MyFormat/
├── fileadapter.json
└── read.m % Opened automatically in editor
Fill in the read.m function:
function data = read(filename)
%READ Read MyFormat file
% data = read(filename) reads a MyFormat file and returns a structure
% with metadata and data fields.
% Read JSON file
fileContent = fileread(filename);
jsonData = jsondecode(fileContent);
% Extract metadata and data
data = struct();
data.metadata = jsonData.metadata;
data.time = jsonData.data(:, 1);
data.channels = struct();
% Map data to channel names
for i = 1:length(jsonData.metadata.channels)
channelName = jsonData.metadata.channels{i};
data.channels.(channelName) = jsonData.data(:, i+1);
end
end% Test with the example file
data = nansen.load('example_data.myformat');
% Verify the structure
disp(data.metadata)
plot(data.time, data.channels.voltage)Create write.m in the same directory:
function write(filename, data)
%WRITE Write data to MyFormat file
% write(filename, data) saves data to a MyFormat JSON file
% Reconstruct the file format
output = struct();
output.metadata = data.metadata;
% Combine time and channel data
channelNames = fieldnames(data.channels);
dataMatrix = [data.time];
for i = 1:length(channelNames)
dataMatrix = [dataMatrix, data.channels.(channelNames{i})];
end
output.data = dataMatrix;
% Write JSON file
jsonText = jsonencode(output, 'PrettyPrint', true);
fid = fopen(filename, 'w');
fprintf(fid, '%s', jsonText);
fclose(fid);
end% Save data as a mat file
nansen.save('output.mat', data);
% Save data in your custom format
nansen.save('output.myformat', data);- Explanation: How the adapter registry resolves files and precedence rules.
- How-to guides:
- Package and share an adapter
- Add write support and round-trip tests
- Handle large files and streaming reads
- Reference: Minimal
fileadapter.jsonschema and adapter API.