Facets

Facets

Muze sets the axes as the ground work for drawing its visualization. Once the axes are set, using multiple sets of dimensions we can convert a single chart into multiple set of charts by dividing each chart with a combination of unique sets of values.

For example, consider that we have the distribution of Horsepower for each Cylinder. This way we get to know what is the average horsepower generated by each cylinder. However, what if we wanted to know this average of the cars coming out of every country.

We will need to draw multiple charts for each combination of Origin and Cylinders. Muze can do just that for you. All you have to do is give in the hierarchy:

This creates three separate bar charts as shown below:

main
run-button
run-button
reset-button
//@preamble-start
loadData('/static/cars.json')
  .then((res) => {
let node = document.getElementById('chart-container');

const env = muze();
const canvas = env.canvas();
const DataModel = muze.DataModel;


const schema = [
	{ name: 'Name', type: 'dimension' },
	{ name: 'Miles_per_Gallon', type: 'measure', defAggFn: 'avg' },
	{ name: 'Cylinders', type: 'dimension' },
	{ name: 'Displacement', type: 'measure', defAggFn: 'max' },
	{ name: 'Horsepower', type: 'measure', defAggFn: 'max' },
	{ name: 'Weight_in_lbs', type: 'measure', defAggFn: 'avg' },
	{ name: 'Acceleration', type: 'measure', defAggFn: 'avg' },
	{ name: 'Year', type: 'dimension' },
	{ name: 'Origin', type: 'dimension' } /* by default dimension */
];
const dataModelInstance = new DataModel(res, schema);
//@preamble-end
canvas
  		.data(dataModelInstance)
		.width(500)
		.height(800)
		.rows(['Origin', 'Cylinders'])
	    .columns(['Horsepower']) /* Year is a temporal field */
		.mount(node) /* Attaching the canvas to DOM element */
});

The above example is what is called faceting. We have faceted our chart by Origin and as such we get a row for each unique facet.

We can still want to compare the makers of all the cars in those countries and how much power the cars of each cylinder type from a particular maker is. That is to say, we want to see all the unique Maker, Cylinder and Origin combinations for the average distribution of Horsepower:

main
run-button
run-button
reset-button
//@preamble-start
loadData('/static/cars.json')
  .then((res) => {
let node = document.getElementById('chart-container');

const env = muze();
const canvas = env.canvas();
const DataModel = muze.DataModel;


const schema = [
	{ name: 'Name', type: 'dimension' },
	{ name: 'Miles_per_Gallon', type: 'measure', defAggFn: 'avg' },
	{ name: 'Cylinders', type: 'dimension' },
	{ name: 'Displacement', type: 'measure', defAggFn: 'max' },
	{ name: 'Horsepower', type: 'measure', defAggFn: 'max' },
	{ name: 'Weight_in_lbs', type: 'measure', defAggFn: 'avg' },
	{ name: 'Acceleration', type: 'measure', defAggFn: 'avg' },
	{ name: 'Year', type: 'dimension' },
	{ name: 'Origin', type: 'dimension' } /* by default dimension */
];
const dataModelInstance = new DataModel(res, schema);
//@preamble-end
canvas
  		.data(dataModelInstance)
		.width(4000)
		.height(400)
		.rows(['Origin', 'Cylinders'])
	    .columns(['Year', 'Horsepower']) /* Year is a temporal field */
		.mount(node) /* Attaching the canvas to DOM element */
});

So what exactly do we mean by Faceting?

alt text

The cube is faceted by removing portions from the cube.

In geometry, Faceting is the process of removing parts of a polygon, polyhedron or polytope, without creating any new vertices, which is where Faceted Search comes from. In a faceted classification system each information element is classified along multiple explicit dimensions, called facets, enabling the classifications to be accessed and ordered in multiple ways rather in any one single way.

In Muze, you are removing parts of a DataModel (or your data source) to get multiple explicit dimensional parts to the DataModel. If your DataModel was the cube in the figure, the faceted DataModel would what you get when you remove a few parts of the Model, thus getting a faceted DataModel

logo

Note

DataModel is an immutable data structure, so every time you facet it, you create a new structure which represents the actual faceting

Therefore, in the earlier example, when we facet the DataModel with the respective Row and Column fields, we are essentially creating multiple faceted DataModels with each combination of facet and based on the visual encoding applied to it, it gets transformed to respective chart.

How Muze establishes Faceting?

First, we facet the original DataModel with all the rows. We get the faceted set of DataModels. Each Faceted DataModel is created by running a selection on the original DataModel with the value of that facet. alt text

For instance, If we have three Origin values as European Union, USA and Japan in the original DataModel, we will get three DataModels, each of which has the set of fields corresponding to the particular Origin:

alt text

Similarly, for multiple sets of facets, we get multiple layers of faceted models, for example a faceting with Origin and Cylinders:

alt text

The above row faceting achieves in providing rows for each of the facet combinations.

Thereafter, we can add column facets to further expand the faceting. Consider that we need to see how the distribution for Horsepower gets affected yearly for every Origin and Cylinder:

main
run-button
run-button
reset-button
//@preamble-start
loadData('/static/cars.json')
  .then((res) => {
let node = document.getElementById('chart-container');

const env = muze();
const canvas = env.canvas();
const DataModel = muze.DataModel;


const schema = [
	{ name: 'Name', type: 'dimension' },
	{ name: 'Miles_per_Gallon', type: 'measure', defAggFn: 'avg' },
	{ name: 'Cylinders', type: 'dimension' },
	{ name: 'Displacement', type: 'measure', defAggFn: 'max' },
	{ name: 'Horsepower', type: 'measure', defAggFn: 'max' },
	{ name: 'Weight_in_lbs', type: 'measure', defAggFn: 'avg' },
	{ name: 'Acceleration', type: 'measure', defAggFn: 'avg' },
	{ name: 'Year', type: 'dimension' },
	{ name: 'Origin', type: 'dimension' } /* by default dimension */
];
const dataModelInstance = new DataModel(res, schema);
//@preamble-end
canvas
  		.data(dataModelInstance)
		.width(4000)
		.height(900)
        .rows(['Origin', 'Cylinders'])
        .columns(['Year', 'Horsepower'])
		.mount(node) /* Attaching the canvas to DOM element */
});

First we facet all the DataModels row-wise and then, each of the rows gets further faceted for each Year Value in the column. Here's how the above process takes place: alt text

By faceting, we can compose a whole set of visualizations based on the values in the DataModel and we can choose to do so RowWise and/or ColumnWise. Here's the output of such a faceting: