EELS: Acquisition and Analysis

This tutorial covers how to acquire EELS data using femtus.acquisition and analyze it using the eels package.

Package

Import path

Description

femtus.acquisition

PyJEM.femtus.acquisition

Scan acquisition via FEMTUS

femtus.worksheet

PyJEM.femtus.worksheet

Access acquired dataset

eels

PyJEM.eels

EELS camera setup and analysis

1from PyJEM import eels
2from PyJEM.femtus import acquisition
3from PyJEM.femtus import worksheet

Flow Overview

Section

Description

SI Cube

EELS SI Cube acquisition and analysis (Shape = 'Rectangle')

Line

EELS line-scan acquisition and analysis (Shape = 'Line')

SI Cube

  1. Acquire using femtus.acquisition with setting['Region']['Shape'] = 'Rectangle'

  2. Generate whole spectrum: eels.create_si_cube_whole_spectrum

  3. Get worksheet element: worksheet.get_worksheet_element

  4. Get image-content / graph-content

  5. Apply calibration: eels.set_calibration_result

Line

  1. Acquire using femtus.acquisition with setting['Region']['Shape'] = 'Line'

  2. Generate whole spectrum: eels.create_line_whole_spectrum

  3. Get worksheet element: worksheet.get_worksheet_element

  4. Get graph-content / graph-content

  5. Apply calibration: eels.set_calibration_result

SI Cube

Acquire EELS SI Cube (spectrum image) data using femtus.acquisition with Shape = 'Rectangle', then analyze using the eels package.

API reference: femtus.acquisition | eels

Acquisition

Configure the acquisition settings and start EELS SI Cube acquisition.

  • Set setting['Detectors'] = ['Image', 'EELS'] to enable both image and EELS detectors.

  • Set setting['Region']['Shape'] = 'Rectangle' for SI Cube (spectrum image) acquisition.

 1result = acquisition.get_settings()
 2if result["Settings"]:
 3    setting = result['Settings'][0]
 4else:
 5    setting = {
 6        'Detectors': [],
 7        'Region': {'Left': 0, 'Top': 0, 'Width': 32, 'Height': 32, 'Points': None, 'Shape': 'Rectangle'},
 8        'Conditions': {'DwellTime': 100, 'PixelResolution': 1, 'IsPlayback': False,
 9                       'CollectionMode': {'Mode': 'Sweep', 'Count': 1}},
10        'DriftCorrection': {'Type': 'None', 'Interval': 1, 'CorrectionRegion': None}
11    }
12
13# Select detectors
14setting['Detectors'] = ['Image', 'EELS']
15
16# Set acquisition region for SI Cube
17setting['Region']['Shape'] = 'Rectangle'
18setting['Region']['Width'] = 32
19setting['Region']['Height'] = 32
20
21# Set acquisition conditions
22setting['Conditions']['DwellTime'] = 100              # microseconds
23setting['Conditions']['CollectionMode']['Mode'] = 'Sweep'
24setting['Conditions']['CollectionMode']['Count'] = 1
25
26setting
{'Id': '08274fde-dd82-44c0-906c-d045552c6a43',
 'Detectors': ['Image', 'EELS'],
 'Region': {'Left': 229,
  'Top': 206,
  'Width': 32,
  'Height': 32,
  'Points': None,
  'Shape': 'Rectangle'},
 'Conditions': {'DwellTime': 100,
  'PixelResolution': 1,
  'IsPlayback': False,
  'CollectionMode': {'Mode': 'Sweep', 'Count': 1}},
 'DriftCorrection': {'Type': 'None', 'Interval': 1, 'CorrectionRegion': None}}
1start_result = acquisition.start(setting)
2acquisition_id = start_result['AcquisitionID']
3start_result
{'AcquisitionID': '6b81ab09-a1c9-4bf3-bc7a-c454369354e3',
 'WorksheetID': '6d33305e-8d86-4867-917f-7d959c3398bb',
 'ReferenceDetector': 'VP_ADF_1',
 'Version': '1.0.0'}
1acquisition_result = acquisition.get_acquisition_result(acquisition_id)
2
3for r in acquisition_result['Results']:
4    print(r['DataType'], '->', r['Id'])
5    if r['DataType'] == 'EELS_Cube':
6        eels_cube_id = r['Id']
STEM_Survey -> 2c63baa5-1c41-4aea-81a2-b186d35595fa
STEM_HAADF_SeleArea -> 4eb6b93b-149f-4225-9e09-b5b2f211a24e
EELS_Cube -> 9ca464f7-5e58-4fc5-b42a-9b5fe7a5221a
{'Results': [{'Id': '2c63baa5-1c41-4aea-81a2-b186d35595fa',
   'DataType': 'STEM_Survey'},
  {'Id': '4eb6b93b-149f-4225-9e09-b5b2f211a24e',
   'DataType': 'STEM_HAADF_SeleArea'},
  {'Id': '9ca464f7-5e58-4fc5-b42a-9b5fe7a5221a', 'DataType': 'EELS_Cube'}]}

SI Cube Analysis

The following cells analyze the acquired SI Cube dataset using the eels package. The following example outlines the procedure for analyzing and outputting the results of the whole spectrum.

eels.create_si_cube_whole_spectrum

Generate a whole-area integrated spectrum from the SI Cube dataset.
The returned object contains an Ids list with IDs for the generated datasets (image content and graph content).

1whole_spectrum = eels.create_si_cube_whole_spectrum(eels_cube_id)
2whole_spectrum

worksheet.get_worksheet_element

create_si_cube_whole_spectrum returns a dict with an Ids list containing two entries:

Index

ContentType

Description

