Examples

The beautifuljason.examples package contains demonstration scripts showcasing practical usage of the BeautifulJASON API. These scripts are intended as a starting point and reference for developers integrating JASON automation into their workflows.

quick_start.py

A minimal example that loads a 1D 1H spectrum, performs multiplet analysis, customizes the visual appearance, and saves the result as a PNG image.

Highlights:

  • Runs without user configuration using bundled test data.

  • Shows how to apply analysis and customize graphics items.

  • Demonstrates document rendering and export to image.

Source code:

 1##
 2##-----------------------------------------------------------------------------
 3##
 4## Copyright (c) 2023 JEOL Ltd.
 5## 1-2 Musashino 3-Chome
 6## Akishima Tokyo 196-8558 Japan
 7##
 8## This software is provided under the MIT License. For full license information,
 9## see the LICENSE file in the project root or visit https://opensource.org/licenses/MIT
10##
11##++---------------------------------------------------------------------------
12##
13## ModuleName : BeautifulJASON
14## ModuleType : Python API for JASON desktop application and JJH5 documents
15## Purpose : Automate processing, analysis, and report generation with JASON
16## Author : Nikolay Larin
17## Language : Python
18##
19####---------------------------------------------------------------------------
20##
21
22def main():
23    import os
24    import tempfile
25    import beautifuljason as bjason
26    from PIL import Image as PILImage
27
28    # Determine the path to the data directory inside the beautifuljason's tests subpackage
29    test_data_dir = os.path.join(os.path.dirname(bjason.__file__), 'tests', 'data')
30
31    # Specify input spectral file and define the path for the output PNG file
32    input_1H_file = os.path.join(test_data_dir, "Ethylindanone_Proton-13-1.jdf")
33    output_file = os.path.join(tempfile.gettempdir(), "Ethylindanone_Proton-13-1.png")
34
35    # Create an instance of the JASON application interface
36    jason = bjason.JASON()
37
38    # Define and customize the default font settings
39    font = bjason.base.Font.default_font()
40    font['family'] = 'Arial'
41    font['point_size'] = 12
42    
43    # Load the 1H spectral file, apply multiplet analysis, and customize its visual appearance
44    with jason.create_document(input_1H_file, actions=[{'name': 'multiplet_analysis'}]) as doc:
45        # Access the first spectral item and adjust its properties
46        spec_item = doc.nmr_items[0]
47        spec_item.header = 'Ethylindanone'
48        spec_item.header_font = font
49        spec_item.x_font = font
50        spec_item.mult_intg_label_font = font
51        spec_item.peak_label_font = font
52        spec_item.plot_1d_color = '#3556d8'
53        spec_item.show_y_axis = False
54
55        # Save the customized document to an image file
56        jason.save(doc, output_file)
57
58    # Display the generated image using the default image viewer
59    image = PILImage.open(output_file)
60    image.show()
61
62if __name__ == '__main__':
63    main()

analyze_and_report.py

A more advanced batch script for automated report generation. Processes multiple input spectra, applies conditional analysis, adds parameter/peak/multiplet tables, customizes layout and appearance, inserts logos, and saves results in various formats.

By default, the script saves the generated output files without launching them in JASON. Use --launch if you also want the resulting .jjh5 files to be opened after saving.

Highlights:

  • Handles both 1H, 13C, and 2D NMR spectra with context-sensitive logic.

  • Generates publication-style multiplet reports for 1H spectra.

  • Adds parameter and peak tables, headers, and corporate branding.

  • Accepts multiple input/output files via command-line arguments.

  • Supports optional post-save launch in JASON via --launch.

