Source code for spider.viewers.viewer_refinement

# **************************************************************************
# *
# * Authors:     J.M. De la Rosa Trevin (
# *
# * 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
# * 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 ''
# *
# **************************************************************************

import os
from glob import glob

import pyworkflow.protocol.params as params
from pyworkflow.viewer import DESKTOP_TKINTER, WEB_DJANGO
from pwem.viewers import (EmPlotter, ChimeraView,
                          EmProtocolViewer, ChimeraAngDist)

from ..constants import *
from ..protocols import SpiderProtRefinement
from ..utils import SpiderDocFile

[docs]class SpiderViewerRefinement(EmProtocolViewer): """ Visualization of Spider refinement results. """ _environments = [DESKTOP_TKINTER, WEB_DJANGO] _targets = [SpiderProtRefinement] _label = 'viewer refinement' def _defineParams(self, form): form.addSection(label='Visualization') form.addParam('viewIter', params.EnumParam, choices=['last', 'selection'], default=ITER_LAST, display=params.EnumParam.DISPLAY_HLIST, label="Iteration to visualize", important=True, help=""" *last*: only the last iteration will be visualized. *selection*: you may specify a range of iterations. Examples: "1,5-8,10" -> [1,5,6,7,8,10] "2,6,9-11" -> [2,6,9,10,11] "2 5, 6-8" -> [2,5,6,7,8] """) form.addParam('iterSelection', params.NumericRangeParam, condition='viewIter==%d' % ITER_SELECTION, label="Iterations list", help="Write the iteration list to visualize.") group = form.addGroup('Angular assignment') group.addParam('displayAngDist', params.EnumParam, choices=['2D plot', 'chimera'], default=ANGDIST_2DPLOT, display=params.EnumParam.DISPLAY_HLIST, label='Display angular distribution', help='*2D plot*: display angular distribution as interative 2D in matplotlib.\n' '*chimera*: display angular distribution using Chimera with red spheres.') group.addParam('spheresScale', params.IntParam, default=-1, condition="displayAngDist == %d" % ANGDIST_CHIMERA, expertLevel=params.LEVEL_ADVANCED, label='Spheres size', help='') group = form.addGroup('Volumes') group.addParam('displayVol', params.EnumParam, choices=['slices', 'chimera'], default=VOLUME_SLICES, display=params.EnumParam.DISPLAY_HLIST, label='Display volume with', help='*slices*: display volumes as 2D slices along z axis.\n' '*chimera*: display volumes as surface with Chimera.') group.addParam('showVolumes', params.EnumParam, default=VOL, choices=self.volList(), label='Volume to visualize', help='Select the volume to visualize') group = form.addGroup('Resolution') group.addParam('showFSC', params.LabelParam, default=True, important=True, label='Display resolution plots (FSC)') group.addParam('groupFSC', params.EnumParam, default=0, choices=['iterations', 'defocus groups'], condition='not isGoldStdProt and viewIter==0', display=params.EnumParam.DISPLAY_HLIST, label='Group FSC plots by', help='Select which FSC curve you want to ' 'show together in the same plot.') group.addParam('groupSelection', params.NumericRangeParam, condition='not isGoldStdProt and groupFSC==1 and viewIter==0', label="Groups list", help="Write the group list to visualize. See examples in iteration list") group.addParam('resolutionThresholdFSC', params.FloatParam, default=0.143, expertLevel=params.LEVEL_ADVANCED, label='Threshold in resolution plots', help='Use 0.5 for refinement with defocus groups, otherwise ' 'for gold-standard refinement use 0.143')
[docs] def isGoldStdProt(self): # True = gold std refinement return self.protocol.protType == 1
[docs] def volList(self): if self.isGoldStdProt(): return ['reconstructed', 'half1', 'half2', 'filtered', 'filtered & centered'] else: return ['reconstructed', 'half1', 'half2']
def _getVisualizeDict(self): # self._load() return { 'showVolumes': self._showVolumes, 'showFSC': self._showFSC, 'displayAngDist': self._displayAngDist } def _validate(self): return [] def _formatFreq(self, value, pos): """ Format function for Matplotlib formatter. """ inv = 999. if value: inv = 1 / value return "1/%0.2f" % inv def _getIterations(self): if self.viewIter == ITER_LAST: return [self.protocol._getLastIterNumber()] else: return self._getListFromRangeString(self.iterSelection.get('')) def _getGroups(self): return self._getListFromRangeString(self.groupSelection.get('')) def _getFinalPath(self, *paths): return self.protocol._getExtraPath('Refinement', 'final', *paths) # ========================================================================= # ShowVolumes # ========================================================================= def _createVolumesSqlite(self): """ Write an sqlite with all volumes selected for visualization. """ volSqlite = self.protocol._getExtraPath('viewer_volumes.sqlite') samplingRate = self.protocol.inputParticles.get().getSamplingRate() self.createVolumesSqlite(self.getVolumeNames(), volSqlite, samplingRate) return [self.objectView(volSqlite)]
[docs] def getVolumeNames(self, it=None): """ If it is not none, return the volume of this iteration only. """ if it is None: iterations = self._getIterations() else: iterations = [it] if self.isGoldStdProt(): volTemplate = VOLNAMES_GOLDSTD[self.showVolumes.get()] else: volTemplate = VOLNAMES_DEFGROUPS[self.showVolumes.get()] volumes = [self._getFinalPath(volTemplate % i) + '.stk' for i in iterations] return volumes
def _showVolumesChimera(self): """ Create a chimera script to visualize selected volumes. """ volumes = self.getVolumeNames() cmdFile = self._getFinalPath('chimera_volumes.cxc') with open(cmdFile, 'w+') as f: for vol in volumes: localVol = os.path.relpath(vol, self.protocol._getFinalPath()) if os.path.exists(vol): f.write("open %s format spider\n" % localVol) f.write('tile\n') view = ChimeraView(cmdFile) return [view] def _showVolumes(self, paramName=None): if self.displayVol == VOLUME_CHIMERA: return self._showVolumesChimera() elif self.displayVol == VOLUME_SLICES: return self._createVolumesSqlite() # =============================================================================== # plotFSC # =============================================================================== def _plotFSC(self, a, fscFile): resolution = [] fsc = [] fscDoc = SpiderDocFile(fscFile) for values in fscDoc: resolution.append(1 / values[1]) fsc.append(values[2]) self.maxfsc = max(fsc) self.minInv = min(resolution) self.maxInv = max(resolution) a.plot(resolution, fsc) from matplotlib.ticker import FuncFormatter a.xaxis.set_major_formatter(FuncFormatter(self._formatFreq)) a.set_ylim([-0.1, 1.1]) fscDoc.close() def _showFSC(self, paramName=None): threshold = self.resolutionThresholdFSC.get() iterations = self._getIterations() groups = self._getGroups() if self.isGoldStdProt(): template = 'fscdoc_m_%02d.stk' title = 'Masked FSC' else: template = 'fscdoc_%02d.stk' title = 'FSC' if self.groupFSC == 0: # group by iterations files = [(it, self._getFinalPath(template % it)) for it in iterations] legendPrefix = 'iter' else: it = iterations[-1] # show only last iteration legendPrefix = 'group' def group(f): # retrieve the group number return int(f.split('_')[-1].split('.')[0]) groupFiles = glob(self._getFinalPath('ofscdoc_%02d_???.stk' % it)) groupFiles.sort() files = [(group(f), f) for f in groupFiles if group(f) in groups] if not files: # empty files return [self.errorMessage("Please select valid groups to display", title="Wrong groups selection")] plotter = EmPlotter(windowTitle='Resolution FSC') a = plotter.createSubPlot(title, 'Angstroms^-1', 'FSC') legends = [] for it, fscFile in files: if os.path.exists(fscFile): self._plotFSC(a, fscFile) legends.append('%s %d' % (legendPrefix, it)) else: print("Missing file: ", fscFile) # plot final FSC curve (from BP) if self.groupFSC == 0 and not self.isGoldStdProt(): lastIter = self.protocol._getLastIterNumber() if lastIter in iterations: fscFinalFile = self._getFinalPath('ofscdoc_%02d.stk' % lastIter) if os.path.exists(fscFinalFile): self._plotFSC(a, fscFinalFile) legends.append('final') if threshold < self.maxfsc: a.plot([self.minInv, self.maxInv], [threshold, threshold], color='black', linestyle='--') plotter.showLegend(legends) a.grid(True) return [plotter] def _iterAngles(self, it): """ Iterate over the angular distribution for a given iteration. """ # Get the alignment files of each group for this iteration if self.isGoldStdProt(): template = 'align_%02d_???_s?.stk' else: template = 'align_%02d_???.stk' files = glob(self._getFinalPath(template % it)) for anglesFile in files: alignDoc = SpiderDocFile(anglesFile) for values in alignDoc: theta = values[1] phi = values[2] if theta > 90: theta = abs(180. - theta) phi += 180 yield phi, theta alignDoc.close() def _displayAngDist(self, *args): iterations = self._getIterations() nparts = self.protocol.inputParticles.get().getSize() views = [] if self.displayAngDist == ANGDIST_2DPLOT: for it in iterations: if it == 1: print("Orientations for the first iteration cannot be plotted. " "Skipping..") continue anglesSqlite = self._getFinalPath('angular_dist_%03d.sqlite' % it) title = 'Angular distribution iter %03d' % it plotter = EmPlotter(windowTitle=title) self.createAngDistributionSqlite(anglesSqlite, nparts, itemDataIterator=self._iterAngles(it)) plotter.plotAngularDistributionFromMd(anglesSqlite, title) views.append(plotter) else: it = iterations[-1] print("Using last iteration: ", it) anglesSqlite = self._getFinalPath('angular_dist_%03d.sqlite' % it) self.createAngDistributionSqlite(anglesSqlite, nparts, itemDataIterator=self._iterAngles(it)) volumes = self.getVolumeNames(it) vol = self.protocol.outputVolume volOrigin = vol.getOrigin(force=True).getShifts() samplingRate = vol.getSamplingRate() views.append(ChimeraAngDist(volumes[0], self.protocol._getTmpPath(), voxelSize=samplingRate, volOrigin=volOrigin, angularDistFile=anglesSqlite, format="spider")) return views