@@ -8,16 +8,193 @@ Example: the ``run_command_file`` plan
88You can use a text file or an Excel spreadsheet as a multi-sample
99batch scan tool using the :func: `run_command_file ` plan.
1010
11+ The Command File
12+ ++++++++++++++++
13+
14+ A command file can be written as either a plain text file or a
15+ spreadsheet (such as from Microsoft Excel or Libre Office).
16+
17+ Text Command File
18+ -----------------
19+
20+ For example, given a text command file (named ``sample_example.txt ``)
21+ with content as shown ...
22+
23+ .. literalinclude :: ../resources/sample_example.txt
24+ :tab-width: 4
25+ :linenos:
26+ :language: guess
27+
28+ ... can be summarized in a bluesky ipython session:
29+
30+ .. code-block :: ipython
31+
32+ In [1]: import apstools.plans
33+ In [2]: apstools.plans.summarize_command_file("sample_example.txt")
34+ Command file: sample_example.xlsx
35+ ====== ========== ===========================================================
36+ line # action parameters
37+ ====== ========== ===========================================================
38+ 3 step_scan 5.07, 8.3, 0.0, Water Blank, deionized
39+ 4 other_scan 5.07, 8.3, 0.0, Water Blank, deionized
40+ 8 this line, will, not, be, recognized, by, execute_command_list()
41+ ====== ========== ===========================================================
42+
43+ Observe which lines (3, 4, and 8) in the text file are part of
44+ the summary. The other lines are either comments or blank.
45+ The action on line 8 will be passed to ``execute_command_list() `` which will
46+ then report the ``this `` action it is not handled.
47+ (Looks like another type of a comment.)
48+ See :func: `~apstools.plans.parse_text_command_file() ` for more details.
49+
50+ Spreadsheet Command File
51+ ------------------------
52+
53+ Follow the example spreadsheet (in the :ref: `examples_downloads ` section)
54+ and accompanying Jupyter notebook [# ]_ to write your own ``Excel_plan() ``.
55+
56+ .. [# ] https://github.com/BCDA-APS/apstools/blob/master/docs/source/resources/excel_scan.ipynb
57+
58+ For example, given a spreadsheet (named ``sample_example.xlsx ``)
59+ with content as shown in the next figure:
60+
61+ .. figure :: ../resources/sample_example.jpg
62+ :width: 95%
63+
64+ Image of ``sample_example.xlsx `` spreadsheet file.
65+
66+ .. tip :: Place the column labels on the fourth row of the spreadsheet,
67+ starting in the first column.
68+ The actions start on the next row. The first blank row indicates
69+ the end of the command table within the spreadsheet.
70+ Use as many columns as you need, one column per argument.
71+
72+ This spreadsheet can be summarized in a bluesky ipython session:
73+
74+ .. code-block :: ipython
75+
76+ In [1]: import apstools.plans
77+ In [2]: apstools.plans.summarize_command_file("sample_example.xlsx")
78+ Command file: sample_example.xlsx
79+ ====== ================================================================== ======================================
80+ line # action parameters
81+ ====== ================================================================== ======================================
82+ 1 step_scan 5.07, 8.3, 0.0, Water Blank, deionized
83+ 2 other_scan 5.07, 8.3, 0.0, Water Blank, deionized
84+ 3 this will be ignored (and also the next blank row will be ignored)
85+ ====== ================================================================== ======================================
86+
87+ Note that lines 9 and 10 in the spreadsheet file are not part of
88+ the summary. The spreadsheet handler will stop reading the list of actions
89+ at the first blank line. The action described on line 3 will not be handled
90+ (since we will not define an action named
91+ ``this will be ignored (and also the next blank row will be ignored) ``).
92+ See :func: `~apstools.plans.parse_Excel_command_file() ` for more details.
93+
94+ The *Actions *
95+ ++++++++++++++++
96+
97+ To use this example with the :func: `~apstools.plans.run_command_file() ` plan, it is
98+ necessary to redefine the :func: `~apstools.plans.execute_command_list() ` plan,
99+ we must write a plan to handle every different type of action described
100+ in the spreadsheet. For ``sample_example.xlsx ``, we need to
101+ handle the ``step_scan `` and ``other_scan `` actions.
102+
103+ .. tip :: Always write these *actions* as bluesky plans.
104+ To test your *actions *, use either
105+ ``bluesky.simulators.summarize_plan(step_scan()) ``
106+ or ``bluesky.simulators.summarize_plan(other_scan()) ``.
107+
108+ Here are examples of those two actions (and a stub for an additional
109+ instrument procedure to make the example more realistic):
110+
111+ .. code-block :: python
112+ :linenos:
113+
114+ def step_scan (sx , sy , thickness , title , md = {}):
115+ md[" sample_title" ] = title # log this metadata
116+ md[" sample_thickness" ] = thickness # log this metadata
117+ yield from bluesky.plan_stubs.mv(
118+ sample_stage.x, sx,
119+ sample_stage.y, sy,
120+ )
121+ yield from prepare_detector(" scintillator" )
122+ yield from bluesky.plans.scan([scaler], motor, 0 , 180 , 360 , md = md)
123+
124+ def other_scan (sx , sy , thickness , title , md = {}):
125+ md[" sample_title" ] = title # log this metadata
126+ md[" sample_thickness" ] = thickness # log this metadata
127+ yield from bluesky.plan_stubs.mv(
128+ sample_stage.x, sx,
129+ sample_stage.y, sy,
130+ )
131+ yield from prepare_detector(" areadetector" )
132+ yield from bluesky.plans.count([areadetector], md = md)
133+
134+ def prepare_detector (detector_name ):
135+ # for this example, we do nothing
136+ # we should move the proper detector into position here
137+ yield from bluesky.plan_stubs.null()
138+
139+ Now, we replace :func: `~apstools.plans.execute_command_list() `
140+ with our own definition to include those two actions:
141+
142+ .. code-block :: python
143+ :linenos:
144+
145+ def execute_command_list (filename , commands , md = {}):
146+ """ our custom execute_command_list"""
147+ full_filename = os.path.abspath(filename)
148+
149+ if len (commands) == 0 :
150+ yield from bps.null()
151+ return
152+
153+ text = f " Command file: { filename} \n "
154+ text += str (apstools.utils.command_list_as_table(commands))
155+ print (text)
156+
157+ for command in commands:
158+ action, args, i, raw_command = command
159+ logger.info(f " file line { i} : { raw_command} " )
160+
161+ _md = {}
162+ _md[" full_filename" ] = full_filename
163+ _md[" filename" ] = filename
164+ _md[" line_number" ] = i
165+ _md[" action" ] = action
166+ _md[" parameters" ] = args # args is shorter than parameters, means the same thing here
167+
168+ _md.update(md or {}) # overlay with user-supplied metadata
169+
170+ action = action.lower()
171+ if action == " step_scan" :
172+ yield from step_scan(* args. md= _md)
173+ elif action == " other_scan" :
174+ yield from other_scan(* args. md= _md)
175+
176+ else :
177+ logger.info(f " no handling for line { i} : { raw_command} " )
178+
179+ Testing
180+ ++++++++++++++++
181+
182+ ``bluesky.simulators.summarize_plan(run_command_file("sample_example.txt")) ``
183+
184+ -tba-
185+
186+ Running
187+ ++++++++++++++++
188+
189+ ``RE(run_command_file("sample_example.txt")) ``
190+
191+ -tba-
192+
11193.. TODO: re-write below per issue 178
12194
13195------------
14196
15- You can use an Excel spreadsheet as a multi-sample batch scan tool. Follow
16- the example spreadsheet (in the
17- :ref: `examples_downloads ` section)
18- and accompanying Jupyter notebook
19- (https://github.com/BCDA-APS/apstools/blob/master/docs/source/resources/excel_scan.ipynb)
20- to write your own ``Excel_plan() ``.
197+ You can use an Excel spreadsheet as a multi-sample batch scan tool.
21198
22199**SIMPLE **: Your Excel spreadsheet could be rather simple...
23200
0 commit comments