Source code:

  1##
  2##-----------------------------------------------------------------------------
  3##
  4## Copyright (c) 2023 JEOL Ltd.
  5## 1-2 Musashino 3-Chome
  6## Akishima Tokyo 196-8558 Japan
  7##
  8## This software is provided under the MIT License. For full license information,
  9## see the LICENSE file in the project root or visit https://opensource.org/licenses/MIT
 10##
 11##++---------------------------------------------------------------------------
 12##
 13## ModuleName : BeautifulJASON
 14## ModuleType : Python API for JASON desktop application and JJH5 documents
 15## Purpose : Automate processing, analysis, and report generation with JASON
 16## Author : Nikolay Larin
 17## Language : Python
 18##
 19####---------------------------------------------------------------------------
 20##
 21
 22import argparse
 23import os.path
 24import datetime
 25import beautifuljason as bjason
 26
 27# Custom column ID for the multiplet name column of the multiplet table.
 28# The value must be negative and unique.
 29ColID_NAME = -1
 30
 31def parse_arguments():
 32    """Parse command line arguments."""
 33    parser = argparse.ArgumentParser(
 34        description='Batch process and analyze spectral files. The script performs automatic analysis of spectra, creates tables, reports, and modifies visual properties. The results are saved in the specified output files.',
 35        usage='%(prog)s [-h] input_files [input_files ...] -o OUTPUT_FILES [OUTPUT_FILES ...] [--launch]'
 36        )
 37    parser.add_argument('input_files', nargs='+', help='List of spectral files to process.')
 38    parser.add_argument('-o', '--output-files', required=True, nargs='+', help='List of output files. Supported formats: .jjh5, .jjj, .jdx, and .pdf.')
 39    parser.add_argument('--launch', action='store_true', help='Launch the resulting .jjh5 file in JASON after saving.')
 40    return parser.parse_args()
 41
 42def customize_layout(doc: bjason.Document):
 43    """Customize the layout of spectral items."""
 44    for spec_item in doc.nmr_items:
 45        old_item_pos = spec_item.pos
 46        old_item_size = spec_item.size
 47        spec_item.pos = (old_item_pos[0] + old_item_size[0] * 0.3, old_item_pos[1])
 48        spec_item.size = (old_item_size[0] * 0.7, old_item_size[1] * 0.9)
 49    
 50def customize_appearance(doc: bjason.Document):
 51    """Customize the appearance of spectral items."""
 52    for spec_item in doc.nmr_items:
 53        spec_data = spec_item.spec_data(0)
 54        spec_item.show_y_axis = spec_data.ndim != 1
 55        spec_item.plot_1d_color = '#006400'
 56
 57def add_parameter_tables(doc: bjason.Document):
 58    """Add parameter tables and adjust their layout."""
 59    for spec_item in doc.nmr_items:
 60        spec_data = spec_item.spec_data(0)
 61        params_item = doc.create_params_table(spec_item, spec_data)
 62        params_item.param_list.append([
 63            {'name': 'Filename', 'value': os.path.basename(spec_data.raw_data.spec_info.get_param('OrigFilename'))},
 64            {'name': 'Nuclide', 'value': spec_data.spec_info.nuclides[0] if len(spec_data.spec_info.nuclides) == 1 else ', '.join(spec_data.spec_info.nuclides)},
 65            {'name': 'Solvent', 'value': spec_data.raw_data.spec_info.get_param('Solvent')}
 66        ])
 67        spec_item_pos = spec_item.pos
 68        spec_item_size = spec_item.size
 69        new_x = spec_item_pos[0] - 3.0/7.0*spec_item_size[0]
 70        params_item.pos = (new_x, spec_item_pos[1])
 71        params_item.size = (spec_item_pos[0] - new_x, spec_item_size[1] * 0.3)
 72
 73def add_peak_and_multiplet_tables(doc: bjason.Document):
 74    """Add peak and/or multiplet tables and adjust their layout. The multilet tables are created for 1H spectra only."""
 75    for spec_item in doc.nmr_items:
 76        spec_data = spec_item.spec_data(0)
 77        table_item: bjason.NMRPeakTableGraphicsItem | bjason.NMRMultipletTableGraphicsItem = None
 78        if spec_data.ndim == 1:
 79            if spec_data.spec_info.nuclides[0] == '1H':
 80                table_item = doc.create_nmrmultiplets_table(spec_item, spec_data)
 81                ColID = bjason.NMRMultipletTableGraphicsItem.ColumnID
 82                # Define visible columns and their order. Negative numbers correspond to custom columns. 
 83                table_item.visual_column_ids = (ColID_NAME, ColID.START0, ColID.END0, ColID.PEAKS_VOLUME, ColID.NORMALIZED)
 84                # Customize standard columns view  
 85                table_item.customized_columns.append((
 86                    {'Type': ColID.START0, 'Digits': 2},
 87                    {'Type': ColID.END0, 'Digits': 2},
 88                    {'Type': ColID.NORMALIZED, 'Digits': 1},
 89                    {'Type': ColID_NAME, 'Digits': -1, 'CustomTitle': 'Name'}
 90                ))
 91        if not table_item:
 92            table_item = doc.create_nmrpeaks_table(spec_item, spec_data)
 93            ColID = bjason.NMRPeakTableGraphicsItem.ColumnID
 94            if spec_data.ndim == 1:
 95                table_item.visual_column_ids = [ColID.POS0, ColID.WIDTH0, ColID.HEIGHT, ColID.VOLUME]
 96            elif spec_data.ndim == 2:
 97                table_item.visual_column_ids = [ColID.POS0, ColID.POS1, ColID.HEIGHT, ColID.VOLUME]
 98        table_item.show_title = True
 99        table_item.alternating_row_colors = True
