diff --git a/content/en/docs/200_hardware-sharing/_index.md b/content/en/docs/200_hardware-sharing/_index.md index 69e5241..09c4434 100644 --- a/content/en/docs/200_hardware-sharing/_index.md +++ b/content/en/docs/200_hardware-sharing/_index.md @@ -85,10 +85,10 @@ This page periodically crawls GitHub for HW_* repositories. It considers users/o ## Adding Published Plug-ins to Your Project -To clone an existing repo on GitHub into to your project's hardware folder, navigate to your project folder (`cd to/your_project_folder/`) and use the following command (requires [Git](/docs/100_development-environment/20_git/)): +To add an existing repo on GitHub into to your project's hardware folder, navigate to your project folder (`cd to/your_project_folder/`) and use the following command (requires [Git](/docs/100_development-environment/20_git/)): ```sh -git clone https://github.com/{THEIR_USER_NAME}/HW_{company_model}.git ScopeFoundryHW/{company_model} +git submodule add https://github.com/{THEIR_USER_NAME}/HW_{company_model}.git ScopeFoundryHW/{company_model} ``` Where `{THEIR_USER_NAME}` and `{company_name}` need to be replaced accordingly. **Hint:** The entries in the [Library](/docs/301_existing-hardware-components/) contain this line completed for the respective HardwareComponent. diff --git a/content/en/docs/20_built-in-measurements/Scanning/spatial-scanning.md b/content/en/docs/20_built-in-measurements/Scanning/Baseraster_scan.md similarity index 60% rename from content/en/docs/20_built-in-measurements/Scanning/spatial-scanning.md rename to content/en/docs/20_built-in-measurements/Scanning/Baseraster_scan.md index b2ad560..5895c70 100644 --- a/content/en/docs/20_built-in-measurements/Scanning/spatial-scanning.md +++ b/content/en/docs/20_built-in-measurements/Scanning/Baseraster_scan.md @@ -1,37 +1,27 @@ --- -title: Spatial Scanning -description: Create mapping measurements. +title: BaseRaster scan +description: Base classes that facilitated implementing scanning Measurements. date: 2025-01-01 -weight: 1 +weight: 100 --- An example can be found by creating a new app using [ScopeFoundry tools](/docs/11_tools-tutorials/1_new-microscope-app/). -There are two variants of the functionally same base class. - -## Traditional vs V2 +## Version 1 vs Version 2 The two versions of these base classes differ in the way movement is defined. 1. The legacy base class is `ScopeFoundry.scanning.BaseRaster2DSlowScan` and requires overriding the following methods: - `move_position_slow` - - `move_position_fast` - - `move_position_start` - - -2. The V2 version, `ScopeFoundry.scanning.BaseRaster2DSlowScanV2`, instead requires defining `actuators` with the settings paths associated with the stage's target position. +2. The V2 version, `ScopeFoundry.scanning.BaseRaster2DSlowScanV2`, instead requires defining [actuators](/docs/20_built-in-measurements/scanning/sweeping/#actuators) with the settings paths associated with the stage's target position. {{% pageinfo color="info" %}} BaseRaster2DSlowScan***V2*** released in ScopeFoundry 2.1 {{% /pageinfo %}} - - An example can be found by creating a new app using [ScopeFoundry tools](/docs/11_tools-tutorials/1_new-microscope-app/). - - diff --git a/content/en/docs/20_built-in-measurements/Scanning/_index.md b/content/en/docs/20_built-in-measurements/Scanning/_index.md index a412180..b8ffc00 100644 --- a/content/en/docs/20_built-in-measurements/Scanning/_index.md +++ b/content/en/docs/20_built-in-measurements/Scanning/_index.md @@ -4,22 +4,14 @@ description: Choose a measurement paradigm based on your needs. date: 2025-06-01 --- -Since version 2.1, ScopeFoundry provides two built in measurements in which the following cycling repeats: +Built in Measurements where the following cycle repeats: 1. Change the position, voltage, ... in predetermined way 2. Collect data -For this common task ScopeFoundry provides several solutions. Read the following to decide which fits your task: +ScopeFoundry 2.2 introduced generic sweeping and scanning Measurements that work out of the box but can also subclassed, see [sweeping](sweeping). -1. For [spatial scanning](spatial-scanning): +Previously, [BaseRaster_scan](Baseraster-scan) were base classes that facilitated implementing scanning Measurements. - - requires subclassing and override a view methods. - - Natively has a concept of spatiality in 2D and 3D, which gives end-users an advanced interaction experience. -2. For generic setting [sweeping](sweeping): - - - Works out of the Box! This Measurement can collect data and run other measurements without subclassing. - - Easier to extend with additional data channels by providing a flexible data structure and composing multiple `Collector` classes. - - -For your own Measurement from scratch consider using this [shortcut](https://scopefoundry.org/docs/30_tips-and-tricks/settings-ranges/). +For your own Measurement from scratch read [this tutorial](/docs/11_tools-tutorials/3_measurement/) where [this](/docs/30_tips-and-tricks/settings-ranges/) might be useful. diff --git a/content/en/docs/20_built-in-measurements/Scanning/sweeping.md b/content/en/docs/20_built-in-measurements/Scanning/sweeping/_index.md similarity index 70% rename from content/en/docs/20_built-in-measurements/Scanning/sweeping.md rename to content/en/docs/20_built-in-measurements/Scanning/sweeping/_index.md index dd4c721..bc03101 100644 --- a/content/en/docs/20_built-in-measurements/Scanning/sweeping.md +++ b/content/en/docs/20_built-in-measurements/Scanning/sweeping/_index.md @@ -22,21 +22,25 @@ class MyFancyApp(BaseMicroscopeApp): ... ``` +![out_of_the_box](out_of_the_box.png) + Depending on the dimensionality, i.e., the number of actuators varied, use: + - Sweep1D - Sweep2D - Sweep3D - Sweep4D + - Map2D -Easy-to-use configurations [below](#more-configurations). Most sweeping tasks are already solved with the out-of-the-box solution. +Easy-to-use configurations [below](#more-configurations). -This article aims to outline further configurability that elevates the usage of these sweep classes. +Most sweeping tasks are already solved with this out-of-the-box solution. This article aims to outline further configurability that elevates the usage of these sweep classes. Note that MapXD extends SweepXD with features that paricularly apply for spattial mapping. ## Basic Concepts The two central ingredients are so-called: -1. *"Actuators"*, the objects that are being varied. These can be defined using a settings path or by providing a function. You can sweep multiple actuators with different sweep modes. Out of the box, any setting that has a write-to-hardware function can be used. Typically, such a setting only acquires a hardware write function after it is connected. The list of possible actuators can be updated after connecting to hardware by pressing the appropriate button in the UI. +1. *"Actuators"*, the objects that are being varied. These can be defined using a settings path or by providing a function (see costume actuator). Such a setting only requires a hardware write function. As settings only get associated with hardware write functions after they are connected the list of possible actuators can be updated after connecting to hardware by pressing the appropriate button in the UI. 2. *"Collectors"*, responsible for collecting data at each sweep point. The user can activate multiple collectors and can change the order in which they are executed by dragging and dropping. Further, each collector can be repeated. For more info on collectors, see below. @@ -48,9 +52,11 @@ Define how data is collected and what is collected at each sweep point. - If you want to run any of your measurements at each sweep point, you *might* get away with using the *any_measurement* option. The resulting data file of the sweep measurement only contains data of the specified sub-measurement if the sub-measurement defines a dictionary named `data`. So this feature works best if all your target measurements populate a dictionary `data` with your data. -- The *any_measurement* is not further configurable. If you need to configure data collection further, implement your own collector class and pass it to your Sweep class. This becomes particularly interesting if you want to use multiple collectors at a given data point and data collection requires changing state before collection. +### Costume collector + +The *any_measurement* is not further configurable. If you need to configure data collection further, implement your own collector class and pass it to your Sweep class. This becomes particularly interesting if you want to use multiple collectors at a given actuator state and each collector requires changing state of the setup before collection. - Here is an example that moves the shutter before and after reading powers (using a target_measurement "power_readout" that implements a "get_data" method): +Here is an example that moves the shutter before and after reading powers (using a target_measurement "power_readout" that implements a "get_data" method): ```python # shuttered_power_collector.py @@ -58,7 +64,7 @@ Define how data is collected and what is collected at each sweep point. class ShutteredPowerCollector(Collector): - name = "power measurement with shutter" + name = "power_measurement_with_shutter" target_measure_name = "power_readout" repeated_dset_names = ("powers",) @@ -90,11 +96,15 @@ Define how data is collected and what is collected at each sweep point. def release(self, host_measurement, *args, **kwargs) -> None: self.app.hardware.my_shutter.settings["position"] = "close" ``` - - The sweep measurement calls these 3 functions at each data point in the following order: - - 1. `prepare` exactly one time. (If you find yourself repeating code for all your custom collectors, you might be better off with a [generic actuator](#generic-actuators)) - 2. `run` according to the number of repetitions the user specified. + + The sweep measurement calls these 3 functions at each sweep point in the following order: + + 1. `prepare` exactly one time. (If you find yourself repeating code for all your custom collectors, you might be better off with a [costume actuator](#costume-actuators)) + + 2. `run` according to the number of repetitions the user specified. Note that the Sweep Measurement incorporates the content of the `data` dictionary. + + The attribute `repeated_dset_names = ("powers",)` informs the sweep measurement that only "powers" is collected for every repetition at each sweep point. + 3. `release` exactly one time. ​ To add your collector to the sweeps, alter the app file: @@ -134,9 +144,9 @@ Note that the above actuator is defined with a tuple of length 2. However, it is ```python explicit_actuators = [ ( - "x", # intuitive name - "hw/xyz_stage/x_position", # path to setting with hardware read function - "hw/xyz_stage/x_target_position", # path to setting with hardware write function + "x", # intuitive name + "hw/xyz_stage/x_target_position", # path to setting with hardware write function + "hw/xyz_stage/x_position", # path to setting with hardware read function ), ... ] ``` @@ -147,34 +157,35 @@ Either way, to add them to your measurement, alter the app file: self.add_measurement(Sweep2D(self, actuators=explicit_actuators)) ``` -### Generic Actuators +### Costume Actuators -The above defines an actuator with lq_paths. You can define more generic actuators using custom functions. Study this example: +The above defines an actuator with lq_paths. You can define more sofisticated actutators by at least defining write function with excalty the new position as an argument. ```python class MyFancyApp(BaseMicroscopeApp): name = "My Fancy App" - def my_generic_actuator_write_function(self, new_position): + def my_actuator_write_function(self, new_position): # new_position self.hardware.my_hardware.settings["target_position"] = new_position self.hardware.my_hardware_2.settings["target_position"] = new_position ** 2 # potentially wait until values are set. ... - def my_generic_actuator_read_function(self) -> float: + def my_actuator_read_function(self) -> float: pass # return a value def setup(self): ... - actuators = [("generic_actuator", self.my_generic_actuator_read_function, self.my_generic_actuator_write_function),] + actuators = [("generic_actuator", self.my_actuator_write_function, self.my_actuator_read_function),] from ScopeFoundry import Map2D, Sweep1D, Sweep2D, Sweep3D, Sweep4D self.add_measurement(Sweep2D(self, actuators=actuators)) ... ``` +The read_function is not required and be completely omitted. ## More Configurations @@ -184,7 +195,7 @@ class MyFancyApp(BaseMicroscopeApp): self.add_measurement(Sweep2D(self, n_any_measurements=5, n_read_any_settings=5)) ``` -- The values that are swept (the sweep array) are by default defined using a start, stop, num pattern (i.e., a single interval). You can use multiple intervals to define the sweep intervals. +- The values that are swept (the sweep array) are by default defined using a start, stop, num pattern to define a single interval with equally spaced values. You can use multiple intervals to define several intervals (with varying density of values). ```python self.add_measurement(Sweep2D(self, range_n_intervals=(3, 5))) ``` diff --git a/content/en/docs/20_built-in-measurements/Scanning/sweeping/out_of_the_box.png b/content/en/docs/20_built-in-measurements/Scanning/sweeping/out_of_the_box.png new file mode 100644 index 0000000..f97b73e Binary files /dev/null and b/content/en/docs/20_built-in-measurements/Scanning/sweeping/out_of_the_box.png differ diff --git a/content/en/docs/30_tips-and-tricks/analyze-with-ipynb/_index.md b/content/en/docs/30_tips-and-tricks/analyze-with-ipynb/_index.md index 4c69217..e96b038 100644 --- a/content/en/docs/30_tips-and-tricks/analyze-with-ipynb/_index.md +++ b/content/en/docs/30_tips-and-tricks/analyze-with-ipynb/_index.md @@ -18,15 +18,13 @@ This feature works best with Jupyter Notebook installed. We recommend the follow 1. Pylance (Microsoft) 2. Jupyter (Microsoft) - - -New in ScopeFoundry 2.2: We recommend to trigger this feature after a success measurement as a new cell that loads the latest measurement is added to the notebook. - - +New in ScopeFoundry 2.2: We recommend to trigger this feature after a success-full measurement as a new cell that loads the latest measurement is appended to the notebook. ## Trigger Feature -There are two ways to start this feature: +Note: In some versions of VS Code the data folder has to be opened explicitly (File -> Open Folder ...) for this feature to work. + +There are two ways to trigger this feature: ### In the app @@ -50,12 +48,15 @@ python -m ScopeFoundry.tools Click the button on the Welcome tab to proceed. -*or* with 2.1 +*or* with 2.3 ```bash -python -m ScopeFoundry ipynb +python -m ScopeFoundry ipynb-XX +# (where XX is 'last' (default), 'all' or 'remaining') ``` +where XX is 'last' (default), 'all' or 'remaining'. + ## Result This feature generates the following: @@ -67,13 +68,23 @@ This feature generates the following: In the notebook, the top two cells are generated: -- **Cell 1**: Imports the data loaders. -- **Cell 2**: Lists paths to each `.h5` file and demonstrates how they can be loaded. +- **`CELL #0`**: Imports the data loaders. +- **`Cell #1`**: Commands to load files in the folder. ## Re-triggering -After adding more datafiles to the folder, it is generally safe to re-trigger this feature to update cell 2 and add more loaders. However, the following caveats apply: +After adding more data-files to the folder, it is generally safe to re-trigger this feature to update `CELL #1` and add more loaders. However, the following caveats apply: + +- `CELL #0` **will be overwritten:** All changes will be lost. +- Content of `CELL #1` will never be deleted. Lines that do not already *exist fuzzily* will be added. For example, a line that has been commented will not be added again. +- Cells onwards are not altered. New in Version 2.2: re-triggering appends a new cell with a line that loads the latest file. + + + +# Clean up data folder + +{{% pageinfo color="info" %}} +New in ScopeFoundry 2.3 +{{% /pageinfo %}} -- **Cell 1 will be overwritten:** All changes will be lost. -- Content of Cell 2 will never be deleted. Lines that do not already *exist fuzzily* will be added. For example, a line that has been commented will not be added again. -- Cell 3 and onwards are not altered. New in Version 2.2: re-triggering appends a new cell with a line that loads the latest file. \ No newline at end of file +See `CELL #0` for instructions to archive .h5 that are not mentioned in your notebook. diff --git a/content/en/docs/30_tips-and-tricks/settings-ranges/_index.md b/content/en/docs/30_tips-and-tricks/settings-ranges/_index.md index 1306765..7a3d678 100644 --- a/content/en/docs/30_tips-and-tricks/settings-ranges/_index.md +++ b/content/en/docs/30_tips-and-tricks/settings-ranges/_index.md @@ -55,3 +55,43 @@ To add corresponding widgets to your `.ui`: range The `sweep_type` determines how the values are traversed. + +## Multi interval ranges + +{{% pageinfo color="info" %}} +New in ScopeFoundry 2.2 +{{% /pageinfo %}} + +Define a range of X-values with up to n (bellow set to 5) intervals, each interval having a start, stop, and step setting. + +```python +from ScopeFoundry.measurement import Measurement + + +class XSweep(Measurement): + + name = "x_sweep" + + def setup(self): + + self.range = self.settings.new_intervaled_range("X", + n_intervals=5, + include_center_span: bool = False, + include_sweep_type: bool = False, + initials=None, + unit=None, + si=False, + ro=False, + vmin=-1_000_000_000_000, + vmax=1_000_000_000_000, + spinbox_decimals=4, + description="", + **kwargs + ) + + def run(self): + # Access the array of X-values + for x in self.range.sweep_array: + # Perform operations for each X-value + ... +``` \ No newline at end of file