0

ImageContent

Retrieved via worksheet.get_image_content()

1

GraphContent

Retrieved via worksheet.get_graph_content()

Use get_worksheet_element to retrieve each dataset by its Id.

1for id in whole_spectrum['Ids']:
2    element = worksheet.get_worksheet_element(id)
3    print(element['ContentSummary']['ContentType'], '->', element['Id'])
ImageContent -> ec2b3897-8040-4dd8-8dff-9b2cb61bf72f
GraphContent -> c283a2b5-7252-4827-ac5c-950624a5c072

ImageContent and GraphContent

Retrieve the image content (Ids[0]) and graph content (Ids[1]) from the worksheet elements.

1# Ids[0]: ImageContent — retrieve with get_image_content
2element = worksheet.get_worksheet_element(whole_spectrum['Ids'][0])
3image_content = worksheet.get_image_content(element['ContentSummary']['Id'])
4image_content
{'Id': '49858513-675f-48a5-af1d-8501e4e453d8',
 'Children': [{'Id': '1734b7c3-dec5-4e1a-b223-5118d3f40187',
   'IsSelected': False,
   'Clump': {'Id': '001eb99e-db3a-4668-9ee6-dd875e1e6231',
    'Information': {'Header': {'Version': '1.0.0',
      'ClumpId': '001eb99e-db3a-4668-9ee6-dd875e1e6231',
      'DataType': 'EELS_Cube',
      'DataSubType': '',
      'DetectorType': 1,
      'ClumpType': 'Clump',
      'Name': 'Cube'},
     'DataInformation': {'TypeInfo': 2,
      'DataBytes': 4,
      'Channel': 1,
      'DimensionLength': 3,
      'Dimensions': [32, 32, 512],
      'ChannelType': 'GrayScale',
      'IsRangeFixed': False,
      'MinimumPossibleIntensity': -1.7976931348623157e+308,
      'MaximumPossibleIntensity': 1.7976931348623157e+308},
     'MeasurementInformation': {'CalibrationCoefficients': [{'Scale': 14.6875,
        'Offset': 0,
        'Unit': 'Nanometer'},
       {'Scale': 14.697265625, 'Offset': 0, 'Unit': 'Nanometer'},
       {'Scale': 2, 'Offset': 0, 'Unit': 'Nanometer'}]},
     'Tags': {'General': {'Instrument': 'JEM-ARM200F',
       'Manufacturer': 'JEOL Ltd.',
       'Comment': '',
       'DateTime': '20260402153944435',
       'ProductName': 'FEMTUS',
       'ProductVersion': '2.0.0.0+8cc42b3fb348c2458c76e358a38bce3fb5cd1063',
       'UpdateDateTime': '20260402153944435',
       'UpdateProductName': 'FEMTUS',
       'UpdateProductVersion': '2.0.0.0+8cc42b3fb348c2458c76e358a38bce3fb5cd1063',
       'AnalysisId': '75f87d81-1242-418e-9d6e-eda2d7417f83',
       'AnalysisDateTime': '20260402153943687',
       'AcquisitionId': 'af9842a2-ec66-476d-9173-79dd2cbec977',
       'AcquisitionDateTime': '20260402153943687'},
      'EELS': {'FilterMode': 'STEM-EELS',
       'FilterSubmode': 'align',
       'DataType': 'Image',
       'Dispersion': 0,
       'CameraLengthCoefficient': 1,
       'MagnificationValue': 1,
       'EnergyLossOffset': 0,
       'DriftTubeVoltage': 0,
       'HighTensionOffset': 0,
       'SectorOffset': 0,
       'SlitMode': 'Out',
       'SlitInserted': False,
       'SlitWidth': 0,
       'EntranceApertureHoleString': 'Out',
       'EntranceApertureInserted': False},
      'ScanGenerator': {},
      'HT': {'GunType': 'Cfeg',
       'AccelerationVoltage': 200000,
       'EnergyShift': 0},
      'EOS': {'OperationMode': 'Scanning',
       'SpotSizeNumber': 0,
       'ConvergenceAngleAlphaNumber': 0,
       'ImageFormingMode': 'MAG',
       'RockingAngle': 0,
       'MagnificationValue': 20000,
       'MagnificationString': 'x20k',
       'CameraLength': 15,
       'CameraLengthString': '1.5cm'},
      'Stage': {'X': {'Position': 0},
       'Y': {'Position': 0},
       'Z': {'Position': 0},
       'TX': {'Position': 0},
       'TY': {'Position': 0},
       'TZ': {'Position': 0},
       'PX': {'Position': 0},
       'PY': {'Position': 0},
       'PZ': {'Position': 0}},
      'Aperture': {'CL': {'ApertureHoleString': '0'},
       'CL2': {'ApertureHoleString': '0'},
       'OL': {'ApertureHoleString': '0'},
       'SA': {'ApertureHoleString': '0'}},
      'Detector': {'DetectorKind': 'Test Camera Name 0',
       'Manufacturer': 'Test Vendor',
       'ModelCode': 'Test Camera Name 0',
       'ModelDisplayName': 'Test Camera Name 0',
       'PixelsPerMeter': {'Horizontal': 200000, 'Vertical': 200000},
       'ImagingArea': {'X': 256, 'Y': 128, 'Width': 512, 'Height': 512},
       'BinningSize': {'X': 2, 'Y': 2},
       'SoftwareCroppingArea': {'X': 0, 'Y': 0, 'Width': 512, 'Height': 512},
       'SoftwareBinningSize': {'X': 1, 'Y': 1},
       'ExposureTimeValue': 100,
       'FrameIntegration': 1}}},
    'ViewInformation': {'Header': {'Version': '2.0.0',
      'ClumpId': '001eb99e-db3a-4668-9ee6-dd875e1e6231'},
     'Tags': {}}}}]}
