package de.mpicbg.knime.scripting.r.generic; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.nio.file.Files; import java.util.Collections; import javax.swing.ImageIcon; import org.knime.core.node.CanceledExecutionException; import org.knime.core.node.ExecutionContext; import org.knime.core.node.ExecutionMonitor; import org.knime.core.node.InvalidSettingsException; import org.knime.core.node.port.PortObject; import org.knime.core.node.port.PortObjectSpec; import org.knime.core.node.port.PortType; import org.rosuda.REngine.Rserve.RConnection; import de.mpicbg.knime.scripting.core.ScriptProvider; import de.mpicbg.knime.scripting.core.ScriptingModelConfig; import de.mpicbg.knime.scripting.core.exceptions.KnimeScriptingException; import de.mpicbg.knime.scripting.r.RColumnSupport; import de.mpicbg.knime.scripting.r.RUtils; import de.mpicbg.knime.scripting.r.node.snippet.RSnippetNodeModel; import de.mpicbg.knime.scripting.r.plots.AbstractRPlotNodeModel; /** * A generic R node which creates a figure from a genericR input. * * @author Holger Brandl */ public class GenericRPlotNodeModel extends AbstractRPlotNodeModel { private static ScriptingModelConfig nodeModelConfig = new ScriptingModelConfig( createPorts(1, RPortObject.TYPE, RPortObject.class), // 1 generic input new PortType[0], // no output new RColumnSupport(), true, // no script false, // open in functionality false); // use chunk settings public GenericRPlotNodeModel() { super(nodeModelConfig); } /** * This constructor is just necessary to allow superclasses to create plot nodes with ouputs */ public GenericRPlotNodeModel(ScriptingModelConfig cfg) { super(cfg); } /** * {@inheritDoc} */ @Override protected PortObjectSpec[] configure(final PortObjectSpec[] inSpecs) throws InvalidSettingsException { super.configure(inSpecs); return new PortObjectSpec[0]; } /** * Prepares the ouput tables of this nodes. As most plot-nodes won't have any data output, this method won't be * overridden in most cases. Just in case a node should have both (an review and a data table output), you may * override it. * @throws KnimeScriptingException */ protected PortObject[] prepareOutput(ExecutionContext exec, RConnection connection) throws KnimeScriptingException { /*PortObject[] outPorts = new PortObject[1]; ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { ImageIO.write(m_image, "png", baos); } catch (IOException e) { throw new KnimeScriptingException(e.getMessage()); } PNGImageContent content = new PNGImageContent(baos.toByteArray()); outPorts[0] = new ImagePortObject(content, IM_PORT_SPEC);*/ return new PortObject[0]; } /** * {@inheritDoc} */ @Override protected PortObject[] executeImpl(PortObject[] inData, ExecutionContext exec) throws Exception { PortObject[] nodeOutput = null; try { // 1) restore the workspace in a different server session if(inData[0] instanceof RPortObject) { m_con = RUtils.createConnection(); RUtils.loadGenericInputs(Collections.singletonMap(RSnippetNodeModel.R_INVAR_BASE_NAME, ((RPortObject)inData[0]).getFile()), m_con); } // just needed for old dose response node else super.executeImpl(inData, exec); // 2) create the figure adaptHardwiredTemplateToContext(ScriptProvider.unwrapPortSpecs(inData)); try { createInternals(m_con); saveFigureAsFile(); } catch (KnimeScriptingException e) { closeRConnection(); throw e; } // 3) prepare the output tables (which will do nothing in most cases, as most plot nodes don't have output) nodeOutput = prepareOutput(exec, m_con); // 3) close the connection to R (which will also delete the temporary workspace on the server) closeRConnection(); } catch(Exception e) { closeRConnection(); throw e; } return nodeOutput; } /** * overwrite this method to support old internal image format (ImageIcon) */ @Override protected void saveInternals(File nodeDir, ExecutionMonitor executionMonitor) throws IOException, CanceledExecutionException { if (m_rWorkspaceFile != null) { File f = new File(nodeDir, "pushtable.R"); Files.copy(m_rWorkspaceFile.toPath(), f.toPath()); } if (m_image != null) { File imageFile = new File(nodeDir, "image.bin"); FileOutputStream f_out = new FileOutputStream(imageFile); // Write object with ObjectOutputStream ObjectOutputStream obj_out = new ObjectOutputStream(new BufferedOutputStream(f_out)); // Write object out to disk obj_out.writeObject(new ImageIcon(m_image)); obj_out.close(); } } /** * {@inheritDoc} */ @Override protected void openIn(PortObject[] inData, ExecutionContext exec) throws KnimeScriptingException { } }