100        spec_item_pos = spec_item.pos
101        spec_item_size = spec_item.size
102        new_x = spec_item_pos[0] - 3.0/7.0*spec_item_size[0]
103        table_item.pos = (new_x, spec_item_pos[1] + spec_item_size[1] * 0.3)
104        table_item.size = (spec_item_pos[0] - new_x, spec_item_size[1] * 0.7)
105
106def add_headers_and_logos(doc: bjason.Document):
107    """Add headers and logos to the document."""
108    logo_width = 200.0
109    logo_image_data = None
110    for spec_item in doc.nmr_items:
111        spec_item.show_header = False
112        text_item = doc.create_text_item()
113        text_item.pos = spec_item.pos
114        text_item.size = (spec_item.size[0], 60.0)
115        text_item.text.html = '<b>{}</b><br/>Copyright (C) My Company. All rights reserved'.format(datetime.datetime.now().isoformat(timespec='seconds'))
116        spec_item.pos = (spec_item.pos[0], text_item.pos[1] + text_item.size[1])
117        if logo_image_data is None:
118            logo_image_data = doc.create_image_data(os.path.abspath(os.path.join(os.path.dirname(__file__), 'JEOL_company_logo.png')))
119        image_item = doc.create_image_item(logo_image_data.id)
120        image_item.pos = (text_item.pos[0] + text_item.size[0] - logo_width, text_item.pos[1])
121        image = image_item.image
122        image_item.size = (logo_width, logo_width * image.height / image.width)
123
124def add_multiplet_reports(doc):
125    """Add multiplet reports to the document. The multiplet reports are created for 1H spectra only."""
126    for spec_item in doc.nmr_items:
127        spec_data = spec_item.spec_data(0)
128        if spec_data.ndim == 1 and spec_data.spec_info.nuclides[0] == '1H':
129            report_item = doc.create_nmrmultiplet_report(spec_item, spec_data)
130            report_item.journal_format = 'Wiley'
131            report_item.pos = spec_item.pos
132            report_item.size = (0.5 * spec_item.size[0], 0.25 * spec_item.size[1])
133
134def apply_analysis(jason, doc):
135    """
136    Apply specific analysis techniques based on the type of spectrum.
137    Specifically, the script performs multiplet analysis for 1H spectra and peak picking for 13C and 2D spectra.
138    """
139    items_1H = []
140    items_13C = []
141    items_2D = []
142    for spec_item in doc.nmr_items:
143        spec_data = spec_item.spec_data(0)
144        if spec_data.ndim == 2:
145            items_2D.append(spec_item.id)
146        elif spec_data.ndim == 1:
147            if spec_data.spec_info.nuclides[0] == '1H':
148                items_1H.append(spec_item.id)
149            elif spec_data.spec_info.nuclides[0] == '13C':
150                items_13C.append(spec_item.id)
151
152    # Apply analysis actions to the document
153    jason.apply_actions(doc, [{'name': 'multiplet_analysis', 'items': items_1H}, {'name': 'peak_picking', 'items': items_13C + items_2D}])
154    for item in doc.items:
155        if item.type == bjason.GraphicsItem.Type.NMRMultipletTable:
156            # Add custom multiplet names to the Name column of the multiplet table
157            table_item: bjason.NMRMultipletTableGraphicsItem = item
158            for i, multiplet in enumerate(item.spec_data.multiplets):
159                table_item.set_custom_value(multiplet.id, ColID_NAME, f'M{i+1}')
160
161def main():
162    """Main entry point of the script."""
163    jason = bjason.JASON() # Create a JASON object 
164    args = parse_arguments() # Parse command line arguments
165
166    # Convert input and output file paths to absolute paths
167    absolute_input_files = [os.path.abspath(file) for file in args.input_files]
168    absolute_output_files = [os.path.abspath(file) for file in args.output_files]
169
170    with jason.create_document(absolute_input_files) as doc:  # Open and process the spectral files in JASON
171        customize_layout(doc) # Customize the layout of spectral items
172        customize_appearance(doc) # Customize the appearance of spectral items
173        add_parameter_tables(doc)  # Add parameter tables and adjust their layout
174        add_peak_and_multiplet_tables(doc) # Add peak and/or multiplet tables and adjust their layout
175        add_headers_and_logos(doc) # Add headers and logos to the document
176        add_multiplet_reports(doc) # Add multiplet reports to the document
177        apply_analysis(jason, doc) # Apply specific analysis techniques based on the type of spectrum
178        jason.save(doc, absolute_output_files)  # Save the document to the specified output files
179
180    # Optionally, open the resulting .jjh5 file in JASON for visual inspection
181    jjh5_files = [output_file for output_file in absolute_output_files if output_file.endswith('.jjh5')]
182    if args.launch and jjh5_files:
183        jason.launch(jjh5_files)
184
185if __name__ == "__main__":
186    main()

These examples are intended to be self-contained and modifiable. Users are encouraged to adapt them to their own datasets and requirements.