1# Ids[1]: GraphContent — retrieve with get_graph_content
2element = worksheet.get_worksheet_element(whole_spectrum['Ids'][1])
3graph_content = worksheet.get_graph_content(element['ContentSummary']['Id'])
4graph_content
{'Id': '68a11875-7cd3-41c0-9d4c-947d18603ada',
 'Children': [{'Id': '80f1c410-8884-46e6-bd54-1e668764ae94',
   'IsSelected': False,
   'Clump': {'Id': '744b96a9-914e-4aea-abd3-464ac6b4d7a9',
    'Information': {'Header': {'Version': '1.0.0',
      'ClumpId': '744b96a9-914e-4aea-abd3-464ac6b4d7a9',
      'DataType': 'EELS_Cube_Spectrum',
      'DataSubType': '',
      'DetectorType': 1,
      'ClumpType': 'Clump',
      'Name': 'Spectrum'},
     'DataInformation': {'TypeInfo': 2,
      'DataBytes': 8,
      'Channel': 1,
      'DimensionLength': 1,
      'Dimensions': [512],
      'ChannelType': 'GrayScale',
      'IsRangeFixed': False,
      'MinimumPossibleIntensity': -1.7976931348623157e+308,
      'MaximumPossibleIntensity': 1.7976931348623157e+308},
     'MeasurementInformation': {'CalibrationCoefficients': [{'Scale': 2,
        'Offset': 0,
        'Unit': 'eV'}]},
     'Tags': {'General': {'Instrument': 'JEM-ARM200F',
       'Manufacturer': 'JEOL Ltd.',
       'Comment': '',
       'DateTime': '20260402153944435',
       'ProductName': 'FEMTUS',
       'ProductVersion': '2.0.0.0+8cc42b3fb348c2458c76e358a38bce3fb5cd1063',
       'UpdateDateTime': '20260402153944435',
       'UpdateProductName': 'FEMTUS',
       'UpdateProductVersion': '2.0.0.0+8cc42b3fb348c2458c76e358a38bce3fb5cd1063',
       'AnalysisId': '2e127b69-0af7-4f1c-8051-e223dcd35342',
       'AnalysisDateTime': '20260402164653468',
       'AcquisitionId': 'af9842a2-ec66-476d-9173-79dd2cbec977',
       'AcquisitionDateTime': '20260402153943687'},
      'EELS': {'FilterMode': 'STEM-EELS',
       'FilterSubmode': 'align',
       'DataType': 'Image',
       'Dispersion': 0,
       'CameraLengthCoefficient': 1,
       'MagnificationValue': 1,
       'EnergyLossOffset': 0,
       'DriftTubeVoltage': 0,
       'HighTensionOffset': 0,
       'SectorOffset': 0,
       'SlitMode': 'Out',
       'SlitInserted': False,
       'SlitWidth': 0,
       'EntranceApertureHoleString': 'Out',
       'EntranceApertureInserted': False},
      'ScanGenerator': {},
      'HT': {'GunType': 'Cfeg',
       'AccelerationVoltage': 200000,
       'EnergyShift': 0},
      'EOS': {'OperationMode': 'Scanning',
       'SpotSizeNumber': 0,
       'ConvergenceAngleAlphaNumber': 0,
       'ImageFormingMode': 'MAG',
       'RockingAngle': 0,
       'MagnificationValue': 20000,
       'MagnificationString': 'x20k',
       'CameraLength': 15,
       'CameraLengthString': '1.5cm'},
      'Stage': {'X': {'Position': 0},
       'Y': {'Position': 0},
       'Z': {'Position': 0},
       'TX': {'Position': 0},
       'TY': {'Position': 0},
       'TZ': {'Position': 0},
       'PX': {'Position': 0},
       'PY': {'Position': 0},
       'PZ': {'Position': 0}},
      'Aperture': {'CL': {'ApertureHoleString': '0'},
       'CL2': {'ApertureHoleString': '0'},
       'OL': {'ApertureHoleString': '0'},
       'SA': {'ApertureHoleString': '0'}},
      'Detector': {'DetectorKind': 'Test Camera Name 0',
       'Manufacturer': 'Test Vendor',
       'ModelCode': 'Test Camera Name 0',
       'ModelDisplayName': 'Test Camera Name 0',
       'PixelsPerMeter': {'Horizontal': 200000, 'Vertical': 200000},
       'ImagingArea': {'X': 256, 'Y': 128, 'Width': 512, 'Height': 512},
       'BinningSize': {'X': 2, 'Y': 2},
       'SoftwareCroppingArea': {'X': 0, 'Y': 0, 'Width': 512, 'Height': 512},
       'SoftwareBinningSize': {'X': 1, 'Y': 1},
       'ExposureTimeValue': 100,
       'FrameIntegration': 1},
      'Processings': [{'Parents': ['001eb99e-db3a-4668-9ee6-dd875e1e6231'],
        'ProcessType': 'ExtractSpectrum',
        'Parameters': [{'ExtractRoi': {'ShapeType': 'Rectangle',
           'Shape': {'X': 0, 'Y': 0, 'Width': 32, 'Height': 32}}}]}]}},
    'ViewInformation': {'Header': {'Version': '2.0.0',
      'ClumpId': '744b96a9-914e-4aea-abd3-464ac6b4d7a9'},
     'Tags': {}}}},
  {'Id': '7a4a064c-4df0-4dda-8d52-c56090f3a1bf',
   'IsSelected': False,
   'Clump': {'Id': '63d2b3a0-db89-433c-9430-4b1ed550d39e',
    'Information': {'Header': {'Version': '1.0.0',
      'ClumpId': '63d2b3a0-db89-433c-9430-4b1ed550d39e',
      'DataType': 'EELS_Cube_Spectrum',
      'DataSubType': '',
      'DetectorType': 0,
      'ClumpType': 'Clump',
      'Name': 'H-K Background'},
     'DataInformation': {'TypeInfo': 2,
      'DataBytes': 8,
      'Channel': 1,
      'DimensionLength': 1,
      'Dimensions': [30],
      'ChannelType': '',
      'IsRangeFixed': False,
      'MinimumPossibleIntensity': -1.7976931348623157e+308,
      'MaximumPossibleIntensity': 1.7976931348623157e+308},
     'MeasurementInformation': {'CalibrationCoefficients': [{'Scale': 2,
        'Offset': 0,
        'Unit': 'eV'}]},
     'Tags': {'General': {'AnalysisId': '9d7668b6-bbee-4789-9e10-3eab1346a470',
       'AnalysisDateTime': '20260402171632000'}}},
    'ViewInformation': {'Header': {'Version': '2.0.0',
      'ClumpId': '63d2b3a0-db89-433c-9430-4b1ed550d39e'},
     'Tags': {'ImagePseudoColor': {'PseudoColor': {'ColorType': 'SINGLECOLOR',
        'R': 0,
        'G': 255,
        'B': 255}}}}}},
  {'Id': '4829260f-2d8d-46ed-8701-3d876ccb1d20',
   'IsSelected': False,
   'Clump': {'Id': '3b7d85d1-52aa-4413-9ddd-4b3fc0238d0d',
    'Information': {'Header': {'Version': '1.0.0',
      'ClumpId': '3b7d85d1-52aa-4413-9ddd-4b3fc0238d0d',
      'DataType': 'EELS_Cube_Spectrum',
      'DataSubType': '',
      'DetectorType': 0,
      'ClumpType': 'Clump',
      'Name': 'H-K Signal'},
     'DataInformation': {'TypeInfo': 2,
      'DataBytes': 8,
      'Channel': 1,
      'DimensionLength': 1,
      'Dimensions': [30],
      'ChannelType': '',
      'IsRangeFixed': False,
      'MinimumPossibleIntensity': -1.7976931348623157e+308,
      'MaximumPossibleIntensity': 1.7976931348623157e+308},
     'MeasurementInformation': {'CalibrationCoefficients': [{'Scale': 2,
        'Offset': 0,
        'Unit': 'eV'}]},
     'Tags': {'General': {'AnalysisId': '79dfcdc3-758d-4069-993d-036f26bc9e9a',
       'AnalysisDateTime': '20260402171632001'}}},
    'ViewInformation': {'Header': {'Version': '2.0.0',
      'ClumpId': '3b7d85d1-52aa-4413-9ddd-4b3fc0238d0d'},
     'Tags': {'ImagePseudoColor': {'PseudoColor': {'ColorType': 'SINGLECOLOR',
        'R': 255,
        'G': 0,
        'B': 0}}}}}}]}

