Tooltips

Tooltips are used in a chart for contextual information. Muze creates tooltip automatically for you based on the variables assigned in encoding channel. You can further modify the behaviour and presentation of Tooltip.

Tooltip Modes

By changing the mode from config, you can configure how tooltips appear on the chart. There are two modes in which the tooltip operates:

  • fragmented
  • consolidated

We'll take a look at both of them separately:

The fragmented tooltip breaks the tooltip into multiple tooltips for multiple points, while the consolidated tooltip displays a single tooltip for a set of points, consolidating the data present in all of them.

Let's draw a stacked bar chart showing the distribution of the Horsepower by Origin and Cylinders. To do so, we'll color the chart using Cylinders

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)
  		.color('Cylinders')
		.rows(['Horsepower'])
		.columns(['Origin'])
		.mount(node) /* Attaching the canvas to DOM element */////      
})

When we hover on the stacked bar chart, it shows a tooltip for all the three Cylinders in the We can change the mode to fragmented to get multiple tooltips for each of the stacks:

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)
    .config({
        interaction: {
            tooltip: {
                mode: 'fragmented'
            }
        }
    })
    .color('Cylinders')
    .rows(['Horsepower'])
    .columns(['Origin'])
    .mount(node);
});

Formatting the tooltip

We can format the content and presentation of tooltip based on how we wish it to be. For instance, you may choose to add or remove information shown in the tooltip or show some different information completely.

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 html = muze.Operators.html;

canvas
    .data(dm)
    .width(600)
    .height(400)
    .config({
        interaction: {
            tooltip: {
                formatter: (dataModel, context) => {
                    const colorAxis = context.axes.color[0];
                    const tooltipData = dataModel.getData().data;
                    const fieldConfig = dataModel.getFieldsConfig();

                    let tooltipContent = '';
                    tooltipData.forEach((dataArray, i) => {
                        const originVal = dataArray[fieldConfig.Origin.index];
                        const hpVal = dataArray[fieldConfig.Horsepower.index];
                        const cylVal = dataArray[fieldConfig.Cylinders.index];
                      	const l = colorAxis.getRawColor(cylVal)[2]; // luminance
                        tooltipContent += `
			${i ? '' : `<h3 style="background-color:#EAEAEA">Country: ${originVal}</h3>`}
			<div style="background: ${colorAxis.getColor(cylVal)}; padding: 4px 8px; color: ${l > 0.45 ? 'black' : 'white' };">
				<u>${cylVal} Cylinders</u> cars with an average power of <b>${hpVal} HP</b>
			</div>
			`;
                        tooltipContent += '<br>';
                    });
                    return html`${tooltipContent}`;
                }
            }
        }
    })
    .color('Cylinders')
    .rows(['Horsepower'])
    .columns(['Origin'])
    .mount(node);a
});

As you can see, we have now formatted the tooltip, but in order to do that we had to write a bunch of code. Let's break it down:

The tooltip property in config accetps a formatter property where we can assign function to give definition of content and its presentation. This function is called with a DataModel which is a data source to tooltip. Usually this DataModel contains the point for which the tooltip is shown. We can extract and transform the data by doing

const tooltipData = dataModel.getData().data; // Gets the data in 2D array format

The syntax of tooltipData is following

[["USA", 158.13084112149534, "8"],
["USA", 98.32432432432432, "6"],
["USA", 77.58333333333333, "4"]]

Now that we have the serialized version of data in 2D array, we need to know which column represents which variable. In order to retrieve that information we call the following api of DataModel

const fieldConfig = dataModel.getFieldsConfig();

The above function returns the configuration in the following manner

{
  "Origin": {
    "index": 0,
    "def": {
      "name": "Origin",
      "type": "dimension",
      "subtype": "categorical"
    }
  },
  "Horsepower": {
    "index": 1,
    "def": {
      "name": "Horsepower",
      "type": "measure",
      "subtype": null
    }
  },
  "Cylinders": {
    "index": 2,
    "def": {
      "name": "Cylinders",
      "type": "dimension",
      "subtype": "categorical"
    }
  }
}

Clearly the index property defines the position of the variable in the serialized data.

Once we have the above two information available rest of work is pretty straight forward. All we have to do is to extract the values of variable, prepare and decorate the content.

Since the instance of DataModel passed to formatter function contains information about the point for which tooltip will be displayed, we can easily retrieve values of variables associated with the point.

tooltipData.forEach((dataArray) => {
    const originVal = dataArray[fieldConfig.Origin.index];
    const hpVal = dataArray[fieldConfig.Horsepower.index];
    const cylVal = dataArray[fieldConfig.Cylinders.index];

Once the content is retrieved, the next step is decoration of the content

tooltipContent += `
    ${i ? '' : `<h3 style="background-color:#EAEAEA">Country: ${originVal}</h3>`}
    <div style="background: ${colorAxis.getColor(cylVal)}; padding: 4px 8px; color: white;">
        <u>${cylVal} Cylinders</u> cars with an average power of <b>${hpVal} HP</b>
    </div>
`;

If you read the above code carefully you will realize, that the background color of tooltip items are taken from legend.

Formatter function needs to return the html content with a tagged template muze.Operators.html

return html`${tooltipContent}`;