示例#1
0
    def set_figure(self, figure):
        """Call this with the matplotlib Figure() object."""
        self.figure = figure

        ax = self.figure.add_axes(
            (0, 0, 1, 1),
            frame_on=False,
            #viewer=self,
            #projection='ginga'
        )
        #ax = fig.add_subplot(111)
        self.ax_img = ax
        # We don't want the axes cleared every time plot() is called
        ax.hold(False)
        # TODO: is this needed, since frame_on == False?
        ax.get_xaxis().set_visible(False)
        ax.get_yaxis().set_visible(False)
        #ax.patch.set_alpha(0.0)
        ax.patch.set_visible(False)
        #ax.autoscale(enable=True, tight=True)
        ax.autoscale(enable=False)

        # Add an overlapped axis for drawing graphics
        newax = self.figure.add_axes(
            self.ax_img.get_position(),
            sharex=ax,
            sharey=ax,
            frameon=False,
            #viewer=self,
            #projection='ginga'
        )
        newax.hold(True)
        newax.autoscale(enable=False)
        newax.get_xaxis().set_visible(False)
        newax.get_yaxis().set_visible(False)
        self.ax_util = newax

        # Create timers
        self._msg_timer = None
        self._defer_timer = None

        if hasattr(figure.canvas, 'new_timer'):
            self._msg_timer = Timer(mplcanvas=figure.canvas)
            self._msg_timer.add_callback(
                'expired', lambda timer: self.onscreen_message(None))

            self._defer_timer = Timer(mplcanvas=figure.canvas)
            self._defer_timer.add_callback('expired',
                                           lambda timer: self.delayed_redraw())

        canvas = figure.canvas
        if hasattr(canvas, 'viewer'):
            canvas.set_viewer(self)
        else:
            canvas.mpl_connect("resize_event", self._resize_cb)

        # Because we don't know if resize callback works with all backends
        left, bottom, wd, ht = self.ax_img.bbox.bounds
        self.configure_window(wd, ht)
示例#2
0
    def set_figure(self, figure):
        """Call this with the matplotlib Figure() object."""
        self.figure = figure

        ax = self.figure.add_axes((0, 0, 1, 1), frame_on=False)
        #ax = fig.add_subplot(111)
        self.ax_img = ax
        # We don't want the axes cleared every time plot() is called
        ax.hold(False)
        # TODO: is this needed, since frame_on == False?
        ax.get_xaxis().set_visible(False)
        ax.get_yaxis().set_visible(False)
        #ax.patch.set_alpha(0.0)
        ax.patch.set_visible(False)
        #ax.autoscale(enable=True, tight=True)
        ax.autoscale(enable=False)

        # Add an overlapped axis for drawing graphics
        newax = self.figure.add_axes(self.ax_img.get_position(),
                                     sharex=ax, sharey=ax,
                                     frameon=False)
        newax.hold(True)
        newax.autoscale(enable=False)
        newax.get_xaxis().set_visible(False)
        newax.get_yaxis().set_visible(False)
        self.ax_util = newax

        # Create timers
        self._msg_timer = None
        self._defer_timer = None

        if hasattr(figure.canvas, 'new_timer'):
            self._msg_timer = Timer(0.0,
                                    lambda timer: self.onscreen_message(None),
                                    mplcanvas=figure.canvas)

            self._defer_timer = Timer(0.0,
                                      lambda timer: self.delayed_redraw(),
                                      mplcanvas=figure.canvas)

        canvas = figure.canvas
        if hasattr(canvas, 'viewer'):
            canvas.set_viewer(self)
        else:
            canvas.mpl_connect("resize_event", self._resize_cb)

        # Because we don't know if resize callback works with all backends
        left, bottom, wd, ht = self.ax_img.bbox.bounds
        self.configure_window(wd, ht)
