# **************************************************************************
# *
# * 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 2 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'
# *
# **************************************************************************
"""
This module implement the wrappers aroung Xmipp CL2D protocol
visualization program.
"""
from pyworkflow.gui import IconButton, Icon
from pyworkflow.gui.form import FormWindow
from pyworkflow.viewer import (ProtocolViewer, DESKTOP_TKINTER, WEB_DJANGO)
from pyworkflow.protocol.params import StringParam, LabelParam, IntParam
from xmipp3.protocols.protocol_consensus_classes3D import XmippProtConsensusClasses3D
from pwem.objects import Class3D
import pickle
import matplotlib.pyplot as plt
FILE_OBJECTIVE_FDATA = 'ObjectiveFData.pkl'
FILE_CLUSTERINGS = 'clusterings.pkl'
FILE_ELBOWCLUSTERS = 'elbowclusters.pkl'
[docs]class XmippClasses3DViewer(ProtocolViewer):
""" Visualization of results from the consensus classes 3D protocol
"""
_label = 'viewer classes 3D'
_targets = [XmippProtConsensusClasses3D]
_environments = [DESKTOP_TKINTER, WEB_DJANGO]
def __init__(self, **kwargs):
ProtocolViewer.__init__(self, **kwargs)
self.nclusters, self.objFValues = self.getObjectiveFData()
self._elbowIdx = self.getElbowIndex()
self._allClusterings = self.getClusterings()
[docs] def getObjectiveFData(self):
loadPath = self.protocol._getExtraPath(FILE_OBJECTIVE_FDATA)
with open(loadPath, 'rb') as f:
self._ObjFData = pickle.load(f)
return self._ObjFData
[docs] def getClusterings(self):
loadPath = self.protocol._getExtraPath(FILE_CLUSTERINGS)
with open(loadPath, 'rb') as f:
self._allClusterings = pickle.load(f)
return self._allClusterings
[docs] def getElbowIndex(self):
loadPath = self.protocol._getExtraPath(FILE_ELBOWCLUSTERS)
with open(loadPath, 'rb') as f:
self.elbowIndex = pickle.load(f)
return self.elbowIndex
def _defineParams(self, form):
form.addSection(label='Visualization')
form.addParam('displayObjectiveFunction', LabelParam,
label='Visualize Objective Function',
help='Open a GUI to visualize the objective function for each number of clusters ')
form.addParam('chooseNumberOfClusters', IntParam, default=-1,
label='Number of Clusters',
help='Choose the final number of clusters in the consensus clustering. Press the eye')
#TODO: set an apply button to change the number of clusters instead of using the eye
'''command = self._chooseNumberOfClusters()
btn = IconButton(self.getWindow(), "Apply", Icon.ACTION_CONTINUE, command=command)
btn.config(relief="flat", activebackground=None, compound='left',
fg='black', overrelief="raised")
btn.bind('<Button-1>')
btn.grid(row=2, column=2, sticky='nw')'''
def _getVisualizeDict(self):
return {'chooseNumberOfClusters': self._chooseNumberOfClusters,
'displayObjectiveFunction': self._visualizeObjectiveFunction}
def _visualizeObjectiveFunction(self, e=None):
nclusters, ob_values = self.nclusters, self.objFValues
elbowIdx = self._elbowIdx
plt.plot(nclusters, ob_values)
plt.scatter([nclusters[elbowIdx]], [ob_values[elbowIdx]], color='green')
plt.xlabel('Number of clusters')
plt.ylabel('Objective values')
plt.title('Objective values for each number of clusters')
plt.show()
def _chooseNumberOfClusters(self, e=None):
views=[]
nclusters = self.nclusters
elbow_nclust = nclusters[self._elbowIdx]
nclust = self.chooseNumberOfClusters.get()
if nclust == -1:
nclust = elbow_nclust
elif nclust > max(nclusters):
nclust = max(nclusters)
scipion_clustering = self.buildSetOfClasses(nclust)
self.protocol._defineOutputs(outputClasses=scipion_clustering)
for item in self.protocol.inputMultiClasses:
self.protocol._defineSourceRelation(item, scipion_clustering)
#TODO: esto es un objeto SetOfClasses3D pero no sabemos como lanzar un viewer con el sin tener el protocolo
#views.append(ObjectView(self._project, self.protocol.strId()))
return views
[docs] def buildSetOfClasses(self, nclust):
'''From a list of clusterings, nclust index it and that clustering
is converted into a scipion setOfClasses'''
clustIdx = self.nclusters.index(nclust)
clustering = self._allClusterings[clustIdx]
inputParticles = self.protocol.inputMultiClasses[0].get().getImages()
outputClasses = self.protocol._createSetOfClasses3D(inputParticles)
for classItem in clustering:
numOfPart = classItem[0]
partIds = classItem[1]
setRepId = classItem[2]
clsRepId = classItem[3]
setRep = self.protocol.inputMultiClasses[setRepId].get()
clRep = setRep[clsRepId]
newClass = Class3D()
# newClass.copyInfo(clRep)
newClass.setAcquisition(clRep.getAcquisition())
newClass.setRepresentative(clRep.getRepresentative())
outputClasses.append(newClass)
enabledClass = outputClasses[newClass.getObjId()]
enabledClass.enableAppend()
for itemId in partIds:
enabledClass.append(inputParticles[itemId])
outputClasses.update(enabledClass)
return outputClasses