NSFopen 2.4.0__tar.gz → 2.4.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. {nsfopen-2.4.0 → nsfopen-2.4.1}/CHANGELOG.md +149 -141
  2. nsfopen-2.4.1/NSFopen/_version.py +1 -0
  3. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/read/read.py +1 -1
  4. {nsfopen-2.4.0 → nsfopen-2.4.1/NSFopen.egg-info}/PKG-INFO +4 -1
  5. {nsfopen-2.4.0/NSFopen.egg-info → nsfopen-2.4.1}/PKG-INFO +4 -1
  6. {nsfopen-2.4.0 → nsfopen-2.4.1}/README.md +178 -175
  7. nsfopen-2.4.0/NSFopen/_version.py +0 -1
  8. {nsfopen-2.4.0 → nsfopen-2.4.1}/LICENSE +0 -0
  9. {nsfopen-2.4.0 → nsfopen-2.4.1}/MANIFEST.in +0 -0
  10. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/__init__.py +0 -0
  11. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Calculate_Roughness/Calculate_Roughness.html +0 -0
  12. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Calculate_Roughness/Calculate_Roughness.ipynb +0 -0
  13. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Calculate_Roughness/Calculate_Roughness.py +0 -0
  14. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Calculate_Roughness/__pycache__/Calculate_Roughness.cpython-310.pyc +0 -0
  15. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Calculate_Roughness/sapphire.nid +0 -0
  16. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Force_Spectroscopy/Contact_Models.py +0 -0
  17. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Force_Spectroscopy/Force_Spectroscopy.html +0 -0
  18. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Force_Spectroscopy/Force_Spectroscopy.ipynb +0 -0
  19. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Force_Spectroscopy/Force_Spectroscopy.py +0 -0
  20. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Force_Spectroscopy/spectroscopy.nid +0 -0
  21. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Grain_Analysis/Grain_Analysis.html +0 -0
  22. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Grain_Analysis/Grain_Analysis.ipynb +0 -0
  23. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Grain_Analysis/Grain_Analysis.py +0 -0
  24. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Lateral_Force/Lateral_Force_Processing.html +0 -0
  25. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Lateral_Force/Lateral_Force_Processing.ipynb +0 -0
  26. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Lateral_Force/Lateral_Force_Processing.py +0 -0
  27. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Lateral_Force/SBS-PMMA.nid +0 -0
  28. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Plane_Removal/Plane_Removal.html +0 -0
  29. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Plane_Removal/Plane_Removal.ipynb +0 -0
  30. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Plane_Removal/Plane_Removal.py +0 -0
  31. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Plane_Removal/circles.nid +0 -0
  32. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Plane_Removal/circles_holes.nid +0 -0
  33. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Plane_Removal/grid.nid +0 -0
  34. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Plane_Removal/squares_holes.nid +0 -0
  35. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Plotting_Data/MoS2.nid +0 -0
  36. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Plotting_Data/Plotting_Data.html +0 -0
  37. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Plotting_Data/Plotting_Data.ipynb +0 -0
  38. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Plotting_Data/Plotting_Data.py +0 -0
  39. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Sharpen_Image/Sharpen_Image.html +0 -0
  40. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Sharpen_Image/Sharpen_Image.ipynb +0 -0
  41. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Sharpen_Image/Sharpen_Image.py +0 -0
  42. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Sharpen_Image/grid.nid +0 -0
  43. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Spring_Constant/Spring_Constant.html +0 -0
  44. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Spring_Constant/Spring_Constant.ipynb +0 -0
  45. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Spring_Constant/Spring_Constant.py +0 -0
  46. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Spring_Constant/__pycache__/Spring_Constant.cpython-310.pyc +0 -0
  47. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Spring_Constant/__pycache__/__init__.cpython-310.pyc +0 -0
  48. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Spring_Constant/sader.py +0 -0
  49. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Spring_Constant/thermal.nid +0 -0
  50. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/example/Spring_Constant/thermal.png +0 -0
  51. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/process/__init__.py +0 -0
  52. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/process/colormaps.py +0 -0
  53. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/process/combine.py +0 -0
  54. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/process/contact.py +0 -0
  55. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/process/fitting.py +0 -0
  56. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/process/grains.py +0 -0
  57. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/process/iv.py +0 -0
  58. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/process/measure.py +0 -0
  59. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/process/ops.py +0 -0
  60. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/process/process.py +0 -0
  61. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/process/profile_iso.py +0 -0
  62. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/process/psdfit.py +0 -0
  63. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/process/spectroscopy.py +0 -0
  64. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/process/surface3d.py +0 -0
  65. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/read/__init__.py +0 -0
  66. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/read/nhf.py +0 -0
  67. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen/read/nhf_spec.py +0 -0
  68. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen.egg-info/SOURCES.txt +0 -0
  69. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen.egg-info/dependency_links.txt +0 -0
  70. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen.egg-info/entry_points.txt +0 -0
  71. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen.egg-info/not-zip-safe +0 -0
  72. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen.egg-info/requires.txt +0 -0
  73. {nsfopen-2.4.0 → nsfopen-2.4.1}/NSFopen.egg-info/top_level.txt +0 -0
  74. {nsfopen-2.4.0 → nsfopen-2.4.1}/pyproject.toml +0 -0
  75. {nsfopen-2.4.0 → nsfopen-2.4.1}/setup.cfg +0 -0
  76. {nsfopen-2.4.0 → nsfopen-2.4.1}/setup.py +0 -0
  77. {nsfopen-2.4.0 → nsfopen-2.4.1}/tests/test_examples.py +0 -0
  78. {nsfopen-2.4.0 → nsfopen-2.4.1}/tests/test_nsfopen.py +0 -0