worksheet.get_clump_num_array_accessor

The following cell generates a spectrum plot from graph_content (spectrum data) using these steps:

  1. Retrieve the ClumpId via get_data_set

  2. Retrieve Dimensions / ElementType via get_clump_num_array

  3. Retrieve the energy-axis Offset / Scale / Unit from MeasurementInformation.CalibrationCoefficients

  4. Retrieve the raw byte array via get_clump_num_array_accessor, infer dtype from the byte count, and convert to a numpy array

  5. Build the energy axis (Energy Loss [eV]) and plot the spectrum with plt.plot

 1import numpy as np
 2import matplotlib.pyplot as plt
 3
 4# Get ClumpId from graph_content Children via get_data_set
 5dataset = worksheet.get_data_set(graph_content['Children'][0]['Id'])
 6clump_id = dataset['Clump']['Id']
 7
 8# Get array dimensions and element type
 9array_info = worksheet.get_clump_num_array(clump_id)
10print('Dimensions:', array_info['Dimensions'])
11print('ElementType:', array_info['ElementType'])
12
13# Get calibration coefficients for energy axis
14calib = dataset['Clump']['Information']['MeasurementInformation']['CalibrationCoefficients'][0]
15offset = calib['Offset']
16scale = calib['Scale']
17unit_map = {'ElectronVolt': 'eV', 'Millielectronvolt': 'meV',
18            'Nanometer': 'nm', 'Angstrom': 'Å', 'Meter': 'm'}
19unit = unit_map.get(calib['Unit'], calib['Unit'])
20print(f"Calibration: offset={offset}, scale={scale}, unit={calib['Unit']}")
21
22# Get raw byte array and infer dtype from byte count
23raw_bytes = worksheet.get_clump_num_array_accessor(clump_id)
24total_elements = 1
25for d in array_info['Dimensions']:
26    total_elements *= d
27bytes_per_element = len(raw_bytes) // total_elements
28dtype_map = {1: np.uint8, 2: np.uint16, 4: np.float32, 8: np.float64}
29dtype = dtype_map.get(bytes_per_element, np.float32)
30narray = np.frombuffer(raw_bytes, dtype=dtype).reshape(array_info['Dimensions'])
31print('dtype:', dtype, '  shape:', narray.shape)
32
33# Build energy axis and plot spectrum
34spectrum = narray.ravel()
35energy_axis = offset + scale * np.arange(len(spectrum))
36
37plt.figure()
38plt.plot(energy_axis, spectrum)
39plt.xlabel(f'Energy Loss [{unit}]')
40plt.ylabel('Intensity [Counts]')
41plt.title(element['Title'])
42plt.show()
Dimensions: [1, 512]
ElementType: Double
Calibration: offset=0, scale=2, unit=eV
dtype: <class 'numpy.float64'>   shape: (1, 512)
../../_images/382749878054a64bb45e263087c233544a47c66bb5c75cc191dc322189cff1b4.png

