nabu 2024.2.14__py3-none-any.whl → 2025.1.0__py3-none-any.whl

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 (197) hide show
  1. doc/doc_config.py +32 -0
  2. nabu/__init__.py +1 -1
  3. nabu/app/bootstrap_stitching.py +4 -2
  4. nabu/app/cast_volume.py +16 -14
  5. nabu/app/cli_configs.py +102 -9
  6. nabu/app/compare_volumes.py +1 -1
  7. nabu/app/composite_cor.py +2 -4
  8. nabu/app/diag_to_pix.py +5 -6
  9. nabu/app/diag_to_rot.py +10 -11
  10. nabu/app/double_flatfield.py +18 -5
  11. nabu/app/estimate_motion.py +75 -0
  12. nabu/app/multicor.py +28 -15
  13. nabu/app/parse_reconstruction_log.py +1 -0
  14. nabu/app/pcaflats.py +122 -0
  15. nabu/app/prepare_weights_double.py +1 -2
  16. nabu/app/reconstruct.py +1 -7
  17. nabu/app/reconstruct_helical.py +5 -9
  18. nabu/app/reduce_dark_flat.py +5 -4
  19. nabu/app/rotate.py +3 -1
  20. nabu/app/stitching.py +7 -2
  21. nabu/app/tests/test_reduce_dark_flat.py +2 -2
  22. nabu/app/validator.py +1 -4
  23. nabu/cuda/convolution.py +1 -1
  24. nabu/cuda/fft.py +1 -1
  25. nabu/cuda/medfilt.py +1 -1
  26. nabu/cuda/padding.py +1 -1
  27. nabu/cuda/src/backproj.cu +6 -6
  28. nabu/cuda/src/cone.cu +4 -0
  29. nabu/cuda/src/hierarchical_backproj.cu +14 -0
  30. nabu/cuda/utils.py +2 -2
  31. nabu/estimation/alignment.py +17 -31
  32. nabu/estimation/cor.py +27 -33
  33. nabu/estimation/cor_sino.py +2 -8
  34. nabu/estimation/focus.py +4 -8
  35. nabu/estimation/motion.py +557 -0
  36. nabu/estimation/tests/test_alignment.py +2 -0
  37. nabu/estimation/tests/test_motion_estimation.py +471 -0
  38. nabu/estimation/tests/test_tilt.py +1 -1
  39. nabu/estimation/tilt.py +6 -5
  40. nabu/estimation/translation.py +47 -1
  41. nabu/io/cast_volume.py +108 -18
  42. nabu/io/detector_distortion.py +5 -6
  43. nabu/io/reader.py +45 -6
  44. nabu/io/reader_helical.py +5 -4
  45. nabu/io/tests/test_cast_volume.py +2 -2
  46. nabu/io/tests/test_readers.py +41 -38
  47. nabu/io/tests/test_remove_volume.py +152 -0
  48. nabu/io/tests/test_writers.py +2 -2
  49. nabu/io/utils.py +8 -4
  50. nabu/io/writer.py +1 -2
  51. nabu/misc/fftshift.py +1 -1
  52. nabu/misc/fourier_filters.py +1 -1
  53. nabu/misc/histogram.py +1 -1
  54. nabu/misc/histogram_cuda.py +1 -1
  55. nabu/misc/padding_base.py +1 -1
  56. nabu/misc/rotation.py +1 -1
  57. nabu/misc/rotation_cuda.py +1 -1
  58. nabu/misc/tests/test_binning.py +1 -1
  59. nabu/misc/transpose.py +1 -1
  60. nabu/misc/unsharp.py +1 -1
  61. nabu/misc/unsharp_cuda.py +1 -1
  62. nabu/misc/unsharp_opencl.py +1 -1
  63. nabu/misc/utils.py +1 -1
  64. nabu/opencl/fft.py +1 -1
  65. nabu/opencl/padding.py +1 -1
  66. nabu/opencl/src/backproj.cl +6 -6
  67. nabu/opencl/utils.py +8 -8
  68. nabu/pipeline/config.py +2 -2
  69. nabu/pipeline/config_validators.py +46 -46
  70. nabu/pipeline/datadump.py +3 -3
  71. nabu/pipeline/estimators.py +271 -11
  72. nabu/pipeline/fullfield/chunked.py +103 -67
  73. nabu/pipeline/fullfield/chunked_cuda.py +5 -2
  74. nabu/pipeline/fullfield/computations.py +4 -1
  75. nabu/pipeline/fullfield/dataset_validator.py +0 -1
  76. nabu/pipeline/fullfield/get_double_flatfield.py +147 -0
  77. nabu/pipeline/fullfield/nabu_config.py +36 -17
  78. nabu/pipeline/fullfield/processconfig.py +41 -7
  79. nabu/pipeline/fullfield/reconstruction.py +14 -10
  80. nabu/pipeline/helical/dataset_validator.py +3 -4
  81. nabu/pipeline/helical/fbp.py +4 -4
  82. nabu/pipeline/helical/filtering.py +5 -4
  83. nabu/pipeline/helical/gridded_accumulator.py +10 -11
  84. nabu/pipeline/helical/helical_chunked_regridded.py +1 -0
  85. nabu/pipeline/helical/helical_reconstruction.py +12 -9
  86. nabu/pipeline/helical/helical_utils.py +1 -2
  87. nabu/pipeline/helical/nabu_config.py +2 -1
  88. nabu/pipeline/helical/span_strategy.py +1 -0
  89. nabu/pipeline/helical/weight_balancer.py +2 -3
  90. nabu/pipeline/params.py +20 -3
  91. nabu/pipeline/tests/__init__.py +0 -0
  92. nabu/pipeline/tests/test_estimators.py +240 -3
  93. nabu/pipeline/utils.py +1 -1
  94. nabu/pipeline/writer.py +1 -1
  95. nabu/preproc/alignment.py +0 -10
  96. nabu/preproc/ccd.py +53 -3
  97. nabu/preproc/ctf.py +8 -8
  98. nabu/preproc/ctf_cuda.py +1 -1
  99. nabu/preproc/double_flatfield_cuda.py +2 -2
  100. nabu/preproc/double_flatfield_variable_region.py +0 -1
  101. nabu/preproc/flatfield.py +307 -2
  102. nabu/preproc/flatfield_cuda.py +1 -2
  103. nabu/preproc/flatfield_variable_region.py +3 -3
  104. nabu/preproc/phase.py +2 -4
  105. nabu/preproc/phase_cuda.py +2 -2
  106. nabu/preproc/shift.py +4 -2
  107. nabu/preproc/shift_cuda.py +0 -1
  108. nabu/preproc/tests/test_ctf.py +4 -4
  109. nabu/preproc/tests/test_double_flatfield.py +1 -1
  110. nabu/preproc/tests/test_flatfield.py +1 -1
  111. nabu/preproc/tests/test_paganin.py +1 -3
  112. nabu/preproc/tests/test_pcaflats.py +154 -0
  113. nabu/preproc/tests/test_vshift.py +4 -1
  114. nabu/processing/azim.py +9 -5
  115. nabu/processing/convolution_cuda.py +6 -4
  116. nabu/processing/fft_base.py +7 -3
  117. nabu/processing/fft_cuda.py +25 -164
  118. nabu/processing/fft_opencl.py +28 -6
  119. nabu/processing/fftshift.py +1 -1
  120. nabu/processing/histogram.py +1 -1
  121. nabu/processing/muladd.py +0 -1
  122. nabu/processing/padding_base.py +1 -1
  123. nabu/processing/padding_cuda.py +0 -2
  124. nabu/processing/processing_base.py +12 -6
  125. nabu/processing/rotation_cuda.py +3 -1
  126. nabu/processing/tests/test_fft.py +2 -64
  127. nabu/processing/tests/test_fftshift.py +1 -1
  128. nabu/processing/tests/test_medfilt.py +1 -3
  129. nabu/processing/tests/test_padding.py +1 -1
  130. nabu/processing/tests/test_roll.py +1 -1
  131. nabu/processing/tests/test_rotation.py +4 -2
  132. nabu/processing/unsharp_opencl.py +1 -1
  133. nabu/reconstruction/astra.py +245 -0
  134. nabu/reconstruction/cone.py +39 -9
  135. nabu/reconstruction/fbp.py +7 -0
  136. nabu/reconstruction/fbp_base.py +36 -5
  137. nabu/reconstruction/filtering.py +59 -25
  138. nabu/reconstruction/filtering_cuda.py +22 -21
  139. nabu/reconstruction/filtering_opencl.py +10 -14
  140. nabu/reconstruction/hbp.py +26 -13
  141. nabu/reconstruction/mlem.py +55 -16
  142. nabu/reconstruction/projection.py +3 -5
  143. nabu/reconstruction/sinogram.py +1 -1
  144. nabu/reconstruction/sinogram_cuda.py +0 -1
  145. nabu/reconstruction/tests/test_cone.py +37 -2
  146. nabu/reconstruction/tests/test_deringer.py +4 -4
  147. nabu/reconstruction/tests/test_fbp.py +36 -15
  148. nabu/reconstruction/tests/test_filtering.py +27 -7
  149. nabu/reconstruction/tests/test_halftomo.py +28 -2
  150. nabu/reconstruction/tests/test_mlem.py +94 -64
  151. nabu/reconstruction/tests/test_projector.py +7 -2
  152. nabu/reconstruction/tests/test_reconstructor.py +1 -1
  153. nabu/reconstruction/tests/test_sino_normalization.py +0 -1
  154. nabu/resources/dataset_analyzer.py +210 -24
  155. nabu/resources/gpu.py +4 -4
  156. nabu/resources/logger.py +4 -4
  157. nabu/resources/nxflatfield.py +103 -37
  158. nabu/resources/tests/test_dataset_analyzer.py +37 -0
  159. nabu/resources/tests/test_extract.py +11 -0
  160. nabu/resources/tests/test_nxflatfield.py +5 -5
  161. nabu/resources/utils.py +16 -10
  162. nabu/stitching/alignment.py +8 -11
  163. nabu/stitching/config.py +44 -35
  164. nabu/stitching/definitions.py +2 -2
  165. nabu/stitching/frame_composition.py +8 -10
  166. nabu/stitching/overlap.py +4 -4
  167. nabu/stitching/sample_normalization.py +5 -5
  168. nabu/stitching/slurm_utils.py +2 -2
  169. nabu/stitching/stitcher/base.py +2 -0
  170. nabu/stitching/stitcher/dumper/base.py +0 -1
  171. nabu/stitching/stitcher/dumper/postprocessing.py +1 -1
  172. nabu/stitching/stitcher/post_processing.py +11 -9
  173. nabu/stitching/stitcher/pre_processing.py +37 -31
  174. nabu/stitching/stitcher/single_axis.py +2 -3
  175. nabu/stitching/stitcher_2D.py +2 -1
  176. nabu/stitching/tests/test_config.py +10 -11
  177. nabu/stitching/tests/test_sample_normalization.py +1 -1
  178. nabu/stitching/tests/test_slurm_utils.py +1 -2
  179. nabu/stitching/tests/test_y_preprocessing_stitching.py +11 -8
  180. nabu/stitching/tests/test_z_postprocessing_stitching.py +3 -3
  181. nabu/stitching/tests/test_z_preprocessing_stitching.py +27 -24
  182. nabu/stitching/utils/tests/__init__.py +0 -0
  183. nabu/stitching/utils/tests/test_post-processing.py +1 -0
  184. nabu/stitching/utils/utils.py +16 -18
  185. nabu/tests.py +0 -3
  186. nabu/testutils.py +62 -9
  187. nabu/utils.py +50 -20
  188. {nabu-2024.2.14.dist-info → nabu-2025.1.0.dist-info}/METADATA +7 -7
  189. nabu-2025.1.0.dist-info/RECORD +328 -0
  190. {nabu-2024.2.14.dist-info → nabu-2025.1.0.dist-info}/WHEEL +1 -1
  191. {nabu-2024.2.14.dist-info → nabu-2025.1.0.dist-info}/entry_points.txt +2 -1
  192. nabu/app/correct_rot.py +0 -70
  193. nabu/io/tests/test_detector_distortion.py +0 -178
  194. nabu-2024.2.14.dist-info/RECORD +0 -317
  195. /nabu/{stitching → app}/tests/__init__.py +0 -0
  196. {nabu-2024.2.14.dist-info → nabu-2025.1.0.dist-info}/licenses/LICENSE +0 -0
  197. {nabu-2024.2.14.dist-info → nabu-2025.1.0.dist-info}/top_level.txt +0 -0
