# **************************************************************************
# *
# * Authors: J.M. De la Rosa Trevin (jmdelarosa@cnb.csic.es)
# *
# * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC
# *
# * This program is free software; you can redistribute it and/or modify
# * it under the terms of the GNU General Public License as published by
# * the Free Software Foundation; either version 3 of the License, or
# * (at your option) any later version.
# *
# * This program is distributed in the hope that it will be useful,
# * but WITHOUT ANY WARRANTY; without even the implied warranty of
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# * GNU General Public License for more details.
# *
# * You should have received a copy of the GNU General Public License
# * along with this program; if not, write to the Free Software
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
# * 02111-1307 USA
# *
# * All comments concerning this program package may be sent to the
# * e-mail address 'scipion@cnb.csic.es'
# *
# **************************************************************************
"""
Several Image tools using Matplotlib.
"""
import tkinter as tk
import matplotlib
import numpy as np
import pyworkflow as pw
from pyworkflow import TK_GRAY_DEFAULT
try:
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
except ImportError:
plt = None
from matplotlib.figure import Figure
import matplotlib.cm as cm
from matplotlib.patches import Wedge
import copy
[docs]class Preview(tk.Frame):
# def __init__(self, parent, dim, dpi=36, label=None):
def __init__(self, parent, dim, dpi=36, label=None, col=0, row=0, listenersDict=None):
tk.Frame.__init__(self, parent)
self.dim = dim
self.bg = np.zeros((int(dim), int(dim)), float)
ddim = dim/dpi
self.figure = Figure(figsize=(ddim, ddim), dpi=dpi, frameon=False)
self.canvas = FigureCanvasTkAgg(self.figure, master=self)
self.canvas.get_tk_widget().grid(column=0, row=0) # , sticky=(N, W, E, S))
self.canvas.get_tk_widget().config(bg=TK_GRAY_DEFAULT)
if label:
self.label = tk.Label(self, text=label)
self.label.grid(column=0, row=1)
self._createAxes()
if listenersDict is not None:
for bindingKey, callback in listenersDict.items():
self.canvas.get_tk_widget().bind(bindingKey, callback)
[docs] def setLabel(self, text):
self.label.config(text=text)
[docs] def setWindowTitle(self, title):
""" Set window title"""
self.canvas.set_window_title(title)
def _createAxes(self):
""" Should be implemented in subclasses. """
pass
def _update(self, *args):
""" Should be implemented in subclasses. """
pass
[docs] def clear(self):
self._update(self.bg)
[docs] def updateData(self, Z):
self.clear()
self._update(Z)
[docs]class ImagePreview(Preview):
def __init__(self, parent, dim, dpi=36, label=None, col=0, listenersDict=None):
Preview.__init__(self, parent, dim, dpi, label, col, listenersDict=listenersDict)
def _createAxes(self):
ax = self.figure.add_axes([0, 0, 1, 1], frameon=False)
self.figureimg = ax.imshow(self.bg, cmap=cm.gray) # , extent=[-h, h, -h, h])
ax.set_axis_off()
self.ax = ax
def _update(self, Z, *args):
# Adjust the Z shape according to the current data structure.
if Z.ndim == 4 and Z.shape[1] == 1:
# Assuming that the second dimension is redundant
ZAdjusted = Z[:, 0, :, :]
else:
ZAdjusted = Z
# If ZAdjusted is a grayscale image (it has only one layer)
if ZAdjusted.ndim == 3 and ZAdjusted.shape[0] == 1:
ZAdjusted = ZAdjusted[0, :, :]
# Checks if ZAdjusted has a form compatible with set_data
if ZAdjusted.ndim == 2 or (ZAdjusted.ndim == 3 and (ZAdjusted.shape[2] == 3 or ZAdjusted.shape[2] == 4)):
self.figureimg.set_data(ZAdjusted)
self.figureimg.autoscale()
self.figureimg.set(extent=[0, ZAdjusted.shape[1], 0, ZAdjusted.shape[0]])
self.canvas.draw()
[docs]class PsdPreview(Preview):
def __init__(self, master, dim, lf, hf, dpi=72, label="PSD", listenersDict=None):
Preview.__init__(self, master, dim, dpi, label, listenersDict=listenersDict)
self.lf = lf
self.hf = hf
if self.ring:
self.createRing()
else:
self.canvas.draw()
def _createAxes(self):
ax = self.figure.add_axes([0, 0, 1, 1], frameon=False)
h = 0.5
ax.set_xlim(-h, h)
ax.set_ylim(-h, h)
ax.tick_params(axis="x", direction="in", pad=-15)
ax.tick_params(axis="y", direction="in", pad=-22)
ax.grid(True)
self.ring = None
self.img = ax.imshow(self.bg, cmap=cm.gray, extent=[-h, h, -h, h])
self.ax = ax
[docs] def createRing(self):
radius = float(self.hf)
width = radius - float(self.lf)
styleArgs = getWedgeExtraParams(self.dim / 2)
self.ring = Wedge((0, 0), radius, 0, 360, width=width, **styleArgs) # Full ring
self.ax.add_patch(self.ring)
self.canvas.draw()
[docs] def updateFreq(self, lf, hf):
self.lf = lf
self.hf = hf
if self.ring:
self.ring.remove()
self.ring = None
if self.hf:
self.createRing()
def _update(self, Z):
if self.ring:
self.ring.remove()
self.ring = None
if self.hf:
self.createRing()
self.img.set_data(Z)
self.img.autoscale()
self.canvas.draw()
[docs]class MaskPreview(ImagePreview):
def __init__(self, parent, dim, dpi=36, label=None, col=0, listenersDict=None):
ImagePreview.__init__(self, parent, dim, dpi, label, col, listenersDict)
self.ring = None
[docs] def updateMask(self, outerRadius, innerRadius=0):
if self.ring is not None:
self.ring.remove()
center = self.dim / 2
width = outerRadius - innerRadius
styleArgs = getWedgeExtraParams(center)
self.ring = Wedge((center, center), outerRadius, 0, 360, width=width, **styleArgs) # Full ring
self.ax.add_patch(self.ring)
self.canvas.draw()
[docs]def getPngData(filename):
import matplotlib.image as mpimg
return mpimg.imread(filename)
[docs]def createBgImage(dim):
return np.ones((dim, dim, 3))