eels.set_calibration_result

Apply energy-axis calibration to the spectrum dataset (graph content).
Specify the dispersion and the first/second energy loss values in eV.

1calibration_param = {
2    'Dispersion': 2,
3    'FirstEnergyLoss': -512,
4    'SecondEnergyLoss': 510
5}
6eels.set_calibration_result(graph_content['Children'][0]['Id'], calibration_param)

Line

Acquire EELS line-scan data using femtus.acquisition with Shape = 'Line', then analyze using the eels package.

API reference: femtus.acquisition | eels

Acquisition

Configure the acquisition settings and start EELS line-scan acquisition.

  • Set setting['Detectors'] = ['Image', 'EELS'] to enable both image and EELS detectors.

  • Set setting['Region']['Shape'] = 'Line' for line-scan acquisition.

 1result = acquisition.get_settings()
 2if result["Settings"]:
 3    setting = result['Settings'][0]
 4else:
 5    setting = {
 6        'Detectors': [],
 7        'Region': {'Left': 0, 'Top': 0, 'Width': 32, 'Height': 1, 'Points': None, 'Shape': 'Line'},
 8        'Conditions': {'DwellTime': 100, 'PixelResolution': 1, 'IsPlayback': False,
 9                       'CollectionMode': {'Mode': 'Sweep', 'Count': 1}},
10        'DriftCorrection': {'Type': 'None', 'Interval': 1, 'CorrectionRegion': None}
11    }
12
13# Select detectors
14setting['Detectors'] = ['Image', 'EELS']
15
16# Set acquisition region for line scan
17setting['Region']['Shape'] = 'Line'
18setting['Region']['Width'] = 32
19setting['Region']['Height'] = 1
20
21# Set acquisition conditions
22setting['Conditions']['DwellTime'] = 100              # microseconds
23setting['Conditions']['CollectionMode']['Mode'] = 'Sweep'
24setting['Conditions']['CollectionMode']['Count'] = 1
25
26setting
{'Id': 'dd37ad22-765a-4df9-94dc-7c27bba80cd5',
 'Detectors': ['Image', 'EELS'],
 'Region': {'Left': 320,
  'Top': 257,
  'Width': 32,
  'Height': 1,
  'Points': None,
  'Shape': 'Line'},
 'Conditions': {'DwellTime': 100,
  'PixelResolution': 1,
  'IsPlayback': False,
  'CollectionMode': {'Mode': 'Sweep', 'Count': 1}},
 'DriftCorrection': {'Type': 'None', 'Interval': 1, 'CorrectionRegion': None}}
1start_result = acquisition.start(setting)
2acquisition_id = start_result['AcquisitionID']
3print('AcquisitionID:', acquisition_id)
4start_result
AcquisitionID: 48c95a79-0d84-4846-a16b-3132969b78ba
{'AcquisitionID': '48c95a79-0d84-4846-a16b-3132969b78ba',
 'WorksheetID': '6d33305e-8d86-4867-917f-7d959c3398bb',
 'ReferenceDetector': 'VP_ADF_1',
 'Version': '1.0.0'}
1acquisition_result = acquisition.get_acquisition_result(acquisition_id)
2
3for r in acquisition_result['Results']:
4    print(r['DataType'], '->', r['Id'])
5    if r['DataType'] == 'EELS_Line':
6        eels_line_id = r['Id']
7
8acquisition_result
STEM_Survey -> 4620d2a7-077c-4673-84c7-25f2ad6eedca
STEM_HAADF_SeleArea -> e4a35256-447a-4047-97f8-822e493777a8
EELS_Line -> d9247652-eb4b-44e1-96b2-2fbea49cd2d7
{'Results': [{'Id': '4620d2a7-077c-4673-84c7-25f2ad6eedca',
   'DataType': 'STEM_Survey'},
  {'Id': 'e4a35256-447a-4047-97f8-822e493777a8',
   'DataType': 'STEM_HAADF_SeleArea'},
  {'Id': 'd9247652-eb4b-44e1-96b2-2fbea49cd2d7', 'DataType': 'EELS_Line'}]}

Line Analysis

The following cells analyze the acquired line-scan dataset using the eels package.

eels.create_line_whole_spectrum

Generate a whole-range integrated spectrum from the line-scan dataset.
The returned object contains an Ids list with IDs for the generated datasets (image content and graph content).

1whole_spectrum = eels.create_line_whole_spectrum(eels_line_id)
2whole_spectrum
{'Ids': ['80051f5e-2480-4612-ae21-b1f9e2c1957a',
  'f54e6008-d36e-4f9a-a2ce-377fa9848b76']}
1for id in whole_spectrum['Ids']:
2    element = worksheet.get_worksheet_element(id)
3    print(element['ContentSummary']['ContentType'], '->', element['Id'])
GraphContent -> 80051f5e-2480-4612-ae21-b1f9e2c1957a
GraphContent -> f54e6008-d36e-4f9a-a2ce-377fa9848b76

ImageContent and GraphContent

Retrieve the graph content (Ids[0], Ids[1]) from the worksheet elements.

worksheet.get_worksheet_element

create_line_whole_spectrum returns a dict with an Ids list containing two entries:

Index

