Rows + Columns + Layout Variations

In this section you will be learning how to render complex layouts by tweaking different variables in rows and columns methods. For illustration we will be using cars.csv data.

Layout construct

Muze has two simple methods using which you can create a simple chart, as well as collection of charts positioned by layout .

  • rows
  • columns

Each method takes at least one array and at most two arrays to define the layout. Only the axes and facets are placed using this layout.

canvas
    .rows([/* LEFT side of plot */], [/* RIGHT side of plot */])
    .columns([/* TOP of the plot */], [/* BOTTOM of the plot */])

alt text

It's okay if you do not get the idea completely, we will be seeing more visual examples of various layout combinations. At the end of this document, you will have an intuitive sense of how the layout is structured.

At any given point of time, if you want to examine how the layout changes with variations of rows and columns, you can edit any of the examples.

In the following sections we will be going through the variations first and then we will see a few use cases where we can use these variations.

Default axis

Lets start with drawing a simple bar chart.

main
run-button
run-button
reset-button
// DataModel instance is created from https://www.charts.com/static/cars.json data,
// https://www.charts.com/static/cars-schema.json schema and assigned to variable dm.

const env = muze();
const canvas = env.canvas();
 
canvas
	.data(dm)
    .width(600)
    .height(400)
    .rows(['Horsepower'])
    .columns(['Year'])
    .mount('#chart-container');
  

The blue print would look like

alt text

If only one field is mapped to rows and columns then x-axis will be created from the field mentioned in columns and y-axis will be created from the field mentioned in rows.

In this example Horsepower measure is plotted on the y-axis and Origin dimension is plotted on the x-axis. Hence we get a vertical bar chart.

logo

Create horizontal bar chart

If you just swap the variables of rows and columns you get horizontal bar chart.

The above example is also shorthand for

canvas.
    .rows([['Horsepower'], []])
    .columns([[], ['Year']])

Repositioning the axis

We move the y-axis to right and x-axis to top just by specifying rows and columns in the following way:

main
run-button
run-button
reset-button
// DataModel instance is created from https://www.charts.com/static/cars.json data,
// https://www.charts.com/static/cars-schema.json schema and assigned to variable dm.

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

canvas
    .data(dm)
    .width(600)
    .height(400)
    .rows([[], ['Miles_per_Gallon']])
    .columns([['Origin'], []])
    .mount('#chart-container') /* Attaching the canvas to DOM element */

alt text

Just as we mentioned in layout construct section, variables from the first array of rows goes to left side of the plot and those from the second array goes right side of the plot.

Similarly variables from first array of columns go to the top of the plot and those from the second array go to the bottom of the plot area.

Axis on both side

As you might have guessed, by specifying fields on both the sides of rows and columns we can create a dual axis chart.

main
run-button
run-button
reset-button
// DataModel instance is created from https://www.charts.com/static/cars.json data,
// https://www.charts.com/static/cars-schema.json schema and assigned to variable dm.

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

canvas
    .data(dm)
    .width(600)
    .height(400)
    .rows([['Miles_per_Gallon'], ['Horsepower']])
    .columns([['Year'], ['Year']])
    .mount('#chart-container') /* Attaching the canvas to DOM element */

alt text

If you have to create dual axis, then provide two same or different measures either in rows or columns.

.rows(['Miles_per_Gallon'], ['Horsepower'])

or

.rows(['Horsepower'], ['Horsepower'])

logo

Only one dimension for dual axes

But only one dimension can be used to create dual axes i.e. .columns(['Year'], ['Year'])

Row wise split canvas

You might be wondering what would happen if we provide two measures in one array.

main
run-button
run-button
reset-button
// DataModel instance is created from https://www.charts.com/static/cars.json data,
// https://www.charts.com/static/cars-schema.json schema and assigned to variable dm.

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

canvas
    .data(dm)
    .width(600)
    .height(800)
    .rows(['Horsepower', 'Miles_per_Gallon'])
    .columns(['Year'])
    .mount('#chart-container') /* Attaching the canvas to DOM element */

alt text

This configuration would create two charts for two measures and stack one top of another.

Dual axis in split canvas

Scale the previous illustration to add two more measures in the right array of rows.

