#pragma TextEncoding = "UTF-8" #pragma rtGlobals=3 // Use modern global access method and strict wave access. #pragma IgorVersion = 6.36 #pragma ModuleName = PearlDataExplorer #pragma version = 2.1 #include , version >= 1.14 #include "pearl-area-import" #include "pearl-area-profiles" #include "pearl-area-display" #include "pearl-compat" #include "pearl-pshell-import" // copyright (c) 2013-22 Paul Scherrer Institut // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http:///www.apache.org/licenses/LICENSE-2.0 /// @file /// @brief preview and import panel for PEARL data /// @ingroup ArpesPackage /// /// /// preview and import panel for PEARL data: /// @arg area detector (HDF5) files from scienta analyser and prosilica cameras (if HDF5.xop is installed). /// @arg igor text files from s-scans and otf-scans. /// @arg pshell (HDF5) data files (if HDF5.xop is installed). /// @namespace PearlDataExplorer /// @brief preview and import panel for PEARL data /// /// PearlDataExplorer is declared in @ref pearl-data-explorer.ipf. static strconstant package_name = "pearl_explorer" static strconstant package_path = "root:packages:pearl_explorer:" static strconstant ks_filematch_adh5 = "*.h5" static strconstant ks_filematch_pshell = "psh*.h5" static strconstant ks_filematch_itx = "*.itx" /// show the pearl data explorer window /// /// create a pearl data explorer window or bring the existing one to the front. /// if a new window is created, also initialize all package variables and load package preferences. /// function pearl_data_explorer() DoWindow /HIDE=0 /F PearlDataExplorer if (v_flag == 0) init_package() load_prefs() execute /q/z "PearlDataExplorer()" MakeListIntoHierarchicalList("PearlDataExplorer", "lb_contents", "PearlDataExplorer#hlp_contents_open", selectionMode=WMHL_SelectionNonContinguous, pathSeparator="/") WMHL_AddColumns("PearlDataExplorer", "lb_contents", 1) WMHL_SetNotificationProc("PearlDataExplorer", "lb_contents", "PearlDataExplorer#hlp_contents_selection", WMHL_SetSelectNotificationProc) ListBox lb_contents win=PearlDataExplorer, widths={6,60,20} update_controls() endif end static function init_package() dfref save_df = GetDataFolderDFR() SetDataFolder root: newdatafolder /o/s packages newdatafolder /o/s $package_name if (exists("v_InitPanelDone") == 2) SetDataFolder save_df return 0 endif make /o/n=0/t wtFiles make /o/n=0/i wSelectedFiles,wSelectedDatasets make /o/n=0/t wtDatasets make /o/n=0/t wtPositioners,wtDetectors make /o/n=0/i wSelectedPositioners,wSelectedDetectors make /o/n=(1,1) preview_image // preview 2D data make /o/n=0 preview_trace // preview 1D data make /o/n=0/t attr_names, attr_values, attr_filter, attr_filter_summary // persistent strings and variables. persistent = saved in preferences string /g s_filepath = "" // directory path to be listed string /g s_hdf_options = "" // recently used HDF5 load options string /g s_reduction_params = "" // recently used reduction parameters string /g s_preview_pvs = "" // semicolon-separated list of EPICS PVs to display in preview. // the list items can contain wildcards for StringMatch s_preview_pvs = "*OP:CURRENT*;*Stats*Total*;*KEITHLEY*READOUT;*CADC*" redimension /n=26 attr_filter_summary attr_filter_summary[0] = "MonoEnergy" attr_filter_summary[1] = "MonoGrating" attr_filter_summary[2] = "ExitSlit" attr_filter_summary[3] = "FrontendHSize" attr_filter_summary[4] = "FrontendVSize" attr_filter_summary[5] = "ManipulatorPhi" attr_filter_summary[6] = "ManipulatorTheta" attr_filter_summary[7] = "ManipulatorTilt" attr_filter_summary[8] = "ManipulatorX" attr_filter_summary[9] = "ManipulatorY" attr_filter_summary[10] = "ManipulatorZ" attr_filter_summary[11] = "PassEnergy" attr_filter_summary[12] = "LensMode" attr_filter_summary[13] = "ScientaDwellTime" attr_filter_summary[14] = "ScientaCenterEnergy" attr_filter_summary[15] = "ScientaChannelBegin" attr_filter_summary[16] = "ScientaChannelEnd" attr_filter_summary[17] = "ScientaSliceBegin" attr_filter_summary[18] = "ScientaSliceEnd" attr_filter_summary[19] = "ScientaNumChannels" attr_filter_summary[20] = "StepSize" attr_filter_summary[21] = "ScientaNumSlices" attr_filter_summary[22] = "ManipulatorTempA" attr_filter_summary[23] = "ManipulatorTempB" attr_filter_summary[24] = "RefCurrent" attr_filter_summary[25] = "SampleCurrent" // non-persistent strings and variables string /g s_short_filepath = "" // abbreviated directory path string /g s_selected_file = "" string /g s_selected_dataset = "" string /g s_preview_file = "" // file or folder name of the current preview string /g s_preview_source = "" // data source, e.g. EPICS channel name, of the current preview string /g s_profiles_graph = "" // window name of the current preview if the data is two-dimensional string /g s_preview_trace_graph = "" // window name of the current preview if the data is one-dimensional string /g s_preview_graph = "" // window name of the most recent preview graph string /g s_file_info = "" // description of selected file string /g s_result = "" // result of last operation variable/g v_InitPanelDone = 1 SetDataFolder save_df end /// save persistent package data to the preferences file. /// /// this function is called when the user clicks the corresponding button. /// the data saved in the file are: data file path, attributes filter /// static function save_prefs() dfref save_df = GetDataFolderDFR() dfref df = $package_path if (DataFolderRefStatus(df) == 1) string fullPath = SpecialDirPath("Packages", 0, 0, 0) fullPath += package_name NewPath/O/C/Q tempPackagePrefsPath, fullPath fullPath += ":preferences.pxp" SetDataFolder df string objects = "attr_filter;attr_filter_summary;s_filepath;s_hdf_options;s_reduction_params;s_preview_pvs" SaveData /O /Q /J=objects fullPath KillPath/Z tempPackagePrefsPath endif SetDataFolder save_df end static function load_prefs() // loads persistent package data from the preferences file // the preferences file is an Igor packed experiment file in a special preferences folder dfref save_df = GetDataFolderDFR() variable result = -1 setdatafolder root: NewDataFolder /O/S packages NewDataFolder /O/S $package_name dfref package_df = GetDataFolderDFR() string fullPath = SpecialDirPath("Packages", 0, 0, 0) fullPath += package_name GetFileFolderInfo /Q /Z fullPath if (V_Flag == 0) // Disk directory exists? fullPath += ":preferences.pxp" GetFileFolderInfo /Q /Z fullPath if (V_Flag == 0) // Preference file exist? LoadData /O /R /Q fullPath result = 0 endif endif if (result == 0) svar /sdfr=package_df filepath = s_filepath NewPath /O/Z pearl_explorer_filepath, filepath update_filepath() update_filelist() endif SetDataFolder save_df return result end /// check whether a file can be imported by this module. /// /// the file type is determined by the extension of the file name. /// /// @return file type /// @arg 0 not a recognized file type /// @arg 1 PShell file (HDF5, name starts with psh_) /// @arg 2 area detector HDF5 file /// @arg 3 Igor text (itx) file /// static function pearl_file_type(filename) string filename if (StringMatch(filename, ks_filematch_pshell)) return 1 elseif (StringMatch(filename, ks_filematch_adh5)) return 2 elseif (StringMatch(filename, ks_filematch_itx)) return 3 else return 0 endif end /// update the file path after path change /// /// read the path info from pearl_explorer_filepath /// and update the path control /// static function update_filepath() PathInfo /S pearl_explorer_filepath svar filepath = $(package_path + "s_filepath") svar shortpath = $(package_path + "s_short_filepath") filepath = s_path shortpath = shorten_filepath(filepath, 40) end /// read a list of PEARL files from the file system /// /// wtFiles and wSelectedFiles in the package data folder are updated. /// only files for which pearl_file_type() returns non-zero are listed. /// static function update_filelist() dfref save_df = GetDataFolderDFR() string all_files wave /t wtFiles = $(package_path + "wtFiles") wave wSelectedFiles = $(package_path + "wSelectedFiles") variable nn PathInfo pearl_explorer_filepath if (v_flag == 1) all_files = IndexedFile(pearl_explorer_filepath, -1, "????") nn = ItemsInList(all_files) else all_files = "" nn = 0 endif make /n=(nn) /t /free wtAllFiles wtAllFiles = StringFromList(p, all_files) Extract /o /t wtAllFiles, wtFiles, pearl_file_type(wtAllFiles[p]) Sort /A /R wtFiles, wtFiles redimension /n=(numpnts(wtFiles)) wSelectedFiles wSelectedFiles = 0 setdatafolder save_df end // ====== metadata ====== /// load the internal structure of a file /// /// this loads metadata for updating the panels. /// /// for a pshell file, metadata includes: /// - list of all datasets with types and dimensions /// - general group /// /// @return 0 if successful /// -1 if no data was loaded because the file was not recognized, /// -2 if no data is found in file /// static function get_file_info(filename) string filename dfref save_df = GetDataFolderDFR() dfref package_df = $package_path variable ft = pearl_file_type(filename) variable result = 0 switch(ft) case 1: case 2: dfref file_df = get_pshell_info("pearl_explorer_filepath", filename) result = hl_contents_update(file_df) result = result >= 3 ? 0 : -2 break default: hl_contents_clear() dfref file_df = package_df:file_info KillDataFolder /z file_df result = -1 endswitch setdatafolder save_df return result end /// load attributes static function attributes_notebook(filename) string filename dfref save_df = GetDataFolderDFR() dfref temp_df = NewFreeDataFolder() load_file(filename, options="mode:load_diags", dest_df=temp_df, quiet=1) svar /sdfr=temp_df /z s_loaded_datasets string scan dfref scan_df if (SVAR_Exists(s_loaded_datasets) && (strlen(s_loaded_datasets) >= 4)) scan = StringFromList(0, psh5_extract_scan_paths(s_loaded_datasets), ";") scan_df = psh5_dataset_to_folder(temp_df, scan) else scan_df = temp_df endif dfref attr_df = ps_find_attr_folder(scan_df) if (DataFolderRefStatus(attr_df)) extract_attributes(attr_df, dest_df=temp_df) wave /t /sdfr=temp_df /z attr_names wave /t /sdfr=temp_df /z attr_values if (WaveExists(attr_names) && WaveExists(attr_values)) create_attributes_notebook(attr_names, attr_values, filename) endif endif setdatafolder save_df end /// extract summary from attribute waves /// /// by default, all existing attributes are copied. /// if a text wave attr_filter exists in the pear_explorer folder, only the attributes referenced therein are copied. /// to set up a filter, duplicate the attr_names wave of a template dataset, and remove unwanted items. /// /// @param attr_df data folder which contains the original data, e.g. the attr, diags or snaps folder in pshell files. /// @param dest_df destination folder. the output is written to the attr_names and attr_values waves. /// default = package folder. /// @param attr_filter (text wave) list of attributes allowed in the output. /// default = use attr_filter of package folder. /// @param include_datawaves @arg 1 (default) include data waves (any numeric wave which has a PV=name note). /// @arg 0 don't include attributes from data waves. /// @param include_infowaves @arg 1 (default) include attributes from info waves (IN, ID, IV, IU). /// @arg 0 don't include attributes from info waves. /// static function extract_attributes(attr_df, [dest_df, attr_filter, include_datawaves, include_infowaves]) dfref attr_df dfref dest_df wave /t attr_filter variable include_datawaves variable include_infowaves dfref save_df = GetDataFolderDFR() dfref package_df = $package_path if (ParamIsDefault(dest_df)) dest_df = GetDataFolderDFR() endif if (ParamIsDefault(attr_filter) || !WaveExists(attr_filter)) wave /t /sdfr=package_df /z attr_filter endif if (ParamIsDefault(include_datawaves)) include_datawaves = 1 endif if (ParamIsDefault(include_infowaves)) include_infowaves = 1 endif setdatafolder dest_df wave /t /z attr_names, attr_values if (!WaveExists(attr_names) || !WaveExists(attr_values)) make /n=(1) /o /t attr_names, attr_values endif attr_names = "" attr_values = "" setdatafolder attr_df wave /t /z IN wave /t /z ID wave /t /z IV wave /t /z IU // compile list of attributes variable nattr // destination attributes variable iattr variable ninfo // info wave elements variable iinfo variable nw // attribute waves variable iw string sw string ss if (WaveExists(IN) && include_infowaves) ninfo = numpnts(IN) else ninfo = 0 endif if (include_datawaves) string waves = WaveList("*", ";", "") string exceptions = "ID;IN;IU;IV" waves = RemoveFromList(exceptions, waves) nw = ItemsInList(waves, ";") else nw = 0 endif if (WaveExists(attr_filter) && (numpnts(attr_filter) >= 1)) nattr = numpnts(attr_filter) redimension /n=(nattr) attr_names attr_names = attr_filter else if(ninfo > 0) redimension /n=(ninfo) attr_names attr_names = SelectString(strlen(ID[p]) >= 0, IN[p], ID[p]) // use ID unless empty endif nattr = ninfo + nw iattr = ninfo redimension /n=(nattr) attr_names for (iw = 0; iw < nw; iw +=1 ) sw = StringFromList(iw, waves, ";") ss = StringByKey("PV", note($sw), "=", "\r") FindValue /text=sw attr_names if ((v_value < 0) && (strlen(ss) >= 0)) attr_names[iattr] = sw iattr += 1 endif endfor nattr = iattr endif redimension /n=(nattr) attr_names, attr_values sort attr_names, attr_names // look up attribute values for (iattr = 0; iattr < nattr; iattr += 1) sw = attr_names[iattr] // try info waves if (ninfo > 0) FindValue /text=sw ID if (v_value >= 0) attr_values[iattr] = IV[v_value] endif FindValue /text=sw IN if (v_value >= 0) attr_values[iattr] = IV[v_value] endif endif // override from attribute wave if existent if (nw > 0) switch (WaveType($sw, 1)) case 1: // numeric wave /z w = $sw if (WaveExists(w) && (numpnts(w) >= 1)) sprintf ss, "%g", w[0] attr_values[iattr] = ss endif break case 2: // text wave /t/z wt = $sw if (WaveExists(wt) && (numpnts(wt) >= 1)) attr_values[iattr] = wt[0] endif break endswitch endif endfor setdatafolder save_df end function test_attributes_notebook() dfref df = GetDataFolderDFR() wave /t /sdfr=df attr_names wave /t /sdfr=df attr_values create_attributes_notebook(attr_names, attr_values, GetDataFolder(0)) end static function create_attributes_notebook(attr_names, attr_values, title) wave /t attr_names wave /t attr_values string title dfref save_df = GetDataFolderDFR() setdatafolder $package_path wave /t/z attr_filter, attr_filter_summary string name = PearlCleanupName("nb_" + title[0,27]) if (WinType(name) == 5) Notebook $name selection={startOfFile, endOfFile} Notebook $name text="" else NewNotebook /F=1 /K=1 /N=$name as title GetWindow $name wsize v_right = v_left + 260 v_bottom = v_top + 360 MoveWindow /W=$name v_left, v_top, v_right, v_bottom Notebook $name tabs={2*72} endif // summary if (WaveExists(attr_filter_summary) && (numpnts(attr_filter_summary) >= 1)) notebook $name fStyle=1, text="Summary\r\r" notebook $name fStyle=0 notebook_add_attributes(name, attr_filter_summary, attr_names, attr_values) notebook $name text="\r" endif // all attributes notebook $name fStyle=1, text="All Attributes\r\r" notebook $name fStyle=0 notebook_add_attributes(name, $"", attr_names, attr_values) notebook $name selection={startOfFile,startOfFile}, findText={"",1} setdatafolder save_df end static function notebook_add_attributes(notebook_name, attr_filter, attr_names, attr_values) string notebook_name wave /t /z attr_filter wave /t attr_names wave /t attr_values variable nw = numpnts(attr_names) variable iw string sw string ss variable do_filter = WaveExists(attr_filter) for (iw = 0; iw < nw; iw += 1) if (do_filter) sw = attr_names[iw] FindValue /text=sw attr_filter else v_value = 0 endif if (v_value >= 0) sprintf ss, "%s\t%s\r", attr_names[iw], attr_values[iw] notebook $notebook_name text=ss endif endfor end /// send general metadata to ELOG panel - if available /// /// the following metatdata are sent. /// they must be present as strings in the specified data folder: /// /// | ELOG parameter | global string | function argument | /// | --- | --- | --- | /// | file | s_filepath | filename | /// | graph attachment | | graphname | /// | author | authors | | /// | p-group | pgroup | | /// | project | proposal | | /// | sample | sample | | /// /// @param file_df data folder that contains the metadata. /// /// @param filename override file path read from s_filepath global string variable. /// if neither is declared, the file name is reset to empty field. /// /// @param graphname select this graph window for attaching. /// default: do not change the selection. /// static function set_elog_attributes(file_df, [filename, graphname]) dfref file_df string filename string graphname if (ParamIsDefault(filename)) svar /sdfr=file_df /z loaded_file=s_filepath if (svar_Exists(loaded_file)) filename = loaded_file else filename = "" endif endif if (ParamIsDefault(graphname)) graphname = "" endif string cmd if (exists("PearlElog#set_panel_attributes") == 6) sprintf cmd, "PearlElog#set_panel_attributes(\"\", \"File=%s\")", ParseFilePath(0, filename, ":", 1, 0) execute /Q/Z cmd if ((strlen(graphname) > 0) && (WinType(graphname) == 1)) sprintf cmd, "PearlElog#set_panel_graphs(\"\", \"%s\")", graphname execute /Q/Z cmd endif svar /sdfr=file_df /z authors if (svar_Exists(authors)) if (strlen(authors)>=1) sprintf cmd, "PearlElog#set_panel_attributes(\"\", \"author=%s\")", authors execute /Q/Z cmd endif endif svar /sdfr=file_df /z pgroup if (svar_Exists(pgroup)) if (strlen(pgroup)>=1) sprintf cmd, "PearlElog#set_panel_attributes(\"\", \"p-group=%s\")", pgroup execute /Q/Z cmd endif endif svar /sdfr=file_df /z proposal if (svar_Exists(proposal)) if (strlen(proposal)>=1) sprintf cmd, "PearlElog#set_panel_attributes(\"\", \"project=%s\")", proposal execute /Q/Z cmd endif endif svar /sdfr=file_df /z proposer svar /sdfr=file_df /z sample if (svar_Exists(sample)) if (strlen(sample)>=1) sprintf cmd, "PearlElog#set_panel_attributes(\"\", \"sample=%s\")", sample execute /Q/Z cmd endif endif endif end // ====== preview ====== static function preview_file(filename) string filename dfref save_df = GetDataFolderDFR() dfref preview_df = $package_path killStrings /z authors, pgroup, proposal, proposer, sample variable ft = pearl_file_type(filename) switch(ft) case 1: wave /z image = preview_pshell_file(filename) break case 2: wave /z image = preview_hdf_file(filename) break case 3: wave /z image = preview_itx_file(filename) break default: wave /z image = $"" endswitch if (WaveExists(image)) show_preview_graph(image) endif setdatafolder save_df return 0 end /// load the preview of a PShell HDF5 file. /// /// the preview is an arbitrary detector image extracted from the file, see adh5_load_preview(). /// the preview is loaded to the preview_image wave in the pear_explorer data folder. /// /// the s_file_info string is updated with information about the scan dimensions. /// /// @param filename name of a file in the directory specified by the pearl_explorer_filepath path object. /// /// @return wave reference of the preview image /// static function /wave preview_pshell_file(filename) string filename dfref save_df = GetDataFolderDFR() setdatafolder $package_path dfref preview_df = GetDataFolderDFR() svar s_preview_file svar s_preview_source svar /z s_file_info if (! svar_exists(s_file_info)) string /g s_file_info endif dfref temp_df = NewFreeDataFolder() dfref file_df = psh5_preview("pearl_explorer_filepath", filename, dest_df=temp_df) svar /z /sdfr=temp_df dataname=s_preview_wave s_preview_file = filename s_preview_source = "" wave /z /sdfr=temp_df data = $dataname if (waveexists(data)) duplicate /o data, preview_df:preview_image else print "no data found in file " + filename endif s_file_info = "" setdatafolder save_df wave /z /sdfr=preview_df preview_image return preview_image end /// load the preview of a PEARL HDF5 file. /// /// the preview is an arbitrary detector image extracted from the file, see adh5_load_preview(). /// the preview is loaded to the preview_image wave in the pear_explorer data folder. /// /// the s_file_info string is updated with information about the scan dimensions. /// /// @param filename name of a file in the directory specified by the pearl_explorer_filepath path object. /// /// @return wave reference of the preview image /// static function /wave preview_hdf_file(filename) string filename dfref save_df = GetDataFolderDFR() setdatafolder $package_path svar s_preview_file svar s_preview_source adh5_load_preview("preview_image", "pearl_explorer_filepath", filename) s_preview_file = filename s_preview_source = "" wave /z preview_image svar /z s_file_info if (! svar_exists(s_file_info)) string /g s_file_info endif if (strlen(s_preview_file) > 0) s_file_info = adh5_load_info("pearl_explorer_filepath", filename) else s_file_info = "" endif setdatafolder save_df return preview_image end /// load the preview of a general ITX file. /// /// the function is designed for PEARL OTF and EPICS scan data converted from MDA files. /// the function picks the first wave whose PV note matches one from the global string s_preview_pvs /// (see @ref preview_datafolder and @ref init_package). /// /// the preview is loaded to the preview_image wave in the pearl_explorer data folder. /// the s_file_info string is updated with information about the scan dimensions. /// /// @note: the ITX files should load their waves into the current data folder (a "free" data folder). /// some early versions of PEARL ITX data files created a data folder of their own. /// both ways are allowed, while the first one is preferred. /// on return, the current data folder must point to either the original free folder or the newly created one. /// /// @param filename name of a file in the directory specified by the pearl_explorer_filepath path object. /// /// @return wave reference of the preview trace. /// empty wave reference if the function failed. /// static function /wave preview_itx_file(filename) string filename dfref save_df = GetDataFolderDFR() setdatafolder $package_path svar s_preview_file svar s_preview_source wave preview_image dfref data_df = newfreedatafolder() setdatafolder data_df LoadWave /t/p=pearl_explorer_filepath/q filename s_preview_file = s_filename s_preview_source = "" preview_datafolder() setdatafolder save_df return preview_image end /// extract a preview image from a wave of arbitrary dimension static function extract_preview_image(data, preview) wave data wave preview variable z1, z2 // extract image switch (WaveDims(data)) case 1: redimension /n=(numpnts(data)) preview preview = data[p] break case 2: redimension /n=(dimsize(data, 0), dimsize(data, 1)) preview preview = data break case 3: redimension /n=(dimsize(data, 0), dimsize(data, 1)) preview z1 = floor(DimSize(data, 2) / 2) z2 = z1 wave slab = ad_extract_slab(data, nan, nan, nan, nan, z1, z2, "", pscale=1) preview = slab break case 4: // not implemented endswitch switch (WaveDims(data)) case 4: case 3: case 2: setscale /p y dimoffset(data, 1), dimdelta(data, 1), waveunits(data, 1), preview case 1: setscale /p x dimoffset(data, 0), dimdelta(data, 0), waveunits(data, 0), preview setscale d 0, 0, waveunits(data, -1), preview endswitch end /// preview data in the current data folder /// /// used by preview_itx_file /// static function preview_datafolder() dfref save_df = GetDataFolderDFR() setdatafolder $package_path svar s_preview_file svar s_preview_source svar s_preview_pvs wave preview_image setdatafolder save_df // select a wave to display // consider only double-precision waves, i.e. ignore text and other special waves // filter by matching PV name to s_preview_pvs string d_names = WaveList("*", ";", "DP:1") variable nw = ItemsInList(d_names, ";") variable npv = ItemsInList(s_preview_pvs, ";") variable iw, ipv string wname, wnote, pv_name, pv_match for (iw = 0; iw < nw; iw += 1) wname = StringFromList(iw, d_names, ";") wnote = note($wname) pv_name = StringByKey("PV", wnote, "=", "\r") // find matching data wave by PV name for (ipv = 0; ipv < npv; ipv += 1) pv_match = StringFromList(ipv, s_preview_pvs) if (StringMatch(pv_name, pv_match)) wave data = $wname s_preview_source = pv_name extract_preview_image(data, preview_image) preview_setscale_x(data, preview_image) npv = 0 nw = 0 endif endfor endfor setdatafolder save_df end static function preview_setscale_x(data, preview) // sets the approximate x scale of OTF data. // requires an Axis1 tag with name of x wave in the wave note. // if any of these conditions is true, the function does not change the scaling: // 1) Axis1 tag or referenced wave is missing. // 2) preview wave is not set to point scaling. // 3) x wave is not monotonic (90% of the steps in the same direction). wave data wave preview if ((DimOffset(preview, 0) == 0) && (DimDelta(preview, 0) == 1)) string xname = StringByKey("Axis1", note(data), "=", "\r") wave /z xwave = $xname if (WaveExists(xwave)) // check for monotonicity variable monotonic = 0 duplicate /free xwave, xdiff differentiate /p xwave /D=xdiff duplicate /free xdiff, xflag xflag = xdiff > 0 monotonic = sum(xflag) > numpnts(xwave) * 0.9 xflag = xdiff < 0 monotonic = monotonic || (sum(xflag) > numpnts(xwave) * 0.9) if (monotonic) setscale /i x xwave[0], xwave[numpnts(xwave)-1], waveunits(xwave, -1), preview endif endif endif end /// displays the graph of a loaded dataset in its own window static function display_dataset(file_df, dataset) dfref file_df // top data folder of file string dataset // dataset path inside data folder dfref save_df = GetDataFolderDFR() dfref data_df = psh5_dataset_to_folder(file_df, dataset) SetDataFolder data_df string data_name = StringFromList(ItemsInList(dataset, "/") - 1, dataset, "/") wave /z data=$data_name if (WaveExists(data)) switch(WaveDims(data)) case 1: case 2: show_preview_graph(data) break case 3: ad_display_slice(data) ad_brick_slicer(data) break endswitch endif setdatafolder save_df return 0 end static function /s show_preview_graph(data, [xdata]) // displays a preview of one- or two-dimensional data wave data // data to be displayed. must either one-dimensional or two-dimensional wave xdata // positions on x axis dfref save_df = GetDataFolderDFR() setdatafolder $package_path svar s_profiles_graph svar s_preview_file svar s_preview_source svar s_preview_trace_graph svar s_preview_graph if ((strlen(s_profiles_graph) > 0) && (WinType(s_profiles_graph) == 1)) KillWindow $s_profiles_graph endif if ((strlen(s_preview_trace_graph) > 0) && (WinType(s_preview_trace_graph) == 1)) KillWindow $s_preview_trace_graph endif string graphname if (wavedims(data) == 2) s_profiles_graph = ad_display_profiles(data) ModifyGraph /w=$s_profiles_graph /z wbRGB=(48640,56832,60160) graphname = s_profiles_graph elseif (wavedims(data) == 1) duplicate /o data, preview_trace if (!ParamIsDefault(xdata)) duplicate /o xdata, preview_trace_x else duplicate /o data, preview_trace_x preview_trace_x = x setscale d 0, 0, WaveUnits(data, 0), preview_trace_x endif s_preview_trace_graph = display_preview_trace(preview_trace_x, preview_trace) ModifyGraph /w=$s_preview_trace_graph wbRGB=(48640,56832,60160) graphname = s_preview_trace_graph else return "" endif string title = "Preview " + s_preview_file if (strlen(s_preview_source) > 0) title = title + " (" + s_preview_source[0,31] + ")" endif dowindow /f/t $graphname, title s_preview_graph = graphname setdatafolder save_df return graphname end static function /s display_preview_trace(xtrace, ytrace) wave /z xtrace wave ytrace if (WaveExists(xtrace)) display /n=pearl_explorer_1d /k=1 ytrace vs xtrace as "Preview" else display /n=pearl_explorer_1d /k=1 ytrace as "Preview" endif string graphname = s_name ModifyGraph /w=$graphname rgb[0]=(0,0,0) ModifyGraph /w=$graphname grid=2 ModifyGraph /w=$graphname mirror=1 ModifyGraph /w=$graphname minor=1 ModifyGraph /w=$graphname axThick=0.5 ModifyGraph /w=$graphname gridRGB=(52224,52224,52224) ModifyGraph /w=$graphname gridHair=0 ModifyGraph /w=$graphname tick=0 ModifyGraph /w=$graphname btLen=4 // axis labels string labels = note(ytrace) string lab lab = StringByKey("AxisLabelX", labels, "=", "\r") if (!strlen(lab)) lab = "X" endif Label /w=$graphname bottom lab + " (\\U)" lab = StringByKey("Dataset", labels, "=", "\r") if (!strlen(lab)) lab = "value" endif Label /w=$graphname left lab + " (\\U)" return s_name end // ====== file loading ====== /// load the selected files /// /// load the files that are selected in the data explorer panel. /// the files are loaded using the load_file() function. /// /// @note this function may change the current data folder! /// static function load_selected_files([options]) string options dfref save_df = GetDataFolderDFR() setdatafolder $package_path wave wSelectedFiles wave/t wtFiles variable nn = numpnts(wSelectedFiles) variable ii for (ii = 0; ii < nn; ii += 1) if (wSelectedFiles[ii]) setdatafolder save_df if (ParamIsDefault(options)) load_file(wtFiles[ii]) else load_file(wtFiles[ii], options=options) endif endif endfor end /// load one file /// /// this can be a PShell, HDF5, or ITX file. /// /// @note this function may change the current data folder! /// /// @param options `key:value;` list of load options. /// the recognized keys are: `mode`, `reduction_func` and `reduction_params`. /// see main text for a description of possible values. /// by default (options not specified), options are read from `s_hdf_options. /// if the option string is empty, the user is prompted for options. /// /// @param dest_df destination data folder. default: a new folder derived from file name under root. /// /// @param quiet @arg 0 (default) print mode and parameters to history. /// @arg 1 do not print to history. /// static function load_file(filename, [options, dest_df, quiet]) string filename string options dfref dest_df variable quiet if (ParamIsDefault(options)) options = "" endif variable ft = pearl_file_type(filename) switch(ft) case 1: load_pshell_file(filename, options=options, dest_df=dest_df, quiet=quiet) break case 2: load_hdf_file(filename, options=options, dest_df=dest_df, quiet=quiet) break case 3: load_itx_file(filename, dest_df=dest_df, quiet=quiet) break default: break endswitch end static function prompt_hdf_options(options) string &options string mode = StringByKey("mode", options, ":", ";") string reduction_func = StringByKey("reduction_func", options, ":", ";") string modes = "load_scan;load_region;load_dataset;load_diags;load_complete;" string reduction_funcs = adh5_list_reduction_funcs() reduction_funcs = RemoveFromList("adh5_default_reduction", reduction_funcs, ";") if (strlen(mode) == 0) mode = StringFromList(0, modes, ";") endif if (strlen(reduction_func) == 0) reduction_func = StringFromList(0, reduction_funcs, ";") endif prompt mode, "Mode", popup, modes prompt reduction_func, "Reduction Function", popup, reduction_funcs doprompt "HDF5 Loading Options", mode, reduction_func if (v_flag == 0) options = ReplaceStringByKey("mode", options, mode, ":", ";") options = ReplaceStringByKey("reduction_func", options, reduction_func, ":", ";") endif return v_flag // 0 = OK, 1 = cancel end /// prototype for prompting for processing function parameters. /// /// the function should prompt the user for function parameters, /// and update the param argument if the user clicked OK. /// returns 0 if the user clicked OK, 1 if the user cancelled. /// /// prompt functions must have the same name as the corresponding reduction function /// with the prefix "prompt_". /// be aware of the limited length of function names in Igor. /// /// this function is a prototype. it does nothing but returns OK. /// function prompt_default_process(param) string ¶m return 0 end function prompt_func_params(func_name, func_param) string func_name string &func_param string prompt_name = "prompt_" + func_name if (exists(prompt_name) == 6) funcref prompt_default_process prompt_func = $prompt_name return prompt_func(func_param) else // ignore missing prompt function return 0 endif end /// load a pshell file /// /// if options is not specified, the complete file is loaded. /// if options is an empty string, the package default options are used. /// /// data selection is extracted from the datasets list box. /// /// the file can be loaded in one of the following modes (`mode` key of the options argument): /// /// @arg `load_complete` load all datasets regardless of selection. /// @arg `load_scan` load default datasets of selected scans. /// @arg `load_region` load default datasets of selected regions. /// @arg `load_dataset` load selected datasets. /// @arg `load_diags` load diagnostic datasets of selected scans. /// /// 3-dimensional datasets can be loaded with dimension reduction. /// in this case, the name of the reduction function must be given under the `reduction_func` key. /// the reduction parameters are prompted for if a prompt function for the reduction function is found. /// the default reduction parameters are the most recent parameters `s_reduction_params` stored in the package data folder. /// /// @arg `reduction_func:...` name of the reduction function. /// /// if a reduction function is specified, default reduction parameters are read from `s_reduction_params` in the package data folder, /// and the user is prompted to review/update the parameters. /// /// @param options `key:value;` list of load options. /// the recognized keys are: `mode`, `reduction_func` and `reduction_params`. /// see main text for a description of possible values. /// by default (options not specified), options are read from `s_hdf_options. /// if the option string is empty, the user is prompted for options. /// /// @param dest_df destination data folder. default: a new folder derived from file name under root. /// /// @param quiet @arg 0 (default) print mode and parameters to history. /// @arg 1 do not print to history. /// /// @return data folder reference of the loaded data. this is the folder which contains the scan sub-folders. /// static function /df load_pshell_file(filename, [options, dest_df, quiet]) string filename string options dfref dest_df variable quiet dfref save_df = GetDataFolderDFR() svar pref_options = $(package_path + "s_hdf_options") svar pref_params = $(package_path + "s_reduction_params") string path = "pearl_explorer_filepath" if (ParamIsDefault(options)) options = pref_options endif if (strlen(options) == 0) if (prompt_hdf_options(options) == 0) pref_options = options else return $"" endif endif string reduction_func = StringByKey("reduction_func", options, ":", ";") string reduction_params = pref_params variable max_rank = 2 if (exists(reduction_func) == 6) max_rank = 3 if (prompt_func_params(reduction_func, reduction_params) == 0) pref_params = reduction_params else return $"" endif endif string mode = StringByKey("mode", options, ":", ";") string selected_datasets = WMHL_SelectedObjectsList("PearlDataExplorer", "lb_contents") string selected_scans = psh5_extract_scan_paths(selected_datasets) string selected_regions = psh5_extract_region_paths(selected_datasets) variable dsc if (!quiet) print mode, filename if (strlen(reduction_func)) print reduction_func, reduction_params endif endif strswitch(mode) case "load_complete": dsc = kDSCAll dfref file_df = psh5_load(path, filename, "", "", "*", classes=dsc, reduction_func=reduction_func, reduction_params=reduction_params, dest_df=dest_df) break case "load_diags": if (ItemsInList(selected_scans, ";") == 0) if (!quiet) print "no scan selected - defaulting to scan 1." endif selected_scans = "/scan1;" endif dsc = kDSCAttrs | kDSCDiags | kDSCSnaps | kDSCMeta | kDSCMonitors dfref file_df = psh5_load(path, filename, selected_scans, "", "", classes=dsc, dest_df=dest_df) break case "load_scan": if (ItemsInList(selected_scans, ";") == 0) if (!quiet) print "no scan selected - defaulting to scan 1." endif selected_scans = "/scan1;" endif dsc = kDSCPositioners | kDSCDetectors | kDSCScientaScaling | kDSCEssentialDiags dfref file_df = psh5_load(path, filename, selected_scans, "", "", classes=dsc, max_rank=max_rank, reduction_func=reduction_func, reduction_params=reduction_params, dest_df=dest_df) break case "load_region": if (ItemsInList(selected_regions, ";") == 0) if (!quiet) print "no region selected - defaulting to scan 1/region 1." endif selected_regions = "/scan1/region1;" endif dsc = kDSCPositioners | kDSCDetectors | kDSCScientaScaling | kDSCEssentialDiags dfref file_df = psh5_load(path, filename, "", selected_regions, "", classes=dsc, max_rank=max_rank, reduction_func=reduction_func, reduction_params=reduction_params, dest_df=dest_df) break case "load_dataset": if (ItemsInList(selected_datasets, ";") > 0) dsc = kDSCAll dfref file_df = psh5_load(path, filename, "", "", selected_datasets, classes=dsc, reduction_func=reduction_func, reduction_params=reduction_params, dest_df=dest_df) else if (!quiet) DoAlert /T="PShell Import" 0, "Please select the datasets to load." endif endif break endswitch if (DataFolderRefStatus(file_df)) setdatafolder file_df string /g pearl_explorer_import = "load_pshell_file" if (!quiet) print "data loaded to", GetDataFolder(1) endif else setdatafolder save_df endif return file_df end static function /df load_hdf_file(filename, [options, dest_df, quiet]) string filename string options dfref dest_df variable quiet dfref save_df = GetDataFolderDFR() string nickname = ad_suggest_foldername(filename) string loaded_filename = "" if (ParamIsDefault(dest_df) || !DataFolderRefStatus(dest_df)) // else DoAlert /T="load_hdf_file" 0, "optional argument dest_df not supported." return $"" endif if (ParamIsDefault(options)) loaded_filename = adh5_load_complete(nickname, "pearl_explorer_filepath", filename) else if (strlen(options) == 0) svar pref_options = $(package_path + "s_hdf_options") options = pref_options if (prompt_hdf_options(options) == 0) // OK pref_options = options else // cancel options = "" endif endif string mode = StringByKey("mode", options, ":", ";") strswitch(mode) case "load_reduced": string reduction_func = StringByKey("reduction_func", options, ":", ";") svar pref_params = $(package_path + "s_reduction_params") string reduction_params = pref_params if (prompt_func_params(reduction_func, reduction_params) == 0) pref_params = reduction_params print reduction_func, reduction_params loaded_filename = adh5_load_reduced(nickname, "pearl_explorer_filepath", filename, $reduction_func, reduction_params) endif break endswitch endif dfref data_df if (strlen(loaded_filename) > 0) setdatafolder $("root:" + nickname) data_df = GetDataFolderDFR() string /g pearl_explorer_import = "load_hdf_file" else setdatafolder save_df endif return data_df end static function /df load_itx_file(filename, [options, dest_df, quiet]) string filename string options dfref dest_df variable quiet dfref save_df = GetDataFolderDFR() string nickname = itx_suggest_foldername(filename) if (ParamIsDefault(options)) options = "" endif variable own_data_df = 0 if (ParamIsDefault(dest_df) || !DataFolderRefStatus(dest_df)) setdatafolder root: newdatafolder /s/o $("root:" + nickname) own_data_df = 1 else setdatafolder dest_df endif dfref data_df = GetDataFolderDFR() // note: some versions of PEARL data files save data to a new data folder, // and leave the newly created folder as the current folder. // the free data folder is used by those files which don't create their own data folder. // this is the new recommended behaviour LoadWave /t/p=pearl_explorer_filepath/q filename svar waves = s_wavenames dfref act_df = GetDataFolderDFR() if (v_flag > 0) string /g pearl_explorer_import = "load_itx_file" endif if (!DataFolderRefsEqual(act_df, data_df) && own_data_df) // the file created its own data folder. // let's kill the pre-allocated folder setdatafolder data_df if (ItemsInList(WaveList("*", ";", ""), ";") == 0) killdatafolder /z data_df endif endif setdatafolder save_df return act_df end /// suggest the name of a data folder based on an igor-text file name /// /// if the file name follows the naming convention source-date-index.extension, /// the function tries to generate the nick name as source_date_index. /// otherwise it's just a cleaned up version of the file name. /// /// igor text is used by the on-the-fly scan tool. /// /// @param filename file name, including extension. /// can also include a folder path (which is ignored). /// the extension is currently ignored, /// but may be used in a later version. /// @param ignoredate if non-zero, the nick name will not include the date part. /// defaults to zero /// @param sourcename nick name of the data source. /// the function tries to detect the source from the file name. /// this option can be used to override auto-detection. /// allowed values: sscan, otf /// @param unique if non-zero, the resulting name is made a unique data folder name in the current data folder. /// defaults to zero /// function /s itx_suggest_foldername(filename, [ignoredate,sourcename,unique]) string filename variable ignoredate string sourcename variable unique if (ParamIsDefault(ignoredate)) ignoredate = 0 endif if (ParamIsDefault(unique)) unique = 0 endif string basename = ParseFilePath(3, filename, ":", 0, 0) string extension = ParseFilePath(4, filename, ":", 0, 0) string nickname string autosource if (strsearch(basename, "X03DA_PC", 0, 2) >= 0) autosource = "sscan" basename = ReplaceString("_", basename, "-") ignoredate = 1 elseif (strsearch(basename, "otf", 0, 2) >= 0) autosource = "otf" endif if (ParamIsDefault(sourcename)) sourcename = autosource endif variable nparts = ItemsInList(basename, "-") if (nparts >= 3) string datepart = StringFromList(nparts - 2, basename, "-") string indexpart = StringFromList(nparts - 1, basename, "-") if (ignoredate) sprintf nickname, "%s_%s", sourcename, indexpart else sprintf nickname, "%s_%s_%s", sourcename, datepart, indexpart endif else nickname = PearlCleanupName(basename) endif if (unique && CheckName(nickname, 11)) nickname = UniqueName(nickname + "_", 11, 0) endif return nickname end // ====== panel ====== Window PearlDataExplorer() : Panel PauseUpdate; Silent 1 // building window... NewPanel /K=1 /W=(510,45,1190,539) as "PEARL Data Explorer" ModifyPanel cbRGB=(48640,56832,60160) GroupBox g_data_reduction,pos={355.00,370.00},size={306.00,49.00},title="data reduction" GroupBox g_data_reduction,help={"data reduction of 3D ScientaImage"} GroupBox gb_filepath,pos={8.00,4.00},size={328.00,48.00},title="file system folder" TitleBox tb_filepath,pos={20.00,28.00},size={279.00,21.00},frame=0 TitleBox tb_filepath,variable= root:packages:pearl_explorer:s_short_filepath,fixedSize=1 Button b_browse_filepath,pos={303.00,24.00},size={20.00,20.00},proc=PearlDataExplorer#bp_browse_filepath,title="..." Button b_browse_filepath,fColor=(65280,48896,32768) GroupBox gb_prefs,pos={8.00,351.00},size={65.00,131.00},title="prefs" GroupBox gb_prefs,help={"explorer package preferences"} Button b_save_prefs,pos={21.00,394.00},size={38.00,17.00},proc=PearlDataExplorer#bp_save_prefs,title="save" Button b_save_prefs,help={"save preferences of the data explorer package (data file path, attributes filter)"} Button b_save_prefs,fColor=(65280,48896,32768) Button b_load_prefs,pos={21.00,374.00},size={38.00,17.00},proc=PearlDataExplorer#bp_load_prefs,title="load" Button b_load_prefs,help={"load preferences of the data explorer package"} Button b_load_prefs,fColor=(65280,48896,32768) GroupBox gb_filelist,pos={8.00,55.00},size={328.00,293.00},title="data files" ListBox lb_files,pos={20.00,83.00},size={303.00,222.00},proc=PearlDataExplorer#lbp_filelist ListBox lb_files,listWave=root:packages:pearl_explorer:wtFiles ListBox lb_files,selWave=root:packages:pearl_explorer:wSelectedFiles,mode= 4 Button b_update_filelist,pos={246.00,315.00},size={76.00,22.00},proc=PearlDataExplorer#bp_update_filelist,title="update list" Button b_update_filelist,fColor=(65280,48896,32768) CheckBox cb_file_preview,pos={78.00,318.00},size={59.00,14.00},title="preview" CheckBox cb_file_preview,help={"enable/disable automatic preview window when selecting a data file"} CheckBox cb_file_preview,value= 0 Button b_file_prev,pos={20.00,314.00},size={22.00,22.00},proc=PearlDataExplorer#bp_file_prev,title="\\W646" Button b_file_prev,help={"previous file"},fColor=(65280,48896,32768) Button b_file_next,pos={44.00,314.00},size={22.00,22.00},proc=PearlDataExplorer#bp_file_next,title="\\W649" Button b_file_next,help={"next file"},fColor=(65280,48896,32768) Button b_goto_dataset,pos={355.00,315.00},size={64.00,22.00},disable=2,proc=PearlDataExplorer#bp_goto_dataset,title="goto DF" Button b_goto_dataset,help={"change the current data folder ot where the selected dataset could be located"} Button b_goto_dataset,fColor=(65280,48896,32768) Button b_display_dataset,pos={423.00,315.00},size={64.00,22.00},disable=2,proc=PearlDataExplorer#bp_display_dataset,title="display" Button b_display_dataset,help={"display the selected dataset in its own window"} Button b_display_dataset,fColor=(65280,48896,32768) Button b_load_complete,pos={355.00,451.00},size={92.00,22.00},disable=2,proc=PearlDataExplorer#bp_load_options,title="all data" Button b_load_complete,help={"load all datasets of the selected file."} Button b_load_complete,userdata= "mode:load_complete;" Button b_load_complete,fColor=(65280,48896,32768) TitleBox tb_selected_file,pos={360.00,28.00},size={309.00,22.00},frame=0 TitleBox tb_selected_file,variable= root:packages:pearl_explorer:s_selected_file,fixedSize=1 GroupBox gb_contents,pos={346.00,55.00},size={327.00,294.00},title="datasets" Button b_attr_notebook,pos={97.00,375.00},size={64.00,22.00},disable=2,proc=PearlDataExplorer#bp_attr_notebook,title="notebook" Button b_attr_notebook,help={"show a summary of attributes in a notebook window"} Button b_attr_notebook,fColor=(65280,48896,32768) ListBox lb_contents,pos={355.00,84.00},size={305.00,222.00} ListBox lb_contents,keySelectCol= 1 GroupBox gb_selected_file,pos={346.00,4.00},size={328.00,48.00},title="selected file" Button b_load_region,pos={355.00,426.00},size={92.00,22.00},disable=2,proc=PearlDataExplorer#bp_load_options,title="region" Button b_load_region,help={"load the selected region"} Button b_load_region,userdata= "mode:load_region;",fColor=(65280,48896,32768) PopupMenu popup_reduction,pos={366.00,391.00},size={200.00,17.00},bodyWidth=200,proc=PearlDataExplorer#pmp_reduction_func PopupMenu popup_reduction,help={"data reduction of 3d ScientaImage. note: the list may contain unsuitable functions. check the code or documentation!"} PopupMenu popup_reduction,mode=1,popvalue="None",value= #"PearlDataExplorer#pm_reduction_values()" GroupBox group_import,pos={346.00,351.00},size={326.00,131.00},title="import" Button b_load_scan,pos={450.00,426.00},size={94.00,22.00},disable=2,proc=PearlDataExplorer#bp_load_options,title="scan" Button b_load_scan,help={"load the selected scan"},userdata= "mode:load_scan;" Button b_load_scan,fColor=(65280,48896,32768) Button b_load_diags,pos={450.00,451.00},size={94.00,22.00},disable=2,proc=PearlDataExplorer#bp_load_options,title="diagnostics" Button b_load_diags,help={"load diagnostics of selected scans"},userdata= "mode:load_diags;" Button b_load_diags,fColor=(65280,48896,32768) Button b_load_dataset,pos={547.00,426.00},size={101.00,22.00},disable=2,proc=PearlDataExplorer#bp_load_options,title="dataset" Button b_load_dataset,help={"load the selected datasets"} Button b_load_dataset,userdata= "mode:load_dataset;",fColor=(65280,48896,32768) Button b_reduction_params,pos={571.00,390.00},size={71.00,19.00},disable=2,proc=PearlDataExplorer#bp_reduction_params,title="set params" Button b_reduction_params,help={"set data reduction parameters"} Button b_reduction_params,fColor=(65280,48896,32768) GroupBox g_fileinfo,pos={85.00,351.00},size={251.00,131.00},title="file info" Button b_elog,pos={97.00,401.00},size={64.00,22.00},disable=2,proc=PearlDataExplorer#bp_elog,title="ELOG" Button b_elog,help={"send file metadata to ELOG panel (does not submit to ELOG)"} Button b_elog,fColor=(65280,48896,32768) ToolsGrid grid=(0,28.35,5) EndMacro /// update controls state /// static function update_controls() dfref package_df = $package_path svar /z /sdfr=package_df hl_contents_datasets wave /z /sdfr=package_df wSelectedFiles variable file_selected = 0 if (WaveExists(wSelectedFiles)) file_selected = sum(wSelectedFiles) endif string selected_datasets = WMHL_SelectedObjectsList("PearlDataExplorer", "lb_contents") variable scan_selected = strsearch(selected_datasets, "scan", 0, 2) == 0 variable region_selected = strsearch(selected_datasets, "region", 0, 2) >= 0 variable dataset_selected = 0 variable nds = ItemsInList(selected_datasets, ";") variable ids string ds if (svar_exists(hl_contents_datasets)) for (ids = 0; ids < nds; ids += 1) ds = "/" + StringFromList(ids, selected_datasets, ";") if (NumType(NumberByKey(ds, hl_contents_datasets, ":", ";")) == 0) dataset_selected = 1 break endif endfor else nds = 0 endif variable dis dis = file_selected ? 0 : 2 Button b_load_complete win=PearlDataExplorer,disable=dis Button b_load_diags win=PearlDataExplorer,disable=dis dis = file_selected && scan_selected ? 0 : 2 Button b_attr_notebook win=PearlDataExplorer,disable=dis dis = file_selected && (strlen(WinList("*ElogPanel*", ";", "WIN:64")) > 1) ? 0 : 2 Button b_elog win=PearlDataExplorer,disable=dis dis = scan_selected ? 0 : 2 Button b_load_scan win=PearlDataExplorer,disable=dis dis = region_selected ? 0 : 2 Button b_load_region win=PearlDataExplorer,disable=dis dis = dataset_selected ? 0 : 2 Button b_load_dataset win=PearlDataExplorer,disable=dis Button b_display_dataset win=PearlDataExplorer,disable=dis dis = file_selected && (nds > 0) ? 0 : 2 Button b_goto_dataset win=PearlDataExplorer,disable=dis ControlInfo /W=PearlDataExplorer popup_reduction if ((cmpstr(S_Value, "None") != 0) && (exists(S_Value) == 6)) GroupBox g_data_reduction win=PearlDataExplorer,labelBack=(65535,49151,49151) Button b_reduction_params win=PearlDataExplorer,disable=0 else GroupBox g_data_reduction win=PearlDataExplorer,labelBack=0 Button b_reduction_params win=PearlDataExplorer,disable=2 endif return 0 end static function bp_load_prefs(ba) : ButtonControl STRUCT WMButtonAction &ba switch( ba.eventCode ) case 2: // mouse up load_prefs() update_controls() break case -1: // control being killed break endswitch return 0 End static function bp_save_prefs(ba) : ButtonControl STRUCT WMButtonAction &ba switch( ba.eventCode ) case 2: // mouse up save_prefs() break case -1: // control being killed break endswitch return 0 End /// shorten a file path for display /// /// @note the result is not a valid path any more! /// static function /s shorten_filepath(long_path, max_len) string long_path variable max_len string path = long_path variable ellipsis = 0 do if (strlen(path) > max_len) path = RemoveListItem(1, path, ":") ellipsis += 1 else break endif while (1) if (ellipsis >= 1) path = AddListItem("…", path, ":", 1) endif return path end static function bp_browse_filepath(ba) : ButtonControl STRUCT WMButtonAction &ba dfref save_df = GetDataFolderDFR() switch( ba.eventCode ) case 2: // mouse up PathInfo /S pearl_explorer_filepath NewPath /M="select data file folder" /O/Z pearl_explorer_filepath if (v_flag == 0) update_filepath() update_filelist() update_controls() endif break case -1: // control being killed break endswitch setdatafolder save_df return 0 End static function bp_update_filelist(ba) : ButtonControl STRUCT WMButtonAction &ba switch( ba.eventCode ) case 2: // mouse up update_filelist() update_controls() break case -1: // control being killed break endswitch return 0 End /// items for data reduction popup static function /s pm_reduction_values() string reduction_funcs = adh5_list_reduction_funcs() reduction_funcs = RemoveFromList("adh5_default_reduction", reduction_funcs, ";") reduction_funcs = AddListItem("None", reduction_funcs, ";", 0) return reduction_funcs end static function pmp_reduction_func(pa) : PopupMenuControl STRUCT WMPopupAction &pa switch( pa.eventCode ) case 2: // mouse up Variable popNum = pa.popNum String popStr = pa.popStr update_controls() break case -1: // control being killed break endswitch return 0 End static function bp_reduction_params(ba) : ButtonControl STRUCT WMButtonAction &ba switch( ba.eventCode ) case 2: // mouse up ControlInfo /W=PearlDataExplorer popup_reduction if ((cmpstr(S_Value, "None") != 0) && (exists(S_Value) == 6)) svar pref_params = $(package_path + "s_reduction_params") string reduction_func = S_Value string reduction_params = pref_params if (prompt_func_params(reduction_func, reduction_params) == 0) pref_params = reduction_params endif endif break case -1: // control being killed break endswitch return 0 End static function bp_load_options(ba) : ButtonControl STRUCT WMButtonAction &ba switch( ba.eventCode ) case 2: // mouse up // options must be in the button's unnamed user data in the form: "mode:load_complete". // see load_pshell_file for recognized values. string options=ba.userData // data reduction popup ControlInfo /W=PearlDataExplorer popup_reduction if ((cmpstr(S_Value, "None") != 0) && (exists(S_Value) == 6)) options = ReplaceStringByKey("reduction_func", options, S_Value, ":", ";") endif load_selected_files(options=options) break case -1: // control being killed break endswitch return 0 End /// actions after a file has been selected /// /// - load metadata /// - load preview if requested /// /// @param file name of selected file /// @param do_preview enable/disable loading of preview data /// non-zero: load preview, /// zero: don't load preview /// static function selected_file(file, do_preview) string file variable do_preview dfref save_df = GetDataFolderDFR() setdatafolder $package_path svar s_selected_file s_selected_file = file get_file_info(file) if (do_preview) preview_file(file) endif update_controls() setdatafolder save_df return 0 end static function bp_file_next(ba) : ButtonControl STRUCT WMButtonAction &ba dfref save_df = GetDataFolderDFR() switch( ba.eventCode ) case 2: // mouse up setdatafolder $package_path wave /t wtFiles wave wSelectedFiles FindValue /i=1 wSelectedFiles v_value += 1 if (v_value >= numpnts(wtFiles)) v_value = min(numpnts(wtFiles) - 1, 0) endif wSelectedFiles = p == v_value if (v_value >= 0) variable ifile = v_value ControlInfo /W=PearlDataExplorer cb_file_preview selected_file(wtFiles[ifile], v_value) endif update_controls() break case -1: // control being killed break endswitch setdatafolder save_df return 0 End static function bp_file_prev(ba) : ButtonControl STRUCT WMButtonAction &ba dfref save_df = GetDataFolderDFR() switch( ba.eventCode ) case 2: // mouse up setdatafolder $package_path wave /t wtFiles wave wSelectedFiles FindValue /i=1 wSelectedFiles v_value -= 1 if (v_value < 0) v_value = numpnts(wtFiles) - 1 endif wSelectedFiles = p == v_value if (v_value >= 0) variable ifile = v_value ControlInfo /W=PearlDataExplorer cb_file_preview selected_file(wtFiles[ifile], v_value) endif update_controls() break case -1: // control being killed break endswitch setdatafolder save_df return 0 End static function lbp_filelist(lba) : ListBoxControl STRUCT WMListboxAction &lba dfref save_df = GetDataFolderDFR() Variable row = lba.row Variable col = lba.col WAVE/T/Z listWave = lba.listWave WAVE/Z selWave = lba.selWave switch( lba.eventCode ) case -1: // control being killed break case 1: // mouse down setdatafolder $package_path wave wSelectedFiles if (selWave[row]) if (sum(wSelectedFiles) == 1) ControlInfo /W=PearlDataExplorer cb_file_preview selected_file(listWave[row], v_value) else selected_file(listWave[row], 0) endif endif update_controls() break case 3: // double click break case 4: // cell selection case 5: // cell selection plus shift key break case 6: // begin edit break case 7: // finish edit break case 13: // checkbox clicked (Igor 6.2 or later) break endswitch setdatafolder save_df return 0 End static function bp_attr_notebook(ba) : ButtonControl STRUCT WMButtonAction &ba dfref save_df = GetDataFolderDFR() switch( ba.eventCode ) case 2: // mouse up setdatafolder $package_path wave wSelectedFiles wave/t wtFiles variable nn = numpnts(wSelectedFiles) variable ii for (ii = 0; ii < nn; ii += 1) if (wSelectedFiles[ii]) attributes_notebook(wtFiles[ii]) break endif endfor break case -1: // control being killed break endswitch setdatafolder save_df return 0 End static function hlp_setup() dfref save_df = GetDataFolderDFR() setdatafolder $package_path MakeListIntoHierarchicalList("PearlDataExplorer", "lb_contents", "hlp_contents_open", selectionMode=WMHL_SelectionSingle, pathSeparator="/") setdatafolder save_df return 0 end static function hl_contents_clear() do if (cmpstr(WMHL_GetItemForRowNumber("PearlDataExplorer", "lb_contents", 0), "") != 0) WMHL_DeleteRowAndChildren("PearlDataExplorer", "lb_contents", 0) else break endif while (1) end /// populate the contents list box with the internal directory of a HDF5 file /// /// @return the number of top-level objects /// static function hl_contents_update(file_df) dfref file_df dfref save_df = GetDataFolderDFR() setdatafolder $package_path hl_contents_clear() variable nds variable ids string ds string extra string /g hl_contents_datasets = "" if (DataFolderRefStatus(file_df)) svar /sdfr=file_df datasets = s_datasets svar /sdfr=file_df datatypes = s_datasets_datatypes svar /sdfr=file_df ranks = s_datasets_ranks svar /sdfr=file_df dimensions = s_datasets_dimensions nds = ItemsInList(datasets, ";") for (ids = 0; ids < nds; ids += 1) ds = StringFromList(ids, datasets, ";") extra = StringFromList(ids, dimensions, ";") hl_contents_datasets = ReplaceStringByKey(ds, hl_contents_datasets, extra, ":", ";") endfor endif variable nobj = hl_add_objects("", hl_contents_datasets) hl_expand_scans() hl_default_selection() setdatafolder save_df return nobj end static function /df get_pshell_info(path_name, file_name, [dest_df]) string path_name string file_name dfref dest_df dfref save_df = GetDataFolderDFR() if (!ParamIsDefault(dest_df)) setdatafolder dest_df else setdatafolder $package_path NewDataFolder /o /s file_info endif dfref file_df = psh5_open_file(path_name, file_name, dest_df=GetDataFolderDFR()) if (DataFolderRefStatus(file_df)) psh5_load_general_group(file_df) psh5_close_file(file_df) endif setdatafolder save_df return file_df end /// populate the contents list box with the given hierarchical paths /// /// @return the number of top-level objects /// static function hl_add_objects(parent_path, objects) string parent_path // e.g. "/a/b" string objects // all objects that might appear in the list. e.g. "/a/b/c:col0|col1;/a/b/d:col0|col1;/d/e/f:col0|col1;" if (cmpstr(parent_path[0], "/") != 0) parent_path = "/" + parent_path endif variable nobj = ItemsInList(objects, ";") variable iobj string obj string extra variable nel string child_path = "" string child_name = "" string child_names = "" // e.g., "child1:1;child3:2;" string extra_data = "" // e.g., "child1:col0|col1;child2:col0|col1;" // filter children of parent for (iobj = 0; iobj < nobj; iobj += 1) obj = StringFromList(iobj, objects, ";") if (cmpstr(obj[0, strlen(parent_path)-1], parent_path) == 0) child_path = StringFromList(0, obj, ":") child_path = child_path[strlen(parent_path), strlen(child_path)-1] if (cmpstr(child_path[0], "/") == 0) child_path = child_path[1, strlen(child_path)-1] endif child_name = StringFromList(0, child_path, "/") nel = ItemsInList(child_path, "/") child_names = ReplaceNumberByKey(child_name, child_names, nel) if (nel == 1) extra = RemoveListItem(0, obj, ":") extra_data = ReplaceStringByKey(child_name, extra_data, extra) endif endif endfor // add rows variable row variable children nobj = ItemsInList(child_names) for (iobj = 0; iobj < nobj; iobj += 1) obj = StringFromList(iobj, child_names) child_name = StringFromList(0, obj, ":") nel = NumberByKey(child_name, child_names) WMHL_AddObject("PearlDataExplorer", "lb_contents", parent_path[1, strlen(parent_path)], child_name, nel > 1) if (nel == 1) extra = StringByKey(child_name, extra_data) row = WMHL_GetRowNumberForItem("PearlDataExplorer", "lb_contents", parent_path[1, strlen(parent_path)] + "/" + child_name) if (row >= 0) WMHL_ExtraColumnData("PearlDataExplorer", "lb_contents", 0, row, StringFromList(0, extra, "|"), 0) endif endif endfor return nobj end static function hl_expand_scans() dfref save_df = GetDataFolderDFR() setdatafolder $package_path svar hl_contents_datasets variable nds = ItemsInList(hl_contents_datasets, ";") variable ids string sds string scan string scans = "" for (ids = 0; ids < nds; ids += 1) sds = StringFromList(ids, hl_contents_datasets, ";") if (cmpstr(sds[0,4], "/scan", 0) == 0) scan = StringFromList(1, sds, "/") scans = ReplaceNumberByKey(scan, scans, 1) endif endfor variable nscans = ItemsInList(scans) variable iscan for (iscan = 0; iscan < nscans; iscan += 1) scan = StringFromList(iscan, scans) scan = StringFromList(0, scan, ":") WMHL_OpenAContainer("PearlDataExplorer", "lb_contents", scan) endfor setdatafolder save_df end static function hl_default_selection() variable row row = WMHL_GetRowNumberForItem("PearlDataExplorer", "lb_contents", "scan 1") if (row < 0) row = WMHL_GetRowNumberForItem("PearlDataExplorer", "lb_contents", "scan1") endif if (row >= 0) WMHL_SelectARow("PearlDataExplorer", "lb_contents", row, 1) endif end static function hlp_contents_open(HostWindow, ListControlName, ContainerPath) String HostWindow, ListControlName, ContainerPath dfref save_df = GetDataFolderDFR() setdatafolder $package_path svar hl_contents_datasets hl_add_objects(ContainerPath, hl_contents_datasets) setdatafolder save_df end static function hlp_contents_selection(HostWindow, ListControlName, SelectedItem, EventCode) String HostWindow, ListControlName String SelectedItem Variable EventCode dfref save_df = GetDataFolderDFR() setdatafolder $package_path switch (eventCode) case 3: // double click // todo: load dataset? break case 4: // cell selection case 5: // cell selection plus shift key update_controls() break endswitch setdatafolder save_df return 0 end /// open data folder corresponding to a file and data path /// /// the function tries to find where a given dataset has been loaded /// and selects the corresponding data folder. /// the data folder must exist (after previous import from the file), /// else an error code is returned and the folder selection will be the closest accessible parent folder of the target. /// /// @param filename file name (without path). /// h5 and otf.itx files are supported. /// @param datapath dataset or group path inside the hdf5 file. /// @return 0 if successful, /// -1 if the file type is unknown /// -2 if the data path can't be found in the tree. /// static function goto_dataset_folder(filename, datapath) string filename string datapath dfref save_df = GetDataFolderDFR() setdatafolder $package_path variable ft = pearl_file_type(filename) string parent_folder string folder string path switch(ft) case 1: case 2: parent_folder = ad_suggest_foldername(filename) path = "root:" + parent_folder if (DataFolderExists(path)) setdatafolder $path else return -2 endif variable nparts = ItemsInList(datapath, "/") variable ipart for (ipart = 0; ipart < nparts; ipart += 1) folder = StringFromList(ipart, datapath, "/") path = ":" + ps_fix_folder_name(folder) if (DataFolderExists(path)) setdatafolder $path endif endfor break case 3: parent_folder = "root:" + itx_suggest_foldername(filename) if (DataFolderExists(parent_folder)) setdatafolder $parent_folder else return -2 endif break default: // unsupported file type return -1 endswitch return 0 end /// "goto DF" button /// /// the button selects the data folder of the selected file and dataset. /// an error message is shown if the data folder doesn't exist. /// static function bp_goto_dataset(ba) : ButtonControl STRUCT WMButtonAction &ba switch( ba.eventCode ) case 2: // mouse up dfref save_df = GetDataFolderDFR() setdatafolder $package_path svar s_selected_file svar hl_contents_datasets string datapath = StringFromList(0, WMHL_SelectedObjectsList("PearlDataExplorer", "lb_contents")) if (strsearch(hl_contents_datasets, datapath, 0) != 0) datapath = datapath + "/" endif variable result = goto_dataset_folder(s_selected_file, datapath) if (result != 0) setdatafolder save_df string msg msg = "Can't find data folder. Has the file been loaded?" DoAlert /T="Goto DF" 0, msg endif break case -1: // control being killed break endswitch return 0 End /// "display dataset" button /// /// static function bp_display_dataset(ba) : ButtonControl STRUCT WMButtonAction &ba switch( ba.eventCode ) case 2: // mouse up dfref save_df = GetDataFolderDFR() setdatafolder $package_path svar s_selected_file svar hl_contents_datasets string datapath = StringFromList(0, WMHL_SelectedObjectsList("PearlDataExplorer", "lb_contents")) if (strsearch(hl_contents_datasets, datapath, 0) < 0) // path leads to folder return 0 endif goto_dataset_folder(s_selected_file, "") display_dataset(GetDataFolderDFR(), datapath) setdatafolder save_df break case -1: // control being killed break endswitch return 0 End /// send file metadata to the ELOG panel /// /// metadate is looked up in the following locations: /// 1. data folder if it exists /// 2. file info folder inside package folder /// 3. package folder if it contains preview data from the selected file (???) /// static function send_to_elog() dfref save_df = GetDataFolderDFR() dfref preview_df = $package_path svar /z /sdfr=preview_df s_selected_file svar /z /sdfr=preview_df s_preview_file svar /z /sdfr=preview_df s_preview_graph if (!SVAR_Exists(s_selected_file) || (strlen(s_selected_file) < 1)) return 0 endif // check data folder variable result = -1 result = goto_dataset_folder(s_selected_file, "") if (result == 0) dfref data_df = GetDataFolderDFR() svar /sdfr=data_df /z authors if (!svar_Exists(authors)) result = -1 endif endif // file info folder dfref infoDF = preview_df:file_info if ((result != 0) && (DataFolderRefStatus(infoDF))) svar /z /sdfr=infoDF s_filepath if (SVAR_Exists(s_filepath) && (strsearch(s_filepath, s_selected_file, inf, 1) >= 0)) dfref data_df = infoDF result = 0 endif endif // check preview (package) folder if ((result != 0) && (SVAR_Exists(s_preview_file) && (cmpstr(s_preview_file, s_selected_file) == 0))) dfref data_df = preview_df result = 0 endif string graphname if (SVAR_Exists(s_preview_graph) && (WinType(s_preview_graph) == 1)) graphname = s_preview_graph else graphname = "" endif if (result == 0) set_elog_attributes(data_df, filename=s_selected_file, graphname=graphname) string windowname windowname = StringFromList(0, WinList("*ElogPanel*", ";", "WIN:64"), ";") DoWindow /F $windowname endif setdatafolder save_df end static function bp_elog(ba) : ButtonControl STRUCT WMButtonAction &ba switch( ba.eventCode ) case 2: // mouse up send_to_elog() break case -1: // control being killed break endswitch return 0 End