ContentType

Description

0

GraphContent

Retrieved via worksheet.get_graph_content()

1

GraphContent

Retrieved via worksheet.get_graph_content()

Use get_worksheet_element to retrieve each dataset by its Id.

1# Ids[0]: GraphContent — retrieve with get_image_content
2element = worksheet.get_worksheet_element(whole_spectrum['Ids'][0])
3graph_content1 = worksheet.get_graph_content(element['ContentSummary']['Id'])
4graph_content1
{'Id': '020cf41c-4e26-4f0c-9fde-e7f907cc9802',
 'Children': [{'Id': 'd9247652-eb4b-44e1-96b2-2fbea49cd2d7',
   'IsSelected': False,
   'Clump': {'Id': '770ae6e5-119e-43e6-9430-54e26af2e1ca',
    'Information': {'Header': {'Version': '1.0.0',
      'ClumpId': '770ae6e5-119e-43e6-9430-54e26af2e1ca',
      'DataType': 'EELS_Line',
      'DataSubType': '',
      'DetectorType': 1,
      'ClumpType': 'Clump',
      'Name': 'Line'},
     'DataInformation': {'TypeInfo': 2,
      'DataBytes': 4,
      'Channel': 1,
      'DimensionLength': 2,
      'Dimensions': [33, 512],
      'ChannelType': 'GrayScale',
      'IsRangeFixed': False,
      'MinimumPossibleIntensity': -1.7976931348623157e+308,
      'MaximumPossibleIntensity': 1.7976931348623157e+308},
     'MeasurementInformation': {'CalibrationCoefficients': [{'Scale': 44.2212586825585,
        'Offset': 0,
        'Unit': 'Nanometer'},
       {'Scale': 200000, 'Offset': 0, 'Unit': 'Nanometer'}]},
     'Tags': {'General': {'Instrument': 'JEM-ARM200F',
       'Manufacturer': 'JEOL Ltd.',
       'Comment': '',
       'DateTime': '20260403141159941',
       'ProductName': 'FEMTUS',
       'ProductVersion': '2.0.0.0+8cc42b3fb348c2458c76e358a38bce3fb5cd1063',
       'UpdateDateTime': '20260403141159941',
       'UpdateProductName': 'FEMTUS',
       'UpdateProductVersion': '2.0.0.0+8cc42b3fb348c2458c76e358a38bce3fb5cd1063',
       'AnalysisId': 'caa769a6-f67d-48a8-b6f2-57df48977f67',
       'AnalysisDateTime': '20260403141158914',
       'AcquisitionId': '48c95a79-0d84-4846-a16b-3132969b78ba',
       'AcquisitionDateTime': '20260403141158914'},
      'EELS': {'FilterMode': 'STEM-EELS',
       'FilterSubmode': 'align',
       'DataType': 'Image',
       'Dispersion': 0,
       'CameraLengthCoefficient': 1,
       'MagnificationValue': 1,
       'EnergyLossOffset': 0,
       'DriftTubeVoltage': 0,
       'HighTensionOffset': 0,
       'SectorOffset': 0,
       'SlitMode': 'Out',
       'SlitInserted': False,
       'SlitWidth': 0,
       'EntranceApertureHoleString': 'Out',
       'EntranceApertureInserted': False},
      'ScanGenerator': {},
      'HT': {'GunType': 'Cfeg',
       'AccelerationVoltage': 200000,
       'EnergyShift': 0},
      'EOS': {'OperationMode': 'Scanning',
       'SpotSizeNumber': 0,
       'ConvergenceAngleAlphaNumber': 0,
       'ImageFormingMode': 'MAG',
       'RockingAngle': 0,
       'MagnificationValue': 20000,
       'MagnificationString': 'x20k',
       'CameraLength': 15,
       'CameraLengthString': '1.5cm'},
      'Stage': {'X': {'Position': 0},
       'Y': {'Position': 0},
       'Z': {'Position': 0},
       'TX': {'Position': 0},
       'TY': {'Position': 0},
       'TZ': {'Position': 0},
       'PX': {'Position': 0},
       'PY': {'Position': 0},
       'PZ': {'Position': 0}},
      'Aperture': {'CL': {'ApertureHoleString': '0'},
       'CL2': {'ApertureHoleString': '0'},
       'OL': {'ApertureHoleString': '0'},
       'SA': {'ApertureHoleString': '0'}},
      'Detector': {'DetectorKind': 'Test Camera Name 0',
       'Manufacturer': 'Test Vendor',
       'ModelCode': 'Test Camera Name 0',
       'ModelDisplayName': 'Test Camera Name 0',
       'PixelsPerMeter': {'Horizontal': 200000, 'Vertical': 200000},
       'ImagingArea': {'X': 256, 'Y': 128, 'Width': 512, 'Height': 512},
       'BinningSize': {'X': 2, 'Y': 2},
       'SoftwareCroppingArea': {'X': 0, 'Y': 0, 'Width': 512, 'Height': 512},
       'SoftwareBinningSize': {'X': 1, 'Y': 1},
       'ExposureTimeValue': 100,
       'FrameIntegration': 1},
      'ScanDataAcquisition': {'AcquiredFrames': 1}}},
    'ViewInformation': {'Header': {'Version': '2.0.0',
      'ClumpId': '770ae6e5-119e-43e6-9430-54e26af2e1ca'},
     'Tags': {'GraphDisplay': {'IsLegendAreaVisible': True}}}}}]}