main
run-button
run-button
reset-button
// DataModel instance is created from https://www.charts.com/static/cars.json data,
// https://www.charts.com/static/cars-schema.json schema and assigned to variable dm.

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

canvas
    .data(dm)
    .width(800)
    .height(800)
    .layers([
    	{ mark: 'line', encoding: { y: 'Horsepower', color: { value: () => '#414141' }}}
  	])
    .rows([['Horsepower', 'Miles_per_Gallon'], ['Weight_in_lbs', 'Acceleration']])
    .columns(['Year'])
    .mount('#chart-container') /* Attaching the canvas to DOM element */

alt text

This behaviour is same for columns. If you add more measures in columns then it gets split column wise.

Row faceting

So far we have been providing multiple measures to rows or columns. But if we push multiple dimensions in one array or push dimensions with measures, we can split the canvas. In this case, facets are created using the dimensions.

  • If all the variables in array are dimensions, then the last variable is used to create axis.
main
run-button
run-button
reset-button
// DataModel instance is created from https://www.charts.com/static/cars.json data,
// https://www.charts.com/static/cars-schema.json schema and assigned to variable dm.

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

canvas
    .data(dm)
  	.minUnitHeight(10)
	.minUnitWidth(10)
    .width(600)
    .height(1800)
    .rows(['Origin', 'Cylinders', 'Maker'])
    .columns(['Miles_per_Gallon'])
    .mount('#chart-container') /* Attaching the canvas to DOM element */

alt text

  • If rows and columns contains both measures and dimensions then only measures are used to create axis
main
run-button
run-button
reset-button
// DataModel instance is created from https://www.charts.com/static/cars.json data,
// https://www.charts.com/static/cars-schema.json schema and assigned to variable dm.
  
const dm = new DataModel(res, schema);
const env = muze();    
const canvas = env.canvas();    

canvas
    .data(dm)
  	.minUnitHeight(10)
	.minUnitWidth(10)
    .width(600)
    .height(1000)
    .rows(['Year', 'Origin', 'Miles_per_Gallon', 'Weight_in_lbs'])
    .columns(['Cylinders'])
    .mount('#chart-container'); /* Attaching the canvas to DOM element */

alt text

You end up getting a visualization like a table. Where cells which are intersections of rows and columns, contain charts.

Row and column faceting

If we apply the similar faceting in both rows and columns we get something called visual crosstab

main
run-button
run-button
reset-button
// DataModel instance is created from https://www.charts.com/static/cars.json data,
// https://www.charts.com/static/cars-schema.json schema and assigned to variable dm.

const dm = new DataModel(res, schema);
const env = muze();    
const canvas = env.canvas();    
canvas
    .data(dm)
  	.minUnitHeight(10)
	.minUnitWidth(10)
    .width(1600)
    .height(800)
    .rows(['Origin', 'Weight_in_lbs'])
    .columns(['Cylinders', 'Year'])
    .mount('#chart-container') /* Attaching the canvas to DOM element */

alt text

This visualization is like a table but instead of numbers you see charts. Visual crosstab is the entry point to Muze.

Specifying axis

We can place axis in one side and facets in different side by specifying from which side the axis should be picked up

main
run-button
run-button
reset-button
// DataModel instance is created from https://www.charts.com/static/cars.json data,
// https://www.charts.com/static/cars-schema.json schema and assigned to variable dm.

const dataModelInstance = new DataModel(res, schema);
canvas
    .data(dataModelInstance)
    .width(600)
    .minUnitHeight(30)
    .height(2400)
    .rows([['Cylinders', 'Year'], ['Origin']])
    .columns(['Acceleration'])
    .config({ axisFrom:{ row: 'right' } })
    .mount('#chart-container') /* Attaching the canvas to DOM element */

alt text

logo

Note

The axisFrom configuration is not applicable all the time. For cases if there is ambiguity of resolving axis this configuration is used to resolve the axis.

Wrapping up

By now, you have an intuitive sense of how layout is constructed. You might feel uncomfortable with some terminologies we used here, like faceting. Head here If you want to know more about faceting. If you are comfortable with the idea of faceting, you can directly jump to retinal encoding.