nabu/estimation/cor.py CHANGED
@@ -132,7 +132,7 @@ class CenterOfRotation(AlignmentBase):
132
132
  img_2 = self._prepare_image(img_2, roi_yxhw=roi_yxhw, median_filt_shape=median_filt_shape)
133
133
 
134
134
  cc = self._compute_correlation_fft(img_1, img_2, padding_mode, high_pass=high_pass, low_pass=low_pass)
135
- img_shape = img_2.shape
135
+ img_shape = cc.shape # Because cc.shape can differ from img_2.shape (e.g. in case of odd nb of cols)
136
136
  cc_vs = np.fft.fftfreq(img_shape[-2], 1 / img_shape[-2])
137
137
  cc_hs = np.fft.fftfreq(img_shape[-1], 1 / img_shape[-1])
138
138
 
@@ -269,10 +269,9 @@ class CenterOfRotationSlidingWindow(CenterOfRotation):
269
269
  win_ind_max = np.argmax(diffs_mean)
270
270
 
271
271
  diffs_std = diffs_std.min() - diffs_std
272
- if not win_ind_max == np.argmax(diffs_std):
272
+ if win_ind_max != np.argmax(diffs_std):
273
273
  self.logger.warning(
274
- "Minimum mean difference and minimum std-dev of differences do not coincide. "
275
- + "This means that the validity of the found solution might be questionable."
274
+ "Minimum mean difference and minimum std-dev of differences do not coincide. This means that the validity of the found solution might be questionable."
276
275
  )
