def redo(self):
        """Image or coordinates have changed. Clear and redraw."""
        if not self.gui_up:
            return

        self.clear_marking()
        self.tree_dict = Bunch.caselessDict()
        self.treeviewbad.clear()
        bad_tree_dict = Bunch.caselessDict()
        nbad = 0
        self._xarr = []
        self._yarr = []
        self._treepaths = []

        image = self.fitsimage.get_image()
        if image is None:
            return

        if not hasattr(image, 'radectopix'):
            self.logger.error(
                'Image as no radectopix() method for coordinates conversion')
            return

        objlist = []
        seqno = 1
        max_x = image.width - 1
        max_y = image.height - 1

        for key, coords in self.coords_dict.items():
            if len(coords) == 0:
                continue

            marktype, marksize, markcolor = key
            kstr = ','.join(map(str, key))
            sub_dict = {}
            bad_sub_dict = {}
            self.tree_dict[kstr] = sub_dict
            bad_tree_dict[kstr] = bad_sub_dict

            for args in coords:
                ra, dec, x, y = args[:4]

                # Use X and Y positions directly. Convert to RA and DEC (deg).
                if ra is None or dec is None:
                    ra, dec = image.pixtoradec(x, y)

                # RA and DEC already in degrees. Convert to pixel X and Y.
                else:
                    x, y = image.radectopix(ra, dec)

                # Display original X/Y (can be 0- or 1-indexed) using
                # our internal 0-indexed values.
                xdisp = x + self.pixelstart
                ydisp = y + self.pixelstart

                seqstr = '{0:04d}'.format(seqno)  # Prepend 0s for proper sort
                bnch = Bunch.Bunch(zip(self.extra_columns, args[4:]))  # Extra
                bnch.update(Bunch.Bunch(MARKID=seqstr, RA=ra, DEC=dec,
                                        X=xdisp, Y=ydisp))

                # Do not draw out of bounds
                if (not np.isfinite(x) or x < 0 or x > max_x or
                        not np.isfinite(y) or y < 0 or y > max_y):
                    self.logger.debug('Ignoring RA={0}, DEC={1} '
                                      '(x={2}, y={3})'.format(ra, dec, x, y))
                    bad_sub_dict[seqstr] = bnch
                    nbad += 1

                # Display point
                else:
                    obj = self._get_markobj(
                        x, y, marktype, marksize, markcolor, self.markwidth)
                    objlist.append(obj)

                    sub_dict[seqstr] = bnch
                    self._xarr.append(x)
                    self._yarr.append(y)
                    self._treepaths.append((kstr, seqstr))

                seqno += 1

        n_obj = len(objlist)
        self.logger.debug('Displaying {0} markings'.format(n_obj))

        if nbad > 0:
            self.treeviewbad.set_tree(bad_tree_dict)

        if n_obj == 0:
            return

        # Convert to Numpy arrays to avoid looping later
        self._xarr = np.array(self._xarr)
        self._yarr = np.array(self._yarr)
        self._treepaths = np.array(self._treepaths)

        # Display info table
        self.recreate_toc()

        # Draw on canvas
        self.marktag = self.canvas.add(self.dc.CompoundObject(*objlist))
        self.fitsimage.redraw()
Image or coordinates have changed. Clear and redraw.