def main(): for name in ("sp", "line", "depth", "mapping"): filename = curdir / "spectra_files" / "{0}.wdf".format(name) print("Testing: ", filename.as_posix()) # if debug=True, debug information will show in stderr reader = WDFReader(filename, debug=True) # Explicitly print into stdout reader.print_info() return
def read(filename): loadables = pd.read_csv("config/import_config.csv") extension = filename.split('.', 1)[1] if (extension == "jpg"): im = Image.open(filename) im.save("temp.png") data = hs.load("temp.png") os.remove("temp.png") return data ''' if (extension == "txt"): raw = np.genfromtxt(filename, delimiter="\t", skip_header=1, dtype=float, names =("X","Y","Wavelength","Intensity")) #raw["X"] *= -1 xCoords = np.unique(raw["X"]).__len__() yCoords = np.unique(raw["Y"]).__len__() wavesize = int(np.shape(raw)[0]/xCoords/yCoords) raw = np.sort(raw, axis=-1, order = ("Y","X","Wavelength")) raw = (raw["Intensity"].reshape((xCoords, yCoords, wavesize))) data = hs.signals.Signal1D(raw) data.metadata.General.title = filename.split('.',1)[0] data.axes_manager[0].name = 'x' data.axes_manager[1].name = 'y' data.axes_manager[2].name = 'wavelength' data.axes_manager[0].units = "um" data.axes_manager[1].units = "um" data.axes_manager[2].units = "1/cm" return data ''' if (extension in loadables["extension"]): if (loadables["extension" == extension]["signal"] == ""): return hs.load(filename, signal_type=loadables["extension" == extension]["signal"]) else: return hs.load(filename) if (extension == "wdf"): reader = WDFReader(filename) reader.spectra = np.flip(reader.spectra,axis=2) data = hs.signals.Signal1D(reader.spectra) data.metadata.General.title = reader.title data.metadata.General.authors = reader.username data.axes_manager[0].name = 'x' data.axes_manager[1].name = 'y' data.axes_manager[2].name = 'wavelength' data.axes_manager[0].units = str(reader.xpos_unit).replace('μ', 'u') data.axes_manager[1].units = str(reader.ypos_unit).replace('μ', 'u') data.axes_manager[2].units = str(reader.xlist_unit) return data else: print("INVALID FILE TYPE")
def main(): filename = curdir / "spectra_files" / "sp.wdf" reader = WDFReader(filename) print("Measurement type is ", reader.measurement_type) print("{0} Spectra obtained with {1} accumulations each".format( reader.count, reader.accumulation_count)) # For ex1.wdf there is only 1 spectrum assert reader.count == 1 wn = reader.xdata # wavenumber sp = reader.spectra # spectrum / spectra in ccd counts # For single spectrum the spectra has shape (point_per_spectrum, ) print(wn.shape, sp.shape) if plot: print("Use matplotlib to plot spectrum") plt.figure(figsize=(6, 4)) plt.plot(wn, sp, label="Spectrum 1") plt.xlabel("Wavenumber (1/cm)") plt.ylabel("Intensity (ccd counts)") plt.title("Spectrum from sp.wdf") plt.show(block=False) plt.tight_layout() plt.pause(3) plt.savefig(imgdir / "sp_spectra.png", dpi=100) plt.close() else: print("No matplotlib, simply print the values") print("Wavenumbers (1/cm): ", wn) print("Intensities (ccd counts): ", sp) return
def main(): filename = curdir / "spectra_files" / "line.wdf" reader = WDFReader(filename) assert reader.measurement_type == 3 # For mapping, xdata is still wavenumber wn = reader.xdata spectra = reader.spectra assert wn.shape[0] == spectra.shape[1] # Now spectra.shape becomes (i, j, spectrum) print(wn.shape, spectra.shape) if plot is True: # Level the spectra with baseline intensity spectra = spectra - spectra.min(axis=1, keepdims=True) # Need to revert matrix for plotting spectra = spectra.T plt.figure(figsize=(6, 4)) # plot the first 5 spectra for i in range(5): plt.plot(wn, spectra[:, i], label="{0:d}".format(i)) plt.legend() plt.xlabel("Wavenumber (1/cm)") plt.ylabel("Intensity (ccd counts)") plt.title("Spectra from line.wdf") plt.show(block=False) plt.pause(3) plt.tight_layout() plt.savefig(imgdir / "linscan.png", dpi=100) plt.close() else: print("Wavenumber is like:", wn) print("Spectra matrix is like: \n", spectra) return
def exportFullImageSVG(path): f3 = WDFReader(path) img3 = mpimg.imread(f3.img, format="jpg") img_x0, img_y0 = f3.img_origins img_w, img_h = f3.img_dimensions map_x = f3.xpos map_y = f3.ypos map_w = f3.map_info["x_span"] map_h = f3.map_info["y_span"] fig = plt.figure() plt.imshow(img3, extent=(img_x0, img_x0 + img_w, img_y0 + img_h, img_y0)) r = plt.Rectangle(xy=(map_x.min(), map_y.min()), width=map_w, height=map_h, fill=False, color='yellow') plt.gca().add_patch(r) plt.savefig(Path(path).expanduser().resolve().with_suffix('.fullmap.svg')) fig.clear() plt.close(fig)
def read_spectra(self): # renishawWiRE is imported here so that its API changes would not block spectroscopy from renishawWiRE import WDFReader # pylint: disable=import-outside-toplevel wdf_file = WDFReader(self.filename) try: if wdf_file.measurement_type == 1: # single point spectra table = self.single_reader(wdf_file) elif wdf_file.measurement_type == 2: # series scan table = self.series_reader(wdf_file) elif wdf_file.measurement_type == 3: # line scan table = self.map_reader(wdf_file) finally: wdf_file.close() return table
def main(): filename = curdir / "spectra_files" / "mapping.wdf" reader = WDFReader(filename) assert reader.measurement_type == 3 wn = reader.xdata spectra = reader.spectra print(wn.shape, spectra.shape) map_x = reader.xpos map_y = reader.ypos map_w = reader.map_info["x_span"] map_h = reader.map_info["y_span"] # w and h are the measure in xy coordinates # Level the spectra spectra = spectra - np.min(spectra, axis=2, keepdims=True) peaks_a = peak_in_range(spectra, wn, [1295, 1340]) peaks_b = peak_in_range(spectra, wn, [1350, 1400]) ratio = peaks_a / peaks_b extent = [0, map_w, map_h, 0] if plot is True: # Must provide the format to read the optical image # img = mpimg.imread(reader.img, format="jpg") img = PIL.Image.open(reader.img) print(reader.img_cropbox) # Desaturate the whitelight image img1 = img.crop(box=reader.img_cropbox).convert("L") plt.figure(figsize=(6, 6)) # Left, plot the white light image and rectangle area # Show the image with upper origin extent See # https://matplotlib.org/3.1.1/gallery/text_labels_and_annotations/text_alignment.html plt.imshow(img1, alpha=0.5, cmap="hot", extent=extent) # Right plot histogram of Peak A/B mapping cm = plt.imshow(ratio, interpolation="bicubic", alpha=0.5, cmap="viridis_r", extent=extent, vmin=0.5, vmax=1.5) plt.xlabel("Mapping x [μm]") plt.ylabel("Mapping y [μm]") cb = plt.colorbar(cm) cb.ax.set_title("Ratio") plt.title("50% Optical + 50% Raman") plt.tight_layout() plt.show(block=False) plt.pause(3) plt.savefig(imgdir / "map-overlay.png", dpi=100) plt.close() else: pass return
def main(): filename = curdir / "spectra_files" / "depth.wdf" reader = WDFReader(filename) # A depth scan assert reader.measurement_type == 2 # For depth scan, xdata is still wavenumber wn = reader.xdata spectra = reader.spectra x = reader.xpos y = reader.ypos z = reader.zpos # print(x, y, z) # In this example only z is non-zero assert all([np.all(x == 0), np.all(y == 0), ~np.all(z == 0)]) assert reader.count == z.shape[0] print(spectra, spectra.shape) print(reader.count) # Distance wn = reader.xdata spectra = reader.spectra # Filter blank spectra cond = np.where(spectra.mean(axis=1) > 0)[0] z = z[cond] spectra = spectra[cond, :] # Data processing spectra = spectra - spectra.min(axis=1, keepdims=True) # Simply get accumulated counts between 1560 and 1620 cm^-1 peak_1 = peak_in_range(spectra, wn, range=[1560, 1620]) peak_2 = peak_in_range(spectra, wn, range=[2650, 2750]) ratio = peak_2 / peak_1 if plot is True: # Level the spectra with baseline intensity plt.figure(figsize=(6, 4)) plt.plot(z, peak_1 / peak_1.max(), "-o", label="G Peak") # plt.plot(z, peak_2 / peak_2.max(), label="2D") # plt.plot(z, ratio, label="2D/G") plt.xlabel("Z [{0}]".format(str(reader.zpos_unit))) plt.legend(loc=0) plt.ylabel("Normed Intensity") plt.title("Results from depth.wdf") plt.show(block=False) plt.pause(3) plt.savefig(imgdir / "depth.png", dpi=100) plt.close() else: print("Wavenumber is like:", wn) print("Z-Distance is like:", z) print("2D/G ratio is like: \n", ratio) return
def main(): filename = curdir / "spectra_files" / "mapping.wdf" reader = WDFReader(filename) assert reader.measurement_type == 3 wn = reader.xdata spectra = reader.spectra print(wn.shape, spectra.shape) x = reader.xpos y = reader.ypos w, h = reader.map_shape print("The size of mapping is {0:d} * {1:d}".format(w, h)) # w and h are the measure in xy coordinates # Level the spectra spectra = spectra - np.min(spectra, axis=2, keepdims=True) peaks_a = peak_in_range(spectra, wn, [1295, 1340]) peaks_b = peak_in_range(spectra, wn, [1350, 1400]) ratio = peaks_a / peaks_b ratio_fl = ratio.flatten() if plot is True: plt.figure(figsize=(10, 5)) # Left plot histogram of Peak A/B ratio plt.subplot(121) plt.hist(ratio_fl, bins=50, range=(0.1, 2)) plt.xlabel("Ratio peak A / peak B") plt.ylabel("Counts") # Right plot histogram of Peak A/B mapping plt.subplot(122) plt.imshow(ratio, interpolation="bicubic", extent=[0, x.max() - x.min(), y.max() - y.min(), 0], vmin=0.5, vmax=1.5) plt.xlabel("Mapping x [μm]") plt.ylabel("Mapping y [μm]") cb = plt.colorbar() cb.ax.set_title("Ratio") plt.tight_layout() plt.show(block=False) plt.pause(3) plt.savefig(imgdir / "mapping.png", dpi=100) plt.close() else: pass return
def exportCroppedImageSVG(path): f3 = WDFReader(path) img3_p = PIL.Image.open(f3.img) img3_ = img3_p.crop(box=f3.img_cropbox) map_w = f3.map_info["x_span"] map_h = f3.map_info["y_span"] extent = [0, map_w, map_h, 0] fig = plt.figure() plt.imshow(img3_, extent=extent) plt.savefig(Path(path).expanduser().resolve().with_suffix('.cropped.svg')) fig.clear() plt.close(fig)
def call_exe(name, extras="", output=None): filename = curdir / "spectra_files" / "{0}.wdf".format(name) root = filename.parent # clean up all reader = WDFReader(filename) assert reader is not None for ext in (".csv", ".txt"): for f in root.glob("*" + ext): print(f) os.remove(f) # Initial name cmd = "wdf-export {0} {1}".format(filename.as_posix(), extras) if output is not None: cmd += "-o {0}".format(output) run = subprocess.run(cmd, shell=True) assert run.returncode == 0 # Manually set output if output is not None: output = Path(output) else: if ".txt" not in extras: output = filename.with_suffix(".csv") else: output = filename.with_suffix(".txt") assert output.is_file() is True # Read the data if output.suffix == ".csv": delimiter = "," else: delimiter = " " data = np.genfromtxt(output, delimiter=delimiter, skip_header=1) wn_data = data[:, 0] spectra_data = data[:, 1:] assert reader.xdata.shape[0] == wn_data.shape[0] assert reader.count == spectra_data.shape[1] spectra_reader = reader.spectra.reshape(reader.count, reader.xdata.shape[0]).T # Only do this for decreasing sequence if reader.xdata[0] > reader.xdata[1]: spectra_reader = spectra_reader[::-1, :] print(spectra_reader) print(spectra_data) assert np.all(np.isclose(spectra_reader, spectra_data, 1e-3))
def main(): filename = curdir / "spectra_files" / "line.wdf" reader = WDFReader(filename) assert reader.measurement_type == 3 # For mapping, xdata is still wavenumber wn = reader.xdata spectra = reader.spectra x = reader.xpos y = reader.ypos print(x.shape, y.shape) assert x.shape[0] == y.shape[0] == spectra.shape[0] # Distance d = np.sqrt(x**2 + y**2) wn = reader.xdata spectra = reader.spectra spectra = spectra - spectra.min(axis=1, keepdims=True) # Simply get accumulated counts between 1560 and 1620 cm^-1 pos = np.where((wn >= 1560) & (wn <= 1620))[0] cut = spectra[:, pos] sum_cnt = np.sum(cut, axis=1) if plot is True: # Level the spectra with baseline intensity plt.figure() plt.plot(d - d[0], sum_cnt, "-o") plt.xlabel("Distance (μm)") plt.ylabel("Sum. Intensity (ccd counts)") plt.title("Results from line.wdf") plt.show(block=False) plt.pause(3) plt.savefig(imgdir / "linxy.png", dpi=100) plt.close() else: print("Wavenumber is like:", wn) print("Distance is like:", d) print("Spectra matrix is like: \n", spectra) return
def load_renishaw(fid, method='gaussian', threshold=0, longpass_cutoff=0): ''' processes a PL map from the renishaw microraman tool fid: path to .wdf file threshold: minimum counts below which map pixels are considered background, set to nan method: how to fit peak counts + wavelength ['gaussian', 'max'] longpass_cutoff: wavelength below which laser longpass is blocking counts. prevents gaussian fitting from considering wavelengths blocked by filter. ''' if method not in fitmethods_key: raise ValueError( f'Invalid fitting method - must be one of {list(fitmethods_key.items())}' ) fitmethod = fitmethods_key[method] d = WDFReader(fid) d.img = np.asarray(Image.open(d.img)) if d.xlist_unit.name == 'Nanometre': d.wl = d.xdata d.shift = nmtoshift(d.wl, d.laser_length) else: d.wl = shifttonm(d.xdata, d.laser_length) d.shift = d.xdata longpass_mask = d.wl <= longpass_cutoff d.maxcts = np.zeros(d.spectra.shape[:-1]) d.fwhm = np.zeros(d.spectra.shape[:-1]) d.peakwl = np.zeros(d.spectra.shape[:-1]) for m, n in tqdm(np.ndindex(d.maxcts.shape), total=np.product(d.maxcts.shape), desc='Fitting Spectra', leave=False): d.maxcts[m, n], d.peakwl[m, n], d.fwhm[m, n] = fitmethod( d.wl[~longpass_mask], d.spectra[m, n, ~longpass_mask]) mask = d.maxcts < threshold d.maxcts[mask] = np.nan d.fwhm[mask] = np.nan d.peakwl[mask] = np.nan d.extent = [d.xpos[0], d.xpos[-1], d.ypos[0], d.ypos[-1]] #map dimensions return d
def main(): usage_msg = """%(prog)s - convert a wdf file to txt %(prog)s [OPTION]... [FILE] Extracts and formats data from a wdf file into multiple txt file. All txt files will be placed into a single directory. """ # Parse arguments parser = ArgumentParser(usage=usage_msg) parser.add_argument('file') parser.add_argument("-o", "--output", help="set OUTPUT as the output directory") parser.add_argument("-b", "--base", help="set BASE as the base name for output files") parser.add_argument("--no-duplicate", action="store_true", help="if specified, causes program to exit if output directory already exists") parser.add_argument("--keep-path", action="store_true", help="if specified, will not strip leading directories when creating output directory") args = parser.parse_args() ### Further argument parsing ### # Strip any trailing extensions from path name no_extension = args.file.split('.')[0] # Strip any leading directories from path no_directories = no_extension.split('/')[-1] # Set base name to stripped file name, if not specified if args.base is None: args.base = no_directories # Set to output directory to stripped file name + "_txt", if not specified # If keep_path specified, retains any leading directories if args.output is None: args.output = (no_extension if args.keep_path else no_directories) + "_wdfout" # Initialize reader reader = WDFReader(args.file) # Create output directory Path(args.output).mkdir(parents=True, exist_ok=not args.no_duplicate) # Parse reader spectra_length = len(reader.spectra) row, col = 0, 0 # Order of iteration: # iterate x and y simultaneously # iterate xdata and spectra simultaneously # spectra[i][j] where i increments ++, and j increments when i = len for i in range(reader.capacity): x = reader.xpos[i] y = reader.ypos[i] spectra = reader.spectra[row][col] # Create file and write line by line with open('{}/{}__X_{}__Y_{}).txt'.format(args.output, args.base, x.round(4), y.round(4)), 'w') as file: for j in reversed(range(reader.point_per_spectrum)): # Format: wavenumber spectra value file.write('{}\t{}\n'.format(reader.xdata[j], spectra[j])) # Determine row, col from i row += 1 if row == spectra_length: row, col = 0, col + 1
def main(): filename = curdir / "spectra_files" / "mapping.wdf" reader = WDFReader(filename) assert reader.measurement_type == 3 wn = reader.xdata spectra = reader.spectra print(wn.shape, spectra.shape) # Test newer API map_x = reader.xpos map_y = reader.ypos map_w = reader.map_info["x_span"] map_h = reader.map_info["y_span"] # w and h are the measure in xy coordinates # Level the spectra spectra = spectra - np.min(spectra, axis=2, keepdims=True) peaks_a = peak_in_range(spectra, wn, [1295, 1340]) peaks_b = peak_in_range(spectra, wn, [1350, 1400]) ratio = peaks_a / peaks_b if plot is True: # Must provide the format to read the optical image img = mpimg.imread(reader.img, format="jpg") img_x0, img_y0 = reader.img_origins img_w, img_h = reader.img_dimensions print(reader.img_dimensions) plt.figure(figsize=(10, 5)) # Left, plot the white light image and rectangle area plt.subplot(121) # Show the image with upper origin extent See # https://matplotlib.org/3.1.1/gallery/text_labels_and_annotations/text_alignment.html plt.imshow(img, extent=(img_x0, img_x0 + img_w, img_y0 + img_h, img_y0)) # Add rectangle for marking r = plt.Rectangle(xy=(map_x.min(), map_y.min()), width=map_w, height=map_h, fill=False) plt.gca().add_patch(r) plt.xlabel("Stage X [μm]") plt.ylabel("Stage Y [μm]") # Right plot histogram of Peak A/B mapping plt.subplot(122) plt.imshow(ratio, interpolation="bicubic", extent=[0, map_w, map_h, 0], vmin=0.5, vmax=1.5) plt.xlabel("Mapping x [μm]") plt.ylabel("Mapping y [μm]") cb = plt.colorbar() cb.ax.set_title("Ratio") plt.tight_layout() plt.show(block=False) plt.pause(3) plt.savefig(imgdir / "map-optical.png", dpi=100) plt.close() else: pass return
def main(): filename = curdir / "spectra_files" / "streamline.wdf" reader = WDFReader(filename) print("Measurement: ", reader.measurement_type) print("Scan: ", reader.scan_type) assert reader.measurement_type == 3 assert reader.scan_type == 6 wn = reader.xdata spectra = reader.spectra print(wn.shape, spectra.shape) x = reader.xpos y = reader.ypos print(len(x), len(y)) w, h = reader.map_shape print("The size of mapping is {0:d} * {1:d}".format(w, h)) # w and h are the measure in xy coordinates # Level the spectra spectra = spectra - np.min(spectra, axis=2, keepdims=True) peaks_a = peak_in_range(spectra, wn, [1295, 1340]) peaks_b = peak_in_range(spectra, wn, [1350, 1400]) ratio = peaks_a / peaks_b ratio_fl = ratio.flatten() if plot is True: plt.figure(figsize=(10, 5)) # Left plot histogram of Peak A/B ratio plt.subplot(121) img = mpimg.imread(reader.img, format="jpg") img_x0, img_y0 = reader.img_origins img_w, img_h = reader.img_dimensions plt.imshow(img, extent=(img_x0, img_x0 + img_w, img_y0 + img_h, img_y0)) plt.scatter(x, y, s=0.4, alpha=0.8) # plt.hist(ratio_fl, bins=50, range=(0.1, 2)) # plt.xlabel("Ratio peak A / peak B") # plt.ylabel("Counts") # Right plot histogram of Peak A/B mapping plt.subplot(122) plt.imshow( peaks_b, interpolation="bicubic", extent=[0, x.max() - x.min(), y.max() - y.min(), 0], ) # vmin=0.5, vmax=1.5) plt.xlabel("Mapping x [μm]") plt.ylabel("Mapping y [μm]") cb = plt.colorbar() cb.ax.set_title("Signal") plt.tight_layout() plt.show(block=False) plt.pause(3) plt.savefig(imgdir / "mapping_streamline.png", dpi=100) plt.close() else: pass return
Raman spectra typically have better signal-to-noise ratios, so there is not background subtracion performed in this program """ from renishawWiRE import WDFReader import matplotlib.pyplot as plt # input file path and file name IN_PATH = r'Z:\Trumann\Renishaw\20210304 PVSe33' FNAME = r'\PVSe33.4_3 Au side raman map0.wdf' # import wdf file filename = IN_PATH+FNAME reader = WDFReader(filename) reader.print_info() # get x-axis of spectral data # keep in mind the units you specified for the measurement # here, raman shift (cm-1) was specified and would be the x-axis of the spectrum shift = reader.xdata # get the spectral data # if .wdf file is a map, 'spectra' is 3D (y_pixel, x_pixel, intensity) # if .wdf file is spot, 'spectra' is 1D (intensity) # if .wdf file is aborted map, 'spectra' is 2D (y_pix*x_pix, intensity) spectra = reader.spectra # check the spectrum of the first pixel # this will not work if the map was aborted
def main(): usage_msg = """%(prog)s - convert a wdf file to txt %(prog)s [OPTION]... [FILE] Extracts and formats data from a wdf file into multiple txt file. All txt files will be placed into a single directory. """ # Parse arguments parser = ArgumentParser(usage=usage_msg) parser.add_argument('file') parser.add_argument("-o", "--output", help="set OUTPUT as the output directory") parser.add_argument("-b", "--base", help="set BASE as the base name for output files") parser.add_argument( "-p", "--parent", help="set PARENT as the parent directory of the output directory") parser.add_argument( "--no-duplicate", action="store_true", help= "if specified, causes program to exit if output directory already exists" ) parser.add_argument( "--keep-path", action="store_true", help= "if specified, will not strip leading directories when creating output directory" ) args = parser.parse_args() ### Further argument parsing ### # Strip any leading directories from path dir_split = args.file.split('/') no_dir = dir_split[-1] # Strip any trailing extension from file stripped = no_dir.split('.')[0] # Set base name to stripped file name, if not specified if args.base is None: args.base = stripped # Set to output directory to stripped file name + "_txt", if not specified # If keep_path specified, will not strip leading directories if args.keep_path: dir_split[-1] = '' stripped = '/'.join(dir_split) + stripped if args.output is None: args.output = stripped + "_txt" # If parent directory specified, make sure to append '/' for proper traversal # Otherwise, leave blank as to not disrupt relative/absolute pathing if args.parent is None: args.parent = '' else: args.parent += '/' dirname = f'{args.parent}{args.output}' try: if not Path(args.file).is_file(): # Error: invalid input file raise Exception(f'invalid input file: {args.file}') # Initialize reader try: reader = WDFReader(args.file) except Exception as e: # Error: cannot read file raise Exception(f'cannot read file: {args.file}') # Create output directory directory = Path(dirname) if directory.exists() and not directory.is_dir(): # Error: existing path is a file raise Exception(f'output directory is already a file: {dirname}') if directory.exists() and args.no_duplicate: # Error: duplicate directory raise Exception(f'directory already exists: {dirname}') directory.mkdir(parents=True, exist_ok=not args.no_duplicate) # Parse reader spectra_length = len(reader.spectra) row, col = 0, 0 spectra = reader.spectra.flatten() start = 0 # Order of iteration: # iterate x and y simultaneously # iterate xdata and spectra simultaneously # spectra[i][j] where i increments ++, and j increments when i = len for i in range(reader.capacity): x = reader.xpos[i] y = reader.ypos[i] # Create file and write line by line filename = f'{dirname}/{args.base}__X_{x.round(4)}__Y_{y.round(4)}.txt' with open(filename, 'w') as file: for j in range(reader.point_per_spectrum): # Format: wavenumber spectra value file.write( f'{reader.xdata[j]:.6f}\t{spectra[start + j]:.6f}\n') start += reader.point_per_spectrum exit(0) except Exception as e: print(e, file=sys.stderr) exit(1)