docstr: Run a UI that gets an angle from the user
docstr_tok: ["Run","a","UI","that","gets","an","angle","from","the","user"]
code: def handle_interaction(self, pixel_data, image_set_number):
      """Run a UI that gets an angle from the user"""
      import wx
  
      if pixel_data.ndim == 2:
          # make a color matrix for consistency
          pixel_data = numpy.dstack(
              (pixel_data, pixel_data, pixel_data)
          )
      pd_min = numpy.min(pixel_data)
      pd_max = numpy.max(pixel_data)
      if pd_min == pd_max:
          pixel_data[:, :, :] = 0
      else:
          pixel_data = (pixel_data - pd_min) * 255.0 / (pd_max - pd_min)
      #
      # Make a 100 x 100 image so it's manageable
      #
      isize = 200
      i, j, k = numpy.mgrid[
          0:isize,
          0 : int(isize * pixel_data.shape[1] / pixel_data.shape[0]),
          0:3,
      ].astype(float)
      i *= float(pixel_data.shape[0]) / float(isize)
      j *= float(pixel_data.shape[0]) / float(isize)
      pixel_data = scipy.ndimage.map_coordinates(pixel_data, (i, j, k))
      #
      # Make a dialog box that contains the image
      #
      dialog_title = "Rotate image - Cycle #%d:" % (image_set_number)
      dialog = wx.Dialog(None, title=dialog_title)
      sizer = wx.BoxSizer(wx.VERTICAL)
      dialog.SetSizer(sizer)
      sizer.Add(
          wx.StaticText(
              dialog, label="Drag image to rotate, hit OK to continue"
          ),
          0,
          wx.ALIGN_CENTER_HORIZONTAL,
      )
      canvas = wx.StaticBitmap(dialog)
      canvas.SetDoubleBuffered(True)
      sizer.Add(
          canvas,
          0,
          wx.ALIGN_CENTER_HORIZONTAL
          | wx.ALIGN_CENTER_VERTICAL
          | wx.ALL,
          5,
      )
      angle = [0]
      angle_text = wx.StaticText(dialog, label="Angle: %d" % angle[0])
      sizer.Add(angle_text, 0, wx.ALIGN_CENTER_HORIZONTAL)
  
      def imshow():
          angle_text.Label = "Angle: %d" % int(angle[0])
          angle_text.Refresh()
          my_angle = -angle[0] * numpy.pi / 180.0
          transform = numpy.array(
              [
                  [numpy.cos(my_angle), -numpy.sin(my_angle)],
                  [numpy.sin(my_angle), numpy.cos(my_angle)],
              ]
          )
          # Make it rotate about the center
          offset = affine_offset(pixel_data.shape, transform)
          x = numpy.dstack(
              (
                  scipy.ndimage.affine_transform(
                      pixel_data[:, :, 0], transform, offset, order=0
                  ),
                  scipy.ndimage.affine_transform(
                      pixel_data[:, :, 1], transform, offset, order=0
                  ),
                  scipy.ndimage.affine_transform(
                      pixel_data[:, :, 2], transform, offset, order=0
                  ),
              )
          )
          buff = x.astype(numpy.uint8).tostring()
          bitmap = wx.Bitmap.FromBuffer(x.shape[1], x.shape[0], buff)
          canvas.SetBitmap(bitmap)
  
      imshow()
      #
      # Install handlers for mouse down, mouse move and mouse up
      #
      dragging = [False]
      initial_angle = [0]
      hand_cursor = wx.Cursor(wx.CURSOR_HAND)
      arrow_cursor = wx.Cursor(wx.CURSOR_ARROW)
  
      def get_angle(event):
          center = numpy.array(canvas.Size) / 2
          point = numpy.array(event.GetPosition())
          offset = point - center
          return -numpy.arctan2(offset[1], offset[0]) * 180.0 / numpy.pi
  
      def on_mouse_down(event):
          canvas.Cursor = hand_cursor
          dragging[0] = True
          initial_angle[0] = get_angle(event) - angle[0]
          canvas.CaptureMouse()
  
      canvas.Bind(wx.EVT_LEFT_DOWN, on_mouse_down)
  
      def on_mouse_up(event):
          if dragging[0]:
              canvas.ReleaseMouse()
              dragging[0] = False
              canvas.Cursor = arrow_cursor
  
      canvas.Bind(wx.EVT_LEFT_UP, on_mouse_up)
  
      def on_mouse_lost(event):
          dragging[0] = False
          canvas.Cursor = arrow_cursor
  
      canvas.Bind(wx.EVT_MOUSE_CAPTURE_LOST, on_mouse_lost)
  
      def on_mouse_move(event):
          if dragging[0]:
              angle[0] = get_angle(event) - initial_angle[0]
              imshow()
              canvas.Refresh(eraseBackground=False)
  
      canvas.Bind(wx.EVT_MOTION, on_mouse_move)
      #
      # Put the OK and Cancel buttons on the bottom
      #
      btnsizer = wx.StdDialogButtonSizer()
  
      btn = wx.Button(dialog, wx.ID_OK)
      btn.SetDefault()
      btnsizer.AddButton(btn)
  
      btn = wx.Button(dialog, wx.ID_CANCEL)
      btnsizer.AddButton(btn)
      btnsizer.Realize()
  
      sizer.Add(btnsizer, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5)
      dialog.Fit()
      result = dialog.ShowModal()
      dialog.Destroy()
      if result == wx.ID_OK:
          return angle[0]
      raise ValueError("Canceled by user in FlipAndRotate")
  
imports: import numpy
  import scipy.ndimage
  from cellprofiler_core.constants.measurement import IMAGE, COLTYPE_FLOAT
  from cellprofiler_core.image import Image
  from cellprofiler_core.module import Module
  from cellprofiler_core.setting import Binary
  from cellprofiler_core.setting import Coordinates
  from cellprofiler_core.setting.choice import Choice
  from cellprofiler_core.setting.subscriber import ImageSubscriber
  from cellprofiler_core.setting.text import ImageName, Float
label_desc: Use image node_id 7 for calling the FlipAndRotate obj's underlying member method code with example usage: obj.handle_interaction(pixel_data, image_set_number) and returns: unknown, angle