示例#3
0
class ImageViewMpl(ImageView.ImageViewBase):
    def __init__(self, logger=None, rgbmap=None, settings=None):
        ImageView.ImageViewBase.__init__(self,
                                         logger=logger,
                                         rgbmap=rgbmap,
                                         settings=settings)
        # Our Figure
        self.figure = None
        # Our Axes
        self.ax_img = None
        self.ax_util = None
        # Holds the image on ax_img
        self.mpimage = None

        # NOTE: matplotlib manages it's Y coordinates by default with
        # the origin at the bottom (see base class)
        self.origin_upper = False

        self.img_fg = (1.0, 1.0, 1.0)
        self.img_bg = (0.5, 0.5, 0.5)

        self.in_axes = False
        # Matplotlib expects RGBA data for color images
        self.rgb_order = 'RGBA'

        self.renderer = CanvasRenderer(self)

        # For timing events
        self._msg_timer = None
        self._defer_timer = None

    def set_figure(self, figure):
        """Call this with the matplotlib Figure() object."""
        self.figure = figure

        ax = self.figure.add_axes((0, 0, 1, 1), frame_on=False)
        #ax = fig.add_subplot(111)
        self.ax_img = ax
        # We don't want the axes cleared every time plot() is called
        ax.hold(False)
        # TODO: is this needed, since frame_on == False?
        ax.get_xaxis().set_visible(False)
        ax.get_yaxis().set_visible(False)
        #ax.patch.set_alpha(0.0)
        ax.patch.set_visible(False)
        #ax.autoscale(enable=True, tight=True)
        ax.autoscale(enable=False)

        # Add an overlapped axis for drawing graphics
        newax = self.figure.add_axes(self.ax_img.get_position(),
                                     sharex=ax,
                                     sharey=ax,
                                     frameon=False)
        newax.hold(True)
        newax.autoscale(enable=False)
        newax.get_xaxis().set_visible(False)
        newax.get_yaxis().set_visible(False)
        self.ax_util = newax

        # Create timers
        self._msg_timer = None
        self._defer_timer = None

        if hasattr(figure.canvas, 'new_timer'):
            self._msg_timer = Timer(mplcanvas=figure.canvas)
            self._msg_timer.add_callback(
                'expired', lambda timer: self.onscreen_message(None))

            self._defer_timer = Timer(mplcanvas=figure.canvas)
            self._defer_timer.add_callback('expired',
                                           lambda timer: self.delayed_redraw())

        canvas = figure.canvas
        if hasattr(canvas, 'viewer'):
            canvas.set_viewer(self)
        else:
            canvas.mpl_connect("resize_event", self._resize_cb)

        # Because we don't know if resize callback works with all backends
        left, bottom, wd, ht = self.ax_img.bbox.bounds
        self.configure_window(wd, ht)

    def get_figure(self):
        return self.figure

    def set_widget(self, canvas):
        if hasattr(canvas, 'viewer'):
            canvas.set_viewer(self)

    def get_widget(self):
        return self.figure.canvas

    def calculate_aspect(self, shape, extent):
        dx = abs(extent[1] - extent[0]) / float(shape[1])
        dy = abs(extent[3] - extent[2]) / float(shape[0])
        return dx / dy

    def render_image1(self, rgbobj, dst_x, dst_y):
        """Render the image represented by (rgbobj) at dst_x, dst_y
        in the pixel space.

        NOTE: this version uses a Figure.FigImage to render the image.
        """
        self.logger.debug("redraw surface")
        if self.figure is None:
            return
        ## left, bottom, width, height = self.ax_img.bbox.bounds
        ## self._imgwin_wd, self._imgwin_ht = width, height

        # Grab the RGB array for the current image and place it in the
        # matplotlib figure axis
        data = self.getwin_array(order=self.rgb_order)

        dst_x = dst_y = 0

        # fill background color
        ## rect = self.figure.patch
        ## rect.set_facecolor(self.img_bg)

        # attempt 1: using a FigureImage (non-scaled)
        if self.mpimage is None:
            self.mpimage = self.figure.figimage(data,
                                                xo=dst_x,
                                                yo=dst_y,
                                                origin='upper')

        else:
            # note: this is not a typo--these offsets have a different
            # attribute name than in the constructor ('ox' vs. 'xo')
            self.mpimage.ox = dst_x
            self.mpimage.oy = dst_y
            self.mpimage.set_data(data)

    def render_image2(self, rgbobj, dst_x, dst_y):
        """Render the image represented by (rgbobj) at dst_x, dst_y
        in the pixel space.

        NOTE: this version renders the image in an Axes with imshow().
        """
        self.logger.debug("redraw surface")
        if self.figure is None:
            return

        ## left, bottom, width, height = self.ax_img.bbox.bounds
        ## self._imgwin_wd, self._imgwin_ht = width, height

        # Grab the RGB array for the current image and place it in the
        # matplotlib figure axis
        arr = self.getwin_array(order=self.rgb_order)

        # Get the data extents
        x0, y0 = 0, 0
        y1, x1 = arr.shape[:2]
        flipx, flipy, swapxy = self.get_transforms()
        if swapxy:
            x0, x1, y0, y1 = y0, y1, x0, x1

        extent = (x0, x1, y1, y0)
        self.logger.debug("extent=%s" % (str(extent)))

        # Calculate aspect ratio
        aspect = self.calculate_aspect(arr.shape, extent)

        if self.mpimage is None:
            img = self.ax_img.imshow(arr,
                                     interpolation='none',
                                     origin="upper",
                                     vmin=0,
                                     vmax=255,
                                     extent=extent,
                                     aspect=aspect)
            self.mpimage = img

        else:
            self.mpimage.set_data(arr)
            self.ax_img.set_aspect(aspect)
            self.mpimage.set_extent(extent)
            #self.ax_img.relim()

    def render_image(self, rgbobj, dst_x, dst_y):

        # Ugly, ugly hack copied from matplotlib.lines to cause line
        # objects to recompute their cached transformed_path
        # Other mpl artists don't seem to have this affliction
        for ax in self.figure.axes:
            if not (ax in (self.ax_img, self.ax_util)):
                if hasattr(ax, "lines"):
                    for line in ax.lines:
                        try:
                            line._transformed_path.invalidate()
                        except AttributeError:
                            pass

        # render_image1() currently seems a little faster
        if self.in_axes:
            self.render_image2(rgbobj, dst_x, dst_y)
        else:
            self.render_image1(rgbobj, dst_x, dst_y)

        # clear utility axis
        self.ax_util.cla()

        # force an update of the figure
        self.figure.canvas.draw()

        # Set the axis limits
        # TODO: should we do this only for those who have autoaxis=True?
        ## wd, ht = self.get_window_size()
        ## x0, y0 = self.get_data_xy(0, 0)
        ## x1, tm = self.get_data_xy(wd-1, 0)
        ## tm, y1 = self.get_data_xy(0, ht-1)
        ## for ax in self.figure.axes:
        ##     ax.set_xlim(x0, x1)
        ##     ax.set_ylim(y0, y1)

    def configure_window(self, width, height):
        self.configure(width, height)

    def _resize_cb(self, event):
        wd, ht = event.width, event.height
        self.logger.debug("canvas resized %dx%d" % (wd, ht))
        self.configure_window(wd, ht)

    def add_axes(self):
        ax = self.figure.add_axes(
            self.ax_img.get_position(),
            #sharex=self.ax_img, sharey=self.ax_img,
            frameon=False,
            viewer=self,
            projection='ginga')
        ax.get_xaxis().set_visible(False)
        ax.get_yaxis().set_visible(False)
        return ax

    def get_png_image_as_buffer(self, output=None):
        ibuf = output
        if ibuf is None:
            ibuf = BytesIO()
        qimg = self.figure.write_to_png(ibuf)
        return ibuf

    def update_image(self):
        pass

    def set_cursor(self, cursor):
        pass

    def onscreen_message(self, text, delay=None, redraw=True):
        if self._msg_timer is not None:
            self._msg_timer.stop()

        self.set_onscreen_message(text, redraw=redraw)

        if self._msg_timer is not None and delay is not None:
            self._msg_timer.start(delay)

    def reschedule_redraw(self, time_sec):
        if self._defer_timer is None:
            self.delayed_redraw()
            return

        self._defer_timer.stop()
        self._defer_timer.start(time_sec)
