/*************************************************************************
* *
* This file is part of the 20n/act project. *
* 20n/act enables DNA prediction for synthetic biology/bioengineering. *
* Copyright (C) 2017 20n Labs, Inc. *
* *
* Please direct all queries to act@20n.com. *
* *
* 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, see <http://www.gnu.org/licenses/>. *
* *
*************************************************************************/
package com.act.biointerpretation.l2expansion;
import chemaxon.calculations.clean.Cleaner;
import chemaxon.formats.MolFormatException;
import chemaxon.formats.MolImporter;
import chemaxon.struc.RxnMolecule;
import com.act.biointerpretation.mechanisminspection.ReactionRenderer;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* Used to create drawings of a PredictionCorpus's predictions, for manual curation.
*/
public class PredictionCorpusRenderer {
private static final Logger LOGGER = LogManager.getFormatterLogger(PredictionCorpusRenderer.class);
// The filename to which to print the corpus as a json file.
private static final String PREDICTION_CORPUS_FILE_NAME = "predictions.json";
// The filename to which to print the raw list of inchis for bing search analysis
private static final String INCHI_LIST_FILE_NAME = "prediction_inchis";
// Settings for printing images
ReactionRenderer reactionRenderer;
public PredictionCorpusRenderer(ReactionRenderer reactionRenderer) {
this.reactionRenderer = reactionRenderer;
}
/**
* Renders the prediction corpus into the specified directory. Prints an image of each predicted reaction, prints
* an image of each reactor used in the corpus, and prints the corpus itself to a json file.
*
* @param predictionCorpus The corpus to render.
* @param imageDirectory The directory in which to put the files.
*/
public void renderCorpus(L2PredictionCorpus predictionCorpus, File imageDirectory) throws IOException {
// Build files for images and corpus
Map<Integer, File> predictionFileMap = getPredictionFileMap(predictionCorpus, imageDirectory);
File outCorpusFile = new File(imageDirectory, PREDICTION_CORPUS_FILE_NAME);
File inchiListFile = new File(imageDirectory, INCHI_LIST_FILE_NAME);
// Print reaction images to file.
for (L2Prediction prediction : predictionCorpus.getCorpus()) {
try {
reactionRenderer.drawRxnMolecule(getRxnMolecule(prediction), predictionFileMap.get(prediction.getId()));
} catch (IOException e) {
LOGGER.error("Couldn't render prediction %d. %s", prediction.getId(), e.getMessage());
}
}
// Print prediction corpus to file.
try {
predictionCorpus.writePredictionsToJsonFile(outCorpusFile);
} catch (IOException e) {
LOGGER.error("Couldn't print prediction corpus to file.");
}
try {
L2InchiCorpus inchiCorpus = new L2InchiCorpus(predictionCorpus.getUniqueProductInchis());
inchiCorpus.writeToFile(inchiListFile);
} catch (IOException e) {
LOGGER.error("Couldn't print product inchis to file.");
}
}
/**
* Create a file for each prediction drawing,and return a map from prediction ids to those files.
*
* @param predictionCorpus The prediction corpus.
* @param imageDir The directory in which the files should be located.
* @return A map from prediction id to the corresponding prediction's file.
*/
private Map<Integer, File> getPredictionFileMap(L2PredictionCorpus predictionCorpus, File imageDir) {
Map<Integer, File> fileMap = new HashMap<Integer, File>();
for (L2Prediction prediction : predictionCorpus.getCorpus()) {
String fileName = getPredictionFileName(prediction) + "." + reactionRenderer.getFormat();
fileMap.put(prediction.getId(), new File(imageDir, fileName));
}
return fileMap;
}
private RxnMolecule getRxnMolecule(L2Prediction prediction)
throws MolFormatException {
RxnMolecule renderedReactionMolecule = new RxnMolecule();
// Add substrates and products to molecule.
for (String substrate : prediction.getSubstrateInchis()) {
renderedReactionMolecule.addComponent(MolImporter.importMol(substrate), RxnMolecule.REACTANTS);
}
for (String product : prediction.getProductInchis()) {
renderedReactionMolecule.addComponent(MolImporter.importMol(product), RxnMolecule.PRODUCTS);
}
// Calculate coordinates with a 2D coordinate system.
Cleaner.clean(renderedReactionMolecule, 2, null);
// Change the reaction arrow type.
renderedReactionMolecule.setReactionArrowType(RxnMolecule.REGULAR_SINGLE);
return renderedReactionMolecule;
}
private String getPredictionFileName(L2Prediction prediction) {
return StringUtils.join("PREDICTION_", prediction.getId());
}
}