Source code for tomo.protocols.protocol_import_coordinates

# coding=utf-8
# **************************************************************************
# *
# * Authors:     Adrian Quintana (adrian@eyeseetea.com) [1]
# *
# * [1] EyeSeeTea Ltd, London, UK
# *
# * 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'
# *
# **************************************************************************

import os
from os.path import basename

from pyworkflow import BETA
import pyworkflow.utils as pwutils

import pyworkflow.protocol.params as params
from pyworkflow.plugin import Domain
from pyworkflow.utils import copyFile

from ..objects import SetOfCoordinates3D
from .protocol_base import ProtTomoImportFiles
from ..convert import TomoImport
from ..utils import existsPlugin

import tomo.constants as const

IMPORT_FROM_AUTO = 'auto'
IMPORT_FROM_TXT = 'txt'
IMPORT_FROM_SQLITE = 'sqlite'
IMPORT_FROM_EMAN = 'eman'
IMPORT_FROM_DYNAMO = 'dynamo'
IMPORT_FROM_CHOICES = [IMPORT_FROM_AUTO, IMPORT_FROM_TXT, IMPORT_FROM_SQLITE,
                       IMPORT_FROM_EMAN, IMPORT_FROM_DYNAMO]


[docs]class ProtImportCoordinates3D(ProtTomoImportFiles): """Protocol to import a set of tomograms to the project""" _outputClassName = 'SetOfCoordinates3D' _label = 'import set of coordinates 3D' _devStatus = BETA def _getImportChoices(self): """ Return a list of possible choices from which the import can be done. (usually packages formats such as: xmipp3, eman2, relion...etc. """ importChoices = [IMPORT_FROM_AUTO, IMPORT_FROM_TXT, IMPORT_FROM_SQLITE] if existsPlugin('emantomo'): importChoices.append(IMPORT_FROM_EMAN) if existsPlugin('dynamo'): importChoices.append(IMPORT_FROM_DYNAMO) return importChoices def _getDefaultChoice(self): return 0 def __init__(self, **args): ProtTomoImportFiles.__init__(self, **args) self.OUTPUT_PREFIX = "outputCoordinates" def _defineParams(self, form): ProtTomoImportFiles._defineParams(self, form) form.addParam('boxSize', params.IntParam, label='Box size') form.addParam('importTomograms', params.PointerParam, pointerClass='SetOfTomograms', label='Input tomograms', help='Select the tomograms/tomogram for which you ' 'want to import coordinates. The file names of the tomogram and ' 'coordinate files must be the same.') def _insertAllSteps(self): self._insertFunctionStep('importCoordinatesStep', self.samplingRate.get()) # --------------------------- STEPS functions -----------------------------
[docs] def importCoordinatesStep(self, samplingRate): importTomograms = self.importTomograms.get() suffix = self._getOutputSuffix(SetOfCoordinates3D) coordsSet = self._createSetOfCoordinates3D(importTomograms, suffix) coordsSet.setSamplingRate(samplingRate) coordsSet.setPrecedents(importTomograms) coordsSet.setBoxSize(self.boxSize.get()) if self.getImportFrom() == IMPORT_FROM_SQLITE: sqliteFile = self.getMatchFiles()[0] newFileName = self._getPath(basename(sqliteFile)) copyFile(sqliteFile, newFileName) coordsSet._mapperPath.set('%s, %s' % (newFileName, '')) coordsSet.load() else: ci = self.getImportClass() for tomo in importTomograms.iterItems(): tomoName = basename(os.path.splitext(tomo.getFileName())[0]) for coordFile, fileId in self.iterFiles(): fileName = basename(os.path.splitext(coordFile)[0]) if tomo is not None and tomoName == fileName: # Parse the coordinates in the given format for this micrograph if self.getImportFrom() == IMPORT_FROM_EMAN or self.getImportFrom() == IMPORT_FROM_TXT: def addCoordinate(coord, x, y, z): coord.setVolume(tomo.clone()) coord.setPosition(x, y, z, const.BOTTOM_LEFT_CORNER) coordsSet.append(coord) ci.importCoordinates3D(coordFile, addCoordinate) elif self.getImportFrom() == IMPORT_FROM_DYNAMO: ci(coordFile, coordsSet, tomo.clone()) args = {} args[self.OUTPUT_PREFIX] = coordsSet self._defineOutputs(**args) self._defineSourceRelation(self.importTomograms, coordsSet)
# --------------------------- INFO functions ------------------------------ def _hasOutput(self): return self.hasAttribute('outputCoordinates3D') def _getCoordsMessage(self): return "Coordinates %s" % self.getObjectTag('outputCoordinates3D') def _summary(self): summary = [] if self._hasOutput(): summary.append("%s imported from:\n%s" % (self._getCoordsMessage(), self.getPattern())) summary.append(u"Sampling rate: *%0.2f* (Å/px)" % self.samplingRate.get()) return summary def _methods(self): methods = [] if self._hasOutput(): methods.append(" %s imported with a sampling rate *%0.2f*" % (self._getCoordsMessage(), self.samplingRate.get()),) return methods def _getVolumeFileName(self, fileName, extension=None): if extension is not None: baseFileName = "import_" + str(basename(fileName)).split(".")[0] + ".%s" % extension else: baseFileName = "import_" + str(basename(fileName)).split(":")[0] return self._getExtraPath(baseFileName) def _validate(self): errors = [] try: next(self.iterFiles()) except StopIteration: errors.append('No files matching the pattern %s were found.' % self.getPattern()) else: if self.getImportFrom() == IMPORT_FROM_SQLITE: matches = self.getMatchFiles() numberMatches = len(matches) if numberMatches > 1: errors.append('Only one sqlite file can be introduced at once. Introduced path - pattern ' 'combinations result in\n%s' % ' '.join(matches)) else: tomoFiles = [pwutils.removeBaseExt(file) for file in self.importTomograms.get().getFiles()] coordFiles = [pwutils.removeBaseExt(file) for file, _ in self.iterFiles()] numberMatches = len(set(tomoFiles) & set(coordFiles)) if numberMatches == 0: errors.append("Cannot relate tomogram and coordinate files. In order to stablish a " "relation, the filename of the corresponding tomogram and coordinate " "files must be equal.") return errors def _warnings(self): warnings = [] if self.getImportFrom() != IMPORT_FROM_SQLITE: tomoFiles = [pwutils.removeBaseExt(file) for file in self.importTomograms.get().getFiles()] coordFiles = [pwutils.removeBaseExt(file) for file, _ in self.iterFiles()] numberMatches = len(set(tomoFiles) & set(coordFiles)) if not existsPlugin('emantomo'): warnings.append('Plugin *scipion-em-emantomo* has not being installed. Please, install the Plugin to ' 'import Eman related formats (currently supported formats: ".json"). Otherwise, the protocol ' 'may have unexpected outputs if Eman files are attempted to be imported.\n') if not existsPlugin('dynamo'): warnings.append('Plugin *scipion-em-dynamo* has not being installed. Please, install the Plugin to ' 'import Dynamo related formats (currently supported formats: ".tbl"). Otherwise, the protocol ' 'may have unexpected outputs if Dynamo files are attempted to be imported.\n') if numberMatches < max(len(tomoFiles), len(coordFiles)): warnings.append("Couldn't find a correspondence between all cordinate and tomogram files. " "Association is performed in terms of the file name of the Tomograms and the coordinates. " "(without the extension). For example, if a Tomogram file is named Tomo_1.mrc, the coordinate " "file to be associated to it should be named Tomo_1.ext (being 'ext' any valid extension " "- '.txt', '.tbl', '.json').\n") mismatches_coords = set(coordFiles).difference(tomoFiles) if mismatches_coords: warnings.append("The following coordinate files will not be associated to any Tomogram " "(name without extension):") for file in mismatches_coords: warnings.append("\t%s" % file) warnings.append("\n") mismatches_tomos = set(tomoFiles).difference(coordFiles) if mismatches_tomos: warnings.append("The following Tomogram files will not be associated to any coordinates " "(name without extension):") for file in mismatches_tomos: warnings.append("\t%s" % file) warnings.append("\n") return warnings # ------------------ UTILS functions --------------------------------------
[docs] def getImportFrom(self): importFrom = self._getImportChoices()[self.importFrom.get()] if importFrom == IMPORT_FROM_AUTO: importFrom = self.getFormat() return importFrom
[docs] def getFormat(self): for coordFile, _ in self.iterFiles(): if coordFile.endswith('.txt'): return IMPORT_FROM_TXT elif coordFile.endswith('.json') and existsPlugin('emantomo'): return IMPORT_FROM_EMAN elif coordFile.endswith('.tbl') and existsPlugin('dynamo'): return IMPORT_FROM_DYNAMO elif coordFile.endswith('.sqlite'): return IMPORT_FROM_SQLITE return -1
[docs] def getImportClass(self): """ Return the class in charge of importing the files. """ importFrom = self.getImportFrom() if importFrom == IMPORT_FROM_EMAN: EmanImport = Domain.importFromPlugin('emantomo.convert', 'EmanTomoImport', errorMsg='Eman is needed to import .json or ' '.box files', doRaise=True) return EmanImport(self, None) elif importFrom == IMPORT_FROM_DYNAMO: readDynCoord = Domain.importFromPlugin("dynamo.convert.convert", "readDynCoord") return readDynCoord elif importFrom == IMPORT_FROM_TXT: return TomoImport(self) else: self.importFilePath = '' return None