277
276
  validity_check_result = cor_result_validity["questionable"]
278
277
  else:
@@ -435,10 +434,9 @@ class CenterOfRotationGrowingWindow(CenterOfRotation):
435
434
  win_ind_max = np.argmax(diffs_mean)
436
435
 
437
436
  diffs_std = diffs_std.min() - diffs_std
438
- if not win_ind_max == np.argmax(diffs_std):
437
+ if win_ind_max != np.argmax(diffs_std):
439
438
  self.logger.warning(
440
- "Minimum mean difference and minimum std-dev of differences do not coincide. "
441
- + "This means that the validity of the found solution might be questionable."
439
+ "Minimum mean difference and minimum std-dev of differences do not coincide. This means that the validity of the found solution might be questionable."
442
440
  )
443
441
  validity_check_result = cor_result_validity["questionable"]
444
442
  else:
@@ -578,8 +576,7 @@ class CenterOfRotationAdaptiveSearch(CenterOfRotation):
578
576
 
579
577
  if lim_2 <= lim_1:
580
578
  message = (
581
- "Image shape or cropped selection too small for global search."
582
- + " After removal of the margins the search limits collide."
579
+ "Image shape or cropped selection too small for global search. After removal of the margins the search limits collide."
583
580
  + " The cropped size is %d\n" % (dim_radio)
584
581
  )
