Loading...
The quantize scale is a discretization scale that divides a continuous data domain into several equal-width intervals and maps these intervals to discrete values in the range. It belongs to a type of segmented scale, primarily used for discretizing continuous data.
Similar to the threshold scale, quantize also maps continuous data to discrete values, but with the following differences:
The difference from the quantile scale is:
The quantize scale works as follows:
For example, with data domain [0, 100] and range ['Small', 'Medium', 'Large']:
The quantize scale is suitable for the following scenarios:
chart.options({type: 'cell',data: salaryData,encode: {color: 'salary',},scale: {color: {type: 'quantize',range: ['#eee', 'pink', 'red'], // Divide data into three groups, each corresponding to a color},},});
The quantize scale is primarily responsible for mapping continuous data domains to discrete ranges. Here are the configuration options for the quantize scale:
Property | Description | Type | Default Value | Required |
---|---|---|---|---|
type | Scale type, must be 'quantize' | string | None | ✓ |
domain | Set the domain range of the data | number[] | [0, 1] | |
range | Set the range of data mapping values | any[] | [0.5] | |
unknown | Return value for undefined , NaN , null empty values | any | undefined | |
tickCount | Set the recommended number of ticks to generate, tickCount is only a suggestion value | number | 5 | |
tickMethod | Set the method for generating ticks, commonly used for custom ticks | (min: number, max: number, count: number) => number[] | wilkinson-extended | |
nice | Extend the domain range to make the output ticks display more friendly | boolean | false |
Below is an example of creating a heatmap using the quantize scale, dividing salary data into three equal-width intervals based on numerical values and mapping them to different colors:
import { Chart } from '@antv/g2';// Create a container elementconst container = document.createElement('div');const chart = new Chart({container: 'container',container,height: 340,});chart.options({type: 'cell',data: {type: 'fetch',value:'https://gw.alipayobjects.com/os/bmw-prod/89c20fe8-0c6f-46c8-b36b-4cb653dba8ed.json',transform: [{ type: 'map', callback: (d) => ({ salary: d }) }],},scale: {color: {type: 'quantize',range: ['#eee', 'pink', 'red'], // Divide data into three groups, corresponding to three colors},},legend: {color: {length: 400,labelFormatter: '.0s', // Format legend labels using abbreviations (e.g., 10K instead of 10000)},},encode: {y: (_, i) => (i % 5) + 1, // Set the row position of the cellx: (_, i) => ((i / 5) | 0) + 1, // Set the column position of the cellcolor: 'salary', // Map salary data to the color channel},style: {stroke: '#000', // Set cell border colorinset: 2, // Set cell padding},animate: {enter: { type: 'fadeIn' }, // Add fade-in animation effect},});chart.render();
In the above example:
.0s
formatter to display large numbers in a more readable form (e.g., 10K)Scale Type | Data Type | Segmentation Method | Use Case |
---|---|---|---|
quantize | Continuous | Equal-width | Uniform data distribution, need to group by range |
quantile | Continuous | Equal-frequency | Uneven data distribution, need equal data per group |
threshold | Continuous | Custom thresholds | Need to group by specific thresholds (e.g., pass/fail) |
The following example shows the difference between quantize and quantile scales when handling skewed data:
(() => {// Create a skewed distribution dataset using integer valuesconst generateSkewedData = () => {const data = [];// Most data concentrated in low value areafor (let i = 0; i < 60; i++) {// Use integer values to avoid decimal overlapdata.push({value: Math.floor(5 + Math.random() * 25),type: 'Skewed Data',});}// Few data points distributed in high value area, more scatteredfor (let i = 0; i < 15; i++) {data.push({value: Math.floor(60 + Math.random() * 20),type: 'Skewed Data',});}// Add some middle values to make distribution more obviousfor (let i = 0; i < 10; i++) {data.push({value: Math.floor(40 + Math.random() * 15),type: 'Skewed Data',});}return data;};const data = generateSkewedData();// Create two charts for comparisonconst container = document.createElement('div');container.style.display = 'flex';container.style.flexDirection = 'column';container.style.gap = '40px'; // Increase spacingcontainer.style.width = '100%';container.style.maxWidth = '800px';container.style.margin = '0 auto'; // Center display// Add titleconst title = document.createElement('h3');title.textContent = 'quantize vs quantile Scale Comparison';title.style.textAlign = 'center';title.style.marginBottom = '10px';container.appendChild(title);// quantize scale chartconst chart1Container = document.createElement('div');chart1Container.style.width = '100%';chart1Container.style.height = '220px'; // Increase heightcontainer.appendChild(chart1Container);const chart1 = new G2.Chart({container: chart1Container,height: 220,autoFit: true, // Auto-fit container sizepadding: [50, 100, 70, 100], // Increase padding, leave more space for labels});chart1.options({type: 'point',data,title: {text: 'quantize Scale (Equal-width Segmentation)',style: {fontSize: 14,fontWeight: 'bold',},},scale: {color: {type: 'quantize',range: ['#e8f4f8', '#a8d5e5', '#4ba3c3', '#0a6c93'], // 4 color segments},value: {nice: true,tickCount: 5, // Reduce tick countformatter: '.0f', // Use G2 built-in formatter to display integers},},encode: {x: 'value',y: 'type',color: 'value',shape: 'circle',size: 8,},style: {fillOpacity: 0.8,stroke: '#fff',lineWidth: 1,},legend: {color: {position: 'top',length: 200, // Set legend lengthlabelFormatter: '.0f', // Use G2 built-in formatter to display integers},},axis: {y: false,x: {labelSpacing: 10, // Increase label spacinglabelFormatter: '.0f', // Use G2 built-in formatter to display integerstickCount: 5, // Reduce tick count},},});chart1.render();// quantile scale chartconst chart2Container = document.createElement('div');chart2Container.style.width = '100%';chart2Container.style.height = '220px'; // Increase heightcontainer.appendChild(chart2Container);const chart2 = new G2.Chart({container: 'container',container: chart2Container,height: 220,autoFit: true, // Auto-fit container sizepadding: [50, 100, 70, 100], // Increase padding, leave more space for labels});chart2.options({type: 'point',data,title: {text: 'quantile Scale (Equal-frequency Segmentation)',style: {fontSize: 14,fontWeight: 'bold',},},scale: {color: {type: 'quantile',range: ['#e8f4f8', '#a8d5e5', '#4ba3c3', '#0a6c93'], // 4 color segments},value: {nice: true,tickCount: 5, // Reduce tick countformatter: '.0f', // Use G2 built-in formatter to display integers},},encode: {x: 'value',y: 'type',color: 'value',shape: 'circle',size: 8,},style: {fillOpacity: 0.8,stroke: '#fff',lineWidth: 1,},legend: {color: {position: 'top',length: 200, // Set legend lengthlabelFormatter: '.0f', // Use G2 built-in formatter to display integers},},axis: {y: false,x: {labelSpacing: 10, // Increase label spacinglabelFormatter: '.0f', // Use G2 built-in formatter to display integerstickCount: 5, // Reduce tick count},},});chart2.render();return container;})();
In the above comparison example:
Below is a more complex example showing how to use the quantize scale to create multiple segments and customize the data domain:
import { Chart } from '@antv/g2';// Create a container elementconst container = document.createElement('div');const chart = new Chart({container: 'container',container,height: 300,});// Generate test dataconst data = Array.from({ length: 100 }, (_, i) => ({value: Math.random() * 100,id: i + 1,}));chart.options({type: 'point',data,scale: {color: {type: 'quantize',domain: [0, 100], // Custom data domainrange: ['#e8f4f8','#d1e6f0','#a8d5e5','#7ec2da','#4ba3c3','#2385ab','#0a6c93',], // 7 colors corresponding to 6 equal-width intervals},y: {nice: true,},},encode: {x: 'id',y: 'value',color: 'value', // Map values to color channelshape: 'circle',size: 10,},style: {fillOpacity: 0.8,stroke: '#fff',lineWidth: 1,},legend: {color: {length: 300,labelFormatter: '.0f', // Format legend labels as integers},},axis: {y: {title: 'Value',},x: {title: 'ID',},},});chart.render();
Here is a complete example using G2 declarative syntax (G2Spec) to configure the quantize scale:
const spec = {type: 'cell',width: 900,height: 300,data: {type: 'fetch',value:'https://gw.alipayobjects.com/os/bmw-prod/89c20fe8-0c6f-46c8-b36b-4cb653dba8ed.json',transform: [{ type: 'map', callback: (d) => ({ salary: d }) }],},scale: {color: {type: 'quantize',range: ['#eeeeee', '#ffc3ce', '#ff0d0d'], // Define three color intervals},},legend: {color: {labelFormatter: '.0s', // Format legend labels},},encode: {y: (_, i) => (i % 5) + 1,x: (_, i) => ((i / 5) | 0) + 1,color: 'salary', // Map salary data to color channel},style: {stroke: '#000',inset: 2,},};// Create a container elementconst container = document.createElement('div');// Render using Chartconst chart = new G2.Chart(container);chart.options(spec);chart.render();
This example demonstrates how to use G2 declarative syntax to create a heatmap using the quantize scale, including the following features:
When using the quantize scale, pay attention to the following points:
Segment Boundary Calculation: Segment boundaries are determined by the minimum and maximum values of the data domain and the length of the range array. For example, for data domain [0, 100] and range length of 3, the boundary points are 33.33 and 66.67.
Scale Selection: Choose quantize if you want to segment evenly by value range; choose quantile if you want each segment to contain the same number of data points.
Data Domain Setting: You can customize the data domain by setting the domain
property, for example domain: [0, 100]
. If not set, G2 will automatically calculate an appropriate data domain based on the data.
Data Distribution Consideration: The quantize scale is suitable for processing continuous numerical data with relatively uniform distribution. If the data distribution is very uneven (such as long-tail distribution), the quantile scale might be more appropriate.
Nice Ticks: When the nice
parameter is set to true
, it extends the range of the data domain to make boundary values more "friendly" (usually integers or easily understandable values), which helps generate more readable tick marks and legend labels.