Task 174: .ELC File Format

Task 174: .ELC File Format

File Format Specifications for .ELC

The .ELC file format is the ASA electrode location file format used in EEG and neurological analysis to store 3D positions of electrodes. It is a simple text-based format consisting of a header with metadata and sections for positions and labels.

1. List of Properties Intrinsic to the File Format

  • ReferenceLabel: The reference type for the electrode positions (e.g., 'avg' for average reference).
  • UnitPosition: The unit of measurement for the coordinates (e.g., 'mm' for millimeters).
  • NumberPositions: The total number of electrodes/positions in the file (an integer).
  • Positions: A list of 3D coordinates, each as three floating-point numbers (X, Y, Z) for each electrode.
  • Labels: A list of string labels identifying each electrode (e.g., 'Cz', 'Fp1').

3. Ghost Blog Embedded HTML JavaScript for Drag and Drop

This is an HTML snippet with JavaScript that can be embedded in a Ghost blog post. It creates a drop zone where a user can drag and drop an .ELC file. The script reads the file, parses it, extracts the properties, and displays them on the screen.

Drag and drop .ELC file here

4. Python Class for .ELC Files

import sys

class ELCFile:
    def __init__(self):
        self.reference_label = ''
        self.unit_position = ''
        self.number_positions = 0
        self.positions = []
        self.labels = []

    def read(self, filename):
        with open(filename, 'r') as f:
            lines = f.readlines()
        section = ''
        for line in lines:
            line = line.strip()
            if line.startswith('#'):
                continue
            if line.startswith('ReferenceLabel'):
                self.reference_label = line.split()[1]
            elif line.startswith('UnitPosition'):
                self.unit_position = line.split()[1]
            elif line.startswith('NumberPositions'):
                self.number_positions = int(line.split('=')[1].strip())
            elif line == 'Positions':
                section = 'positions'
            elif line == 'Labels':
                section = 'labels'
            elif section == 'positions' and line:
                coords = list(map(float, line.split()))
                if len(coords) == 3:
                    self.positions.append(coords)
            elif section == 'labels' and line:
                self.labels.append(line)
    
    def print_properties(self):
        print(f"ReferenceLabel: {self.reference_label}")
        print(f"UnitPosition: {self.unit_position}")
        print(f"NumberPositions: {self.number_positions}")
        print("Positions:")
        for pos in self.positions:
            print(pos)
        print("Labels:")
        for label in self.labels:
            print(label)
    
    def write(self, filename):
        with open(filename, 'w') as f:
            f.write('# ASA electrode file\n')
            f.write(f"ReferenceLabel {self.reference_label}\n")
            f.write(f"UnitPosition {self.unit_position}\n")
            f.write(f"NumberPositions= {self.number_positions}\n")
            f.write("Positions\n")
            for pos in self.positions:
                f.write(f"{pos[0]} {pos[1]} {pos[2]}\n")
            f.write("Labels\n")
            for label in self.labels:
                f.write(f"{label}\n")

# Example usage
if __name__ == "__main__":
    if len(sys.argv) > 1:
        elc = ELCFile()
        elc.read(sys.argv[1])
        elc.print_properties()