1# Ids[1]: GraphContent — retrieve with get_graph_content
2element = worksheet.get_worksheet_element(whole_spectrum['Ids'][1])
3graph_content2 = worksheet.get_graph_content(element['ContentSummary']['Id'])
4graph_content2
{'Id': '7ff78347-0ee0-4829-9c88-22a4b119b375',
 'Children': [{'Id': '2ac3a4c6-9c76-412b-92f0-0180a2a40b28',
   'IsSelected': False,
   'Clump': {'Id': '092084a4-e896-4118-bea5-90082f91a1d5',
    'Information': {'Header': {'Version': '1.0.0',
      'ClumpId': '092084a4-e896-4118-bea5-90082f91a1d5',
      'DataType': 'EELS_Line_Spectrum',
      'DataSubType': '',
      'DetectorType': 1,
      'ClumpType': 'Clump',
      'Name': 'Spectrum'},
     'DataInformation': {'TypeInfo': 2,
      'DataBytes': 8,
      'Channel': 1,
      'DimensionLength': 1,
      'Dimensions': [512],
      'ChannelType': 'GrayScale',
      'IsRangeFixed': False,
      'MinimumPossibleIntensity': -1.7976931348623157e+308,
      'MaximumPossibleIntensity': 1.7976931348623157e+308},
     'MeasurementInformation': {'CalibrationCoefficients': [{'Scale': 200000,
        'Offset': 0,
        'Unit': 'eV'}]},
     'Tags': {'General': {'Instrument': 'JEM-ARM200F',
       'Manufacturer': 'JEOL Ltd.',
       'Comment': '',
       'DateTime': '20260403141159941',
       'ProductName': 'FEMTUS',
       'ProductVersion': '2.0.0.0+8cc42b3fb348c2458c76e358a38bce3fb5cd1063',
       'UpdateDateTime': '20260403141159941',
       'UpdateProductName': 'FEMTUS',
       'UpdateProductVersion': '2.0.0.0+8cc42b3fb348c2458c76e358a38bce3fb5cd1063',
       'AnalysisId': '718d54b6-52b4-4849-8fe9-47d78b53f770',
       'AnalysisDateTime': '20260403141213159',
       'AcquisitionId': '48c95a79-0d84-4846-a16b-3132969b78ba',
       'AcquisitionDateTime': '20260403141158914'},
      'EELS': {'FilterMode': 'STEM-EELS',
       'FilterSubmode': 'align',
       'DataType': 'Image',
       'Dispersion': 0,
       'CameraLengthCoefficient': 1,
       'MagnificationValue': 1,
       'EnergyLossOffset': 0,
       'DriftTubeVoltage': 0,
       'HighTensionOffset': 0,
       'SectorOffset': 0,
       'SlitMode': 'Out',
       'SlitInserted': False,
       'SlitWidth': 0,
       'EntranceApertureHoleString': 'Out',
       'EntranceApertureInserted': False},
      'ScanGenerator': {},
      'HT': {'GunType': 'Cfeg',
       'AccelerationVoltage': 200000,
       'EnergyShift': 0},
      'EOS': {'OperationMode': 'Scanning',
       'SpotSizeNumber': 0,
       'ConvergenceAngleAlphaNumber': 0,
       'ImageFormingMode': 'MAG',
       'RockingAngle': 0,
       'MagnificationValue': 20000,
       'MagnificationString': 'x20k',
       'CameraLength': 15,
       'CameraLengthString': '1.5cm'},
      'Stage': {'X': {'Position': 0},
       'Y': {'Position': 0},
       'Z': {'Position': 0},
       'TX': {'Position': 0},
       'TY': {'Position': 0},
       'TZ': {'Position': 0},
       'PX': {'Position': 0},
       'PY': {'Position': 0},
       'PZ': {'Position': 0}},
      'Aperture': {'CL': {'ApertureHoleString': '0'},
       'CL2': {'ApertureHoleString': '0'},
       'OL': {'ApertureHoleString': '0'},
       'SA': {'ApertureHoleString': '0'}},
      'Detector': {'DetectorKind': 'Test Camera Name 0',
       'Manufacturer': 'Test Vendor',
       'ModelCode': 'Test Camera Name 0',
       'ModelDisplayName': 'Test Camera Name 0',
       'PixelsPerMeter': {'Horizontal': 200000, 'Vertical': 200000},
       'ImagingArea': {'X': 256, 'Y': 128, 'Width': 512, 'Height': 512},
       'BinningSize': {'X': 2, 'Y': 2},
       'SoftwareCroppingArea': {'X': 0, 'Y': 0, 'Width': 512, 'Height': 512},
       'SoftwareBinningSize': {'X': 1, 'Y': 1},
       'ExposureTimeValue': 100,
       'FrameIntegration': 1},
      'ScanDataAcquisition': {'AcquiredFrames': 1},
      'Processings': [{'Parents': ['770ae6e5-119e-43e6-9430-54e26af2e1ca'],
        'ProcessType': 'ExtractSpectrum',
        'Parameters': [{'ExtractRoi': {'ShapeType': 'Rectangle',
           'Shape': {'X': 0, 'Y': 0, 'Width': 33, 'Height': 512}}}]}]}},
    'ViewInformation': {'Header': {'Version': '2.0.0',
      'ClumpId': '092084a4-e896-4118-bea5-90082f91a1d5'},
     'Tags': {}}}}]}

worksheet.get_clump_num_array_accessor

