[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1035717: unblock: binoculars/0.0.13-1



Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock
X-Debbugs-Cc: binoculars@packages.debian.org
Control: affects -1 + src:binoculars

Please unblock package binoculars


The current binoculars available in testing  doesn not work with pyqt5, numpy and matplotlib available in bookworms.
        As the upstream of this software, I prepared a new version of binoculars with only the relevant patch
        - replace numpy.bool -> numpy.bool_ (trivial)
        - replace numpy.alen -> len (this method was removed in the current numpy..., trivial)
        - remove the vtk code which is not used anymore (so one less dependency on a complex module)
        - adapt binoculars-gui for the new matplotlib

        These small modifications where extensively tested in our institut (synchrotron soleil).


I would be glade if you could accept this new version in boockworms. It would avoid a broken software in bookworms.

thanks for considering.


(Please provide enough (but not too much) information to help
the release team to judge the request efficiently. E.g. by
filling in the sections below.)

[ Reason ]

The version currently available in Bookworms is unusable with the current pyqt5, numpy and matplotlib. a bunch of methods where removed from numpy, and a modifications of the axes class of 
matplotlib make the plot unreadable (superposition of two axes with different values).

[ Impact ]

A non working software. the binoculars-gui program failed by raising an Exception.


[ Tests ]

The autopkgtest are ok, except for the s390x whcih is not installable due to a missing build of silx. The modifications where extensively tested in our institut. (I am the upstream of binoculars). 
(What automated or manual tests cover the affected code?)

[ Risks ]

I think that there is very little risk , this package is a leaf python module use by no other package. The trivial modifications involved are:

 - replace numpy.bool -> numpy.bool_ or bool
 - replace numpy.alen -> len (from Python)

less trivial but not that extensive
 - remove the code expecting vtk (this code is not used anymore, and remove the python3-vtk9 complex dependency)
 - adapted binoculars-gui to the current matplotlib. (I end up with a minimal change for this purpose).

[ Checklist ]
  [X] all changes are documented in the d/changelog
  [X] I reviewed all changes and I approve them
  [X] attach debdiff against the package in testing

[ Other info ]


unblock binoculars/0.0.13-1
diff -Nru binoculars-0.0.12/binoculars/backends/bm32.py binoculars-0.0.13/binoculars/backends/bm32.py
--- binoculars-0.0.12/binoculars/backends/bm32.py	2022-11-24 12:15:26.000000000 +0100
+++ binoculars-0.0.13/binoculars/backends/bm32.py	2023-04-14 19:05:35.000000000 +0200
@@ -524,11 +524,11 @@
     if os.path.exists(filename):
         ext = os.path.splitext(filename)[-1]
         if ext == ".txt":
-            return numpy.array(numpy.loadtxt(filename), dtype=numpy.bool)
+            return numpy.array(numpy.loadtxt(filename), dtype=numpy.bool_)
         elif ext == ".npy":
-            return numpy.array(numpy.load(filename), dtype=numpy.bool)
+            return numpy.array(numpy.load(filename), dtype=numpy.bool_)
         elif ext == ".edf":
-            return numpy.array(EdfFile.EdfFile(filename).getData(0), dtype=numpy.bool)
+            return numpy.array(EdfFile.EdfFile(filename).getData(0), dtype=numpy.bool_)
         else:
             raise ValueError(
                 "unknown extension {0}, unable to load matrix!\n".format(ext)
diff -Nru binoculars-0.0.12/binoculars/backends/id03.py binoculars-0.0.13/binoculars/backends/id03.py
--- binoculars-0.0.12/binoculars/backends/id03.py	2022-11-24 12:15:26.000000000 +0100
+++ binoculars-0.0.13/binoculars/backends/id03.py	2023-04-14 19:05:35.000000000 +0200
@@ -1172,11 +1172,11 @@
     if os.path.exists(filename):
         ext = os.path.splitext(filename)[-1]
         if ext == ".txt":
-            return numpy.array(numpy.loadtxt(filename), dtype=numpy.bool)
+            return numpy.array(numpy.loadtxt(filename), dtype=numpy.bool_)
         elif ext == ".npy":
-            return numpy.array(numpy.load(filename), dtype=numpy.bool)
+            return numpy.array(numpy.load(filename), dtype=numpy.bool_)
         elif ext == ".edf":
-            return numpy.array(EdfFile.EdfFile(filename).getData(0), dtype=numpy.bool)
+            return numpy.array(EdfFile.EdfFile(filename).getData(0), dtype=numpy.bool_)
         else:
             raise ValueError(
                 "unknown extension {0}, unable to load matrix!\n".format(ext)
diff -Nru binoculars-0.0.12/binoculars/backends/io7.py binoculars-0.0.13/binoculars/backends/io7.py
--- binoculars-0.0.12/binoculars/backends/io7.py	2022-11-24 12:15:26.000000000 +0100
+++ binoculars-0.0.13/binoculars/backends/io7.py	2023-04-14 19:05:35.000000000 +0200
@@ -14,7 +14,7 @@
   You should have received a copy of the GNU General Public License
   along with the hkl library.  If not, see <http://www.gnu.org/licenses/>.
 
-  Copyright (C) 2012-2015 European Synchrotron Radiation Facility
+  Copyright (C) 2012-2015, 2023 European Synchrotron Radiation Facility
                           Grenoble, France
 
   Authors: Willem Onderwaater <onderwaa@esrf.fr>
@@ -454,9 +454,9 @@
     if os.path.exists(filename):
         ext = os.path.splitext(filename)[-1]
         if ext == ".txt":
-            return numpy.array(numpy.loadtxt(filename), dtype=numpy.bool)
+            return numpy.array(numpy.loadtxt(filename), dtype=numpy.bool_)
         elif ext == ".npy":
-            return numpy.array(numpy.load(filename), dtype=numpy.bool)
+            return numpy.array(numpy.load(filename), dtype=numpy.bool_)
         else:
             raise ValueError(
                 "unknown extension {0}, unable to load matrix!\n".format(ext)
diff -Nru binoculars-0.0.12/binoculars/backends/sixs.py binoculars-0.0.13/binoculars/backends/sixs.py
--- binoculars-0.0.12/binoculars/backends/sixs.py	2022-11-24 12:15:26.000000000 +0100
+++ binoculars-0.0.13/binoculars/backends/sixs.py	2023-04-14 19:05:35.000000000 +0200
@@ -14,7 +14,7 @@
   along with the hkl library.  If not, see
   <http://www.gnu.org/licenses/>.
 
-  Copyright (C) 2015-2021 Synchrotron SOLEIL
+  Copyright (C) 2015-2021, 2023 Synchrotron SOLEIL
                           L'Orme des Merisiers Saint-Aubin
                           BP 48 91192 GIF-sur-YVETTE CEDEX
 
@@ -1004,10 +1004,10 @@
 
     def get_mask(self, detector: Detector, fnmask: Optional[str]=None) -> ndarray:
         if detector.name == "ufxc":
-            mask = numpy.zeros((256, 257)).astype(bool)
+            mask = numpy.zeros((256, 257)).astype(numpy.bool_)
         else:
             detector = ALL_DETECTORS[detector.name]()
-            mask = detector.mask.astype(numpy.bool)
+            mask = detector.mask.astype(numpy.bool_)
         maskmatrix = load_matrix(fnmask)
         if maskmatrix is not None:
             mask = numpy.bitwise_or(mask, maskmatrix)
@@ -1524,9 +1524,9 @@
     if os.path.exists(filename):
         ext = os.path.splitext(filename)[-1]
         if ext == ".txt":
-            return numpy.array(numpy.loadtxt(filename), dtype=numpy.bool)
+            return numpy.array(numpy.loadtxt(filename), dtype=numpy.bool_)
         elif ext == ".npy":
-            mask = numpy.array(numpy.load(filename), dtype=numpy.bool)
+            mask = numpy.array(numpy.load(filename), dtype=numpy.bool_)
             print("loaded mask sum: ", numpy.sum(mask))
             return mask
         else:
diff -Nru binoculars-0.0.12/binoculars/dispatcher.py binoculars-0.0.13/binoculars/dispatcher.py
--- binoculars-0.0.12/binoculars/dispatcher.py	2022-11-24 12:15:26.000000000 +0100
+++ binoculars-0.0.13/binoculars/dispatcher.py	2023-04-14 19:05:35.000000000 +0200
@@ -43,12 +43,10 @@
             self.value = verse
         elif self.type == "tmp":
             verse.tofile(self.filename)
-            # verse.tovti(self.filename + ".vti")
         elif self.type == "final":
             for sp, fn in zip(verse.spaces, self.final_filenames()):
                 sp.config = self.config
                 sp.tofile(fn)
-                # sp.tovti(fn + ".vti")
 
     def retrieve(self):
         if self.type == "memory":
diff -Nru binoculars-0.0.12/binoculars/plot.py binoculars-0.0.13/binoculars/plot.py
--- binoculars-0.0.12/binoculars/plot.py	2022-11-24 12:15:26.000000000 +0100
+++ binoculars-0.0.13/binoculars/plot.py	2023-04-14 19:05:35.000000000 +0200
@@ -106,7 +106,7 @@
 
     if log:
         data = data[data > 0]
-        if numpy.alen(data) == 0:
+        if len(data) == 0:
             return matplotlib.colors.LogNorm(1, 10)
 
     if clipping:
diff -Nru binoculars-0.0.12/binoculars/space.py binoculars-0.0.13/binoculars/space.py
--- binoculars-0.0.12/binoculars/space.py	2022-11-24 12:15:26.000000000 +0100
+++ binoculars-0.0.13/binoculars/space.py	2023-04-14 19:05:35.000000000 +0200
@@ -10,8 +10,6 @@
 
 from numpy import ndarray
 from numpy.ma import MaskedArray
-from vtk import vtkImageData, vtkXMLImageDataWriter
-from vtk.util import numpy_support
 
 from . import util, errors
 
@@ -773,7 +771,7 @@
         intensity     data intensity array"""
 
         if limits is not None:
-            invalid = numpy.zeros(intensity.shape).astype(numpy.bool)
+            invalid = numpy.zeros(intensity.shape).astype(numpy.bool_)
             for coord, sl in zip(coordinates, limits):
                 if sl.start is None and sl.stop is not None:
                     invalid += coord > sl.stop
@@ -796,33 +794,6 @@
         newspace.process_image(coordinates, intensity, weights)
         return newspace
 
-    def tovti(self, filename: str) -> None:
-        assert self.dimension == 3, "only array with three dimensions are allowed"
-
-        data = self.photons / self.contributions
-
-        spacing = tuple(a.res for a in self.axes.axes)
-        origin = tuple(a.min for a in self.axes.axes)
-        name = str(tuple(a.label for a in self.axes.axes))
-
-        image_data = vtkImageData()
-        image_data.SetSpacing(spacing)
-        image_data.SetOrigin(origin)
-        image_data.SetDimensions(data.shape)
-
-        temp_array = numpy.transpose(numpy.flip(data, 2)).flatten()
-        temp_array = numpy_support.numpy_to_vtk(temp_array, deep=1)
-
-        pd = image_data.GetPointData()
-        pd.SetScalars(temp_array)
-        pd.GetArray(0).SetName(name)
-
-        # export data to file
-        writer = vtkXMLImageDataWriter()
-        writer.SetFileName(filename)
-        writer.SetInputData(image_data)
-        writer.Write()
-
     def tofile(self, filename):
         """Store Space in HDF5 file."""
         with util.atomic_write(filename) as tmpname:
@@ -1139,7 +1110,7 @@
 
 
 def make_compatible(spaces):
-    if not numpy.alen(numpy.unique(len(space.axes) for space in spaces)) == 1:
+    if not len(numpy.unique(len(space.axes) for space in spaces)) == 1:
         raise ValueError("cannot make spaces with different dimensionality compatible")
     ax0 = tuple(ax.label for ax in spaces[0].axes)
     resmax = tuple(
diff -Nru binoculars-0.0.12/debian/changelog binoculars-0.0.13/debian/changelog
--- binoculars-0.0.12/debian/changelog	2023-02-21 14:13:26.000000000 +0100
+++ binoculars-0.0.13/debian/changelog	2023-04-14 19:23:27.000000000 +0200
@@ -1,3 +1,11 @@
+binoculars (0.0.13-1) unstable; urgency=medium
+
+  * New upstream version 0.0.13
+  * d/control: B-D removed python3-vtk9
+  * d/patches: removed all patch (upstreamed)
+
+ -- Picca Frédéric-Emmanuel <picca@debian.org>  Fri, 14 Apr 2023 19:23:27 +0200
+
 binoculars (0.0.12-1.2) unstable; urgency=medium
 
   * Non-maintainer upload.
diff -Nru binoculars-0.0.12/debian/control binoculars-0.0.13/debian/control
--- binoculars-0.0.12/debian/control	2023-02-21 13:50:46.000000000 +0100
+++ binoculars-0.0.13/debian/control	2023-04-14 19:23:27.000000000 +0200
@@ -17,7 +17,6 @@
  python3-pymca5,
  python3-setuptools,
  python3-sphinx,
- python3-vtk9,
  python3-xrayutilities,
 Standards-Version: 4.6.1
 Vcs-Browser: https://salsa.debian.org/science-team/binoculars
@@ -50,7 +49,6 @@
 Section: python
 Depends:
  gir1.2-hkl-5.0,
- python3-vtk9,
  ${misc:Depends},
  ${python3:Depends},
 Suggests:
diff -Nru binoculars-0.0.12/debian/patches/numpy-1.24.patch binoculars-0.0.13/debian/patches/numpy-1.24.patch
--- binoculars-0.0.12/debian/patches/numpy-1.24.patch	2023-01-11 17:48:13.000000000 +0100
+++ binoculars-0.0.13/debian/patches/numpy-1.24.patch	1970-01-01 01:00:00.000000000 +0100
@@ -1,176 +0,0 @@
-Description: Fix test failure with Numpy 1.24.
-Author: Bas Couwenberg <sebastic@debian.org>
-Bug-Debian: https://bugs.debian.org/1027192
-
---- a/scripts/binoviewer.py
-+++ b/scripts/binoviewer.py
-@@ -184,7 +184,7 @@ def mask_linear_defects(data, threshold=
-     temp.mask = lup
-     np.ma.apply_along_axis(remove_masked_slices, 1, temp, *(length,))
- 
--    mask = np.zeros_like(data, dtype=np.bool)
-+    mask = np.zeros_like(data, dtype=bool)
-     mask[1:-1] = np.logical_or(ldown, temp.mask)
-     return mask
- 
-@@ -344,7 +344,7 @@ class MaskedImageNan(MaskedImageItem):
-         if inside:
-             self.data[iy0:iy1, ix0:ix1] = np.ma.masked
-         else:
--            indexes = np.ones(self.data.shape, dtype=np.bool)
-+            indexes = np.ones(self.data.shape, dtype=bool)
-             indexes[iy0:iy1, ix0:ix1] = False
-             self.data[indexes] = np.ma.masked
-         if trace:
-@@ -369,7 +369,7 @@ class MaskedImageNan(MaskedImageItem):
-         if inside:
-             self.data[iy0:iy1, ix0:ix1] = np.ma.masked
-         else:
--            indexes = np.ones(self.data.shape, dtype=np.bool)
-+            indexes = np.ones(self.data.shape, dtype=bool)
-             indexes[iy0:iy1, ix0:ix1] = False
-             self.data[indexes] = np.ma.masked
-         if trace:
-@@ -474,7 +474,7 @@ class MaskedImageNan(MaskedImageItem):
-         if inside:
-             self.data.mask[iy0:iy1, ix0:ix1] = False
-         else:
--            indexes = np.ones(self.data.shape, dtype=np.bool)
-+            indexes = np.ones(self.data.shape, dtype=bool)
-             indexes[iy0:iy1, ix0:ix1] = False
-             self.data.mask[indexes] = False
-         if trace:
-@@ -501,7 +501,7 @@ class MaskedImageNan(MaskedImageItem):
-         if inside:
-             self.data.mask[iy0:iy1, ix0:ix1] = False
-         else:
--            indexes = np.ones(self.data.shape, dtype=np.bool)
-+            indexes = np.ones(self.data.shape, dtype=bool)
-             indexes[iy0:iy1, ix0:ix1] = False
-             self.data.mask[indexes] = False
-         if trace:
-@@ -2780,7 +2780,7 @@ class ImageMaskingWidget(PanelWidget):
-         radius = self.sizebox.value()
-         L = np.arange(-radius, radius + 1)
-         X, Y = np.meshgrid(L, L)
--        struct = np.array((X ** 2 + Y ** 2) <= radius ** 2, dtype=np.bool)
-+        struct = np.array((X ** 2 + Y ** 2) <= radius ** 2, dtype=bool)
- 
-         self.masked_image.data.mask = (
-             signal.fftconvolve(self.masked_image.data.mask, struct, "same") > 0.5
-@@ -2797,7 +2797,7 @@ class ImageMaskingWidget(PanelWidget):
-         radius = self.sizebox.value()
-         L = np.arange(-radius, radius + 1)
-         X, Y = np.meshgrid(L, L)
--        struct = np.array((X ** 2 + Y ** 2) <= radius ** 2, dtype=np.bool)
-+        struct = np.array((X ** 2 + Y ** 2) <= radius ** 2, dtype=bool)
- 
-         self.masked_image.data.mask = (
-             signal.fftconvolve(
---- a/binoculars/backends/bm32.py
-+++ b/binoculars/backends/bm32.py
-@@ -524,11 +524,11 @@ def load_matrix(filename):
-     if os.path.exists(filename):
-         ext = os.path.splitext(filename)[-1]
-         if ext == ".txt":
--            return numpy.array(numpy.loadtxt(filename), dtype=numpy.bool)
-+            return numpy.array(numpy.loadtxt(filename), dtype=bool)
-         elif ext == ".npy":
--            return numpy.array(numpy.load(filename), dtype=numpy.bool)
-+            return numpy.array(numpy.load(filename), dtype=bool)
-         elif ext == ".edf":
--            return numpy.array(EdfFile.EdfFile(filename).getData(0), dtype=numpy.bool)
-+            return numpy.array(EdfFile.EdfFile(filename).getData(0), dtype=bool)
-         else:
-             raise ValueError(
-                 "unknown extension {0}, unable to load matrix!\n".format(ext)
---- a/binoculars/backends/id03.py
-+++ b/binoculars/backends/id03.py
-@@ -1172,11 +1172,11 @@ def load_matrix(filename):
-     if os.path.exists(filename):
-         ext = os.path.splitext(filename)[-1]
-         if ext == ".txt":
--            return numpy.array(numpy.loadtxt(filename), dtype=numpy.bool)
-+            return numpy.array(numpy.loadtxt(filename), dtype=bool)
-         elif ext == ".npy":
--            return numpy.array(numpy.load(filename), dtype=numpy.bool)
-+            return numpy.array(numpy.load(filename), dtype=bool)
-         elif ext == ".edf":
--            return numpy.array(EdfFile.EdfFile(filename).getData(0), dtype=numpy.bool)
-+            return numpy.array(EdfFile.EdfFile(filename).getData(0), dtype=bool)
-         else:
-             raise ValueError(
-                 "unknown extension {0}, unable to load matrix!\n".format(ext)
---- a/binoculars/backends/io7.py
-+++ b/binoculars/backends/io7.py
-@@ -454,9 +454,9 @@ def load_matrix(filename):
-     if os.path.exists(filename):
-         ext = os.path.splitext(filename)[-1]
-         if ext == ".txt":
--            return numpy.array(numpy.loadtxt(filename), dtype=numpy.bool)
-+            return numpy.array(numpy.loadtxt(filename), dtype=bool)
-         elif ext == ".npy":
--            return numpy.array(numpy.load(filename), dtype=numpy.bool)
-+            return numpy.array(numpy.load(filename), dtype=bool)
-         else:
-             raise ValueError(
-                 "unknown extension {0}, unable to load matrix!\n".format(ext)
---- a/binoculars/backends/sixs.py
-+++ b/binoculars/backends/sixs.py
-@@ -1007,7 +1007,7 @@ class FlyScanUHV(SIXS):
-             mask = numpy.zeros((256, 257)).astype(bool)
-         else:
-             detector = ALL_DETECTORS[detector.name]()
--            mask = detector.mask.astype(numpy.bool)
-+            mask = detector.mask.astype(bool)
-         maskmatrix = load_matrix(fnmask)
-         if maskmatrix is not None:
-             mask = numpy.bitwise_or(mask, maskmatrix)
-@@ -1524,9 +1524,9 @@ def load_matrix(filename):
-     if os.path.exists(filename):
-         ext = os.path.splitext(filename)[-1]
-         if ext == ".txt":
--            return numpy.array(numpy.loadtxt(filename), dtype=numpy.bool)
-+            return numpy.array(numpy.loadtxt(filename), dtype=bool)
-         elif ext == ".npy":
--            mask = numpy.array(numpy.load(filename), dtype=numpy.bool)
-+            mask = numpy.array(numpy.load(filename), dtype=bool)
-             print("loaded mask sum: ", numpy.sum(mask))
-             return mask
-         else:
---- a/binoculars/space.py
-+++ b/binoculars/space.py
-@@ -773,7 +773,7 @@ class Space(object):
-         intensity     data intensity array"""
- 
-         if limits is not None:
--            invalid = numpy.zeros(intensity.shape).astype(numpy.bool)
-+            invalid = numpy.zeros(intensity.shape).astype(bool)
-             for coord, sl in zip(coordinates, limits):
-                 if sl.start is None and sl.stop is not None:
-                     invalid += coord > sl.stop
---- a/scripts/binoculars-fitaid
-+++ b/scripts/binoculars-fitaid
-@@ -207,9 +207,9 @@ class RodData(FitData):
-             if key not in group:
-                 dataset = group.create_dataset(key, (self.rodlength(),))
-                 dataset = group.create_dataset(mkey, (self.rodlength(),),
--                                               dtype=numpy.bool)
-+                                               dtype=bool)
-                 dataset.write_direct(
--                    numpy.ones(self.rodlength(), dtype=numpy.bool)
-+                    numpy.ones(self.rodlength(), dtype=bool)
-                 )
-             group[key][index] = value
-             group[mkey][index] = 0
---- a/scripts/binoculars-gui
-+++ b/scripts/binoculars-gui
-@@ -1156,7 +1156,7 @@ class LimitWidget(QWidget):
-             hbox.addWidget(box)
-             box.stateChanged.connect(self.update_checkbox)
- 
--        self.state = numpy.array(self.state, dtype = numpy.bool)
-+        self.state = numpy.array(self.state, dtype = bool)
-         self.init_checkbox()
- 
-         vbox.addLayout(hbox)
diff -Nru binoculars-0.0.12/debian/patches/series binoculars-0.0.13/debian/patches/series
--- binoculars-0.0.12/debian/patches/series	2023-01-11 17:48:13.000000000 +0100
+++ binoculars-0.0.13/debian/patches/series	1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-numpy-1.24.patch
diff -Nru binoculars-0.0.12/scripts/binoculars-fitaid binoculars-0.0.13/scripts/binoculars-fitaid
--- binoculars-0.0.12/scripts/binoculars-fitaid	2022-11-24 12:15:26.000000000 +0100
+++ binoculars-0.0.13/scripts/binoculars-fitaid	2023-04-14 19:05:35.000000000 +0200
@@ -145,7 +145,7 @@
 
     def rodlength(self) -> int:
         bins, ax, axindex = self.get_bins()
-        return numpy.alen(bins) - 1
+        return len(bins) - 1
 
     def get_index_value(self, index: int) -> ndarray:
         values = get_axis_values(self.axdict[self.rodkey],
@@ -207,9 +207,9 @@
             if key not in group:
                 dataset = group.create_dataset(key, (self.rodlength(),))
                 dataset = group.create_dataset(mkey, (self.rodlength(),),
-                                               dtype=numpy.bool)
+                                               dtype=numpy.bool_)
                 dataset.write_direct(
-                    numpy.ones(self.rodlength(), dtype=numpy.bool)
+                    numpy.ones(self.rodlength(), dtype=numpy.bool_)
                 )
             group[key][index] = value
             group[mkey][index] = 0
@@ -1078,12 +1078,12 @@
                     fitintensity = fitdata[key].data.flatten()
                     fitbkg = numpy.hstack([fitdata[space.get_key(bkgkey)].data.flatten()  # noqa
                                            for bkgkey in self.bkgkeys(loc, axes)])
-                    if numpy.alen(fitbkg) == 0:
+                    if len(fitbkg) == 0:
                         fitstructurefactor = fitintensity.sum()
-                    elif numpy.alen(fitintensity) == 0:
+                    elif len(fitintensity) == 0:
                         fitstructurefactor = numpy.nan
                     else:
-                        fitstructurefactor = numpy.sqrt(fitintensity.sum() - numpy.alen(fitintensity) * 1.0 / numpy.alen(fitbkg) * fitbkg.sum())  # noqa
+                        fitstructurefactor = numpy.sqrt(fitintensity.sum() - len(fitintensity) * 1.0 / len(fitbkg) * fitbkg.sum())  # noqa
                     self.database.save_sliceattr(
                         index, 'fitsf', fitstructurefactor)
 
@@ -1108,15 +1108,15 @@
                     intensity = numpy.array([])
                     bkg = numpy.array([])
 
-                if numpy.alen(intensity) == 0:
+                if len(intensity) == 0:
                     structurefactor = numpy.nan
                     nistructurefactor = numpy.nan
-                elif numpy.alen(bkg) == 0:
+                elif len(bkg) == 0:
                     structurefactor = numpy.sqrt(intensity.sum())
                     nistructurefactor = numpy.sqrt(niintensity.sum())
                 else:
-                    structurefactor = numpy.sqrt(intensity.sum() - numpy.alen(intensity) * 1.0 / numpy.alen(bkg) * bkg.sum())  # noqa
-                    nistructurefactor = numpy.sqrt(niintensity.sum() - numpy.alen(niintensity) * 1.0 / numpy.alen(bkg) * bkg.sum())  # noqa
+                    structurefactor = numpy.sqrt(intensity.sum() - len(intensity) * 1.0 / len(bkg) * bkg.sum())  # noqa
+                    nistructurefactor = numpy.sqrt(niintensity.sum() - len(niintensity) * 1.0 / numpy.alen(bkg) * bkg.sum())  # noqa
 
                 self.database.save_sliceattr(index, 'sf', structurefactor)
                 self.database.save_sliceattr(index, 'nisf', nistructurefactor)
diff -Nru binoculars-0.0.12/scripts/binoculars-gui binoculars-0.0.13/scripts/binoculars-gui
--- binoculars-0.0.12/scripts/binoculars-gui	2022-11-24 12:15:26.000000000 +0100
+++ binoculars-0.0.13/scripts/binoculars-gui	2023-04-14 19:05:35.000000000 +0200
@@ -818,7 +818,7 @@
             filename = self.table.selection[i]
             basename = os.path.splitext(os.path.basename(filename))[0]
             if plotcount > 1:
-                if dimension == 1 and (plotoption == 'stack' or plotoption == None):
+                if dimension == 1 and (plotoption == 'stack' or plotoption is None):
                     self.ax = self.figure.add_subplot(111)
                 if dimension == 2 and plotoption != 'grid':
                     sys.stderr.write('warning: stack display not supported for multi-file-plotting, falling back to grid\n')
@@ -826,8 +826,6 @@
                 elif dimension > 3:
                     sys.stderr.write('error: cannot display 4 or higher dimensional data, use --project or --slice to decrease dimensionality\n')
                     sys.exit(1)
-            else:
-                self.ax = self.figure.add_subplot(111)
 
             if plotoption == 'grid':
                 if dimension == 1 or dimension == 2:
@@ -835,6 +833,8 @@
                 elif self.threed.isChecked():
                     self.ax = self.figure.gca(projection='3d')
                 self.ax.set_title(basename)
+            else:
+                self.ax = self.figure.add_subplot(111)
 
             if dimension == 2 and self.swap_axes.checkState():
                 space = space.reorder(list(ax.label for ax in space.axes)[::-1])
@@ -1156,7 +1156,7 @@
             hbox.addWidget(box)
             box.stateChanged.connect(self.update_checkbox)
 
-        self.state = numpy.array(self.state, dtype = numpy.bool)
+        self.state = numpy.array(self.state, dtype = numpy.bool_)
         self.init_checkbox()
 
         vbox.addLayout(hbox)
@@ -1269,11 +1269,11 @@
         self.send_signal()
 
     def init_checkbox(self):
-        while numpy.alen(self.state) - self.state.sum() > 2:
+        while len(self.state) - self.state.sum() > 2:
             _index = numpy.where(self.state == False)[-1]
             self.state[-1] = True
         for box, state in zip(self.checkbox, self.state):
-            box.setChecked(state)
+            box.setChecked(bool(state))
 
     def axes_update(self, axes):
         if not set(ax.label for ax in self.axes) == set(ax.label for ax in axes):
diff -Nru binoculars-0.0.12/scripts/binoviewer.py binoculars-0.0.13/scripts/binoviewer.py
--- binoculars-0.0.12/scripts/binoviewer.py	2022-11-24 12:15:26.000000000 +0100
+++ binoculars-0.0.13/scripts/binoviewer.py	2023-04-14 19:05:35.000000000 +0200
@@ -11,7 +11,7 @@
 
 # -*- coding: utf-8 -*-
 #
-# Copyright © 2009-2011, 2020, 2021 CEA
+# Copyright © 2009-2011, 2020, 2021, 2023 CEA
 # Pierre Raybaut
 # Licensed under the terms of the CECILL License
 # (see guiqwt/__init__.py for details)
@@ -184,7 +184,7 @@
     temp.mask = lup
     np.ma.apply_along_axis(remove_masked_slices, 1, temp, *(length,))
 
-    mask = np.zeros_like(data, dtype=np.bool)
+    mask = np.zeros_like(data, dtype=np.bool_)
     mask[1:-1] = np.logical_or(ldown, temp.mask)
     return mask
 
@@ -344,7 +344,7 @@
         if inside:
             self.data[iy0:iy1, ix0:ix1] = np.ma.masked
         else:
-            indexes = np.ones(self.data.shape, dtype=np.bool)
+            indexes = np.ones(self.data.shape, dtype=np.bool_)
             indexes[iy0:iy1, ix0:ix1] = False
             self.data[indexes] = np.ma.masked
         if trace:
@@ -369,7 +369,7 @@
         if inside:
             self.data[iy0:iy1, ix0:ix1] = np.ma.masked
         else:
-            indexes = np.ones(self.data.shape, dtype=np.bool)
+            indexes = np.ones(self.data.shape, dtype=np.bool_)
             indexes[iy0:iy1, ix0:ix1] = False
             self.data[indexes] = np.ma.masked
         if trace:
@@ -474,7 +474,7 @@
         if inside:
             self.data.mask[iy0:iy1, ix0:ix1] = False
         else:
-            indexes = np.ones(self.data.shape, dtype=np.bool)
+            indexes = np.ones(self.data.shape, dtype=np.bool_)
             indexes[iy0:iy1, ix0:ix1] = False
             self.data.mask[indexes] = False
         if trace:
@@ -501,7 +501,7 @@
         if inside:
             self.data.mask[iy0:iy1, ix0:ix1] = False
         else:
-            indexes = np.ones(self.data.shape, dtype=np.bool)
+            indexes = np.ones(self.data.shape, dtype=np.bool_)
             indexes[iy0:iy1, ix0:ix1] = False
             self.data.mask[indexes] = False
         if trace:
@@ -2780,7 +2780,7 @@
         radius = self.sizebox.value()
         L = np.arange(-radius, radius + 1)
         X, Y = np.meshgrid(L, L)
-        struct = np.array((X ** 2 + Y ** 2) <= radius ** 2, dtype=np.bool)
+        struct = np.array((X ** 2 + Y ** 2) <= radius ** 2, dtype=np.bool_)
 
         self.masked_image.data.mask = (
             signal.fftconvolve(self.masked_image.data.mask, struct, "same") > 0.5
@@ -2797,7 +2797,7 @@
         radius = self.sizebox.value()
         L = np.arange(-radius, radius + 1)
         X, Y = np.meshgrid(L, L)
-        struct = np.array((X ** 2 + Y ** 2) <= radius ** 2, dtype=np.bool)
+        struct = np.array((X ** 2 + Y ** 2) <= radius ** 2, dtype=np.bool_)
 
         self.masked_image.data.mask = (
             signal.fftconvolve(

Reply to: