Retinal Encoding

In order to perceive information that is not constrained to faceting and planar encodings( rows and columns), we can resort to encodings that are sensitive to the human eye, like color, shape and size.

Colors differentiates the value of the variables by changing the color of the data points with respect to the value.

Shapes changes the shape of a data point ( like circle, square, triangle, etc) based on discrete values of a vairable.

Size affects the sizes of the visual structures, increasing or decreasing their sizes(like height, width, area, etc) based on the values mapped to them.

Color, shape and size are called retinal encoding.

In this section we are going to see how retinal encoding adds more information in a visualization.

Data

We will be using cars.json data for illustraiton.

Color encoding

First let us make a simple bar chart. Refer this tutorial for step by step instructions to make a simple 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();
const sortedDM = dm.sort([['Origin']]);
canvas
	.data(sortedDM)
  	.width(600)
  	.height(400)
  	.rows(['Horsepower'])
  	.columns(['Maker'])
  	.mount('#chart-container') /* Attaching the canvas to DOM element */

The above chart shows average Horsepower for cars produced by different car Makers.

Once the above chart is created, additional encodings to the same chart can be applied using the retinal encodings.

Let's now say we need to see the same distribution but with additional information of Origin of the manufacturer (Maker).

We'll color the above chart by Origin to achieve that:

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();
const sortedDM = dm.sort([['Origin']]);

canvas
    .data(sortedDM)
    .width(600)
    .height(400)
    .rows(['Horsepower'])
    .columns(['Maker'])
    .color('Origin')
    .mount('#chart-container') /* Attaching the canvas to DOM element */

As it can be seen in the chart above, each bar has been colored based on its Origin. So far, the bars have been simply colored based on their Origin values, since each Maker of car belongs to one country of Origin. For group bar and column bar plot checkout the examples.

When a field is assigned to the color encoding channel, Muze internally picks up the color from its default palette. You might want to change the color palette by mentioning range of the encoding channel.

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(['Weight_in_lbs'])
  	.columns(['Horsepower'])
  	.detail(['Name'])
  	.color({ field: 'Origin', range: ['#009688', '#ff9800', '#3f51b5'] })
    .mount('#chart-container') /* Attaching the canvas to DOM element */

The above visualizaiton is a correlation check of two measures: Weight_in_lbs and Horsepower where the data points are colored using Origin dimension with a different palette.

logo

Try it

You can try assign a measure to the color encoding channel, Muze automatically renders a gradient legend if you color the plots using measure.

Head to color api to checkout variations of applying color.

Shape Encoding

Just like color encoding, you can assign a variable to shape encoding channel. The data points take different shape based on the value of variables assigned in the shape encoding channel.

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(['Weight_in_lbs'])
  	.columns(['Horsepower'])
  	.detail(['Name'])
	.shape('Origin')
    .mount('#chart-container') /* Attaching the canvas to DOM element */

In the above chart, each dimensional value of Origin gets assigned to a different shape. When a point data gets rendered, it checks which dimensional value of Origin is associated with that point and based on that, the shape is determined for the point

You can even reorder the shape palette based on your requirement. :

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(['Weight_in_lbs'])
  	.columns(['Horsepower'])
  	.detail(['Name'])
	.shape({
    	field: 'Origin',
      	range : ['square', 'cross', 'triangle']
    })
    .mount('#chart-container') /* Attaching the canvas to DOM element */

If you want to know more on the different variations of shape, read the API documentation for shape.

logo

No measures in shape encoding

Intuitively you can not assign a measure in shape encoding channel, one can't have interpolation between two shape.

Size Encoding

When we talk about size, intuitively, it refers to the dimensions a point occupies in a particular space, which for a 2d-space is its area. Thus, size is a reference to how the chart renders the areas of the points based on the values of field assigned in size encoding.

For example, a variable having values like 30, 50 and 70, will have three points having three different sizes with 70 being the largest and 30 being the smallest.

We'll see how this works for our data.

Let's say, we want our same Horsepower to Weight_in_lbs distribution but with it, we would like to see how Cylinders affect the visualization.

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(['Weight_in_lbs'])
  	.columns(['Horsepower'])
  	.detail(['Name'])
	.size('Cylinders')
    .mount('#chart-container') /* Attaching the canvas to DOM element */

Notice, how the points change their sizes based on the values of Cylinders associated with it. You can also assign a measure field to the size encoding channel.

By default the limit of the sizes are taken from Muze's internal config. You can change the range of the size by mentioning the range configuration. Checkout the following example which shows custom range definition with a measure assigned to shape encoding channel.

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(['Weight_in_lbs'])
  	.columns(['Horsepower'])
  	.detail(['Name'])
	.size({
    	field: 'Acceleration',
    	range: [100, 500]
	})
    .mount('#chart-container') /* Attaching the canvas to DOM element */

All three retinal encoding together

Remember, how we said each of the retinal encodings "encodes" more information in the chart. You can use three retinal encoding channels together to apply more dimensions in the 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(['Weight_in_lbs'])
  	.columns(['Horsepower'])
  	.detail(['Name'])
	.size('Miles_per_Gallon')
  	.shape('Origin')
  	.color('Cylinders')
    .mount('#chart-container') /* Attaching the canvas to DOM element */
logo

Not more than three encoding channels

Even if you have three retinal encoding channels and two planer encoding channels (x and y), it’s not a good idea to use more than three encoding channel. The information overload would would be much higher if this rule is not maintained.

Wrapping up

In this article we saw how you can encode more information by using color, shape and size API. Once you are comfortable with the concepts here, you might head to see the power of layers in Muze.