The following cells generate plots from graph_content1 (line-scan data) and graph_content2 (spectrum data) using these steps:

  1. Retrieve the ClumpId via get_data_set

  2. Retrieve Dimensions / ElementType via get_clump_num_array

  3. Retrieve the axis Offset / Scale / Unit from MeasurementInformation.CalibrationCoefficients

  4. Retrieve the raw byte array via get_clump_num_array_accessor, infer dtype from the byte count, and convert to a numpy array

  5. For line-scan data: integrate over the spectral axis and plot as a distance profile (Distance [nm])

  6. For spectrum data: build the energy axis (Energy Loss [eV]) and plot with plt.plot

 1import numpy as np
 2import matplotlib.pyplot as plt
 3
 4# Get ClumpId from graph_content1 Children via get_data_set
 5dataset = worksheet.get_data_set(graph_content1['Children'][0]['Id'])
 6clump_id = dataset['Clump']['Id']
 7
 8# Get array dimensions and element type
 9array_info = worksheet.get_clump_num_array(clump_id)
10print('Dimensions:', array_info['Dimensions'])
11print('ElementType:', array_info['ElementType'])
12
13# Get spatial calibration (distance axis)
14calib = dataset['Clump']['Information']['MeasurementInformation']['CalibrationCoefficients'][0]
15offset = calib['Offset']
16scale = calib['Scale']
17unit_map = {'ElectronVolt': 'eV', 'Millielectronvolt': 'meV',
18            'Nanometer': 'nm', 'Angstrom': 'Å', 'Meter': 'm'}
19unit = unit_map.get(calib['Unit'], calib['Unit'])
20print(f"Calibration: offset={offset}, scale={scale}, unit={calib['Unit']}")
21
22# Get raw byte array and infer dtype from byte count
23raw_bytes = worksheet.get_clump_num_array_accessor(clump_id)
24total_elements = 1
25for d in array_info['Dimensions']:
26    total_elements *= d
27bytes_per_element = len(raw_bytes) // total_elements
28dtype_map = {1: np.uint8, 2: np.uint16, 4: np.float32, 8: np.float64}
29dtype = dtype_map.get(bytes_per_element, np.float32)
30narray = np.frombuffer(raw_bytes, dtype=dtype).reshape(array_info['Dimensions'])
31print('dtype:', dtype, '  shape:', narray.shape)
32
33# Squeeze singleton dims → (N_points, N_channels) or (N_points,)
34data = narray.squeeze()
35
36# Integrate over spectral (last) axis to get intensity per scan point
37if data.ndim >= 2:
38    profile = data.sum(axis=-1)
39else:
40    profile = data
41
42dist_axis = offset + scale * np.arange(len(profile))
43
44plt.figure()
45plt.plot(dist_axis, profile)
46plt.xlabel(f'Distance [{unit}]')
47plt.ylabel('Intensity [Counts]')
48plt.title(element['Title'])
49plt.show()
Dimensions: [1, 33, 512]
ElementType: Single
Calibration: offset=0, scale=44.2212586825585, unit=Nanometer
dtype: <class 'numpy.float32'>   shape: (1, 33, 512)
../../_images/06254bcf0c4f05bfff9c7b84a47a91f7cd4ada93b8f6004f4b2c7dc3b9b060ed.png
 1import numpy as np
 2import matplotlib.pyplot as plt
 3
 4# Get ClumpId from graph_content Children via get_data_set
 5dataset = worksheet.get_data_set(graph_content2['Children'][0]['Id'])
 6clump_id = dataset['Clump']['Id']
 7
 8# Get array dimensions and element type
 9array_info = worksheet.get_clump_num_array(clump_id)
10print('Dimensions:', array_info['Dimensions'])
11print('ElementType:', array_info['ElementType'])
12
13# Get calibration coefficients for energy axis
14calib = dataset['Clump']['Information']['MeasurementInformation']['CalibrationCoefficients'][0]
15offset = calib['Offset']
16scale = calib['Scale']
17unit_map = {'ElectronVolt': 'eV', 'Millielectronvolt': 'meV',
18            'Nanometer': 'nm', 'Angstrom': 'Å', 'Meter': 'm'}
19unit = unit_map.get(calib['Unit'], calib['Unit'])
20print(f"Calibration: offset={offset}, scale={scale}, unit={calib['Unit']}")
21
22# Get raw byte array and infer dtype from byte count
23raw_bytes = worksheet.get_clump_num_array_accessor(clump_id)
24total_elements = 1
25for d in array_info['Dimensions']:
26    total_elements *= d
27bytes_per_element = len(raw_bytes) // total_elements
28dtype_map = {1: np.uint8, 2: np.uint16, 4: np.float32, 8: np.float64}
29dtype = dtype_map.get(bytes_per_element, np.float32)
30narray = np.frombuffer(raw_bytes, dtype=dtype).reshape(array_info['Dimensions'])
31print('dtype:', dtype, '  shape:', narray.shape)
32
33# Build energy axis and plot spectrum
34spectrum = narray.ravel()
35energy_axis = offset + scale * np.arange(len(spectrum))
36
37plt.figure()
38plt.plot(energy_axis, spectrum)
39plt.xlabel(f'Energy Loss [{unit}]')
40plt.ylabel('Intensity [Counts]')
41plt.title(element['Title'])
42plt.show()
Dimensions: [1, 512]
ElementType: Double
Calibration: offset=0, scale=200000, unit=eV
dtype: <class 'numpy.float64'>   shape: (1, 512)
../../_images/7ca72405a084cd568ee59e42c8de966a85402f7898a603c4b3dd8a05dd0f3ff8.png

eels.set_calibration_result

Apply energy-axis calibration to the spectrum dataset (graph content).
Specify the dispersion and the first/second energy loss values in eV.

1calibration_param = {
2    'Dispersion': 2,
3    'FirstEnergyLoss': -512,
4    'SecondEnergyLoss': 510
5}
6eels.set_calibration_result(graph_content['Children'][0]['Id'], calibration_param)