示例#4
0
class ImageViewMpl(ImageView.ImageViewBase):

    def __init__(self, logger=None, rgbmap=None, settings=None):
        ImageView.ImageViewBase.__init__(self, logger=logger,
                                         rgbmap=rgbmap,
                                         settings=settings)
        # Our Figure
        self.figure = None
        # Our Axes
        self.ax_img = None
        self.ax_util = None
        # Holds the image on ax_img
        self.mpimage = None

        # NOTE: matplotlib manages it's Y coordinates by default with
        # the origin at the bottom (see base class)
        self._originUpper = False

        self.img_fg = (1.0, 1.0, 1.0)
        self.img_bg = (0.5, 0.5, 0.5)

        self.in_axes = False
        # Matplotlib expects RGBA data for color images
        self._rgb_order = 'RGBA'

        self.renderer = CanvasRenderer(self)

        # cursors
        self.cursor = {}

        # For timing events
        self._msg_timer = None
        self._defer_timer = None

    def set_figure(self, figure):
        """Call this with the matplotlib Figure() object."""
        self.figure = figure

        ax = self.figure.add_axes((0, 0, 1, 1), frame_on=False)
        #ax = fig.add_subplot(111)
        self.ax_img = ax
        # We don't want the axes cleared every time plot() is called
        ax.hold(False)
        # TODO: is this needed, since frame_on == False?
        ax.get_xaxis().set_visible(False)
        ax.get_yaxis().set_visible(False)
        #ax.patch.set_alpha(0.0)
        ax.patch.set_visible(False)
        #ax.autoscale(enable=True, tight=True)
        ax.autoscale(enable=False)

        # Add an overlapped axis for drawing graphics
        newax = self.figure.add_axes(self.ax_img.get_position(),
                                     sharex=ax, sharey=ax,
                                     frameon=False)
        newax.hold(True)
        newax.autoscale(enable=False)
        newax.get_xaxis().set_visible(False)
        newax.get_yaxis().set_visible(False)
        self.ax_util = newax

        # Create timers
        self._msg_timer = None
        self._defer_timer = None

        if hasattr(figure.canvas, 'new_timer'):
            self._msg_timer = Timer(0.0,
                                    lambda timer: self.onscreen_message(None),
                                    mplcanvas=figure.canvas)

            self._defer_timer = Timer(0.0,
                                      lambda timer: self.delayed_redraw(),
                                      mplcanvas=figure.canvas)

        canvas = figure.canvas
        if hasattr(canvas, 'viewer'):
            canvas.set_viewer(self)
        else:
            canvas.mpl_connect("resize_event", self._resize_cb)

        # Because we don't know if resize callback works with all backends
        left, bottom, wd, ht = self.ax_img.bbox.bounds
        self.configure_window(wd, ht)

    def get_figure(self):
        return self.figure

    def set_widget(self, canvas):
        if hasattr(canvas, 'viewer'):
            canvas.set_viewer(self)

    def get_widget(self):
        return self.figure.canvas

    def get_rgb_order(self):
        return self._rgb_order

    def calculate_aspect(self, shape, extent):
        dx = abs(extent[1] - extent[0]) / float(shape[1])
        dy = abs(extent[3] - extent[2]) / float(shape[0])
        return dx / dy

    def render_image1(self, rgbobj, dst_x, dst_y):
        """Render the image represented by (rgbobj) at dst_x, dst_y
        in the pixel space.

        NOTE: this version uses a Figure.FigImage to render the image.
        """
        self.logger.debug("redraw surface")
        if self.figure is None:
            return
        ## left, bottom, width, height = self.ax_img.bbox.bounds
        ## self._imgwin_wd, self._imgwin_ht = width, height

        # Grab the RGB array for the current image and place it in the
        # matplotlib figure axis
        data = self.getwin_array(order=self._rgb_order)

        dst_x = dst_y = 0

        # fill background color
        ## rect = self.figure.patch
        ## rect.set_facecolor(self.img_bg)

        # attempt 1: using a FigureImage (non-scaled)
        if self.mpimage is None:
            self.mpimage = self.figure.figimage(data, xo=dst_x, yo=dst_y,
                                                origin='upper')

        else:
            # note: this is not a typo--these offsets have a different
            # attribute name than in the constructor ('ox' vs. 'xo')
            self.mpimage.ox = dst_x
            self.mpimage.oy = dst_y
            self.mpimage.set_data(data)

    def render_image2(self, rgbobj, dst_x, dst_y):
        """Render the image represented by (rgbobj) at dst_x, dst_y
        in the pixel space.

        NOTE: this version renders the image in an Axes with imshow().
        """
        self.logger.debug("redraw surface")
        if self.figure is None:
            return

        ## left, bottom, width, height = self.ax_img.bbox.bounds
        ## self._imgwin_wd, self._imgwin_ht = width, height

        # Grab the RGB array for the current image and place it in the
        # matplotlib figure axis
        arr = self.getwin_array(order=self._rgb_order)

        # Get the data extents
        x0, y0 = 0, 0
        y1, x1 = arr.shape[:2]
        flipx, flipy, swapxy = self.get_transforms()
        if swapxy:
            x0, x1, y0, y1 = y0, y1, x0, x1

        extent = (x0, x1, y1, y0)
        self.logger.debug("extent=%s" % (str(extent)))

        # Calculate aspect ratio
        aspect = self.calculate_aspect(arr.shape, extent)

        if self.mpimage is None:
            img = self.ax_img.imshow(arr, interpolation='none',
                                   origin="upper",
                                   vmin=0, vmax=255,
                                   extent=extent,
                                   aspect=aspect)
            self.mpimage = img

        else:
            self.mpimage.set_data(arr)
            self.ax_img.set_aspect(aspect)
            self.mpimage.set_extent(extent)
            #self.ax_img.relim()

    def render_image(self, rgbobj, dst_x, dst_y):

        # Ugly, ugly hack copied from matplotlib.lines to cause line
        # objects to recompute their cached transformed_path
        # Other mpl artists don't seem to have this affliction
        for ax in self.figure.axes:
            if not (ax in (self.ax_img, self.ax_util)):
                if hasattr(ax, "lines"):
                    for line in ax.lines:
                        try:
                            line._transformed_path.invalidate()
                        except AttributeError:
                            pass

        # render_image1() currently seems a little faster
        if self.in_axes:
            self.render_image2(rgbobj, dst_x, dst_y)
        else:
            self.render_image1(rgbobj, dst_x, dst_y)

        # clear utility axis
        self.ax_util.cla()

        # force an update of the figure
        self.figure.canvas.draw()

        # Set the axis limits
        # TODO: should we do this only for those who have autoaxis=True?
        ## wd, ht = self.get_window_size()
        ## x0, y0 = self.get_data_xy(0, 0)
        ## x1, tm = self.get_data_xy(wd-1, 0)
        ## tm, y1 = self.get_data_xy(0, ht-1)
        ## for ax in self.figure.axes:
        ##     ax.set_xlim(x0, x1)
        ##     ax.set_ylim(y0, y1)

    def configure_window(self, width, height):
        self.configure(width, height)

    def _resize_cb(self, event):
        wd, ht = event.width, event.height
        self.logger.debug("canvas resized %dx%d" % (wd, ht))
        self.configure_window(wd, ht)

    def add_axes(self):
        ax = self.figure.add_axes(self.ax_img.get_position(),
                                  #sharex=self.ax_img, sharey=self.ax_img,
                                  frameon=False,
                                  viewer=self,
                                  projection='ginga')
        ax.get_xaxis().set_visible(False)
        ax.get_yaxis().set_visible(False)
        return ax

    def get_png_image_as_buffer(self, output=None):
        ibuf = output
        if ibuf is None:
            ibuf = BytesIO()
        qimg = self.figure.write_to_png(ibuf)
        return ibuf

    def update_image(self):
        pass

    def set_cursor(self, cursor):
        pass

    def define_cursor(self, ctype, cursor):
        self.cursor[ctype] = cursor

    def get_cursor(self, ctype):
        return self.cursor[ctype]

    def switch_cursor(self, ctype):
        self.set_cursor(self.cursor[ctype])

    def onscreen_message(self, text, delay=None, redraw=True):
        if self._msg_timer is not None:
            self._msg_timer.cancel()

        self.set_onscreen_message(text, redraw=redraw)

        if self._msg_timer is not None and delay is not None:
            self._msg_timer.start(delay)

    def reschedule_redraw(self, time_sec):
        if self._defer_timer is None:
            self.delayed_redraw()
            return

        self._defer_timer.cancel()
        self._defer_timer.start(time_sec)