We would like to assume you would like to implement a learner that learns a certain model from the data and that you would subsequently like to have a predictor node that uses the learned model in order to classify new data. To accomplish this, you need a facility to pass the learned model from the learner to the predictor. The KNIME framework provides this functionality using the ModelPort concept. To roughly explain this concept we will now create the learned model for our numeric binner and write the interval bounds for every bin into a model. For this purpose it is necessary to overwrite the `saveModelContent`

method of the `NodeModel`

. If we had a node with a ModelInport we would have to overwrite the `loadModelContent`

method in order to be able to load the model when it is connected to the inport. Although it is possible to write your model directly to the `ModelContent`

object it is good practice and highly recommended to have an object that represents the external model of your node and which is solely responsible for the loading from and saving to the `ModelContent`

. In our case we create a class `NumericBinModel`

. It is then very easy to share your model with other nodes. To increase the usability of the model we store the lower and upper bound as an interval for every bin. Since we only have a `ModelOutport`

we only have to implement the `saveTo`

method, as can be seen below:

/** * Saves this model to the model content * @param modelContent the model content to save to. */`public void`

saveTo(`final`

ModelContentWO modelContent) { modelContent.addInt(NUMBER_OF_BINS, m_intervals.size());`int`

intervalNr = 0;`for`

(Interval interval : m_intervals) { ModelContentWO intervalModel = modelContent.addModelContent( INTERVAL + intervalNr++); intervalModel.addDouble(LOWER_BOUND, interval.getLowerBound()); intervalModel.addDouble(UPPER_BOUND, interval.getUpperBound()); } }

The interval simply stores the lower bound upper bound pair. In addition the model provides some methods to add intervals and retrieve the intervals:

/** * * @param binNumber the number of the bin for which the lower bound * should be returned * @return the lower bound of the specified interval. */`public double`

getLowerBoundForInterval(`final int`

binNumber) {`return`

m_intervals.get(binNumber).getLowerBound(); } /** * * @param binNumber the number of the bin for which the upper bound * should be returned * @return the upper bound of the specified interval. */`public double`

getUpperBoundForInterval(`final int`

binNumber) {`return`

m_intervals.get(binNumber).getUpperBound(); } /** * * @return the number of bins, i.e. intervals. */`public int`

getNumberOfBins() {`return`

m_intervals.size(); } /** * Adds an interval to this model. * @param lowerBound the lower bound of the interval * @param upperBound the upper bound of the interval */`public void`

addInterval(`final double`

lowerBound,`final double`

upperBound) { Interval interval =`new`

Interval(lowerBound, upperBound); m_intervals.add(interval); }

Now, we have to fill the model in the for-loop of the `NodeModel`

's `execute`

method:

...`double`

intervalUpperBound = lowerBound; // create the external model m_model =`new`

NumericBinModel();`double`

intervalLowerBound = lowerBound;`for`

(`int`

i = 0; i < m_numberOfBins.getIntValue(); i++) { intervalLowerBound = intervalUpperBound; intervalUpperBound += interval; // fill the external model m_model.addInterval(intervalLowerBound, intervalUpperBound); splitPoints.add(intervalUpperBound); // fill the bins with empty representations m_bins[i] =`new`

NumericBin(); } ...

Once the model has been filled with the information about the intervals it is possible to save it in the `saveModelContent`

method of the `NodeModel`

:

/** * Only the saveModelContent method has to be overwritten, since there is * only a ModelOutport. * * @see de.unikn.knime.core.node.NodeModel#saveModelContent(int, * de.unikn.knime.core.node.ModelContentWO) */ @Override`protected void`

saveModelContent(`final int`

index,`final`

ModelContentWO modelContent)`throws`

InvalidSettingsException { m_model.saveTo(modelContent); }

Since we now provide an external model of our node we have to add a `ModelOutport`

. This is completed in the constructor of the `NodeModel`

, where the number of DataIn- and Outports is defined with the first two parameters and the number of ModelIn- and Outports with the last two parameters. Since we have no ModelInport and one ModelOutport the resulting new constructor looks like this:

/** * Constructor for the node model. */`protected`

NumericBinnerNodeModel() { // we have one inport for the numeric data to bin // and two outports: // one for the original data with the binning information appended // and one for the bins and their used interval bounds.`super`

(1, 1, 0, 1); }

Having adapted your constructor in this way you will notice the following error the next time you start your workbench:

ERROR NumericBinnerNodeFactory CODING PROBLEM Missing or surplus predictor output port name

To avoid this you have to adapt your node description, which is explained in the next section.