Public
Edited
Sep 7, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function createLinePlot(
featureMaps,
featureMapKey,
originalData,
yMin = null,
yMax = null,
width = 150,
height = 150
) {
const { plotData, histogramData } = preprocess1DData(
featureMaps,
featureMapKey,
originalData
);
const featureName = featureMaps["1D"][featureMapKey].feature;
const className = featureMaps["1D"][featureMapKey].class;
const classIndex = featureMaps["1D"][featureMapKey].classIndex;
const score = featureMaps["1D"][featureMapKey].importance;

const xValues = data.map((d) => d[featureName]);
const minXValue = Math.min(...xValues);
const maxXValue = Math.max(...xValues);

// Calculate yMin and yMax if not provided
if (yMin === null || yMax === null) {
const yValues = plotData.map((d) => d.y);
yMin = Math.min(...yValues);
yMax = Math.max(...yValues);
}

const linePlot = vl
.markBar() // Make a line chart
.data(plotData) // Using the provided data
.encode(
vl.color().value("black"),
vl.x().fieldO("x").title(featureName), // For x, use the x field and set the title
vl
.y()
.fieldQ("y")
.title("Output")
.scale({ domain: [yMin, yMax] }), // For y, use the y field and set the scale
vl.tooltip().fieldN("class") // For tooltips, show the class field
);

const numBins = 20;

// Calculate the bin size
const binSize = (maxXValue - minXValue) / numBins;

// Create an array of bin edges
const binEdges = Array.from(
{ length: numBins + 1 },
(_, i) => minXValue + i * binSize
);

// Determine the number of target classes
const targetClasses = [...new Set(originalData.map((d) => d.target))].sort(
(a, b) => a - b
);

// Create an object to store the bins for each class
const bins = targetClasses.reduce((acc, target) => {
acc[target] = binEdges.slice(0, -1).map((binStart, i) => ({
binStart,
binEnd: binEdges[i + 1],
count: 0,
class: target // Encode the target class in the bins' data
}));
return acc;
}, {});

// Iterate over the data and increment the count for the appropriate bin and class
originalData.forEach((d) => {
const binIndex = Math.floor((d[featureName] - minXValue) / binSize);
if (binIndex >= 0 && binIndex < numBins) {
bins[d.target][binIndex].count += 1;
}
});

// Find the maximum bin size
let maxBinSize = 0;
targetClasses.forEach((target) => {
bins[target].forEach((bin) => {
maxBinSize = Math.max(maxBinSize, bin.count);
});
});

// Dynamically create histograms for each target class
const histograms = targetClasses.map((target, index) => {
const startY = (index * height) / targetClasses.length;
const endY = ((index + 1) * height) / targetClasses.length;

return vl
.markBar()
.data(
bins[target].map((bin) => ({
...bin,
target // Add the target field to the bins' data
}))
)
.encode(
vl.y().value(startY), // Set the starting y-value based on the current index
vl.y2().value(endY), // Set the ending y-value based on the current index
vl.x().fieldQ("binStart"),
vl.x2().fieldQ("binEnd"),
vl
.opacity()
.fieldQ("count")
.scale({ domain: [0, maxBinSize], range: [0, 1] }),
// .legend({
// title: "Count",
// values: [
// roundToNearestBase(maxBinSize * 0.1, 5),
// roundToNearestBase(maxBinSize / 2, 5),
// roundToNearestBase(maxBinSize * 0.9, 5)
// ]
// }),
vl
.color()
.fieldN("target")
.scale({
domain: targetClasses.map((target) => target), // Map target indices to class names
range: targetClasses.map((target) => getColor(target))
})
.legend(null)
);
});

const zeroLine = vl
.markRule({ strokeDash: [5, 5] }) // Make a dashed line
.data([{ y: 0 }]) // At y=0
.encode(vl.y().fieldQ("y"));

return vl
.layer(...histograms, linePlot, zeroLine)
.height(height)
.width(width)
.title({
text: `${featureName} for ${className}, Score: ${score.toFixed(2)}`,
color: getColor(classIndex)
}) // Set the overall chart title
.render(); // Combine the charts using layer
}
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more