class_docstr: A frame to get sampling settings and to calculate samples for a
  CellProfiler module.
  
  A few important data members and data structures are maintained:
  'self.__module': the module selected by the user.
  'self.__pipeline': the pipeline containing the module.
  'self.__parameters_list': a list of all unbounded parameters that will
      be displayed to the user. Eg,
          [(label_1, m_1), (label_2, m_2), ...], where
          parameter i maps to the tuple (label_i, m_i) with 'label_i' its
          text label and 'm_i' its 1-based index in 'self.__module'.
  'self.__parameters_to_widgets_list': a list of lists representing the
      mapping from parameters (see above), to 'groups of widgets'. Ie,
      some parameters will have more than two values and, hence, will
      have two groups of widgets. Eg,
          [[0, 1], [[2]], [3, 4], represents a mapping
          param 0 -> widget group 0 and 1, etc.
      In practice, each such mapping will correspond exactly to a
      check box and one or more rows of spin controls, depending on how
      many values a particular parameter takes.
  'self.__sample_list': a list of samples of the selected parameters. Eg,
      suppose that parameters p_1, p_2 and p_3 are selected, then a list
      of the form
          [[s_11, s_21, s_31], [s_12, s_22, s_32], ...]
      will be returned.
      NB: for those parameters displayed, but not selected by the user, this
      list will contain the value 'None'. Eg, suppose p2 is deselected, then
      the list will have the form:
          [[s_11, None, s_31], [s_12, None, s_32], ...].
code: def __init__(
      self,
      parent,
      module,
      pipeline,
      identifier=-1,
      pos=wx.DefaultPosition,
      size=wx.DefaultSize,
      style=wx.DEFAULT_FRAME_STYLE,
      name=wx.FrameNameStr,
  ):
      # Flag to check during event handling: widgets generate events as they
      # are created leading to referencing errors before all data structs
      # have been initialized.
      self.__initialized = False
  
      # Init frame
      self.__module = module
      self.__pipeline = pipeline
      self.__frame = parent
  
      # Data members for running pipeline
      self.__measurements = None
      self.__object_set = None
      self.__image_set_list = None
      self.__keys = None
      self.__groupings = None
      self.__grouping_index = None
      self.__within_group_index = None
      self.__outlines = None
      self.__grids = None
  
      frame_title = (
          "Sampling settings for module, " + self.__module.module_name
      )
      wx.Frame.__init__(
          self,
          self.__frame,
          identifier,
          frame_title,
          pos,
          size,
          style,
          name,
      )
      self.__frame_sizer = wx.BoxSizer(wx.VERTICAL)
      self.SetSize(wx.Size(700, 350))
      self.SetSizer(self.__frame_sizer)
  
      # Get parameters
      self.__parameters_list = self.get_parameters_list()
      if len(self.__parameters_list) == 0:
          dialog = wx.MessageDialog(
              self,
              self.__module.module_name
              + " has no unbounded parameters.",
              caption="No unbounded parameters",
              style=wx.OK,
          )
          dialog.ShowModal()
          self.Close(True)
  
      # Init settings panel
      self.__settings_panel = wx.Panel(self, -1)
      self.__settings_panel_sizer = wx.BoxSizer(wx.VERTICAL)
      self.__settings_panel.SetSizer(self.__settings_panel_sizer)
      self.__frame_sizer.Add(
          self.__settings_panel, 1, wx.EXPAND | wx.ALL, 5
      )
  
      # Init settings scrolled window
      self.__settings_scrolled_window = wx.ScrolledWindow(
          self.__settings_panel
      )
      self.__settings_scrolled_window.SetScrollRate(20, 20)
      self.__settings_scrolled_window.EnableScrolling(True, True)
      self.__settings_scrolled_window_sizer = wx.FlexGridSizer(
          rows=0, cols=5
      )
      self.__settings_scrolled_window.SetSizer(
          self.__settings_scrolled_window_sizer
      )
      self.__settings_scrolled_window_sizer.AddGrowableCol(0)
      self.__settings_panel_sizer.Add(
          self.__settings_scrolled_window, 1, wx.EXPAND | wx.ALL, 5
      )
  
      # Headings
      self.__settings_scrolled_window_sizer.Add(
          wx.StaticText(
              self.__settings_scrolled_window, -1, "Parameter"
          ),
          0,
          wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.TOP,
          5,
      )
      self.__settings_scrolled_window_sizer.Add(
          wx.StaticText(
              self.__settings_scrolled_window, -1, "Current value"
          ),
          0,
          wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.TOP,
          5,
      )
      self.__settings_scrolled_window_sizer.Add(
          wx.StaticText(
              self.__settings_scrolled_window, -1, "Lower bound"
          ),
          0,
          wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.TOP,
          5,
      )
      self.__settings_scrolled_window_sizer.Add(
          wx.StaticText(
              self.__settings_scrolled_window, -1, "Upper bound"
          ),
          0,
          wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.TOP,
          5,
      )
      self.__settings_scrolled_window_sizer.Add(
          wx.StaticText(
              self.__settings_scrolled_window, -1, "Number samples"
          ),
          0,
          wx.ALIGN_CENTER
          | wx.ALIGN_CENTER_VERTICAL
          | wx.LEFT
          | wx.TOP
          | wx.RIGHT,
          5,
      )
  
      # Init dynamic widgets based on parameters
      self.__parameters_to_widgets_list = (
          self.get_parameters_to_widgets_list(self.__parameters_list)
      )
  
      self.__check_box_list = []
      self.__current_static_text_list = []
      self.__lower_bound_spin_ctrl_list = []
      self.__upper_bound_spin_ctrl_list = []
      self.__number_spin_ctrl_list = []
      for i in range(len(self.__parameters_to_widgets_list)):
          label = self.__parameters_list[i][0]
          setting = self.__module.setting(self.__parameters_list[i][1])
          value = setting.get_value()
  
          for j in range(len(self.__parameters_to_widgets_list[i])):
              # Checkbox & label
              if j == 0:
                  check_box = wx.CheckBox(
                      self.__settings_scrolled_window, -1, label
                  )
                  check_box.Bind(wx.EVT_CHECKBOX, self.on_check_box)
                  self.__settings_scrolled_window_sizer.Add(
                      check_box,
                      0,
                      wx.ALIGN_LEFT
                      | wx.ALIGN_CENTER_VERTICAL
                      | wx.LEFT
                      | wx.TOP,
                      5,
                  )
                  self.__check_box_list.append(check_box)
              else:
                  self.__settings_scrolled_window_sizer.Add(
                      wx.Panel(self.__settings_scrolled_window, -1)
                  )
  
              # Current value
              if self.is_parameter_int(setting):
                  if self.get_parameter_input_size(setting) == 1:
                      cur_value = str(value)
                  elif self.get_parameter_input_size(setting) == 2:
                      cur_value = str(value[j])
              elif self.is_parameter_float(setting):
                  if self.get_parameter_input_size(setting) == 1:
                      cur_value = str(
                          round(value, FLOAT_DIGITS_TO_ROUND_TO)
                      )
                  elif self.get_parameter_input_size(setting) == 2:
                      cur_value = str(
                          round(value[j], FLOAT_DIGITS_TO_ROUND_TO)
                      )
              current_static_text = wx.StaticText(
                  self.__settings_scrolled_window, -1, cur_value
              )
              self.__settings_scrolled_window_sizer.Add(
                  current_static_text,
                  0,
                  wx.ALIGN_CENTER_VERTICAL
                  | wx.LEFT
                  | wx.TOP
                  | wx.RIGHT,
                  5,
              )
              self.__current_static_text_list.append(
                  current_static_text
              )
  
              # Lower and upper bounds
              if self.is_parameter_int(setting):
                  # Integer
                  lower_spin_ctrl = wx.SpinCtrl(
                      self.__settings_scrolled_window, wx.NewId()
                  )
                  lower_spin_ctrl.SetRange(
                      INT_LOWER_BOUND, INT_UPPER_BOUND
                  )
                  lower_spin_ctrl.Bind(
                      wx.EVT_SPINCTRL, self.on_lower_spin_ctrl
                  )
  
                  upper_spin_ctrl = wx.SpinCtrl(
                      self.__settings_scrolled_window, wx.NewId()
                  )
                  upper_spin_ctrl.SetRange(
                      INT_LOWER_BOUND, INT_UPPER_BOUND
                  )
                  upper_spin_ctrl.Bind(
                      wx.EVT_SPINCTRL, self.on_upper_spin_ctrl
                  )
  
                  interval = (
                      DEFAULT_NUMBER_SAMPLES - 1
                  )  # Used later to set upper bound
              elif self.is_parameter_float(setting):
                  # Float
                  lower_spin_ctrl = wx.lib.agw.floatspin.FloatSpin(
                      self.__settings_scrolled_window,
                      wx.NewId(),
                      size=wx.DefaultSize,
                  )  # NB: if not set, spin buttons are hidden
                  lower_spin_ctrl.SetDigits(FLOAT_DIGITS_TO_ROUND_TO)
                  lower_spin_ctrl.SetIncrement(
                      10**-FLOAT_DIGITS_TO_ROUND_TO
                  )
                  lower_spin_ctrl.SetRange(
                      FLOAT_LOWER_BOUND, FLOAT_UPPER_BOUND
                  )
                  lower_spin_ctrl.Bind(
                      wx.lib.agw.floatspin.EVT_FLOATSPIN,
                      self.on_lower_float_spin,
                  )
  
                  upper_spin_ctrl = wx.lib.agw.floatspin.FloatSpin(
                      self.__settings_scrolled_window,
                      wx.NewId(),
                      size=wx.DefaultSize,
                  )  # NB: if not set, spin buttons are hidden
                  upper_spin_ctrl.SetDigits(FLOAT_DIGITS_TO_ROUND_TO)
                  upper_spin_ctrl.SetIncrement(
                      10**-FLOAT_DIGITS_TO_ROUND_TO
                  )
                  upper_spin_ctrl.SetRange(
                      FLOAT_LOWER_BOUND, FLOAT_UPPER_BOUND
                  )
                  upper_spin_ctrl.Bind(
                      wx.lib.agw.floatspin.EVT_FLOATSPIN,
                      self.on_upper_float_spin,
                  )
  
                  interval = (
                      upper_spin_ctrl.GetIncrement()
                  )  # Used later to set upper bound
  
              if self.get_parameter_input_size(setting) == 1:
                  lower_spin_ctrl.SetValue(
                      value
                  )  # Set value after range to avoid rounding
                  upper_spin_ctrl.SetValue(value + interval)
              elif self.get_parameter_input_size(setting) == 2:
                  lower_spin_ctrl.SetValue(value[j])
                  upper_spin_ctrl.SetValue(value[j] + interval)
  
              lower_spin_ctrl.Enable(False)
              self.__settings_scrolled_window_sizer.Add(
                  lower_spin_ctrl,
                  0,
                  wx.EXPAND | wx.ALIGN_LEFT | wx.LEFT | wx.TOP,
                  5,
              )
              self.__lower_bound_spin_ctrl_list.append(lower_spin_ctrl)
  
              upper_spin_ctrl.Enable(False)
              self.__settings_scrolled_window_sizer.Add(
                  upper_spin_ctrl, 0, wx.LEFT | wx.TOP, 5
              )
              self.__upper_bound_spin_ctrl_list.append(upper_spin_ctrl)
  
              # Number samples
              num_spin_ctrl = wx.SpinCtrl(
                  self.__settings_scrolled_window, wx.NewId()
              )
              num_spin_ctrl.Enable(False)
              num_spin_ctrl.SetRange(1, 100)
              num_spin_ctrl.SetValue(10)
              num_spin_ctrl.Bind(
                  wx.EVT_SPINCTRL, self.on_number_spin_ctrl
              )
              self.__settings_scrolled_window_sizer.Add(
                  num_spin_ctrl, 0, wx.LEFT | wx.TOP | wx.RIGHT, 5
              )
              self.__number_spin_ctrl_list.append(num_spin_ctrl)
  
      self.__settings_scrolled_window.Layout()
      self.__settings_panel.Layout()
  
      # Add button
      self.sample_button = wx.Button(self, ID_SAMPLE_BUTTON, "Sample")
      self.sample_button.Bind(wx.EVT_BUTTON, self.on_button)
      self.sample_button.Enable(False)
      self.__frame_sizer.Add(
          self.sample_button, 0, wx.ALIGN_RIGHT | wx.ALL, 5
      )
  
      self.__initialized = True
  
imports: import os
  import traceback
  import numpy
  import skimage.io
  import wx
  import wx.lib.agw.floatspin
  from cellprofiler_core.image import ImageSetList
  from cellprofiler_core.measurement import Measurements
  from cellprofiler_core.object import ObjectSet
  from cellprofiler_core.pipeline import RunException
  from cellprofiler_core.setting import Binary, Divider, FigureSubscriber, Measurement, ValidationError
  from cellprofiler_core.setting.choice import Choice
  from cellprofiler_core.setting.do_something import DoSomething, RemoveSettingButton
  from cellprofiler_core.setting.range import FloatRange, IntegerRange, IntegerOrUnboundedRange
  from cellprofiler_core.setting.subscriber import ImageSubscriber
  from cellprofiler_core.setting.text import Float, Integer, Name, Text, ImageName
  import cellprofiler.gui._workspace_model
label_desc: Use image node_id 1 to create a new ParameterSampleFrame object from inherited base classes: wx with example: obj = ParameterSampleFrame(parent, module, pipeline, identifier, pos, size, style, name)