585
582
  raise ValueError(message)
@@ -616,11 +613,11 @@ class CenterOfRotationAdaptiveSearch(CenterOfRotation):
616
613
  if "positions are outside the input margins" in str(err):
617
614
  x_cor = min(x_cor + x_cor * self.step_fraction, x_cor + (dim_radio - x_cor) * self.step_fraction)
618
615
  continue
619
- except:
620
- message = "Unexpected error from base class CenterOfRotation.find_shift in CenterOfRotationAdaptiveSearch.find_shift : {err}".format(
621
- err=err
616
+ except Exception as err:
617
+ self.logger.error(
618
+ "Unexpected error from base class CenterOfRotation.find_shift in CenterOfRotationAdaptiveSearch.find_shift: %s"
619
+ % (str(err))
622
620
  )
623
- self.logger.error(message)
624
621
  raise
625
622
 
626
623
  p_1 = cor_position * 2
@@ -643,8 +640,8 @@ class CenterOfRotationAdaptiveSearch(CenterOfRotation):
643
640
  * self.sigma_fraction
644
641
  )
645
642
 
646
- M1 = int(round(cor_position + img_1.shape[1] // 2)) - int(round(tmp_sigma))
647
- M2 = int(round(cor_position + img_1.shape[1] // 2)) + int(round(tmp_sigma))
643
+ M1 = round(cor_position + img_1.shape[1] // 2) - round(tmp_sigma)
644
+ M2 = round(cor_position + img_1.shape[1] // 2) + round(tmp_sigma)
648
645
 
649
646
  piece_1 = img_filtered_1[:, M1:M2]
650
647
  piece_2 = img_filtered_2[:, img_1.shape[1] - M2 : img_1.shape[1] - M1]
@@ -656,16 +653,13 @@ class CenterOfRotationAdaptiveSearch(CenterOfRotation):
656
653
  diff_energy = np.array((piece_1 - piece_2) * (piece_1 - piece_2), "d").sum()
657
654
  cost = diff_energy / energy
658
655
 
659
- if not np.isnan(cost):
660
- if tmp_sigma * 2 > abs(x_cor_rel - cor_position):
661
- found_centers.append([cost, abs(x_cor_rel - cor_position), cor_position, energy])
656
+ if not np.isnan(cost) and tmp_sigma * 2 > abs(x_cor_rel - cor_position):
657
+ found_centers.append([cost, abs(x_cor_rel - cor_position), cor_position, energy])
662
658
 
663
659
  x_cor = min(x_cor + x_cor * self.step_fraction, x_cor + (dim_radio - x_cor) * self.step_fraction)
664
660
 
665
661
  if len(found_centers) == 0:
666
- message = "Unable to find any valid CoR candidate in {my_class}.find_shift ".format(
667
- my_class=self.__class__.__name__
668
- )
662
+ message = f"Unable to find any valid CoR candidate in {self.__class__.__name__}.find_shift "
669
663
  raise ValueError(message)
670
664
 
671
665
  # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -674,6 +668,7 @@ class CenterOfRotationAdaptiveSearch(CenterOfRotation):
674
668
 
675
669
  filtered_found_centers = []
676
670
  for i in range(len(found_centers)):
671
+ # ruff: noqa: SIM102
677
672
  if i > 0:
678
673
  if abs(found_centers[i][2] - found_centers[i - 1][2]) < 0.5:
679
674
  filtered_found_centers.append(found_centers[i])
@@ -683,7 +678,7 @@ class CenterOfRotationAdaptiveSearch(CenterOfRotation):
683
678
  filtered_found_centers.append(found_centers[i])
684
679
  continue
685
680
 
686
- if len(filtered_found_centers):
681
+ if len(filtered_found_centers) > 0:
687
682
  found_centers = filtered_found_centers
688
683
 
689
684
  min_choice = min(found_centers)
@@ -711,8 +706,7 @@ class CenterOfRotationAdaptiveSearch(CenterOfRotation):
711
706
  validity_check_result = cor_result_validity["sound"]
712
707
  else:
713
708
  self.logger.warning(
714
- "Minimum mean difference and minimum std-dev of differences do not coincide. "
715
- + "This means that the validity of the found solution might be questionable."
709
+ "Minimum mean difference and minimum std-dev of differences do not coincide. This means that the validity of the found solution might be questionable."
716
710
  )
717
711
  validity_check_result = cor_result_validity["questionable"]
718
712
 
@@ -802,7 +796,7 @@ class CenterOfRotationOctaveAccurate(CenterOfRotation):
802
796
  return res
803
797
  return res
804
798
 
805
- def _interpolate(self, input, shift, mode="mean", interpolation_method="linear"):
799
+ def _interpolate(self, input_, shift, mode="mean", interpolation_method="linear"):
806
800
  """Applies to the input a translation by a vector `shift`. Based on
807
801
  `scipy.ndimage.affine_transform` function.
808
802
  JL: This Octave function was initially used in the refine clause of the local_correlation (Octave find_shift).
@@ -811,7 +805,7 @@ class CenterOfRotationOctaveAccurate(CenterOfRotation):
811
805
 
812
806
  Parameters
813
807
  ----------
814
- input : array
808
+ input_ : array
815
809
  Array to which the translation is applied.
816
810
  shift : tuple, list or array of length 2.
817
811
  mode : str
@@ -862,19 +856,19 @@ class CenterOfRotationOctaveAccurate(CenterOfRotation):
862
856
 
863
857
  if mode == "mean":
864
858
  mode = "constant"
865
- cval = input.mean()
866
- return affine_transform(input, matrix, mode=mode, order=order, cval=cval)
859
+ cval = input_.mean()
860
+ return affine_transform(input_, matrix, mode=mode, order=order, cval=cval)
867
861
  elif mode not in admissible_modes:
868
862
  raise ValueError(f"Pad method is {mode} and should be in {admissible_modes}.")
869
863
 
870
- return affine_transform(input, matrix, mode=mode, order=order)
864
+ return affine_transform(input_, matrix, mode=mode, order=order)
871
865
 
872
866
  def _local_correlation(
873
867
  self,
874
868
  z1,
875
869
  z2,
876
- maxsize=[5, 5],
877
- cor_estimate=[0, 0],
870
+ maxsize=(5, 5),
871
+ cor_estimate=(0, 0),
878
872
  refine=None,
879
873
  pmcc=False,
880
874
  normalize=True,
@@ -1005,7 +999,7 @@ class CenterOfRotationOctaveAccurate(CenterOfRotation):
1005
999
  z1p /= z1p.mean()
1006
1000
 
1007
1001
  for k in range(cc.shape[0]):
1008
- for l in range(cc.shape[1]):
1002
+ for l in range(cc.shape[1]): # noqa: E741
1009
1003
  if pmcc:
1010
1004
  z2p = z2[z2beg[0] - k : z2end[0] - k, z2beg[1] - l : z2end[1] - l].flatten()
1011
1005
  std_z2p = z2p.std()
@@ -1096,7 +1090,7 @@ class CenterOfRotationOctaveAccurate(CenterOfRotation):
1096
1090
  padding_mode=None,
1097
1091
  low_pass=0.01,
1098
1092
  high_pass=None,
1099
- maxsize=[5, 5],
1093
+ maxsize=(5, 5),
1100
1094
  refine=None,
1101
1095
  pmcc=False,
1102
1096
  normalize=True,
@@ -21,12 +21,10 @@ class SinoCor:
21
21
  """
22
22
 
23
23
  def __init__(self, img_1, img_2, logger=None):
24
- """ """
25
24
  self.logger = LoggerOrPrint(logger)
26
25
  self.sx = img_1.shape[1]
27
26
 
28
27
  # algorithm cannot accept odd number of projs. This is handled in the SinoCORFinder class.
29
- nproj2 = img_1.shape[0]
30
28
 
31
29
  # extract upper and lower part of sinogram, flipping H the upper part
32
30
  self.data1 = img_1
@@ -141,9 +139,6 @@ class SinoCor:
141
139
  xc1 = self.rcor_abs - int(xwin / 2)
142
140
  xc2 = self.sx - self.rcor_abs - int(xwin / 2) - 1
143
141
 
144
- im1 = self.data1[:, xc1 : xc1 + xwin]
145
- im2 = self.data2[:, xc2 : xc2 + xwin]
146
-
147
142
  pixs = p_sign * (np.arange(neighborhood) - ng2)
148
143
  diff0 = 1000000000.0
149
144
 
@@ -289,9 +284,8 @@ class CenterOfRotationFourierAngles:
289
284
 
290
285
  def _px(self, detector_width, abs_pos, near_width, near_std, crop_around_cor, near_step):
291
286
  sym_range = None
292
- if abs_pos is not None:
293
- if crop_around_cor:
294
- sym_range = int(abs_pos - near_std * 2), int(abs_pos + near_std * 2)
287
+ if abs_pos is not None and crop_around_cor:
288
+ sym_range = int(abs_pos - near_std * 2), int(abs_pos + near_std * 2)
295
289
 
296
290
  window = near_width
297
291
  if sym_range is not None:
nabu/estimation/focus.py CHANGED
@@ -159,10 +159,8 @@ class CameraFocus(CenterOfRotation):
159
159
 
160
160
  if self.verbose:
161
161
  self.logger.info(
162
- "Fitted focus motor position:",
163
- focus_pos,
164
- "and corresponding image position:",
165
- focus_ind,
162
+ "Fitted focus motor position: %s and corresponding image position: %s"
163
+ % (str(focus_pos), str(focus_ind))
166
164
  )
167
165
  f, ax = plt.subplots(1, 1)
168
166
  self._add_plot_window(f, ax=ax)
@@ -383,10 +381,8 @@ class CameraFocus(CenterOfRotation):
383
381
 
384
382
  if self.verbose:
385
383
  self.logger.info(
386
- "Fitted focus motor position:",
387
- focus_pos,
388
- "and corresponding image position:",
389
- focus_ind,
384
+ "Fitted focus motor position: %s and corresponding image position: %s"
385
+ % (str(focus_pos), str(focus_ind))
390
386
  )
391
387
  self.logger.info("Fitted tilts (to be divided by pixel size, and converted to deg): (v, h) %s" % tilts_vh)
392
388
  fig = plt.figure()