StackGenVis: Alignment of Data, Algorithms, and Models for Stacking Ensemble Learning Using Performance Metrics
https://doi.org/10.1109/TVCG.2020.3030352
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
120 lines
3.1 KiB
120 lines
3.1 KiB
4 years ago
|
/**
|
||
|
* Implementation detail
|
||
|
*/
|
||
|
function Node(handler) {
|
||
|
this.description = handler.description || "unnamed";
|
||
|
this.incoming = handler.incoming || function (ctx, event) { ctx.sendNext(event) };
|
||
|
this.outgoing = handler.outgoing || function (ctx, event) { ctx.sendNext(event) };
|
||
|
this.next = null;
|
||
|
this.prev = null;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Implementation of the Pipeline class
|
||
|
* Pipeline is a bi-directional, ordered chain of functions. Each function in the pipeline
|
||
|
* communicates with the next function through an interface provided by the pipeline.
|
||
|
*
|
||
|
* Functions inside the pipeline need to accept events and context objects. Context objects provide a
|
||
|
* way to communicate with the next or previous functions and access to pipe-level global variables.
|
||
|
*
|
||
|
* 'Pipeline' is inspired by pipelines of Java's netty and grizzly projects. It implements a
|
||
|
* bi-directional 'intercepting-filter.'
|
||
|
*
|
||
|
* The implementation of based on a linked-list.
|
||
|
*/
|
||
|
function Pipeline(stream) {
|
||
|
var self = this;
|
||
|
this.first = null;
|
||
|
this.last = null;
|
||
|
this.state = {};
|
||
|
|
||
|
this.addHandler = function (handler) {
|
||
|
var node = new Node(handler);
|
||
|
if (self.first === null) {
|
||
|
self.first = node;
|
||
|
self.last = node;
|
||
|
node.next = null;
|
||
|
}
|
||
|
else {
|
||
|
self.last.next = node;
|
||
|
node.prev = self.last;
|
||
|
self.last = node;
|
||
|
node.next = null;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
this.pushIncoming = function (evt) {
|
||
|
|
||
|
self.first.incoming(makeCtx(self.first, stream, true, self.state), evt);
|
||
|
};
|
||
|
|
||
|
this.pushOutgoing = function (evt) {
|
||
|
|
||
|
self.last.outgoing(makeCtx(self.last, stream, false, self.state), evt);
|
||
|
};
|
||
|
|
||
|
this.pushIncomingData = function (data) {
|
||
|
|
||
|
self.first.incoming(makeCtx(self.first, stream, true, self.state), {
|
||
|
eventType: "data",
|
||
|
data: data
|
||
|
});
|
||
|
};
|
||
|
|
||
|
this.pushOutgoingData = function (data) {
|
||
|
|
||
|
self.last.outgoing(makeCtx(self.last, stream, false, self.state), {
|
||
|
eventType: "data",
|
||
|
data: data
|
||
|
});
|
||
|
};
|
||
|
|
||
|
|
||
|
this.toString = function () {
|
||
|
var nodes = [];
|
||
|
var node = self.first;
|
||
|
while (node !== null) {
|
||
|
nodes.push(node.description);
|
||
|
node = node.next;
|
||
|
}
|
||
|
return nodes.join(","); //TODO add 'state' object to the output as well
|
||
|
};
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
function makeCtx(node, stream, isIncoming, stateobj) {
|
||
|
|
||
|
var incomingCtx = function (evt) {
|
||
|
if (node.next !== null) {
|
||
|
node.next.incoming(makeCtx(node.next, stream, true, stateobj), evt);
|
||
|
}
|
||
|
};
|
||
|
var outgoingCtx = function (evt) {
|
||
|
if (node.prev != null) {
|
||
|
node.prev.outgoing(makeCtx(node.prev, stream, false, stateobj), evt);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
if (isIncoming) {
|
||
|
return {
|
||
|
sendNext: incomingCtx,
|
||
|
sendPrev: outgoingCtx,
|
||
|
stream: stream,
|
||
|
state: stateobj
|
||
|
};
|
||
|
}
|
||
|
else {
|
||
|
return {
|
||
|
sendNext: outgoingCtx,
|
||
|
sendPrev: incomingCtx,
|
||
|
stream: stream,
|
||
|
state: stateobj
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
exports.makePipe = function (stream) {
|
||
|
return new Pipeline(stream);
|
||
|
}
|