PAVED is an interactive visualization built to ease cost-benefit trade-offs when deciding among a set of multi-attribute items.
About PAVED PAVED uses parallel coordinates as a visualization technique to provide a compact yet lossless overview of all items and their properties. It facilitates multi-attribute decisions by offering simple interactions for filtering out undesired items, exploring attribute conflicts, and bookmarking favorite items. It can be used for decisions in professional contexts like product development or engineering design but also helps with personal decisions like apartment rental or car purchase.
- Responsive design
- Heterogeneous attribute types (numerical, categorical, boolean)
- Axis re-ordering via drag and drop
- Various filtering capabilities: standard selection rectangle, preference brush, gradient brush, line brush
- Bookmarking of polylines
- Curve smoothing
- React wrapper (coming soon)
- Demo application with test dataset
- API documentation (coming soon)
The setup requires Node.js v16 or higher.
git clone https://github.com/fraunhofer-igd-iva/pavedjs.git
cd pavedjs
npm install
npm run build
This generates the production build in ./lib/
.
From there, the library can be embedded in an HTML document by adding it as an external script file using a relative path:
`<script src="../pavedjs/lib/index.js"></script>`
The same relative path can also be used to add it as a local dependency to your package.json
:
"dependencies": {
"pavedjs": "file:../pavedjs/lib"
}
You can also add the library as a git dependency to your package.json
:
"dependencies": {
"pavedjs": "fraunhofer-igd-iva/pavedjs"
}
The following usage examples assume an installation via external script file.
To try out this example, open the file ./src/Examples/MinimalUsageExamplePC.html
in a browser of your choice.
// Generate some demo data
const rows = [];
const categories = ["Category 1", "Category 2", "Category 3"];
for (let i = 0; i < 50; ++i) {
rows.push({
"Attribute 1": Math.random() * (3.2 - 0.5) + 0.5,
"Attribute 2": Math.random() * (0.68 - 0.28) + 0.28,
"Attribute 3": categories[Math.floor(Math.random() * 3)],
"Attribute 4": Math.random() * (96 - 60) + 60,
"Attribute 5": Math.random() * (153 - 130) + 153,
});
}
// Render visualization
const chart = PAVEDJS.asParallelCoordinates(document.body, rows);
To try out this example, open the file ./src/Examples/MinimalUsageExamplePAVED.html
in a browser of your choice.
// Generate some demo data
const rows = [];
const categories = ["Category 1", "Category 2", "Category 3"];
for (let i = 0; i < 50; ++i) {
rows.push({
"Attribute 1": Math.random() * (3.2 - 0.5) + 0.5,
"Attribute 2": Math.random() * (0.68 - 0.28) + 0.28,
"Attribute 3": categories[Math.floor(Math.random() * 3)],
"Attribute 4": Math.random() * (96 - 60) + 60,
"Attribute 5": Math.random() * (153 - 130) + 153,
});
}
// Add optimization directions as meta data for attributes
const columns = [
{
name: "Attribute 1",
obj: "MIN",
},
{
name: "Attribute 2",
obj: "MAX",
},
{
name: "Attribute 5",
obj: "MIN",
},
];
const data = {
columns: columns,
rows: rows,
};
// Render visualization
const chart = PAVEDJS.asPAVED(document.body, data);
To try out this example, open the file ./src/Examples/AdvancedUsageExamplePAVED.html
in a browser of your choice.
// Generate some demo data
const rows = [];
const categories = ["Category 1", "Category 2", "Category 3"];
for (let i = 0; i < 50; ++i) {
rows.push({
"Attribute 1": Math.random() * (3.2 - 0.5) + 0.5,
"Attribute 2": Math.random() * (0.68 - 0.28) + 0.28,
"Attribute 3": categories[Math.floor(Math.random() * 3)],
"Attribute 4": Math.random() * (96 - 60) + 60,
"Attribute 5": Math.random() * (153 - 130) + 153,
});
}
// Configure visualization
const options = {
padding: {
top: 50,
right: 40,
bottom: 60,
left: 40,
},
};
const builder = PAVEDJS.builder(rows, options);
builder
.registerOptimizationDirections({
"Attribute 1": PAVEDJS.OPTIMIZATION_TYPE.MIN,
"Attribute 2": PAVEDJS.OPTIMIZATION_TYPE.MAX,
"Attribute 4": PAVEDJS.OPTIMIZATION_TYPE.MIN,
})
.registerHEXColors({
"Attribute 1": "#FF0000",
"Attribute 2": "#00FF00",
"Attribute 4": "#0000FF",
})
.registerUnits({
"Attribute 1": "mm",
"Attribute 2": "EUR",
"Attribute 4": "mm",
});
// Render visualization
const chart = builder.buildPAVED(document.body);
// Subsequent modifications. Do not forget to update the chart.
chart
.setTheme(PAVEDJS.THEME.DARK)
.setHoveredIDChangeHandler((id) => {
console.log("Hovered ID", id);
})
.setFlaggedIDsChangeHandler((ids) => {
console.log("Flagged IDs", ids);
})
.update();
The following changes are typically triggered by user interaction, e.g., by button clicks when using the example file. Data updates must not change the type of an attribute, i.e., from nominal to numerical or vice versa.
// Load new data
const alternativeRows = [];
const categories = ["Category 1", "Category 2", "Category 3", "Category 4"];
for (let i = 0; i < 10; ++i) {
alternativeRows.push({
"Attribute 2": Math.random() * (0.55 - 0.13) + 0.13,
"Attribute 3": categories[Math.floor(Math.random() * 4)],
"Attribute 4": Math.random() * (162 - 121) + 121,
"Attribute 5": Math.random() * (3.2 - 0.8) + 0.8,
"Attribute 6": Math.random(),
});
}
chart
.setRows(alternativeRows)
//.setDimensionSubset(["Attribute 3", "Attribute 4"])
.update();
// Activate gradient brush on a particular attribute
chart
.enableColorCoding({
type: PAVEDJS.COLOR_CODING.GRADIENT_BRUSH,
attribute: "Attribute 4",
})
.update();
// Activate curve smoothing
chart
.setCurveSmoothing(true)
.update();
Feature | Parallel Coordinates | PAVED |
---|---|---|
Heterogeneous attributes | ✅ | ✅ |
Unit metadata | ✅ | ✅ |
Axis re-ordering | ✅ | ✅ |
Light and dark mode | ✅ | ✅ |
Polyline highlighting on hover | ✅ | ✅ |
Standard selection rectangle | ✅ | ✅ |
Optimization direction metadata | ❌ | ✅ |
Objective color metadata | ❌ | ✅ |
Axis tooltips on hover | ❌ | ✅ |
Preference brush | ❌ | ✅ |
Gradient brush | ❌ | ✅ |
Line brush | ❌ | ✅ |
Polyline bookmarks | ❌ | ✅ |
Curve smoothing | ❌ | ✅ |
A demo application of PAVED is deployed at https://paved.iva.igd.fraunhofer.de/. It showcases a dataset containing 168 electric motors. Which of the motor designs offers the best compromise? Compare five quality criteria and nine geometry parameters to decide. The data is provided by LCM.
Coming soon.
Coming soon.
Lena Cibulski, Hubert Mitterhofer, Thorsten May, Jörn Kohlhammer. PAVED: Pareto Front Visualization for Engineering Design. In Computer Graphics Forum, 39(3), pp. 405-416, doi:10.1111/cgf.13990, 2020. 📄Paper 🎬Talk (12 Min.)
PAVED.js depends on
Development Dependencies Webpack is used as build tool. PAVED.js itself is written in TypeScript.
PAVED.js is released under the MIT license. See the LICENSE file for detailed information.
We welcome and appreciate all contributions to this project. Before getting started, try searching the issue tracker for known issues or fixes. For significant changes, in particular those that are based on your personal opinion, please open an issue first describing the changes you would like to make.
Lena Cibulski, Fraunhofer IGD
This work was funded by the EC Horizon 2020 programme under grant agreement n°768892.
This work has been supported by the Linz Center of Mechatronics within the framework of the Austrian COMET-K2 program.