docs: def locate_unknown_arc_lines(self, slitlet2d,
                                   times_sigma_threshold=15,
                                   minimum_threshold=None,
                                   delta_x_max=30,
                                   delta_y_min=30,
                                   min_dist_from_middle=15):
          """Determine the location of known arc lines in slitlet.
  
          Parameters
          ----------
          slitlet2d : numpy array
              Image containing the 2d slitlet image.
          times_sigma_threshold : float
              Times (robust) sigma above the median of the image to look
              for arc lines.
          minimum_threshold : float or None
              Minimum threshold to look for arc lines.
          delta_x_max : float
              Maximum size of potential arc line in the X direction.
          delta_y_min : float
              Minimum size of potential arc line in the Y direction.
          min_dist_from_middle : float
              Minimum Y distance from the middle spectrum trail to the
              extreme of the potential arc line. This constraint avoid
              detecting arc line reflections as bone fide arc lines.
  
          """
  
          # smooth denoising of slitlet2d
          slitlet2d_rs, coef_rs = rescale_array_to_z1z2(slitlet2d, z1z2=(-1, 1))
          slitlet2d_dn = restoration.denoise_nl_means(slitlet2d_rs,
                                                      patch_size=3,
                                                      patch_distance=2,
                                                      multichannel=False)
          slitlet2d_dn = rescale_array_from_z1z2(slitlet2d_dn, coef_rs)
  
          # compute basic statistics
          q25, q50, q75 = np.percentile(slitlet2d_dn, q=[25.0, 50.0, 75.0])
          sigmag = 0.7413 * (q75 - q25)  # robust standard deviation
          if abs(self.debugplot) >= 10:
              q16, q84 = np.percentile(slitlet2d_dn, q=[15.87, 84.13])
              print('>>> q16...:', q16)
              print('>>> q25...:', q25)
              print('>>> q50...:', q50)
              print('>>> q75...:', q75)
              print('>>> q84...:', q84)
              print('>>> sigmaG:', sigmag)
          if abs(self.debugplot) in [21, 22]:
              # display initial image with zscale cuts
              title = "Slitlet#" + str(self.islitlet) + \
                      " (locate_unknown_arc_lines, step #1)"
              ximshow(slitlet2d, title=title,
                      first_pixel=(self.bb_nc1_orig, self.bb_ns1_orig),
                      debugplot=self.debugplot)
              # display denoised image with zscale cuts
              title = "Slitlet#" + str(self.islitlet) + \
                      " (locate_unknown_arc_lines, step #2)"
              ximshow(slitlet2d_dn, title=title,
                      first_pixel=(self.bb_nc1_orig, self.bb_ns1_orig),
                      debugplot=self.debugplot)
              # display image with different cuts
              z1z2 = (q50 + times_sigma_threshold * sigmag,
                      q50 + 2 * times_sigma_threshold * sigmag)
              title = "Slitlet#" + str(self.islitlet) + \
                      " (locate_unknown_arc_lines, step #3)"
              ximshow(slitlet2d_dn, title=title, z1z2=z1z2,
                      first_pixel=(self.bb_nc1_orig, self.bb_ns1_orig),
                      debugplot=self.debugplot)
  
          # determine threshold (using the maximum of q50 + t *sigmag or
          # minimum_threshold)
          threshold = q50 + times_sigma_threshold * sigmag
          if minimum_threshold is not None:
              if minimum_threshold > threshold:
                  threshold = minimum_threshold
  
          # identify objects in slitlet2d above threshold
          labels2d_objects, no_objects = ndimage.label(slitlet2d_dn > threshold)
          if abs(self.debugplot) >= 10:
              print("Number of objects initially found:", no_objects)
          if abs(self.debugplot) in [21, 22]:
              # display all objects identified in the image
              title = "Slitlet#" + str(self.islitlet) + \
                      " (locate_unknown_arc_lines, step #4)"
              z1z2 = (labels2d_objects.min(), labels2d_objects.max())
              ximshow(labels2d_objects, title=title,
                      first_pixel=(self.bb_nc1_orig, self.bb_ns1_orig),
                      cbar_label="Object number",
                      z1z2=z1z2, cmap="nipy_spectral",
                      debugplot=self.debugplot)
  
          # select arc lines by imposing the criteria based on the
          # dimensions of the detected objects and the intersection with
          # the middle spectrum trail
          slices_possible_arc_lines = ndimage.find_objects(labels2d_objects)
          slices_ok = np.repeat([False], no_objects)  # flag
          for i in range(no_objects):
              if abs(self.debugplot) >= 10:
                  print('object', i + 1,
                        '[in np.array coordinates]:',
                        slices_possible_arc_lines[i])
              slice_x = slices_possible_arc_lines[i][1]
              slice_y = slices_possible_arc_lines[i][0]
              # note that the width computation doesn't require to
              # add +1 since slice_x.stop (and slice_y.stop) is
              # already the upper limit +1 (in np.array coordinates)
              delta_x = slice_x.stop - slice_x.start
              delta_y = slice_y.stop - slice_y.start
              # dimensions criterion
              if delta_x <= delta_x_max and delta_y >= delta_y_min:
                  # intersection with middle spectrum trail criterion;
                  # note that slice_x and slice_y are given in np.array
                  # coordinates and are transformed into image coordinates;
                  # in addition, -0.5 shift the origin to the lower left
                  # corner of the pixel
                  xini_slice = slice_x.start + self.bb_nc1_orig - 0.5
                  xmiddle_slice = xini_slice + delta_x / 2
                  polydum = \
                      self.list_spectrails[self.i_middle_spectrail].poly_funct
                  ymiddle_slice = polydum(xmiddle_slice)
                  yini_slice = slice_y.start + self.bb_ns1_orig - 0.5
                  yend_slice = yini_slice + delta_y
                  if yini_slice + min_dist_from_middle <= ymiddle_slice <= \
                          yend_slice - min_dist_from_middle:
                      slices_ok[i] = True
  
          # generate list with ID of arc lines (note that first object is
          # number 0 and not 1)
          list_slices_ok = []
          for i in range(no_objects):
              if slices_ok[i]:
                  list_slices_ok.append(i + 1)
          number_arc_lines = len(list_slices_ok)
          if abs(self.debugplot) >= 10:
              print("\nNumber of arc lines initially identified is:",
                    number_arc_lines)
              if number_arc_lines > 0:
                  print("Slice ID of lines passing the selection:\n",
                        list_slices_ok)
          if number_arc_lines == 0:
              return
  
          # display arc lines
          if abs(self.debugplot) in [21, 22]:
              # display all objects identified in the image
              title = "Slitlet#" + str(self.islitlet) + \
                      " (locate_unknown_arc_lines, step #5)"
              z1z2 = (labels2d_objects.min(),
                      labels2d_objects.max())
              ax = ximshow(labels2d_objects, show=False, title=title,
                           first_pixel=(self.bb_nc1_orig, self.bb_ns1_orig),
                           cbar_label="Object number",
                           z1z2=z1z2, cmap="nipy_spectral",
                           debugplot=self.debugplot)
              # plot rectangle around identified arc lines
              for i in range(no_objects):
                  if slices_ok[i]:
                      slice_x = slices_possible_arc_lines[i][1]
                      slice_y = slices_possible_arc_lines[i][0]
                      # note that slice_x and slice_y are given in np.array
                      # coordinates and are transformed into image coordinates;
                      # in addition, -0.5 shift the origin to the lower left
                      # corner of the pixel
                      xini_slice = slice_x.start + self.bb_nc1_orig - 0.5
                      yini_slice = slice_y.start + self.bb_ns1_orig - 0.5
                      # note that the width computation doesn't require to
                      # add +1 since slice_x.stop (and slice_y.stop) is
                      # already the upper limit +1 (in np.array coordinates)
                      xwidth_slice = slice_x.stop - slice_x.start
                      ywidth_slice = slice_y.stop - slice_y.start
                      rect = Rectangle((xini_slice, yini_slice),
                                       xwidth_slice, ywidth_slice,
                                       edgecolor='w', facecolor='none')
                      ax.add_patch(rect)
              # show plot
              pause_debugplot(self.debugplot, pltshow=True)
  
          # adjust individual arc lines passing the initial selection
          self.list_arc_lines = []  # list of ArcLines
          for k in range(number_arc_lines):  # fit each arc line
              # select points to be fitted for a particular arc line
              xy_tmp = np.where(labels2d_objects == list_slices_ok[k])
              x_tmp = xy_tmp[1] + self.bb_nc1_orig  # use image coordinates
              y_tmp = xy_tmp[0] + self.bb_ns1_orig  # use image coordinates
              w_tmp = slitlet2d_dn[xy_tmp]
              # declare new ArcLine instance
              arc_line = ArcLine()
              # define new ArcLine using a weighted fit
              # (note that it must be X vs Y)
              arc_line.fit(x=x_tmp, y=y_tmp, deg=1, w=w_tmp, y_vs_x=False)
              if len(arc_line.poly_funct.coef) == 2:
                  # update list with identified ArcLines
                  self.list_arc_lines.append(arc_line)
              else:
                  # ignore (sometimes the arc_line.fit returns a constant!)
                  pass
  
          # recompute number_arc_lines just in case in the previous fits
          # some lines have just given a zero degree polynomial
          number_arc_lines = len(self.list_arc_lines)
  
          # remove arc lines with unexpected slopes
          yfit = np.array([self.list_arc_lines[k].poly_funct.coef[1]
                           for k in range(number_arc_lines)])
          xfit = np.zeros(number_arc_lines)
          # intersection between middle spectrum trail and arc line
          for k in range(number_arc_lines):
              arcline = self.list_arc_lines[k]
              xfit[k], ydum = intersection_spectrail_arcline(
                  self.list_spectrails[self.i_middle_spectrail], arcline
              )
  
          # fit slope versus x-coordinate of the intersection of the arc line
          # with the middle spectrum trail
          if len(yfit) > 5:
              degeff = 5
          else:
              degeff = len(yfit) - 1
          polydum, residum, rejected = polfit_residuals_with_sigma_rejection(
              x=xfit, y=yfit, deg=degeff, times_sigma_reject=4.0,
              xlabel='arc line center (islitlet #' + str(self.islitlet) + ')',
              ylabel='arc line slope', debugplot=0
          )
          # remove rejected arc lines
          if len(rejected) > 0:
              if abs(self.debugplot) >= 10:
                  print('Rejecting', sum(rejected),
                        'arc lines with suspicious slopes: Slice ID',
                        [list_slices_ok[k] for k in range(number_arc_lines)
                         if rejected[k]])
              self.list_arc_lines = \
                  [self.list_arc_lines[k] for k in range(number_arc_lines)
                   if not rejected[k]]
              # recompute number of arc lines
              number_arc_lines = len(self.list_arc_lines)
              if abs(self.debugplot) >= 10:
                  print("\nNumber of arc lines finally identified is:",
                        number_arc_lines)
  
          if abs(self.debugplot) >= 20:
              # print list of arc lines
              print('\nlist_arc_lines:')
              for k in range(number_arc_lines):
                  print(k, '->', self.list_arc_lines[k], '\n')
  
          # display results
          if abs(self.debugplot) in [21, 22]:
              # generate mask with all the arc-line points passing the selection
              mask_arc_lines = np.zeros_like(slitlet2d_dn)
              for k in list_slices_ok:
                  mask_arc_lines[labels2d_objects == k] = 1
              # compute image with only the arc lines passing the selection
              labels2d_arc_lines = labels2d_objects * mask_arc_lines
              # display background image with filtered arc lines
              title = "Slitlet#" + str(self.islitlet) + \
                      " (locate_unknown_arc_lines, step #6)"
              z1z2 = (labels2d_arc_lines.min(),
                      labels2d_arc_lines.max())
              ax = ximshow(labels2d_arc_lines, show=False,
                           first_pixel=(self.bb_nc1_orig, self.bb_ns1_orig),
                           cbar_label="Object number",
                           title=title, z1z2=z1z2, cmap="nipy_spectral",
                           debugplot=self.debugplot)
              # plot weighted fit for each arc line (note that the fit is
              # X vs Y)
              for k in range(number_arc_lines):
                  xpol, ypol = self.list_arc_lines[k].linspace_pix()
                  ax.plot(xpol, ypol, 'g--')
              # display lower and upper points of each arc line
              x_tmp = [arc_line.xlower_line for arc_line in self.list_arc_lines]
              y_tmp = [arc_line.ylower_line for arc_line in self.list_arc_lines]
              ax.plot(x_tmp, y_tmp, 'w+')
              x_tmp = [arc_line.xupper_line for arc_line in self.list_arc_lines]
              y_tmp = [arc_line.yupper_line for arc_line in self.list_arc_lines]
              ax.plot(x_tmp, y_tmp, 'w+')
              # show plot
              pause_debugplot(self.debugplot, pltshow=True)