5. Java Class for .ELC Files

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class ELCFile {
    private String referenceLabel = "";
    private String unitPosition = "";
    private int numberPositions = 0;
    private List<double[]> positions = new ArrayList<>();
    private List<String> labels = new ArrayList<>();

    public void read(String filename) throws IOException {
        try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
            String line;
            String section = "";
            while ((line = br.readLine()) != null) {
                line = line.trim();
                if (line.startsWith("#")) continue;
                if (line.startsWith("ReferenceLabel")) {
                    referenceLabel = line.split("\\s+")[1];
                } else if (line.startsWith("UnitPosition")) {
                    unitPosition = line.split("\\s+")[1];
                } else if (line.startsWith("NumberPositions")) {
                    numberPositions = Integer.parseInt(line.split("[= ]+")[1]);
                } else if (line.equals("Positions")) {
                    section = "positions";
                } else if (line.equals("Labels")) {
                    section = "labels";
                } else if ("positions".equals(section) && !line.isEmpty()) {
                    String[] coordsStr = line.split("\\s+");
                    if (coordsStr.length == 3) {
                        double[] coords = new double[3];
                        coords[0] = Double.parseDouble(coordsStr[0]);
                        coords[1] = Double.parseDouble(coordsStr[1]);
                        coords[2] = Double.parseDouble(coordsStr[2]);
                        positions.add(coords);
                    }
                } else if ("labels".equals(section) && !line.isEmpty()) {
                    labels.add(line);
                }
            }
        }
    }

    public void printProperties() {
        System.out.println("ReferenceLabel: " + referenceLabel);
        System.out.println("UnitPosition: " + unitPosition);
        System.out.println("NumberPositions: " + numberPositions);
        System.out.println("Positions:");
        for (double[] pos : positions) {
            System.out.println(pos[0] + " " + pos[1] + " " + pos[2]);
        }
        System.out.println("Labels:");
        for (String label : labels) {
            System.out.println(label);
        }
    }

    public void write(String filename) throws IOException {
        try (PrintWriter pw = new PrintWriter(new FileWriter(filename))) {
            pw.println("# ASA electrode file");
            pw.println("ReferenceLabel " + referenceLabel);
            pw.println("UnitPosition " + unitPosition);
            pw.println("NumberPositions= " + numberPositions);
            pw.println("Positions");
            for (double[] pos : positions) {
                pw.println(pos[0] + " " + pos[1] + " " + pos[2]);
            }
            pw.println("Labels");
            for (String label : labels) {
                pw.println(label);
            }
        }
    }

    public static void main(String[] args) throws IOException {
        if (args.length > 0) {
            ELCFile elc = new ELCFile();
            elc.read(args[0]);
            elc.printProperties();
        }
    }
}

6. JavaScript Class for .ELC Files

class ELCFile {
  constructor() {
    this.referenceLabel = '';
    this.unitPosition = '';
    this.numberPositions = 0;
    this.positions = [];
    this.labels = [];
  }

  read(text) {
    const lines = text.trim().split('\n');
    let section = '';
    lines.forEach((line) => {
      line = line.trim();
      if (line.startsWith('#')) return;
      if (line.startsWith('ReferenceLabel')) {
        this.referenceLabel = line.split(/\s+/)[1];
      } else if (line.startsWith('UnitPosition')) {
        this.unitPosition = line.split(/\s+/)[1];
      } else if (line.startsWith('NumberPositions')) {
        this.numberPositions = parseInt(line.split(/[= ]+/)[1], 10);
      } else if (line === 'Positions') {
        section = 'positions';
      } else if (line === 'Labels') {
        section = 'labels';
      } else if (section === 'positions' && line) {
        const coords = line.split(/\s+/).map(parseFloat);
        if (coords.length === 3) this.positions.push(coords);
      } else if (section === 'labels' && line) {
        this.labels.push(line);
      }
    });
  }

  printProperties() {
    console.log(`ReferenceLabel: ${this.referenceLabel}`);
    console.log(`UnitPosition: ${this.unitPosition}`);
    console.log(`NumberPositions: ${this.numberPositions}`);
    console.log('Positions:');
    this.positions.forEach(pos => console.log(pos));
    console.log('Labels:');
    this.labels.forEach(label => console.log(label));
  }

  write() {
    let content = '# ASA electrode file\n';
    content += `ReferenceLabel ${this.referenceLabel}\n`;
    content += `UnitPosition ${this.unitPosition}\n`;
    content += `NumberPositions= ${this.numberPositions}\n`;
    content += 'Positions\n';
    this.positions.forEach(pos => content += `${pos[0]} ${pos[1]} ${pos[2]}\n`);
    content += 'Labels\n';
    this.labels.forEach(label => content += `${label}\n`);
    return content;
  }
}

// Example usage (assuming text from file is provided)
const elc = new ELCFile();
// elc.read(fileText);
// elc.printProperties();

7. C Class for .ELC Files

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_LINE 256
#define MAX_POSITIONS 1024

typedef struct {
    char referenceLabel[64];
    char unitPosition[64];
    int numberPositions;
    double positions[MAX_POSITIONS][3];
    char labels[MAX_POSITIONS][64];
} ELCFile;

void readELC(ELCFile *elc, const char *filename) {
    FILE *fp = fopen(filename, "r");
    if (!fp) {
        perror("Failed to open file");
        return;
    }

    char line[MAX_LINE];
    char section[64] = "";
    elc->numberPositions = 0;
    int posIndex = 0;
    int labelIndex = 0;

    while (fgets(line, MAX_LINE, fp)) {
        char *trimmed = strtok(line, "\n");
        if (trimmed[0] == '#') continue;
        if (strstr(trimmed, "ReferenceLabel")) {
            sscanf(trimmed, "ReferenceLabel %s", elc->referenceLabel);
        } else if (strstr(trimmed, "UnitPosition")) {
            sscanf(trimmed, "UnitPosition %s", elc->unitPosition);
        } else if (strstr(trimmed, "NumberPositions")) {
            sscanf(trimmed, "NumberPositions= %d", &elc->numberPositions);
        } else if (strcmp(trimmed, "Positions") == 0) {
            strcpy(section, "positions");
        } else if (strcmp(trimmed, "Labels") == 0) {
            strcpy(section, "labels");
        } else if (strcmp(section, "positions") == 0 && trimmed[0] != '\0') {
            sscanf(trimmed, "%lf %lf %lf", &elc->positions[posIndex][0], &elc->positions[posIndex][1], &elc->positions[posIndex][2]);
            posIndex++;
        } else if (strcmp(section, "labels") == 0 && trimmed[0] != '\0') {
            strcpy(elc->labels[labelIndex], trimmed);
            labelIndex++;
        }
    }
    fclose(fp);
}

void printProperties(ELCFile *elc) {
    printf("ReferenceLabel: %s\n", elc->referenceLabel);
    printf("UnitPosition: %s\n", elc->unitPosition);
    printf("NumberPositions: %d\n", elc->numberPositions);
    printf("Positions:\n");
    for (int i = 0; i < elc->numberPositions; i++) {
        printf("%f %f %f\n", elc->positions[i][0], elc->positions[i][1], elc->positions[i][2]);
    }
    printf("Labels:\n");
    for (int i = 0; i < elc->numberPositions; i++) {
        printf("%s\n", elc->labels[i]);
    }
}

void writeELC(ELCFile *elc, const char *filename) {
    FILE *fp = fopen(filename, "w");
    if (!fp) {
        perror("Failed to open file");
        return;
    }

    fprintf(fp, "# ASA electrode file\n");
    fprintf(fp, "ReferenceLabel %s\n", elc->referenceLabel);
    fprintf(fp, "UnitPosition %s\n", elc->unitPosition);
    fprintf(fp, "NumberPositions= %d\n", elc->numberPositions);
    fprintf(fp, "Positions\n");
    for (int i = 0; i < elc->numberPositions; i++) {
        fprintf(fp, "%f %f %f\n", elc->positions[i][0], elc->positions[i][1], elc->positions[i][2]);
    }
    fprintf(fp, "Labels\n");
    for (int i = 0; i < elc->numberPositions; i++) {
        fprintf(fp, "%s\n", elc->labels[i]);
    }
    fclose(fp);
}

int main(int argc, char *argv[]) {
    if (argc > 1) {
        ELCFile elc;
        readELC(&elc, argv[1]);
        printProperties(&elc);
    }
    return 0;
}