@@ -1,141 +1,149 @@
1
- # Change log
2
-
3
- ## 2.4.0 (not yet released)
4
-
5
- Compared to **2.3.0**.
6
-
7
- ### Force spectroscopy analysis
8
- Added, in `NSFopen.process` (the calculations of the Spectroscopy page of NSSA, the NSF Surface and Spectroscopy
9
- Analyzer, so a script and the program give the same numbers):
10
- - `contact`: elastic contact of a tip pressed into a flat sample. Models Hertz, Sneddon (exact), DMT, JKR and
11
- Oliver-Pharr; tip shapes sphere, cone, four-sided pyramid, flat cylinder punch and hyperboloid. `fit_elastic`,
12
- `fit_jkr`, `fit_oliver_pharr` give the Young's modulus, reduced modulus, contact point, adhesion and the fit quality.
13
- - `spectroscopy`: `SpecFile` opens the force curves and force maps of NID and NHF files. `ForceSettings` and
14
- `ForceAnalysis` process them: smoothing, baseline (offset, tilt, or an interference sine with its period found),
15
- contact point, indentation, adhesion, pull-off, adhesion and dissipated energy, and the model fit. `Results` has
16
- statistics, maps, masks, fits of different models on different regions, a quality filter (leave out fits below an R²)
17
- and CSV export. Maps can be analyzed partly (every n-th line and column, or a region).
18
- - `iv`: I-V curves with dI/dV, normalized conductance, zero-bias conductance and resistance, gap and rectification.
19
-
20
- ### Color maps
21
- - 12 maps are defined in `colormaps.py` (`NANOSURF`): Sky (the default for heights), Warm, Flare, Caribbean, Strata,
22
- Gold, Digitalis, Neon, Plum, Cold, Spectrum and Maple, plus BlueBlackRed. `register()` adds them and their reversed
23
- versions (`Sky_r`) to matplotlib; `colormap(name)` returns any of them or a matplotlib map.
24
- - The 59 Gwyddion gradient files that 2.3.0 included are removed: they are GPL, NSFopen is MIT. An installed Gwyddion's
25
- gradients are found on Windows, macOS and Linux (`gwyddion_dirs`, `gwyddion_gradients`, `register(gwyddion=True)`), and
26
- `colors(name)` uses them when the name is not one of the 12.
27
-
28
- ### Changes that can affect existing scripts
29
- | What | 2.3.0 | 2.4.0 |
30
- |---|---|---|
31
- | `colors(name)` with a Gwyddion name | 59 gradient files in the package | 12 maps defined in the code; `Pm3d`, `Blend2`, `Code-V` open as `Flare`, `Strata`, `Spectrum`; the others only with an installed Gwyddion or `gwy_dir=` |
32
- | `colormaps.GRADIENTS` | The gradient folder | Removed |
33
-
34
- ### Examples
35
- - New `Force_Spectroscopy/Contact_Models.py`: a force map fitted with `process.spectroscopy`, with statistics, the
36
- quality filter, maps of the modulus and adhesion, and the stiffest curve with its fit.
37
-
38
- ### Packaging
39
- - Credentials (`tokens.json`, `.env`, `*.token`) in the example folders are never packaged.
40
-
41
- ## 2.3.0 (November 2, 2026)
42
-
43
- Compared to **2.2.4**, the latest version on PyPI (August 2024).
44
-
45
- ### Highlights
46
- - `pip install NSFopen` now works by itself: the `nanosurf` and `scikit-learn` packages are no longer needed.
47
- - NID files are read about 5 times faster, and line flattening is about twice as fast.
48
- - NHF spectroscopy files of any size open immediately, and their curves are read when asked for.
49
- - WaveMode NMA files are read, with a curve for every pixel and maps of any quantity.
50
- - `process` has many new image analysis functions, brought over from the Nanosurf Surface Analyzer (now NSSA).
51
- - Figures take their units and labels from the file, can be placed in subplots, and there is a new 3D plot.
52
-
53
- ### Reading files
54
- Added:
55
- - New NHF reader that needs only h5py, for file versions 1.1 and 2.0 to 2.6. Images are identical to those of Nanosurf's
56
- reader on versions 1.1, 2.0, 2.3, 2.4 and 2.6.
57
- - Spectroscopy (`afm.spec`): segments, grid position, other units through the file's calibration, force curves.
58
- - WaveMode NMA (`afm.nma`): `curve()` gives Z, interaction and force of a pixel; `map()` builds per-pixel maps.
59
- - `afm.units` holds the unit of every channel. `afm.close()` releases an NHF file; `read` also works in a `with` block.
60
- - `read(..., measurement=)` picks a measurement of an NHF file.
61
-
62
- Fixed:
63
- - 2.2.4 needed `nanosurf` to be imported but did not declare it, and failed on NHF files with `nanosurf` 2.0.7.
64
- - NID headers were read as Latin-1, so units and sizes came out as `°` and `3µm`.
65
- - Duplicate `Wait` segments of older NHF files overwrote each other: the second is now `Wait 2`.
66
- - A third NID channel of the same name overwrote the second: they are now `Amplitude`, `Amplitude2`, `Amplitude3`.
67
- - A truncated NID file now says so.
68
-
69
- ### Processing images
70
- Added:
71
- - Leveling: `level_flatten`, `level_poly2d`, `level_lines`, `level_align_rows`, `level_facet`, `level_three_point`,
72
- `level_median`, `level_rolling_ball`, `level_shift`.
73
- - Filters: `filter_basic`, `filter_median`, `filter_gaussian`, `filter_fft`, `filter_notch`.
74
- - Glitches: `glitch_spikes`, `glitch_lines`, `glitch_auto_lines`, `glitch_scars`, `glitch_step_lines`, `glitch_fill_mask`.
75
- - Masks, kept per channel: `set_mask` and `mask_threshold`, `mask_otsu`, `mask_watershed`, `mask_outliers`, `mask_scars`,
76
- `mask_shape`, `mask_floodfill`, `mask_grow`, `mask_shrink`, `mask_invert`, `mask_clear`, `mask_remove_small`,
77
- `mask_fill_holes`. Leveling, filters and statistics can use the mask.
78
- - Geometry and scale: `geometry_crop`, `geometry_flip`, `geometry_rotate`, `geometry_resample`, `geometry_square_pixels`,
79
- `rescale_scale`, `rescale_z_to_reference`, `rescale_xy`.
80
- - Statistics after ISO 25178: `statistics`, `bearing_curve`, `histogram_fit`, `slope_distributions`.
81
- - Lines: `line_profile`, `step_heights`, `critical_dimension`, `masked_step_height`, and `profile_roughness` after
82
- ISO 21920.
83
- - Spectra and texture: `psd`, `psd_fit`, `spectrum`, `acf`, `line_functions`, `rms_by_scale`, `lattice`.
84
- - Grain analysis: `grains`.
85
- - Two channels: `combine`, `find_shift`.
86
- - Access: `channels`, `array`, `set_channel`, `size`, `unit`, `origin`, and `apply` and `operations`.
87
-
88
- Fixed:
89
- - `NSFopen.process` could not be imported, because `colormaps.py` imported itself.
90
- - `flatten(inplace=False)` and similar calls changed the data as well as returning the result.
91
- - `plane_level` was wrong on non-square images.
92
- - The physical sizes of non-square NHF images were swapped.
93
-
94
- ### Figures
95
- Added:
96
- - `plot3d`, a 3D view after the Surface Analyzer's, with materials, lighting and overlays of another channel. It needs no
97
- graphics card.
98
- - `plot_profile`, `plot_psd`, `plot_histogram_fit`, `plot_bearing`, `plot_acf`.
99
- - `ax=` to draw into subplots, and `figsize`, `dpi`, `theme` and `color_range` on the plots.
100
- - `image(profile=)` shows where a line cut lies.
101
- - Color maps by name, including the Gwyddion gradients now included with the package: `cmap='Gold'`.
102
-
103
- Fixed:
104
- - The default scale bar had zero length on scans of about 2.5 µm or less, and non-integer lengths were labelled wrongly.
105
- - `hist(color=)` raised an error.
106
-
107
- ### Changes that can affect existing scripts
108
- | What | 2.2.4 | 2.3.0 |
109
- |---|---|---|
110
- | NHF force curves `[row, col]` | Position in the file | True grid position, row 0 at the bottom |
111
- | NHF force curves | Arrays | Read on access; `np.asarray(curves)` gives the array |
112
- | `image` and `hist`, `scale` | `1e9` for every channel | A readable unit from the channel; `scale=1e9` still forces it |
113
- | `hist`, `xlabel` | `Z-Axis [nm]` for every channel | The channel and its unit |
114
- | `image`, color bar | Only with `cbar=` | Always; `colorbar=False` turns it off |
115
- | `image`, pixels | matplotlib's default | `interpolation='nearest'`; can be overridden |
116
- | `remove_outliers` | Nearest neighbors with scikit-learn | Interpolation from the pixels around; the numbers differ, and `neighbors` is gone |
117
- | Unknown channel | pandas `KeyError` | `ValueError` that lists the channels |
118
- | Default channel | `Z-Axis` only | Falls back to `Topography` in files that have no `Z-Axis` |
119
- | `NSFopen.read.checkFileType` | Present | Removed |
120
-
121
- `stats()` keeps its results, including `Sku` as excess kurtosis (0 for a Gaussian surface). The new `statistics()` gives
122
- the ISO value of `Sku` (3 for a Gaussian surface).
123
-
124
- ### Examples
125
- - All are rewritten around `process`, and there is a new `Grain_Analysis`.
126
- - **`Spring_Constant`: the result changes from 14.5 to 24.0 N/m.** The old fit used a power formula on amplitude data and
127
- found Q = 253; the file records Nanosurf's own Q of 442, and the corrected fit finds 417.
128
- - `Plotting_Data`: the image was drawn upside down.
129
- - `Force_Spectroscopy`: the map axes were labelled µm but showed pixels.
130
- - `Sharpen_Image`: it no longer passes the data through an 8-bit JPEG, and needs neither OpenCV nor PIL.
131
- - `Plane_Removal`: it crashed on non-square images, and its clipping changed the data.
132
- - `Lateral_Force`: the offset between the scans is measured instead of set by hand.
133
- - Renamed without spaces: `Plotting_Data.py`, `Lateral_Force_Processing.py`, `Sharpen_Image.py`.
134
-
135
- ### Requirements
136
- - matplotlib 3.6 or newer; the other requirements are unchanged (numpy, scipy, pandas, h5py, Python 3.9 or newer).
137
- - Removed: `nanosurf` and `scikit-learn`, which 2.2.4 used without declaring them.
138
-
139
- ## Earlier versions
140
- The earlier releases have no change notes. Their list and dates are on
141
- [PyPI](https://pypi.org/project/NSFopen/#history).
1
+ # Change log
2
+
3
+ ## 2.4.1 (November 4, 2026)
4
+
5
+ ### Fixed
6
+ - Reading a NID file gave a pandas warning (`Series.dropna(inplace=True)` is deprecated from pandas 3.1). The data is
7
+ the same.
8
+
9
+ ## 2.4.0 (November 4, 2026)
10
+
11
+ Compared to **2.3.0**.
12
+
13
+ ### Force spectroscopy analysis
14
+ Added, in `NSFopen.process` (the calculations of the Spectroscopy page of NSSA, the NSF Surface and Spectroscopy
15
+ Analyzer, so a script and the program give the same numbers):
16
+ - `contact`: elastic contact of a tip pressed into a flat sample. Models Hertz, Sneddon (exact), DMT, JKR and
17
+ Oliver-Pharr; tip shapes sphere, cone, four-sided pyramid, flat cylinder punch and hyperboloid. `fit_elastic`,
18
+ `fit_jkr`, `fit_oliver_pharr` give the Young's modulus, reduced modulus, contact point, adhesion and the fit quality.
19
+ - `spectroscopy`: `SpecFile` opens the force curves and force maps of NID and NHF files. `ForceSettings` and
20
+ `ForceAnalysis` process them: smoothing, baseline (offset, tilt, or an interference sine with its period found),
21
+ contact point, indentation, adhesion, pull-off, adhesion and dissipated energy, and the model fit. `Results` has
22
+ statistics, maps, masks, fits of different models on different regions, a quality filter (leave out fits below an R²)
23
+ and CSV export. Maps can be analyzed partly (every n-th line and column, or a region).
24
+ - `iv`: I-V curves with dI/dV, normalized conductance, zero-bias conductance and resistance, gap and rectification.
25
+
26
+ ### Color maps
27
+ - 12 maps are defined in `colormaps.py` (`NANOSURF`): Sky (the default for heights), Warm, Flare, Caribbean, Strata,
28
+ Gold, Digitalis, Neon, Plum, Cold, Spectrum and Maple, plus BlueBlackRed. `register()` adds them and their reversed
29
+ versions (`Sky_r`) to matplotlib; `colormap(name)` returns any of them or a matplotlib map.
30
+ - The 59 Gwyddion gradient files that 2.3.0 included are removed: they are GPL, NSFopen is MIT. An installed Gwyddion's
31
+ gradients are found on Windows, macOS and Linux (`gwyddion_dirs`, `gwyddion_gradients`, `register(gwyddion=True)`), and
32
+ `colors(name)` uses them when the name is not one of the 12.
33
+
34
+ ### Changes that can affect existing scripts
35
+ | What | 2.3.0 | 2.4.0 |
36
+ |---|---|---|
37
+ | `colors(name)` with a Gwyddion name | 59 gradient files in the package | 12 maps defined in the code; `Pm3d`, `Blend2`, `Code-V` open as `Flare`, `Strata`, `Spectrum`; the others only with an installed Gwyddion or `gwy_dir=` |
38
+ | `colormaps.GRADIENTS` | The gradient folder | Removed |
39
+
40
+ ### Examples
41
+ - New `Force_Spectroscopy/Contact_Models.py`: a force map fitted with `process.spectroscopy`, with statistics, the
42
+ quality filter, maps of the modulus and adhesion, and the stiffest curve with its fit.
43
+
44
+ ### Packaging
45
+ - Credentials (`tokens.json`, `.env`, `*.token`) in the example folders are never packaged.
46
+
47
+ ## 2.3.0 (November 2, 2026, yanked on PyPI)
48
+
49
+ Yanked because the package included the GPL-licensed Gwyddion gradient files; use 2.4.0 or newer.
50
+
51
+ Compared to **2.2.4**, the latest version on PyPI (August 2024).
52
+
53
+ ### Highlights
54
+ - `pip install NSFopen` now works by itself: the `nanosurf` and `scikit-learn` packages are no longer needed.
55
+ - NID files are read about 5 times faster, and line flattening is about twice as fast.
56
+ - NHF spectroscopy files of any size open immediately, and their curves are read when asked for.
57
+ - WaveMode NMA files are read, with a curve for every pixel and maps of any quantity.
58
+ - `process` has many new image analysis functions, brought over from the Nanosurf Surface Analyzer (now NSSA).
59
+ - Figures take their units and labels from the file, can be placed in subplots, and there is a new 3D plot.
60
+
61
+ ### Reading files
62
+ Added:
63
+ - New NHF reader that needs only h5py, for file versions 1.1 and 2.0 to 2.6. Images are identical to those of Nanosurf's
64
+ reader on versions 1.1, 2.0, 2.3, 2.4 and 2.6.
65
+ - Spectroscopy (`afm.spec`): segments, grid position, other units through the file's calibration, force curves.
66
+ - WaveMode NMA (`afm.nma`): `curve()` gives Z, interaction and force of a pixel; `map()` builds per-pixel maps.
67
+ - `afm.units` holds the unit of every channel. `afm.close()` releases an NHF file; `read` also works in a `with` block.
68
+ - `read(..., measurement=)` picks a measurement of an NHF file.
69
+
70
+ Fixed:
71
+ - 2.2.4 needed `nanosurf` to be imported but did not declare it, and failed on NHF files with `nanosurf` 2.0.7.
72
+ - NID headers were read as Latin-1, so units and sizes came out as `°` and `3µm`.
73
+ - Duplicate `Wait` segments of older NHF files overwrote each other: the second is now `Wait 2`.
74
+ - A third NID channel of the same name overwrote the second: they are now `Amplitude`, `Amplitude2`, `Amplitude3`.
75
+ - A truncated NID file now says so.
76
+
77
+ ### Processing images
78
+ Added:
79
+ - Leveling: `level_flatten`, `level_poly2d`, `level_lines`, `level_align_rows`, `level_facet`, `level_three_point`,
80
+ `level_median`, `level_rolling_ball`, `level_shift`.
81
+ - Filters: `filter_basic`, `filter_median`, `filter_gaussian`, `filter_fft`, `filter_notch`.
82
+ - Glitches: `glitch_spikes`, `glitch_lines`, `glitch_auto_lines`, `glitch_scars`, `glitch_step_lines`, `glitch_fill_mask`.
83
+ - Masks, kept per channel: `set_mask` and `mask_threshold`, `mask_otsu`, `mask_watershed`, `mask_outliers`, `mask_scars`,
84
+ `mask_shape`, `mask_floodfill`, `mask_grow`, `mask_shrink`, `mask_invert`, `mask_clear`, `mask_remove_small`,
85
+ `mask_fill_holes`. Leveling, filters and statistics can use the mask.
86
+ - Geometry and scale: `geometry_crop`, `geometry_flip`, `geometry_rotate`, `geometry_resample`, `geometry_square_pixels`,
87
+ `rescale_scale`, `rescale_z_to_reference`, `rescale_xy`.
88
+ - Statistics after ISO 25178: `statistics`, `bearing_curve`, `histogram_fit`, `slope_distributions`.
89
+ - Lines: `line_profile`, `step_heights`, `critical_dimension`, `masked_step_height`, and `profile_roughness` after
90
+ ISO 21920.
91
+ - Spectra and texture: `psd`, `psd_fit`, `spectrum`, `acf`, `line_functions`, `rms_by_scale`, `lattice`.
92
+ - Grain analysis: `grains`.
93
+ - Two channels: `combine`, `find_shift`.
94
+ - Access: `channels`, `array`, `set_channel`, `size`, `unit`, `origin`, and `apply` and `operations`.
95
+
96
+ Fixed:
97
+ - `NSFopen.process` could not be imported, because `colormaps.py` imported itself.
98
+ - `flatten(inplace=False)` and similar calls changed the data as well as returning the result.
99
+ - `plane_level` was wrong on non-square images.
100
+ - The physical sizes of non-square NHF images were swapped.
101
+
102
+ ### Figures
103
+ Added:
104
+ - `plot3d`, a 3D view after the Surface Analyzer's, with materials, lighting and overlays of another channel. It needs no
105
+ graphics card.
106
+ - `plot_profile`, `plot_psd`, `plot_histogram_fit`, `plot_bearing`, `plot_acf`.
107
+ - `ax=` to draw into subplots, and `figsize`, `dpi`, `theme` and `color_range` on the plots.
108
+ - `image(profile=)` shows where a line cut lies.
109
+ - Color maps by name, including the Gwyddion gradients now included with the package: `cmap='Gold'`.
110
+
111
+ Fixed:
112
+ - The default scale bar had zero length on scans of about 2.5 µm or less, and non-integer lengths were labelled wrongly.
113
+ - `hist(color=)` raised an error.
114
+
115
+ ### Changes that can affect existing scripts
116
+ | What | 2.2.4 | 2.3.0 |
117
+ |---|---|---|
118
+ | NHF force curves `[row, col]` | Position in the file | True grid position, row 0 at the bottom |
119
+ | NHF force curves | Arrays | Read on access; `np.asarray(curves)` gives the array |
120
+ | `image` and `hist`, `scale` | `1e9` for every channel | A readable unit from the channel; `scale=1e9` still forces it |
121
+ | `hist`, `xlabel` | `Z-Axis [nm]` for every channel | The channel and its unit |
122
+ | `image`, color bar | Only with `cbar=` | Always; `colorbar=False` turns it off |
123
+ | `image`, pixels | matplotlib's default | `interpolation='nearest'`; can be overridden |
124
+ | `remove_outliers` | Nearest neighbors with scikit-learn | Interpolation from the pixels around; the numbers differ, and `neighbors` is gone |
125
+ | Unknown channel | pandas `KeyError` | `ValueError` that lists the channels |
126
+ | Default channel | `Z-Axis` only | Falls back to `Topography` in files that have no `Z-Axis` |
127
+ | `NSFopen.read.checkFileType` | Present | Removed |
128
+
129
+ `stats()` keeps its results, including `Sku` as excess kurtosis (0 for a Gaussian surface). The new `statistics()` gives
130
+ the ISO value of `Sku` (3 for a Gaussian surface).
131
+
132
+ ### Examples
133
+ - All are rewritten around `process`, and there is a new `Grain_Analysis`.
134
+ - **`Spring_Constant`: the result changes from 14.5 to 24.0 N/m.** The old fit used a power formula on amplitude data and
135
+ found Q = 253; the file records Nanosurf's own Q of 442, and the corrected fit finds 417.
136
+ - `Plotting_Data`: the image was drawn upside down.
137
+ - `Force_Spectroscopy`: the map axes were labelled µm but showed pixels.
138
+ - `Sharpen_Image`: it no longer passes the data through an 8-bit JPEG, and needs neither OpenCV nor PIL.
139
+ - `Plane_Removal`: it crashed on non-square images, and its clipping changed the data.
140
+ - `Lateral_Force`: the offset between the scans is measured instead of set by hand.
141
+ - Renamed without spaces: `Plotting_Data.py`, `Lateral_Force_Processing.py`, `Sharpen_Image.py`.
142
+
143
+ ### Requirements
144
+ - matplotlib 3.6 or newer; the other requirements are unchanged (numpy, scipy, pandas, h5py, Python 3.9 or newer).
145
+ - Removed: `nanosurf` and `scikit-learn`, which 2.2.4 used without declaring them.
146
+
147
+ ## Earlier versions
148
+ The earlier releases have no change notes. Their list and dates are on
149
+ [PyPI](https://pypi.org/project/NSFopen/#history).
@@ -0,0 +1 @@
1
+ __version__ = "2.4.1"
@@ -524,7 +524,7 @@ class nid_read:
524
524
  if self.__dataframe:
525
525
  # import pandas as pd
526
526
  self.data = toPandaDF(dataout).unstack(level=0)
527
- self.data.dropna(inplace=True)
527
+ self.data = self.data.dropna() # not inplace=True: deprecated from pandas 3.1 (PDEP-8)
528
528
  # self.specunits = pd.DataFrame(specUnits)
529
529
  self.param = toPandaSeries(parameters)
530
530
  else:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: NSFopen
3
- Version: 2.4.0
3
+ Version: 2.4.1
4
4
  Summary: Python module to open and analyze Nanosurf NID and NHF files
5
5
  Author: Nanosurf AG
6
6
  Author-email: scripting@nanosurf.com
@@ -30,6 +30,9 @@ Dynamic: summary
30
30
  # NSFopen
31
31
  Open and analyze Nanosurf NID and NHF files in Python: images, force spectroscopy and WaveMode NMA.
32
32
 
33
+ ## What's new in 2.4.1
34
+ A fix: reading NID files no longer gives a pandas warning (pandas 3.1 and newer).
35
+
33
36
  ## What's new in 2.4.0
34
37
  Compared to 2.3.0:
35
38
  - **Force curve analysis:** `process.spectroscopy` and `process.contact` fit force curves and force maps with Hertz,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: NSFopen
3
- Version: 2.4.0
3
+ Version: 2.4.1
4
4
  Summary: Python module to open and analyze Nanosurf NID and NHF files
5
5
  Author: Nanosurf AG
6
6
  Author-email: scripting@nanosurf.com
@@ -30,6 +30,9 @@ Dynamic: summary
30
30
  # NSFopen
31
31
  Open and analyze Nanosurf NID and NHF files in Python: images, force spectroscopy and WaveMode NMA.
32
32
 
33
+ ## What's new in 2.4.1
34
+ A fix: reading NID files no longer gives a pandas warning (pandas 3.1 and newer).
35
+
33
36
  ## What's new in 2.4.0
34
37
  Compared to 2.3.0:
35
38
  - **Force curve analysis:** `process.spectroscopy` and `process.contact` fit force curves and force maps with Hertz,
@@ -1,175 +1,178 @@
1
- # NSFopen
2
- Open and analyze Nanosurf NID and NHF files in Python: images, force spectroscopy and WaveMode NMA.
3
-
4
- ## What's new in 2.4.0
5
- Compared to 2.3.0:
6
- - **Force curve analysis:** `process.spectroscopy` and `process.contact` fit force curves and force maps with Hertz,
7
- Sneddon, DMT, JKR and Oliver-Pharr for sphere, cone, pyramid, flat punch and hyperboloid tips, with baseline and
8
- interference removal, statistics, maps and CSV; `process.iv` analyzes I-V curves. The same calculations as the
9
- Spectroscopy page of NSSA (NSF Surface and Spectroscopy Analyzer).
10
- - **Color maps of its own:** 12 named maps (`Sky`, `Warm`, `Flare`, ...) defined in the code; `register()` makes them
11
- usable by name in matplotlib. The Gwyddion gradient files are no longer included, but an installed Gwyddion's are
12
- found on Windows, macOS and Linux.
13
-
14
- ## What's new in 2.3.0
15
- Compared to 2.2.4:
16
- - **Works by itself:** the `nanosurf` and `scikit-learn` packages are no longer needed.
17
- - **NHF spectroscopy and WaveMode NMA:** files of any size open immediately, and curves are read when asked for.
18
- - **Image analysis from NSSA (then called Nanosurf Surface Analyzer):** leveling, filters, masks, ISO statistics, line
19
- cuts, step heights, critical dimension, PSD fits, lattice and grains.
20
- - **Better figures:** units and labels from the file, subplots with `ax=`, a new 3D plot, and plots of the analysis results.
21
- - **Examples rewritten,** with several bugs fixed. The `Spring_Constant` result changes from 14.5 to 24.0 N/m, because the
22
- old fit used the wrong formula.
23
-
24
- Some defaults changed, which can affect existing scripts:
25
- - NHF force curves `[row, col]` now give the true grid position.
26
- - `image` and `hist` choose their unit from the channel; `scale=1e9` still forces nm.
27
- - `image` shows a color bar unless `colorbar=False`.
28
- - `remove_outliers` gives different numbers and no longer takes `neighbors`.
29
-
30
- `CHANGELOG.md`, in the source distribution, has the full list.
31
-
32
- ## Installing
33
- From PyPi
34
- ```
35
- pip install NSFopen
36
- ```
37
-
38
- Needs numpy, scipy, pandas, h5py and matplotlib 3.6 or newer. Examples are in the example folder; `NSFopen_help` shows where. Each
39
- is a notebook with its `.py` and `.html`, to run from its own folder:
40
-
41
- | Example | Shows |
42
- |---|---|
43
- | `Plotting_Data` | Leveling with a mask, figures for a report, subplots, 3D |
44
- | `Calculate_Roughness` | Surface statistics, height distribution, bearing curve, PSD, roughness along a line |
45
- | `Plane_Removal` | Leveling all the files of a folder |
46
- | `Grain_Analysis` | Finding features and measuring each of them |
47
- | `Lateral_Force` | Friction from the forward and backward scans |
48
- | `Force_Spectroscopy` | Fitting a force map with the DMT model; `Contact_Models.py`: the same with `process.spectroscopy`, maps and the quality filter |
49
- | `Spring_Constant` | Sader method from a thermal tune |
50
- | `Sharpen_Image` | Your own processing on the arrays, stored back as channels |
51
-
52
- ## Reading files
53
- ```python
54
- from NSFopen.read import read
55
-
56
- afm = read('filename.nid') # or .nhf
57
- afm.data['Image']['Forward']['Z-Axis'] # an image, in SI units
58
- afm.param # parameters of the file
59
- afm.units[('Image', 'Forward', 'Z-Axis')]
60
- ```
61
- Row 0 of an image is the first line scanned, which is the bottom of the picture for an upward scan.
62
-
63
- ### Spectroscopy (.nhf)
64
- Files of any size open immediately: curves are read when you ask for them.
65
- ```python
66
- afm = read('grid.nhf')
67
- afm.spec.segments, afm.spec.shape, afm.spec.n_points
68
-
69
- deflection = afm.spec['Retract 1']['Deflection']
70
- deflection[10] # 11th curve in acquisition order
71
- deflection[2, 3] # curve at row 2, column 3 of the grid, row 0 at the bottom
72
- deflection.to('m')[2, 3] # in another unit, if the file holds its calibration
73
- deflection.curves() # all curves, which may differ in length
74
- deflection.array() # all curves as (rows, columns, samples), padded with NaN
75
-
76
- z, force = afm.spec.force_curve('Retract 1', (2, 3))
77
- afm.close()
78
- ```
79
- `afm.data['Spec']['Retract 1']['Deflection']` is the same object.
80
-
81
- ### WaveMode NMA (.nhf)
82
- The scalar channels are in `afm.data` as for any image, the per-pixel curves in `afm.nma`.
83
- ```python
84
- afm = read('nma.nhf')
85
- curve = afm.nma.curve((100, 200), scan='Forward') # row, column
86
- curve.z, curve.interaction, curve.force
87
- z_advance, force_advance = curve.advance
88
- z_retract, force_retract = curve.retract
89
-
90
- adhesion = afm.nma.map() # most negative interaction of every pixel, in V
91
- stiff = afm.nma.map(lambda block: block.max(axis=1), scan='Backward') # any function of (pixels, samples)
92
- ```
93
-
94
- ## Processing images
95
- ```python
96
- from NSFopen.process import process
97
-
98
- afm = process('filename.nhf')
99
- afm.level_flatten() # align the lines, then subtract a plane
100
- afm.mask_otsu() # two-level image: mask the upper level
101
- afm.flatten(fit_on='exclude') # level the lines on what is not masked
102
-
103
- afm.statistics(region='unmasked') # Sa, Sq, Ssk, Sku, Sdq, Sdr, Sal, Str, ... with units
104
- grains = afm.grains(split='height') # one row per grain in grains.table
105
- profile = afm.line_profile((0, 1e-6), (2e-6, 1e-6), width=5) # end points in m
106
- afm.step_heights(profile).steps
107
- afm.critical_dimension(profile).features
108
- afm.profile_roughness(profile).params # ISO 21920
109
- afm.psd_fit().summary() # corner, power law, noise floor, resolution
110
- afm.lattice().summary()
111
-
112
- afm.image(show_mask=True)
113
- afm.hist()
114
- afm.plot3d() # 3D, colored by height
115
- afm.plot3d(material='Gold', tilt=60) # 3D, a material under a light
116
- afm.plot3d(color='Phase') # 3D, colored by another channel
117
- ```
118
- `afm.array()` gives a channel as an array and `afm.set_channel(values, channel='Name', unit='m')` stores your own array
119
- as a channel, for all the functions below.
120
-
121
- All processing works on one channel, by default `direction='Forward'` and the height, which files call `Z-Axis` or
122
- `Topography`; `afm.channels` lists them all. It changes the channel unless `inplace=False`, when the new array is
123
- returned instead.
124
-
125
- | Group | Methods |
126
- |---|---|
127
- | Leveling | `flatten`, `plane_level`, `level_flatten`, `level_poly2d`, `level_lines`, `level_align_rows`, `level_facet`, `level_three_point`, `level_median`, `level_rolling_ball`, `level_shift` |
128
- | Filters | `denoise`, `filter_basic`, `filter_median`, `filter_gaussian`, `filter_fft`, `filter_notch` |
129
- | Glitches | `remove_outliers`, `glitch_spikes`, `glitch_lines`, `glitch_auto_lines`, `glitch_scars`, `glitch_step_lines`, `glitch_fill_mask` |
130
- | Masks | `set_mask`, `mask_threshold`, `mask_otsu`, `mask_watershed`, `mask_outliers`, `mask_scars`, `mask_shape`, `mask_floodfill`, `mask_grow`, `mask_shrink`, `mask_invert`, `mask_clear`, `mask_remove_small`, `mask_fill_holes` |
131
- | Geometry and scale | `geometry_crop`, `geometry_flip`, `geometry_rotate`, `geometry_resample`, `geometry_square_pixels`, `rescale_scale`, `rescale_z_to_reference`, `rescale_xy` |
132
- | Height statistics | `stats`, `statistics`, `bearing_curve`, `histogram_fit`, `slope_distributions` |
133
- | Lines | `line_profile`, `step_heights`, `critical_dimension`, `profile_roughness`, `masked_step_height` |
134
- | Spectra and texture | `psd`, `psd_fit`, `spectrum`, `acf`, `line_functions`, `rms_by_scale`, `lattice` |
135
- | Grains | `grains` |
136
- | Two channels | `combine`, `find_shift` |
137
- | Plots | `image`, `thumb`, `hist`, `plot3d`, `plot_profile`, `plot_psd`, `plot_histogram_fit`, `plot_bearing`, `plot_acf` |
138
-
139
- `help(process.level_rolling_ball)` explains a method and its parameters; `process.operations()` lists the operations
140
- with their defaults.
141
-
142
- ## Figures
143
- `image`, `hist`, `thumb` and `plot3d` take a channel and return a matplotlib figure, with the unit (nm, mV, ...) and
144
- labels from the file.
145
- ```python
146
- fig = afm.image(channel='Phase', color_range='p1', cmap='viridis') # color range: 'full', 'p1' (1-99 %) or (low, high)
147
- fig.savefig('phase.png')
148
-
149
- afm.image(scalebar=True, title=None, figsize=(4, 4), dpi=600, theme='dark')
150
-
151
- import matplotlib.pyplot as plt
152
- fig, axes = plt.subplots(1, 3, figsize=(12, 4), layout='constrained')
153
- afm.image(ax=axes[0])
154
- afm.hist(ax=axes[1])
155
- afm.plot3d(material='Gold', ax=axes[2])
156
- ```
157
-
158
- Results of the analysis have their plots too, with the same options:
159
- ```python
160
- profile = afm.line_profile((0, 1e-6), (2e-6, 1e-6), width=5)
161
- afm.image(profile=profile) # where the line is
162
- afm.plot_profile(profile, steps=afm.step_heights(profile)) # or cd=afm.critical_dimension(profile)
163
- afm.plot_psd() # with a fit; fit=None for the data alone
164
- afm.plot_histogram_fit(model='gauss2')
165
- afm.plot_bearing()
166
- afm.plot_acf()
167
- ```
168
-
169
- ## Color maps
170
- ```python
171
- from NSFopen.process import colors
172
- afm.image(cmap='Gold') # by name
173
- afm.image(cmap=colors('Gold').cmap)
174
- ```
175
- The Gwyddion gradients are included with the package.
1
+ # NSFopen
2
+ Open and analyze Nanosurf NID and NHF files in Python: images, force spectroscopy and WaveMode NMA.
3
+
4
+ ## What's new in 2.4.1
5
+ A fix: reading NID files no longer gives a pandas warning (pandas 3.1 and newer).
6
+
7
+ ## What's new in 2.4.0
8
+ Compared to 2.3.0:
9
+ - **Force curve analysis:** `process.spectroscopy` and `process.contact` fit force curves and force maps with Hertz,
10
+ Sneddon, DMT, JKR and Oliver-Pharr for sphere, cone, pyramid, flat punch and hyperboloid tips, with baseline and
11
+ interference removal, statistics, maps and CSV; `process.iv` analyzes I-V curves. The same calculations as the
12
+ Spectroscopy page of NSSA (NSF Surface and Spectroscopy Analyzer).
13
+ - **Color maps of its own:** 12 named maps (`Sky`, `Warm`, `Flare`, ...) defined in the code; `register()` makes them
14
+ usable by name in matplotlib. The Gwyddion gradient files are no longer included, but an installed Gwyddion's are
15
+ found on Windows, macOS and Linux.
16
+
17
+ ## What's new in 2.3.0
18
+ Compared to 2.2.4:
19
+ - **Works by itself:** the `nanosurf` and `scikit-learn` packages are no longer needed.
20
+ - **NHF spectroscopy and WaveMode NMA:** files of any size open immediately, and curves are read when asked for.
21
+ - **Image analysis from NSSA (then called Nanosurf Surface Analyzer):** leveling, filters, masks, ISO statistics, line
22
+ cuts, step heights, critical dimension, PSD fits, lattice and grains.
23
+ - **Better figures:** units and labels from the file, subplots with `ax=`, a new 3D plot, and plots of the analysis results.
24
+ - **Examples rewritten,** with several bugs fixed. The `Spring_Constant` result changes from 14.5 to 24.0 N/m, because the
25
+ old fit used the wrong formula.
26
+
27
+ Some defaults changed, which can affect existing scripts:
28
+ - NHF force curves `[row, col]` now give the true grid position.
29
+ - `image` and `hist` choose their unit from the channel; `scale=1e9` still forces nm.
30
+ - `image` shows a color bar unless `colorbar=False`.
31
+ - `remove_outliers` gives different numbers and no longer takes `neighbors`.
32
+
33
+ `CHANGELOG.md`, in the source distribution, has the full list.
34
+
35
+ ## Installing
36
+ From PyPi
37
+ ```
38
+ pip install NSFopen
39
+ ```
40
+
41
+ Needs numpy, scipy, pandas, h5py and matplotlib 3.6 or newer. Examples are in the example folder; `NSFopen_help` shows where. Each
42
+ is a notebook with its `.py` and `.html`, to run from its own folder:
43
+
44
+ | Example | Shows |
45
+ |---|---|
46
+ | `Plotting_Data` | Leveling with a mask, figures for a report, subplots, 3D |
47
+ | `Calculate_Roughness` | Surface statistics, height distribution, bearing curve, PSD, roughness along a line |
48
+ | `Plane_Removal` | Leveling all the files of a folder |
49
+ | `Grain_Analysis` | Finding features and measuring each of them |
50
+ | `Lateral_Force` | Friction from the forward and backward scans |
51
+ | `Force_Spectroscopy` | Fitting a force map with the DMT model; `Contact_Models.py`: the same with `process.spectroscopy`, maps and the quality filter |
52
+ | `Spring_Constant` | Sader method from a thermal tune |
53
+ | `Sharpen_Image` | Your own processing on the arrays, stored back as channels |
54
+
55
+ ## Reading files
56
+ ```python
57
+ from NSFopen.read import read
58
+
59
+ afm = read('filename.nid') # or .nhf
60
+ afm.data['Image']['Forward']['Z-Axis'] # an image, in SI units
61
+ afm.param # parameters of the file
62
+ afm.units[('Image', 'Forward', 'Z-Axis')]
63
+ ```
64
+ Row 0 of an image is the first line scanned, which is the bottom of the picture for an upward scan.
65
+
66
+ ### Spectroscopy (.nhf)
67
+ Files of any size open immediately: curves are read when you ask for them.
68
+ ```python
69
+ afm = read('grid.nhf')
70
+ afm.spec.segments, afm.spec.shape, afm.spec.n_points
71
+
72
+ deflection = afm.spec['Retract 1']['Deflection']
73
+ deflection[10] # 11th curve in acquisition order
74
+ deflection[2, 3] # curve at row 2, column 3 of the grid, row 0 at the bottom
75
+ deflection.to('m')[2, 3] # in another unit, if the file holds its calibration
76
+ deflection.curves() # all curves, which may differ in length
77
+ deflection.array() # all curves as (rows, columns, samples), padded with NaN
78
+
79
+ z, force = afm.spec.force_curve('Retract 1', (2, 3))
80
+ afm.close()
81
+ ```
82
+ `afm.data['Spec']['Retract 1']['Deflection']` is the same object.
83
+
84
+ ### WaveMode NMA (.nhf)
85
+ The scalar channels are in `afm.data` as for any image, the per-pixel curves in `afm.nma`.
86
+ ```python
87
+ afm = read('nma.nhf')
88
+ curve = afm.nma.curve((100, 200), scan='Forward') # row, column
89
+ curve.z, curve.interaction, curve.force
90
+ z_advance, force_advance = curve.advance
91
+ z_retract, force_retract = curve.retract
92
+
93
+ adhesion = afm.nma.map() # most negative interaction of every pixel, in V
94
+ stiff = afm.nma.map(lambda block: block.max(axis=1), scan='Backward') # any function of (pixels, samples)
95
+ ```
96
+
97
+ ## Processing images
98
+ ```python
99
+ from NSFopen.process import process
100
+
101
+ afm = process('filename.nhf')
102
+ afm.level_flatten() # align the lines, then subtract a plane
103
+ afm.mask_otsu() # two-level image: mask the upper level
104
+ afm.flatten(fit_on='exclude') # level the lines on what is not masked
105
+
106
+ afm.statistics(region='unmasked') # Sa, Sq, Ssk, Sku, Sdq, Sdr, Sal, Str, ... with units
107
+ grains = afm.grains(split='height') # one row per grain in grains.table
108
+ profile = afm.line_profile((0, 1e-6), (2e-6, 1e-6), width=5) # end points in m
109
+ afm.step_heights(profile).steps
110
+ afm.critical_dimension(profile).features
111
+ afm.profile_roughness(profile).params # ISO 21920
112
+ afm.psd_fit().summary() # corner, power law, noise floor, resolution
113
+ afm.lattice().summary()
114
+
115
+ afm.image(show_mask=True)
116
+ afm.hist()
117
+ afm.plot3d() # 3D, colored by height
118
+ afm.plot3d(material='Gold', tilt=60) # 3D, a material under a light
119
+ afm.plot3d(color='Phase') # 3D, colored by another channel
120
+ ```
121
+ `afm.array()` gives a channel as an array and `afm.set_channel(values, channel='Name', unit='m')` stores your own array
122
+ as a channel, for all the functions below.
123
+
124
+ All processing works on one channel, by default `direction='Forward'` and the height, which files call `Z-Axis` or
125
+ `Topography`; `afm.channels` lists them all. It changes the channel unless `inplace=False`, when the new array is
126
+ returned instead.
127
+
128
+ | Group | Methods |
129
+ |---|---|
130
+ | Leveling | `flatten`, `plane_level`, `level_flatten`, `level_poly2d`, `level_lines`, `level_align_rows`, `level_facet`, `level_three_point`, `level_median`, `level_rolling_ball`, `level_shift` |
131
+ | Filters | `denoise`, `filter_basic`, `filter_median`, `filter_gaussian`, `filter_fft`, `filter_notch` |
132
+ | Glitches | `remove_outliers`, `glitch_spikes`, `glitch_lines`, `glitch_auto_lines`, `glitch_scars`, `glitch_step_lines`, `glitch_fill_mask` |
133
+ | Masks | `set_mask`, `mask_threshold`, `mask_otsu`, `mask_watershed`, `mask_outliers`, `mask_scars`, `mask_shape`, `mask_floodfill`, `mask_grow`, `mask_shrink`, `mask_invert`, `mask_clear`, `mask_remove_small`, `mask_fill_holes` |
134
+ | Geometry and scale | `geometry_crop`, `geometry_flip`, `geometry_rotate`, `geometry_resample`, `geometry_square_pixels`, `rescale_scale`, `rescale_z_to_reference`, `rescale_xy` |
135
+ | Height statistics | `stats`, `statistics`, `bearing_curve`, `histogram_fit`, `slope_distributions` |
136
+ | Lines | `line_profile`, `step_heights`, `critical_dimension`, `profile_roughness`, `masked_step_height` |
137
+ | Spectra and texture | `psd`, `psd_fit`, `spectrum`, `acf`, `line_functions`, `rms_by_scale`, `lattice` |
138
+ | Grains | `grains` |
139
+ | Two channels | `combine`, `find_shift` |
140
+ | Plots | `image`, `thumb`, `hist`, `plot3d`, `plot_profile`, `plot_psd`, `plot_histogram_fit`, `plot_bearing`, `plot_acf` |
141
+
142
+ `help(process.level_rolling_ball)` explains a method and its parameters; `process.operations()` lists the operations
143
+ with their defaults.
144
+
145
+ ## Figures
146
+ `image`, `hist`, `thumb` and `plot3d` take a channel and return a matplotlib figure, with the unit (nm, mV, ...) and
147
+ labels from the file.
148
+ ```python
149
+ fig = afm.image(channel='Phase', color_range='p1', cmap='viridis') # color range: 'full', 'p1' (1-99 %) or (low, high)
150
+ fig.savefig('phase.png')
151
+
152
+ afm.image(scalebar=True, title=None, figsize=(4, 4), dpi=600, theme='dark')
153
+
154
+ import matplotlib.pyplot as plt
155
+ fig, axes = plt.subplots(1, 3, figsize=(12, 4), layout='constrained')
156
+ afm.image(ax=axes[0])
157
+ afm.hist(ax=axes[1])
158
+ afm.plot3d(material='Gold', ax=axes[2])
159
+ ```
160
+
161
+ Results of the analysis have their plots too, with the same options:
162
+ ```python
163
+ profile = afm.line_profile((0, 1e-6), (2e-6, 1e-6), width=5)
164
+ afm.image(profile=profile) # where the line is
165
+ afm.plot_profile(profile, steps=afm.step_heights(profile)) # or cd=afm.critical_dimension(profile)
166
+ afm.plot_psd() # with a fit; fit=None for the data alone
167
+ afm.plot_histogram_fit(model='gauss2')
168
+ afm.plot_bearing()
169
+ afm.plot_acf()
170
+ ```
171
+
172
+ ## Color maps
173
+ ```python
174
+ from NSFopen.process import colors
175
+ afm.image(cmap='Gold') # by name
176
+ afm.image(cmap=colors('Gold').cmap)
177
+ ```
178
+ The Gwyddion gradients are included with the package.
@@ -1 +0,0 @@
1
- __version__ = "2.4.0"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes