diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index ca4ae80b16..9a02ed63e6 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -28,7 +28,7 @@ importers: '@visactor/vtable-calendar': 1.19.0-alpha.0 '@visactor/vtable-editors': 1.19.0-alpha.0 '@visactor/vtable-gantt': 1.19.0-alpha.0 - '@visactor/vutils': ~1.0.6 + '@visactor/vutils': ~1.0.11 '@vitejs/plugin-react': 3.1.0 axios: ^1.4.0 buble: ^0.20.0 @@ -65,7 +65,7 @@ importers: '@visactor/vtable-calendar': 1.19.0-alpha.0 '@visactor/vtable-editors': 1.19.0-alpha.0 '@visactor/vtable-gantt': 1.19.0-alpha.0 - '@visactor/vutils': 1.0.6 + '@visactor/vutils': 1.0.11 axios: 1.9.0 buble: 0.20.0 highlight.js: 11.11.1 @@ -146,7 +146,7 @@ importers: '@visactor/vchart': workspace:2.0.6 '@visactor/vrender-core': ~1.0.18 '@visactor/vrender-kits': ~1.0.18 - '@visactor/vutils': ~1.0.6 + '@visactor/vutils': ~1.0.11 '@vitejs/plugin-react': 3.1.0 eslint: ~8.18.0 eslint-config-prettier: 8.5.0 @@ -166,7 +166,7 @@ importers: '@visactor/vchart': link:../vchart '@visactor/vrender-core': 1.0.18 '@visactor/vrender-kits': 1.0.18 - '@visactor/vutils': 1.0.6 + '@visactor/vutils': 1.0.11 react-is: 18.3.1 devDependencies: '@internal/bundler': link:../../tools/bundler @@ -210,7 +210,7 @@ importers: '@visactor/vchart-extension': workspace:2.0.6 '@visactor/vrender-core': ~1.0.18 '@visactor/vrender-kits': ~1.0.18 - '@visactor/vutils': ~1.0.6 + '@visactor/vutils': ~1.0.11 '@vitejs/plugin-react': 3.1.0 eslint: ~8.18.0 eslint-config-prettier: 8.5.0 @@ -232,7 +232,7 @@ importers: '@visactor/vchart-extension': link:../vchart-extension '@visactor/vrender-core': 1.0.18 '@visactor/vrender-kits': 1.0.18 - '@visactor/vutils': 1.0.6 + '@visactor/vutils': 1.0.11 react-is: 18.3.1 devDependencies: '@internal/bundler': link:../../tools/bundler @@ -369,15 +369,15 @@ importers: '@types/jest': ^26.0.0 '@types/node': '*' '@types/offscreencanvas': 2019.6.4 - '@visactor/vdataset': ~1.0.6 - '@visactor/vlayouts': ~1.0.6 + '@visactor/vdataset': ~1.0.11 + '@visactor/vlayouts': ~1.0.11 '@visactor/vrender-animate': ~1.0.18 '@visactor/vrender-components': ~1.0.18 '@visactor/vrender-core': ~1.0.18 '@visactor/vrender-kits': ~1.0.18 - '@visactor/vscale': ~1.0.6 - '@visactor/vutils': ~1.0.6 '@visactor/vutils-extension': workspace:2.0.6 + '@visactor/vscale': ~1.0.11 + '@visactor/vutils': ~1.0.11 canvas: 2.11.2 cross-env: ^7.0.3 d3-array: ^1.2.4 @@ -411,14 +411,14 @@ importers: typescript: 4.9.5 vite: 3.2.6 dependencies: - '@visactor/vdataset': 1.0.6 - '@visactor/vlayouts': 1.0.6 + '@visactor/vdataset': 1.0.11 + '@visactor/vlayouts': 1.0.11 '@visactor/vrender-animate': 1.0.18 '@visactor/vrender-components': 1.0.18 '@visactor/vrender-core': 1.0.18 '@visactor/vrender-kits': 1.0.18 - '@visactor/vscale': 1.0.6 - '@visactor/vutils': 1.0.6 + '@visactor/vscale': 1.0.11 + '@visactor/vutils': 1.0.11 '@visactor/vutils-extension': link:../vutils-extension devDependencies: '@esbuild-plugins/node-globals-polyfill': 0.1.1 @@ -476,13 +476,13 @@ importers: '@types/react': ^18.0.0 '@types/react-dom': ^18.0.0 '@visactor/vchart': workspace:2.0.6 - '@visactor/vdataset': ~1.0.6 - '@visactor/vlayouts': ~1.0.6 + '@visactor/vdataset': ~1.0.11 + '@visactor/vlayouts': ~1.0.11 '@visactor/vrender-animate': ~1.0.18 '@visactor/vrender-components': ~1.0.18 '@visactor/vrender-core': ~1.0.18 '@visactor/vrender-kits': ~1.0.18 - '@visactor/vutils': ~1.0.6 + '@visactor/vutils': ~1.0.11 '@vitejs/plugin-react': 3.1.0 canvas: 2.11.2 eslint: ~8.18.0 @@ -501,13 +501,13 @@ importers: vite: 3.2.6 dependencies: '@visactor/vchart': link:../vchart - '@visactor/vdataset': 1.0.6 - '@visactor/vlayouts': 1.0.6 + '@visactor/vdataset': 1.0.11 + '@visactor/vlayouts': 1.0.11 '@visactor/vrender-animate': 1.0.18 '@visactor/vrender-components': 1.0.18 '@visactor/vrender-core': 1.0.18 '@visactor/vrender-kits': 1.0.18 - '@visactor/vutils': 1.0.6 + '@visactor/vutils': 1.0.11 devDependencies: '@internal/bundler': link:../../tools/bundler '@internal/eslint-config': link:../../share/eslint-config @@ -581,8 +581,8 @@ importers: '@types/jest': ^26.0.0 '@types/node': '*' '@types/offscreencanvas': 2019.6.4 - '@visactor/vdataset': ~1.0.6 - '@visactor/vutils': ~1.0.6 + '@visactor/vdataset': ~1.0.11 + '@visactor/vutils': ~1.0.11 eslint: ~8.18.0 husky: 7.0.4 jest: ^26.0.0 @@ -599,8 +599,8 @@ importers: typescript: 4.9.5 vite: 3.2.6 dependencies: - '@visactor/vdataset': 1.0.6 - '@visactor/vutils': 1.0.6 + '@visactor/vdataset': 1.0.11 + '@visactor/vutils': 1.0.11 devDependencies: '@internal/bundler': link:../../tools/bundler '@internal/eslint-config': link:../../share/eslint-config @@ -881,7 +881,7 @@ importers: '@visactor/vrender': ~1.0.18 '@visactor/vrender-core': ~1.0.18 '@visactor/vrender-kits': ~1.0.18 - '@visactor/vutils': ~1.0.6 + '@visactor/vutils': ~1.0.11 cross-env: ^7.0.3 eslint: ~8.18.0 jest: ^26.0.0 @@ -896,7 +896,7 @@ importers: '@visactor/vrender': 1.0.18 '@visactor/vrender-core': 1.0.18 '@visactor/vrender-kits': 1.0.18 - '@visactor/vutils': 1.0.6 + '@visactor/vutils': 1.0.11 devDependencies: '@internal/bundler': link:../bundler '@internal/eslint-config': link:../../share/eslint-config @@ -4827,13 +4827,13 @@ packages: topojson-client: 3.1.0 dev: false - /@visactor/vdataset/1.0.6: - resolution: {integrity: sha512-RhsC1JcrWGOOysBwGTHevn+VmOIDgaohFWNLkAAv4Qvd0Psdg8jH7VCP/Lp3HjV/vGBAg4ToL9ADfAjqT5SzcA==} + /@visactor/vdataset/1.0.11: + resolution: {integrity: sha512-GqLbAeOLyL8HkAcE8jzo1dx3aJKt9jpdSa7AU1BpqJY41X49A7NKUmx7OTLQOIOHBmEu38/MGGCK+htF4+vC+Q==} dependencies: '@turf/flatten': 6.5.0 '@turf/helpers': 6.5.0 '@turf/rewind': 6.5.0 - '@visactor/vutils': 1.0.6 + '@visactor/vutils': 1.0.11 d3-dsv: 2.0.0 d3-geo: 1.12.1 d3-hexbin: 0.2.2 @@ -4849,13 +4849,13 @@ packages: topojson-client: 3.1.0 dev: false - /@visactor/vlayouts/1.0.6: - resolution: {integrity: sha512-0HUoNos83LjOSXuJWscerFF6I0teLYDvDW6FIrm5w/b/q9CXvfeujQNm4pRR4AJgbND/bsJy5FAkPG2ne/rdvg==} + /@visactor/vlayouts/1.0.11: + resolution: {integrity: sha512-dqfdQPvK6ASskgFq7tPLYa73wk1FCNGdIVCfG40cN2FHJcvCDEAzpm0ZH1RfanIxC+gphYdXYcddFOY4mSzD3w==} dependencies: '@turf/helpers': 6.5.0 '@turf/invariant': 6.5.0 - '@visactor/vscale': 1.0.6 - '@visactor/vutils': 1.0.6 + '@visactor/vscale': 1.0.11 + '@visactor/vutils': 1.0.11 eventemitter3: 4.0.7 dev: false @@ -4962,6 +4962,12 @@ packages: '@visactor/vutils': 0.18.18 dev: false + /@visactor/vscale/1.0.11: + resolution: {integrity: sha512-8COVGktVkww9+WZ6Dejuf68ijKO7Cjrc2LoesUCsZC7GCxbrKvRkON+yY9Cd1/Xtd5JKXSNvAFBujTO4efm7cg==} + dependencies: + '@visactor/vutils': 1.0.11 + dev: false + /@visactor/vscale/1.0.4: resolution: {integrity: sha512-mXuX0gbQ5dmsU+dOfrDfFT45ijTZrFh1wYeIY44cdMhFo4v+tVdeihN0F+3CEI7oSZiZENbpJ7dXvxnu04xG/g==} dependencies: @@ -5045,6 +5051,14 @@ packages: eventemitter3: 4.0.7 dev: false + /@visactor/vutils/1.0.11: + resolution: {integrity: sha512-QOs/JvpIWTnl5SCsBHTTu9RR4CmqXLy1i3xEDusSy4326IJ3AsBXTTOCTyA4BuT7WAvwaqmRBYLRkdHftq0HPA==} + dependencies: + '@turf/helpers': 6.5.0 + '@turf/invariant': 6.5.0 + eventemitter3: 4.0.7 + dev: false + /@visactor/vutils/1.0.4: resolution: {integrity: sha512-GE149SM5WAc9DMNV7bGtPD4xHP68vbHMRuxGPJ3ndzAGLC/KuXpClteMw6bTY1fRX1vDLY/tQ/GVthgeOx4kDw==} dependencies: diff --git a/docs/assets/examples/en/bar-chart/bar-poly-regression-line.md b/docs/assets/examples/en/bar-chart/bar-poly-regression-line.md new file mode 100644 index 0000000000..d1d31ddd56 --- /dev/null +++ b/docs/assets/examples/en/bar-chart/bar-poly-regression-line.md @@ -0,0 +1,174 @@ +--- +category: examples +group: bar chart +title: 基础条形图 +keywords: barChart,comparison,distribution,rank,rectangle +order: 2-7 +cover: https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vchart/preview/bar-chart/bar-regression-line.png +option: barChart +--- + +# Simple Bar Chart + Regression Line + +## Key Configuration + +By passing different configuration items to the `appendBarRegressionLineConfig` method, you can add multiple regression lines of different degrees and styles to the bar chart. + +- `degree`: The degree of the polynomial regression, e.g., 2 for quadratic, 3 for cubic. +- `color`: The color of the regression line. +- `line.style`: Style configuration for the regression line, such as `lineWidth` for line thickness. +- `confidenceInterval.visible`: Whether to display the confidence interval (boolean). +- `confidenceInterval.style`: Style configuration for the confidence interval, such as `fillOpacity` for opacity. +- `label.text`: The label text for the regression line. + +## Code Example + +```javascript livedemo +/** --Add the following code when using in your project-- */ +// When using in your project, please additionally install @visactor/vchart-extension, and keep the package version consistent with vchart +// import { appendBarRegressionLineConfig, registerRegressionLine } from '@visactor/vchart-extension'; +/** --Add the above code when using in your project-- */ + +/** --Remove the following code when using in your project-- */ +const { appendBarRegressionLineConfig, registerRegressionLine } = VChartExtension; +/** --Remove the above code when using in your project-- */ + +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { + name: 'Apple', + value: 214480 + }, + { + name: 'Google', + value: 155506 + }, + { + name: 'Amazon', + value: 100764 + }, + { + name: 'Microsoft', + value: 92715 + }, + { + name: 'Coca-Cola', + value: 66341 + }, + { + name: 'Samsung', + value: 59890 + }, + { + name: 'Toyota', + value: 53404 + }, + { + name: 'Mercedes-Benz', + value: 48601 + }, + { + name: 'Facebook', + value: 45168 + }, + { + name: "McDonald's", + value: 43417 + }, + { + name: 'Intel', + value: 43293 + }, + { + name: 'IBM', + value: 42972 + }, + { + name: 'BMW', + value: 41006 + }, + { + name: 'Disney', + value: 39874 + }, + { + name: 'Cisco', + value: 34575 + }, + { + name: 'GE', + value: 32757 + }, + { + name: 'Nike', + value: 30120 + }, + { + name: 'Louis Vuitton', + value: 28152 + }, + { + name: 'Oracle', + value: 26133 + }, + { + name: 'Honda', + value: 23682 + } + ] + } + ], + xField: 'name', + yField: 'value' +}; + +registerRegressionLine(); +appendBarRegressionLineConfig(spec, [ + { + degree: 2, + color: 'red', + line: { + style: { + lineWidth: 2 + } + }, + confidenceInterval: { + visible: false + }, + label: { + text: '2 次多项式拟合' + } + }, + { + degree: 3, + color: 'green', + line: { + style: { + lineWidth: 2 + } + }, + confidenceInterval: { + style: { + fillOpacity: 0.2 + } + }, + label: { + text: '3 次多项式拟合' + } + } +]); + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); + +// Just for the convenience of console debugging, DO NOT COPY! +window['vchart'] = vchart; +``` + +``` + +``` diff --git a/docs/assets/examples/en/histogram-chart/histogram-bin.md b/docs/assets/examples/en/histogram-chart/histogram-bin.md new file mode 100644 index 0000000000..9c6acd32c3 --- /dev/null +++ b/docs/assets/examples/en/histogram-chart/histogram-bin.md @@ -0,0 +1,125 @@ +--- +category: examples +group: histogram chart +title: 基础直方图 +keywords: histogram,distribution,rectangle +order: 3-4 +cover: https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vchart/preview/histogram-chart/histogram-bin_2.0.7.png +option: histogramChart +--- + +# Basic Histogram + +This example demonstrates how to use binning to process raw data and generate a basic histogram. By configuring `xField`, `x2Field`, and `yField`, you can specify the start, end, and frequency fields of each bin, respectively. + +## Key Configuration Details + +- `xField`: Specifies the left endpoint field of each bin (e.g., `x0`). +- `x2Field`: Specifies the right endpoint field of each bin (e.g., `x1`). +- `yField`: Specifies the frequency field for each bin (e.g., `frequency`). + +With these configurations, you can convert detailed data into the binned statistical data required for a histogram, enabling visualization of data distribution. + +## 代码演示 + +```javascript livedemo +const spec = { + data: [ + { + name: 'data1', + transforms: [ + { + type: 'bin', + options: { + step: 2, + field: 'value', + outputNames: { x0: 'x0', x1: 'x1', count: 'frequency' } + } + } + ], + values: [ + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2.3 }, + { value: 2.3 }, + { value: 2.3 }, + { value: 2.3 }, + { value: 2.3 }, + { value: 2.3 }, + { value: 2.3 }, + { value: 4 }, + { value: 4 }, + { value: 4 }, + { value: 4 }, + { value: 4 }, + { value: 7 }, + { value: 7 }, + { value: 7 }, + { value: 7 }, + { value: 7 }, + { value: 7 }, + { value: 7 }, + { value: 7 }, + { value: 7 }, + { value: 7 }, + { value: 7 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 } + ] + } + ], + type: 'histogram', + xField: 'x0', + x2Field: 'x1', + yField: 'frequency', + bar: { + style: { + stroke: 'white', + lineWidth: 1 + } + }, + title: { + text: 'Histogram by bin transform' + }, + tooltip: { + visible: true, + mark: { + title: { + key: 'title', + value: 'frequency' + }, + content: [ + { + key: datum => datum['x0'] + '~' + datum['x1'], + value: datum => datum['frequency'] + } + ] + } + } +}; +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); + +// Just for the convenience of console debugging, DO NOT COPY! +window['vchart'] = vchart; +``` diff --git a/docs/assets/examples/en/histogram-chart/histogram-regression-line.md b/docs/assets/examples/en/histogram-chart/histogram-regression-line.md new file mode 100644 index 0000000000..4b3148e121 --- /dev/null +++ b/docs/assets/examples/en/histogram-chart/histogram-regression-line.md @@ -0,0 +1,147 @@ +--- +category: examples +group: histogram chart +title: 基础直方图 +keywords: histogram,distribution,rectangle +order: 3-4 +cover: https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vchart/preview/histogram-chart/histogram-regression-line.png +option: histogramChart +--- + +# Histogram Regression Line + +## Key Information + +- Use `bin` binning to process raw data and generate the intervals and frequency data required for the histogram. +- In the histogram configuration, you need to specify the following fields: + - `xField`: Represents the left endpoint of each interval (e.g., `x0`). + - `x2Field`: Represents the right endpoint of each interval (e.g., `x1`). + - `yField`: Represents the frequency of each interval (e.g., `frequency`). +- You can add regression lines (such as KDE kernel density estimation and ECDF empirical cumulative distribution function) via extended configuration to help analyze the data distribution. + +## Code Example + +```javascript livedemo +/** --Add the following code when using in your project-- */ +// When using in your project, please additionally depend on @visactor/vchart-extension, and keep the package version consistent with vchart +// import { registerRegressionLine, appendHistogramRegressionLineConfig } from '@visactor/vchart-extension'; +/** --Add the above code when using in your project-- */ + +/** --Delete the following code when using in your project-- */ +const { registerRegressionLine, appendHistogramRegressionLineConfig } = VChartExtension; +/** --Delete the above code when using in your project-- */ +``` + +function boxMullerRandom() { +let u = 0; +let v = 0; +while (u === 0) { +u = Math.random(); +} +while (v === 0) { +v = Math.random(); +} +return Math.sqrt(-2.0 _ Math.log(u)) _ Math.cos(2.0 _ Math.PI _ v); +} + +function generateGaussian(count, mean = 0, sd = 1) { +const out = []; +for (let i = 0; i < count; i++) { +out.push(mean + boxMullerRandom() \* sd); +} +return out; +} + +function generateMixtureGaussianSamples() { +const a = generateGaussian(160, 5, 4, 1); // cluster A +// const b = generateGaussian(80, 2.3, 0.08, 2); // cluster B +// const c = generateGaussian(140, 9.3, 0.35, 3); // cluster C +const outliers = [5.0, 6.2, 3.5, 12.0, 0.5]; +const arr = [...a, ...outliers]; +return arr.map(v => ({ value: v })); +} + +const spec = { +data: [ +{ +name: 'data1', +transforms: [ +{ +type: 'bin', +options: { +step: 2, +field: 'value', +outputNames: { x0: 'x0', x1: 'x1', count: 'frequency' } +} +} +], +values: generateMixtureGaussianSamples() +} +], +type: 'histogram', +xField: 'x0', +x2Field: 'x1', +yField: 'frequency', +bar: { +style: { +stroke: 'white', +lineWidth: 1 +} +}, +title: { +text: 'Histogram of Gaussian data' +}, +tooltip: { +visible: true, +mark: { +title: { +key: 'title', +value: 'frequency' +}, +content: [ +{ +key: datum => datum['x0'] + '~' + datum['x1'], +value: datum => datum['frequency'] +} +] +} +} +}; + +registerRegressionLine(); +appendHistogramRegressionLineConfig(spec, [ +{ +type: 'kde', // 支持 'kde' 和 'ecdf' +line: { +style: { +stroke: 'red', +lineWidth: 2 +} +}, +label: { +text: 'KDE 核密度估计' +} +}, +{ +type: 'ecdf', // 支持 'kde' 和 'ecdf' +line: { +style: { +stroke: 'green', +lineWidth: 2 +} +}, +label: { +text: '经验累积分布函数(ECDF)' +} +} +]); + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); + +// Just for the convenience of console debugging, DO NOT COPY! +window['vchart'] = vchart; + +``` + +``` diff --git a/docs/assets/examples/en/scatter-chart/scatter-regression-line.md b/docs/assets/examples/en/scatter-chart/scatter-regression-line.md new file mode 100644 index 0000000000..2333f8f4cd --- /dev/null +++ b/docs/assets/examples/en/scatter-chart/scatter-regression-line.md @@ -0,0 +1,561 @@ +--- +category: examples +group: extension chart +title: 时序散点图-支持kde背景 +keywords: regression-line, scatterChart +order: +cover: https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vchart/preview/scatter-chart/scatter-regression-line.png +option: scatterChart +--- + +# Scatter Plot with Regression Line Support + +## Key Configurations + +- Register the regression line extension using `registerRegressionLine()` +- Use `appendScatterRegressionLineConfig(spec, [...])` to configure multiple regression lines (such as polynomial regression, linear regression, etc.) +- You can set the regression line type (`type: 'linear' | 'logistic' | 'lowess' | 'polynomial'`), color, degree (for polynomial), confidence interval style, label, and more + +## Code Example + +```javascript livedemo +/** --Add the following code when using in your project-- */ +// When using in your project, please additionally install @visactor/vchart-extension, and keep the package version consistent with vchart +// import { registerRegressionLine, appendScatterRegressionLineConfig } from '@visactor/vchart-extension'; +/** --Add the above code when using in your project-- */ + +/** --Remove the following code when using in your project-- */ +const { registerRegressionLine, appendScatterRegressionLineConfig } = VChartExtension; +/** --Remove the above code when using in your project-- */ + +const data = [ + { name: 'chevrolet chevelle malibu', milesPerGallon: 18, cylinders: 8, horsepower: 130 }, + { name: 'buick skylark 320', milesPerGallon: 15, cylinders: 8, horsepower: 165 }, + { name: 'plymouth satellite', milesPerGallon: 18, cylinders: 8, horsepower: 150 }, + { name: 'amc rebel sst', milesPerGallon: 16, cylinders: 8, horsepower: 150 }, + { name: 'ford torino', milesPerGallon: 17, cylinders: 8, horsepower: 140 }, + { name: 'ford galaxie 500', milesPerGallon: 15, cylinders: 8, horsepower: 198 }, + { name: 'chevrolet impala', milesPerGallon: 14, cylinders: 8, horsepower: 220 }, + { name: 'plymouth fury iii', milesPerGallon: 14, cylinders: 8, horsepower: 215 }, + { name: 'pontiac catalina', milesPerGallon: 14, cylinders: 8, horsepower: 225 }, + { name: 'amc ambassador dpl', milesPerGallon: 15, cylinders: 8, horsepower: 190 }, + { name: 'citroen ds-21 pallas', milesPerGallon: 0, cylinders: 4, horsepower: 115 }, + { name: 'chevrolet chevelle concours (sw)', milesPerGallon: 0, cylinders: 8, horsepower: 165 }, + { name: 'ford torino (sw)', milesPerGallon: 0, cylinders: 8, horsepower: 153 }, + { name: 'plymouth satellite (sw)', milesPerGallon: 0, cylinders: 8, horsepower: 175 }, + { name: 'amc rebel sst (sw)', milesPerGallon: 0, cylinders: 8, horsepower: 175 }, + { name: 'dodge challenger se', milesPerGallon: 15, cylinders: 8, horsepower: 170 }, + { name: "plymouth 'cuda 340", milesPerGallon: 14, cylinders: 8, horsepower: 160 }, + { name: 'ford mustang boss 302', milesPerGallon: 0, cylinders: 8, horsepower: 140 }, + { name: 'chevrolet monte carlo', milesPerGallon: 15, cylinders: 8, horsepower: 150 }, + { name: 'buick estate wagon (sw)', milesPerGallon: 14, cylinders: 8, horsepower: 225 }, + { name: 'toyota corona mark ii', milesPerGallon: 24, cylinders: 4, horsepower: 95 }, + { name: 'plymouth duster', milesPerGallon: 22, cylinders: 6, horsepower: 95 }, + { name: 'amc hornet', milesPerGallon: 18, cylinders: 6, horsepower: 97 }, + { name: 'ford maverick', milesPerGallon: 21, cylinders: 6, horsepower: 85 }, + { name: 'datsun pl510', milesPerGallon: 27, cylinders: 4, horsepower: 88 }, + { name: 'volkswagen 1131 deluxe sedan', milesPerGallon: 26, cylinders: 4, horsepower: 46 }, + { name: 'peugeot 504', milesPerGallon: 25, cylinders: 4, horsepower: 87 }, + { name: 'audi 100 ls', milesPerGallon: 24, cylinders: 4, horsepower: 90 }, + { name: 'saab 99e', milesPerGallon: 25, cylinders: 4, horsepower: 95 }, + { name: 'bmw 2002', milesPerGallon: 26, cylinders: 4, horsepower: 113 }, + { name: 'amc gremlin', milesPerGallon: 21, cylinders: 6, horsepower: 90 }, + { name: 'ford f250', milesPerGallon: 10, cylinders: 8, horsepower: 215 }, + { name: 'chevy c20', milesPerGallon: 10, cylinders: 8, horsepower: 200 }, + { name: 'dodge d200', milesPerGallon: 11, cylinders: 8, horsepower: 210 }, + { name: 'hi 1200d', milesPerGallon: 9, cylinders: 8, horsepower: 193 }, + { name: 'datsun pl510', milesPerGallon: 27, cylinders: 4, horsepower: 88 }, + { name: 'chevrolet vega 2300', milesPerGallon: 28, cylinders: 4, horsepower: 90 }, + { name: 'toyota corona', milesPerGallon: 25, cylinders: 4, horsepower: 95 }, + { name: 'ford pinto', milesPerGallon: 25, cylinders: 4, horsepower: 0 }, + { name: 'volkswagen super beetle 117', milesPerGallon: 0, cylinders: 4, horsepower: 48 }, + { name: 'amc gremlin', milesPerGallon: 19, cylinders: 6, horsepower: 100 }, + { name: 'plymouth satellite custom', milesPerGallon: 16, cylinders: 6, horsepower: 105 }, + { name: 'chevrolet chevelle malibu', milesPerGallon: 17, cylinders: 6, horsepower: 100 }, + { name: 'ford torino 500', milesPerGallon: 19, cylinders: 6, horsepower: 88 }, + { name: 'amc matador', milesPerGallon: 18, cylinders: 6, horsepower: 100 }, + { name: 'chevrolet impala', milesPerGallon: 14, cylinders: 8, horsepower: 165 }, + { name: 'pontiac catalina brougham', milesPerGallon: 14, cylinders: 8, horsepower: 175 }, + { name: 'ford galaxie 500', milesPerGallon: 14, cylinders: 8, horsepower: 153 }, + { name: 'plymouth fury iii', milesPerGallon: 14, cylinders: 8, horsepower: 150 }, + { name: 'dodge monaco (sw)', milesPerGallon: 12, cylinders: 8, horsepower: 180 }, + { name: 'ford country squire (sw)', milesPerGallon: 13, cylinders: 8, horsepower: 170 }, + { name: 'pontiac safari (sw)', milesPerGallon: 13, cylinders: 8, horsepower: 175 }, + { name: 'amc hornet sportabout (sw)', milesPerGallon: 18, cylinders: 6, horsepower: 110 }, + { name: 'chevrolet vega (sw)', milesPerGallon: 22, cylinders: 4, horsepower: 72 }, + { name: 'pontiac firebird', milesPerGallon: 19, cylinders: 6, horsepower: 100 }, + { name: 'ford mustang', milesPerGallon: 18, cylinders: 6, horsepower: 88 }, + { name: 'mercury capri 2000', milesPerGallon: 23, cylinders: 4, horsepower: 86 }, + { name: 'opel 1900', milesPerGallon: 28, cylinders: 4, horsepower: 90 }, + { name: 'peugeot 304', milesPerGallon: 30, cylinders: 4, horsepower: 70 }, + { name: 'fiat 124b', milesPerGallon: 30, cylinders: 4, horsepower: 76 }, + { name: 'toyota corolla 1200', milesPerGallon: 31, cylinders: 4, horsepower: 65 }, + { name: 'datsun 1200', milesPerGallon: 35, cylinders: 4, horsepower: 69 }, + { name: 'volkswagen model 111', milesPerGallon: 27, cylinders: 4, horsepower: 60 }, + { name: 'plymouth cricket', milesPerGallon: 26, cylinders: 4, horsepower: 70 }, + { name: 'toyota corona hardtop', milesPerGallon: 24, cylinders: 4, horsepower: 95 }, + { name: 'dodge colt hardtop', milesPerGallon: 25, cylinders: 4, horsepower: 80 }, + { name: 'volkswagen type 3', milesPerGallon: 23, cylinders: 4, horsepower: 54 }, + { name: 'chevrolet vega', milesPerGallon: 20, cylinders: 4, horsepower: 90 }, + { name: 'ford pinto runabout', milesPerGallon: 21, cylinders: 4, horsepower: 86 }, + { name: 'chevrolet impala', milesPerGallon: 13, cylinders: 8, horsepower: 165 }, + { name: 'pontiac catalina', milesPerGallon: 14, cylinders: 8, horsepower: 175 }, + { name: 'plymouth fury iii', milesPerGallon: 15, cylinders: 8, horsepower: 150 }, + { name: 'ford galaxie 500', milesPerGallon: 14, cylinders: 8, horsepower: 153 }, + { name: 'amc ambassador sst', milesPerGallon: 17, cylinders: 8, horsepower: 150 }, + { name: 'mercury marquis', milesPerGallon: 11, cylinders: 8, horsepower: 208 }, + { name: 'buick lesabre custom', milesPerGallon: 13, cylinders: 8, horsepower: 155 }, + { name: 'oldsmobile delta 88 royale', milesPerGallon: 12, cylinders: 8, horsepower: 160 }, + { name: 'chrysler newport royal', milesPerGallon: 13, cylinders: 8, horsepower: 190 }, + { name: 'mazda rx2 coupe', milesPerGallon: 19, cylinders: 3, horsepower: 97 }, + { name: 'amc matador (sw)', milesPerGallon: 15, cylinders: 8, horsepower: 150 }, + { name: 'chevrolet chevelle concours (sw)', milesPerGallon: 13, cylinders: 8, horsepower: 130 }, + { name: 'ford gran torino (sw)', milesPerGallon: 13, cylinders: 8, horsepower: 140 }, + { name: 'plymouth satellite custom (sw)', milesPerGallon: 14, cylinders: 8, horsepower: 150 }, + { name: 'volvo 145e (sw)', milesPerGallon: 18, cylinders: 4, horsepower: 112 }, + { name: 'volkswagen 411 (sw)', milesPerGallon: 22, cylinders: 4, horsepower: 76 }, + { name: 'peugeot 504 (sw)', milesPerGallon: 21, cylinders: 4, horsepower: 87 }, + { name: 'renault 12 (sw)', milesPerGallon: 26, cylinders: 4, horsepower: 69 }, + { name: 'ford pinto (sw)', milesPerGallon: 22, cylinders: 4, horsepower: 86 }, + { name: 'datsun 510 (sw)', milesPerGallon: 28, cylinders: 4, horsepower: 92 }, + { name: 'toyouta corona mark ii (sw)', milesPerGallon: 23, cylinders: 4, horsepower: 97 }, + { name: 'dodge colt (sw)', milesPerGallon: 28, cylinders: 4, horsepower: 80 }, + { name: 'toyota corolla 1600 (sw)', milesPerGallon: 27, cylinders: 4, horsepower: 88 }, + { name: 'buick century 350', milesPerGallon: 13, cylinders: 8, horsepower: 175 }, + { name: 'amc matador', milesPerGallon: 14, cylinders: 8, horsepower: 150 }, + { name: 'chevrolet malibu', milesPerGallon: 13, cylinders: 8, horsepower: 145 }, + { name: 'ford gran torino', milesPerGallon: 14, cylinders: 8, horsepower: 137 }, + { name: 'dodge coronet custom', milesPerGallon: 15, cylinders: 8, horsepower: 150 }, + { name: 'mercury marquis brougham', milesPerGallon: 12, cylinders: 8, horsepower: 198 }, + { name: 'chevrolet caprice classic', milesPerGallon: 13, cylinders: 8, horsepower: 150 }, + { name: 'ford ltd', milesPerGallon: 13, cylinders: 8, horsepower: 158 }, + { name: 'plymouth fury gran sedan', milesPerGallon: 14, cylinders: 8, horsepower: 150 }, + { name: 'chrysler new yorker brougham', milesPerGallon: 13, cylinders: 8, horsepower: 215 }, + { name: 'buick electra 225 custom', milesPerGallon: 12, cylinders: 8, horsepower: 225 }, + { name: 'amc ambassador brougham', milesPerGallon: 13, cylinders: 8, horsepower: 175 }, + { name: 'plymouth valiant', milesPerGallon: 18, cylinders: 6, horsepower: 105 }, + { name: 'chevrolet nova custom', milesPerGallon: 16, cylinders: 6, horsepower: 100 }, + { name: 'amc hornet', milesPerGallon: 18, cylinders: 6, horsepower: 100 }, + { name: 'ford maverick', milesPerGallon: 18, cylinders: 6, horsepower: 88 }, + { name: 'plymouth duster', milesPerGallon: 23, cylinders: 6, horsepower: 95 }, + { name: 'volkswagen super beetle', milesPerGallon: 26, cylinders: 4, horsepower: 46 }, + { name: 'chevrolet impala', milesPerGallon: 11, cylinders: 8, horsepower: 150 }, + { name: 'ford country', milesPerGallon: 12, cylinders: 8, horsepower: 167 }, + { name: 'plymouth custom suburb', milesPerGallon: 13, cylinders: 8, horsepower: 170 }, + { name: 'oldsmobile vista cruiser', milesPerGallon: 12, cylinders: 8, horsepower: 180 }, + { name: 'amc gremlin', milesPerGallon: 18, cylinders: 6, horsepower: 100 }, + { name: 'toyota carina', milesPerGallon: 20, cylinders: 4, horsepower: 88 }, + { name: 'chevrolet vega', milesPerGallon: 21, cylinders: 4, horsepower: 72 }, + { name: 'datsun 610', milesPerGallon: 22, cylinders: 4, horsepower: 94 }, + { name: 'maxda rx3', milesPerGallon: 18, cylinders: 3, horsepower: 90 }, + { name: 'ford pinto', milesPerGallon: 19, cylinders: 4, horsepower: 85 }, + { name: 'mercury capri v6', milesPerGallon: 21, cylinders: 6, horsepower: 107 }, + { name: 'fiat 124 sport coupe', milesPerGallon: 26, cylinders: 4, horsepower: 90 }, + { name: 'chevrolet monte carlo s', milesPerGallon: 15, cylinders: 8, horsepower: 145 }, + { name: 'pontiac grand prix', milesPerGallon: 16, cylinders: 8, horsepower: 230 }, + { name: 'fiat 128', milesPerGallon: 29, cylinders: 4, horsepower: 49 }, + { name: 'opel manta', milesPerGallon: 24, cylinders: 4, horsepower: 75 }, + { name: 'audi 100ls', milesPerGallon: 20, cylinders: 4, horsepower: 91 }, + { name: 'volvo 144ea', milesPerGallon: 19, cylinders: 4, horsepower: 112 }, + { name: 'dodge dart custom', milesPerGallon: 15, cylinders: 8, horsepower: 150 }, + { name: 'saab 99le', milesPerGallon: 24, cylinders: 4, horsepower: 110 }, + { name: 'toyota mark ii', milesPerGallon: 20, cylinders: 6, horsepower: 122 }, + { name: 'oldsmobile omega', milesPerGallon: 11, cylinders: 8, horsepower: 180 }, + { name: 'plymouth duster', milesPerGallon: 20, cylinders: 6, horsepower: 95 }, + { name: 'ford maverick', milesPerGallon: 21, cylinders: 6, horsepower: 0 }, + { name: 'amc hornet', milesPerGallon: 19, cylinders: 6, horsepower: 100 }, + { name: 'chevrolet nova', milesPerGallon: 15, cylinders: 6, horsepower: 100 }, + { name: 'datsun b210', milesPerGallon: 31, cylinders: 4, horsepower: 67 }, + { name: 'ford pinto', milesPerGallon: 26, cylinders: 4, horsepower: 80 }, + { name: 'toyota corolla 1200', milesPerGallon: 32, cylinders: 4, horsepower: 65 }, + { name: 'chevrolet vega', milesPerGallon: 25, cylinders: 4, horsepower: 75 }, + { name: 'chevrolet chevelle malibu classic', milesPerGallon: 16, cylinders: 6, horsepower: 100 }, + { name: 'amc matador', milesPerGallon: 16, cylinders: 6, horsepower: 110 }, + { name: 'plymouth satellite sebring', milesPerGallon: 18, cylinders: 6, horsepower: 105 }, + { name: 'ford gran torino', milesPerGallon: 16, cylinders: 8, horsepower: 140 }, + { name: 'buick century luxus (sw)', milesPerGallon: 13, cylinders: 8, horsepower: 150 }, + { name: 'dodge coronet custom (sw)', milesPerGallon: 14, cylinders: 8, horsepower: 150 }, + { name: 'ford gran torino (sw)', milesPerGallon: 14, cylinders: 8, horsepower: 140 }, + { name: 'amc matador (sw)', milesPerGallon: 14, cylinders: 8, horsepower: 150 }, + { name: 'audi fox', milesPerGallon: 29, cylinders: 4, horsepower: 83 }, + { name: 'volkswagen dasher', milesPerGallon: 26, cylinders: 4, horsepower: 67 }, + { name: 'opel manta', milesPerGallon: 26, cylinders: 4, horsepower: 78 }, + { name: 'toyota corona', milesPerGallon: 31, cylinders: 4, horsepower: 52 }, + { name: 'datsun 710', milesPerGallon: 32, cylinders: 4, horsepower: 61 }, + { name: 'dodge colt', milesPerGallon: 28, cylinders: 4, horsepower: 75 }, + { name: 'fiat 128', milesPerGallon: 24, cylinders: 4, horsepower: 75 }, + { name: 'fiat 124 tc', milesPerGallon: 26, cylinders: 4, horsepower: 75 }, + { name: 'honda civic', milesPerGallon: 24, cylinders: 4, horsepower: 97 }, + { name: 'subaru', milesPerGallon: 26, cylinders: 4, horsepower: 93 }, + { name: 'fiat x1.9', milesPerGallon: 31, cylinders: 4, horsepower: 67 }, + { name: 'plymouth valiant custom', milesPerGallon: 19, cylinders: 6, horsepower: 95 }, + { name: 'chevrolet nova', milesPerGallon: 18, cylinders: 6, horsepower: 105 }, + { name: 'mercury monarch', milesPerGallon: 15, cylinders: 6, horsepower: 72 }, + { name: 'ford maverick', milesPerGallon: 15, cylinders: 6, horsepower: 72 }, + { name: 'pontiac catalina', milesPerGallon: 16, cylinders: 8, horsepower: 170 }, + { name: 'chevrolet bel air', milesPerGallon: 15, cylinders: 8, horsepower: 145 }, + { name: 'plymouth grand fury', milesPerGallon: 16, cylinders: 8, horsepower: 150 }, + { name: 'ford ltd', milesPerGallon: 14, cylinders: 8, horsepower: 148 }, + { name: 'buick century', milesPerGallon: 17, cylinders: 6, horsepower: 110 }, + { name: 'chevroelt chevelle malibu', milesPerGallon: 16, cylinders: 6, horsepower: 105 }, + { name: 'amc matador', milesPerGallon: 15, cylinders: 6, horsepower: 110 }, + { name: 'plymouth fury', milesPerGallon: 18, cylinders: 6, horsepower: 95 }, + { name: 'buick skyhawk', milesPerGallon: 21, cylinders: 6, horsepower: 110 }, + { name: 'chevrolet monza 2+2', milesPerGallon: 20, cylinders: 8, horsepower: 110 }, + { name: 'ford mustang ii', milesPerGallon: 13, cylinders: 8, horsepower: 129 }, + { name: 'toyota corolla', milesPerGallon: 29, cylinders: 4, horsepower: 75 }, + { name: 'ford pinto', milesPerGallon: 23, cylinders: 4, horsepower: 83 }, + { name: 'amc gremlin', milesPerGallon: 20, cylinders: 6, horsepower: 100 }, + { name: 'pontiac astro', milesPerGallon: 23, cylinders: 4, horsepower: 78 }, + { name: 'toyota corona', milesPerGallon: 24, cylinders: 4, horsepower: 96 }, + { name: 'volkswagen dasher', milesPerGallon: 25, cylinders: 4, horsepower: 71 }, + { name: 'datsun 710', milesPerGallon: 24, cylinders: 4, horsepower: 97 }, + { name: 'ford pinto', milesPerGallon: 18, cylinders: 6, horsepower: 97 }, + { name: 'volkswagen rabbit', milesPerGallon: 29, cylinders: 4, horsepower: 70 }, + { name: 'amc pacer', milesPerGallon: 19, cylinders: 6, horsepower: 90 }, + { name: 'audi 100ls', milesPerGallon: 23, cylinders: 4, horsepower: 95 }, + { name: 'peugeot 504', milesPerGallon: 23, cylinders: 4, horsepower: 88 }, + { name: 'volvo 244dl', milesPerGallon: 22, cylinders: 4, horsepower: 98 }, + { name: 'saab 99le', milesPerGallon: 25, cylinders: 4, horsepower: 115 }, + { name: 'honda civic cvcc', milesPerGallon: 33, cylinders: 4, horsepower: 53 }, + { name: 'fiat 131', milesPerGallon: 28, cylinders: 4, horsepower: 86 }, + { name: 'opel 1900', milesPerGallon: 25, cylinders: 4, horsepower: 81 }, + { name: 'capri ii', milesPerGallon: 25, cylinders: 4, horsepower: 92 }, + { name: 'dodge colt', milesPerGallon: 26, cylinders: 4, horsepower: 79 }, + { name: 'renault 12tl', milesPerGallon: 27, cylinders: 4, horsepower: 83 }, + { name: 'chevrolet chevelle malibu classic', milesPerGallon: 17.5, cylinders: 8, horsepower: 140 }, + { name: 'dodge coronet brougham', milesPerGallon: 16, cylinders: 8, horsepower: 150 }, + { name: 'amc matador', milesPerGallon: 15.5, cylinders: 8, horsepower: 120 }, + { name: 'ford gran torino', milesPerGallon: 14.5, cylinders: 8, horsepower: 152 }, + { name: 'plymouth valiant', milesPerGallon: 22, cylinders: 6, horsepower: 100 }, + { name: 'chevrolet nova', milesPerGallon: 22, cylinders: 6, horsepower: 105 }, + { name: 'ford maverick', milesPerGallon: 24, cylinders: 6, horsepower: 81 }, + { name: 'amc hornet', milesPerGallon: 22.5, cylinders: 6, horsepower: 90 }, + { name: 'chevrolet chevette', milesPerGallon: 29, cylinders: 4, horsepower: 52 }, + { name: 'chevrolet woody', milesPerGallon: 24.5, cylinders: 4, horsepower: 60 }, + { name: 'vw rabbit', milesPerGallon: 29, cylinders: 4, horsepower: 70 }, + { name: 'honda civic', milesPerGallon: 33, cylinders: 4, horsepower: 53 }, + { name: 'dodge aspen se', milesPerGallon: 20, cylinders: 6, horsepower: 100 }, + { name: 'ford granada ghia', milesPerGallon: 18, cylinders: 6, horsepower: 78 }, + { name: 'pontiac ventura sj', milesPerGallon: 18.5, cylinders: 6, horsepower: 110 }, + { name: 'amc pacer d/l', milesPerGallon: 17.5, cylinders: 6, horsepower: 95 }, + { name: 'volkswagen rabbit', milesPerGallon: 29.5, cylinders: 4, horsepower: 71 }, + { name: 'datsun b-210', milesPerGallon: 32, cylinders: 4, horsepower: 70 }, + { name: 'toyota corolla', milesPerGallon: 28, cylinders: 4, horsepower: 75 }, + { name: 'ford pinto', milesPerGallon: 26.5, cylinders: 4, horsepower: 72 }, + { name: 'volvo 245', milesPerGallon: 20, cylinders: 4, horsepower: 102 }, + { name: 'plymouth volare premier v8', milesPerGallon: 13, cylinders: 8, horsepower: 150 }, + { name: 'peugeot 504', milesPerGallon: 19, cylinders: 4, horsepower: 88 }, + { name: 'toyota mark ii', milesPerGallon: 19, cylinders: 6, horsepower: 108 }, + { name: 'mercedes-benz 280s', milesPerGallon: 16.5, cylinders: 6, horsepower: 120 }, + { name: 'cadillac seville', milesPerGallon: 16.5, cylinders: 8, horsepower: 180 }, + { name: 'chevy c10', milesPerGallon: 13, cylinders: 8, horsepower: 145 }, + { name: 'ford f108', milesPerGallon: 13, cylinders: 8, horsepower: 130 }, + { name: 'dodge d100', milesPerGallon: 13, cylinders: 8, horsepower: 150 }, + { name: 'honda Accelerationord cvcc', milesPerGallon: 31.5, cylinders: 4, horsepower: 68 }, + { name: 'buick opel isuzu deluxe', milesPerGallon: 30, cylinders: 4, horsepower: 80 }, + { name: 'renault 5 gtl', milesPerGallon: 36, cylinders: 4, horsepower: 58 }, + { name: 'plymouth arrow gs', milesPerGallon: 25.5, cylinders: 4, horsepower: 96 }, + { name: 'datsun f-10 hatchback', milesPerGallon: 33.5, cylinders: 4, horsepower: 70 }, + { name: 'chevrolet caprice classic', milesPerGallon: 17.5, cylinders: 8, horsepower: 145 }, + { name: 'oldsmobile cutlass supreme', milesPerGallon: 17, cylinders: 8, horsepower: 110 }, + { name: 'dodge monaco brougham', milesPerGallon: 15.5, cylinders: 8, horsepower: 145 }, + { name: 'mercury cougar brougham', milesPerGallon: 15, cylinders: 8, horsepower: 130 }, + { name: 'chevrolet concours', milesPerGallon: 17.5, cylinders: 6, horsepower: 110 }, + { name: 'buick skylark', milesPerGallon: 20.5, cylinders: 6, horsepower: 105 }, + { name: 'plymouth volare custom', milesPerGallon: 19, cylinders: 6, horsepower: 100 }, + { name: 'ford granada', milesPerGallon: 18.5, cylinders: 6, horsepower: 98 }, + { name: 'pontiac grand prix lj', milesPerGallon: 16, cylinders: 8, horsepower: 180 }, + { name: 'chevrolet monte carlo landau', milesPerGallon: 15.5, cylinders: 8, horsepower: 170 }, + { name: 'chrysler cordoba', milesPerGallon: 15.5, cylinders: 8, horsepower: 190 }, + { name: 'ford thunderbird', milesPerGallon: 16, cylinders: 8, horsepower: 149 }, + { name: 'volkswagen rabbit custom', milesPerGallon: 29, cylinders: 4, horsepower: 78 }, + { name: 'pontiac sunbird coupe', milesPerGallon: 24.5, cylinders: 4, horsepower: 88 }, + { name: 'toyota corolla liftback', milesPerGallon: 26, cylinders: 4, horsepower: 75 }, + { name: 'ford mustang ii 2+2', milesPerGallon: 25.5, cylinders: 4, horsepower: 89 }, + { name: 'chevrolet chevette', milesPerGallon: 30.5, cylinders: 4, horsepower: 63 }, + { name: 'dodge colt m/m', milesPerGallon: 33.5, cylinders: 4, horsepower: 83 }, + { name: 'subaru dl', milesPerGallon: 30, cylinders: 4, horsepower: 67 }, + { name: 'volkswagen dasher', milesPerGallon: 30.5, cylinders: 4, horsepower: 78 }, + { name: 'datsun 810', milesPerGallon: 22, cylinders: 6, horsepower: 97 }, + { name: 'bmw 320i', milesPerGallon: 21.5, cylinders: 4, horsepower: 110 }, + { name: 'mazda rx-4', milesPerGallon: 21.5, cylinders: 3, horsepower: 110 }, + { name: 'volkswagen rabbit custom diesel', milesPerGallon: 43.1, cylinders: 4, horsepower: 48 }, + { name: 'ford fiesta', milesPerGallon: 36.1, cylinders: 4, horsepower: 66 }, + { name: 'mazda glc deluxe', milesPerGallon: 32.8, cylinders: 4, horsepower: 52 }, + { name: 'datsun b210 gx', milesPerGallon: 39.4, cylinders: 4, horsepower: 70 }, + { name: 'honda civic cvcc', milesPerGallon: 36.1, cylinders: 4, horsepower: 60 }, + { name: 'oldsmobile cutlass salon brougham', milesPerGallon: 19.9, cylinders: 8, horsepower: 110 }, + { name: 'dodge diplomat', milesPerGallon: 19.4, cylinders: 8, horsepower: 140 }, + { name: 'mercury monarch ghia', milesPerGallon: 20.2, cylinders: 8, horsepower: 139 }, + { name: 'pontiac phoenix lj', milesPerGallon: 19.2, cylinders: 6, horsepower: 105 }, + { name: 'chevrolet malibu', milesPerGallon: 20.5, cylinders: 6, horsepower: 95 }, + { name: 'ford fairmont (auto)', milesPerGallon: 20.2, cylinders: 6, horsepower: 85 }, + { name: 'ford fairmont (man)', milesPerGallon: 25.1, cylinders: 4, horsepower: 88 }, + { name: 'plymouth volare', milesPerGallon: 20.5, cylinders: 6, horsepower: 100 }, + { name: 'amc concord', milesPerGallon: 19.4, cylinders: 6, horsepower: 90 }, + { name: 'buick century special', milesPerGallon: 20.6, cylinders: 6, horsepower: 105 }, + { name: 'mercury zephyr', milesPerGallon: 20.8, cylinders: 6, horsepower: 85 }, + { name: 'dodge aspen', milesPerGallon: 18.6, cylinders: 6, horsepower: 110 }, + { name: 'amc concord d/l', milesPerGallon: 18.1, cylinders: 6, horsepower: 120 }, + { name: 'chevrolet monte carlo landau', milesPerGallon: 19.2, cylinders: 8, horsepower: 145 }, + { name: 'buick regal sport coupe (turbo)', milesPerGallon: 17.7, cylinders: 6, horsepower: 165 }, + { name: 'ford futura', milesPerGallon: 18.1, cylinders: 8, horsepower: 139 }, + { name: 'dodge magnum xe', milesPerGallon: 17.5, cylinders: 8, horsepower: 140 }, + { name: 'chevrolet chevette', milesPerGallon: 30, cylinders: 4, horsepower: 68 }, + { name: 'toyota corona', milesPerGallon: 27.5, cylinders: 4, horsepower: 95 }, + { name: 'datsun 510', milesPerGallon: 27.2, cylinders: 4, horsepower: 97 }, + { name: 'dodge omni', milesPerGallon: 30.9, cylinders: 4, horsepower: 75 }, + { name: 'toyota celica gt liftback', milesPerGallon: 21.1, cylinders: 4, horsepower: 95 }, + { name: 'plymouth sapporo', milesPerGallon: 23.2, cylinders: 4, horsepower: 105 }, + { name: 'oldsmobile starfire sx', milesPerGallon: 23.8, cylinders: 4, horsepower: 85 }, + { name: 'datsun 200-sx', milesPerGallon: 23.9, cylinders: 4, horsepower: 97 }, + { name: 'audi 5000', milesPerGallon: 20.3, cylinders: 5, horsepower: 103 }, + { name: 'volvo 264gl', milesPerGallon: 17, cylinders: 6, horsepower: 125 }, + { name: 'saab 99gle', milesPerGallon: 21.6, cylinders: 4, horsepower: 115 }, + { name: 'peugeot 604sl', milesPerGallon: 16.2, cylinders: 6, horsepower: 133 }, + { name: 'volkswagen scirocco', milesPerGallon: 31.5, cylinders: 4, horsepower: 71 }, + { name: 'honda Accelerationord lx', milesPerGallon: 29.5, cylinders: 4, horsepower: 68 }, + { name: 'pontiac lemans v6', milesPerGallon: 21.5, cylinders: 6, horsepower: 115 }, + { name: 'mercury zephyr 6', milesPerGallon: 19.8, cylinders: 6, horsepower: 85 }, + { name: 'ford fairmont 4', milesPerGallon: 22.3, cylinders: 4, horsepower: 88 }, + { name: 'amc concord dl 6', milesPerGallon: 20.2, cylinders: 6, horsepower: 90 }, + { name: 'dodge aspen 6', milesPerGallon: 20.6, cylinders: 6, horsepower: 110 }, + { name: 'chevrolet caprice classic', milesPerGallon: 17, cylinders: 8, horsepower: 130 }, + { name: 'ford ltd landau', milesPerGallon: 17.6, cylinders: 8, horsepower: 129 }, + { name: 'mercury grand marquis', milesPerGallon: 16.5, cylinders: 8, horsepower: 138 }, + { name: 'dodge st. regis', milesPerGallon: 18.2, cylinders: 8, horsepower: 135 }, + { name: 'buick estate wagon (sw)', milesPerGallon: 16.9, cylinders: 8, horsepower: 155 }, + { name: 'ford country squire (sw)', milesPerGallon: 15.5, cylinders: 8, horsepower: 142 }, + { name: 'chevrolet malibu classic (sw)', milesPerGallon: 19.2, cylinders: 8, horsepower: 125 }, + { name: 'chrysler lebaron town @ country (sw)', milesPerGallon: 18.5, cylinders: 8, horsepower: 150 }, + { name: 'vw rabbit custom', milesPerGallon: 31.9, cylinders: 4, horsepower: 71 }, + { name: 'maxda glc deluxe', milesPerGallon: 34.1, cylinders: 4, horsepower: 65 }, + { name: 'dodge colt hatchback custom', milesPerGallon: 35.7, cylinders: 4, horsepower: 80 }, + { name: 'amc spirit dl', milesPerGallon: 27.4, cylinders: 4, horsepower: 80 }, + { name: 'mercedes benz 300d', milesPerGallon: 25.4, cylinders: 5, horsepower: 77 }, + { name: 'cadillac eldorado', milesPerGallon: 23, cylinders: 8, horsepower: 125 }, + { name: 'peugeot 504', milesPerGallon: 27.2, cylinders: 4, horsepower: 71 }, + { name: 'oldsmobile cutlass salon brougham', milesPerGallon: 23.9, cylinders: 8, horsepower: 90 }, + { name: 'plymouth horizon', milesPerGallon: 34.2, cylinders: 4, horsepower: 70 }, + { name: 'plymouth horizon tc3', milesPerGallon: 34.5, cylinders: 4, horsepower: 70 }, + { name: 'datsun 210', milesPerGallon: 31.8, cylinders: 4, horsepower: 65 }, + { name: 'fiat strada custom', milesPerGallon: 37.3, cylinders: 4, horsepower: 69 }, + { name: 'buick skylark limited', milesPerGallon: 28.4, cylinders: 4, horsepower: 90 }, + { name: 'chevrolet citation', milesPerGallon: 28.8, cylinders: 6, horsepower: 115 }, + { name: 'oldsmobile omega brougham', milesPerGallon: 26.8, cylinders: 6, horsepower: 115 }, + { name: 'pontiac phoenix', milesPerGallon: 33.5, cylinders: 4, horsepower: 90 }, + { name: 'vw rabbit', milesPerGallon: 41.5, cylinders: 4, horsepower: 76 }, + { name: 'toyota corolla tercel', milesPerGallon: 38.1, cylinders: 4, horsepower: 60 }, + { name: 'chevrolet chevette', milesPerGallon: 32.1, cylinders: 4, horsepower: 70 }, + { name: 'datsun 310', milesPerGallon: 37.2, cylinders: 4, horsepower: 65 }, + { name: 'chevrolet citation', milesPerGallon: 28, cylinders: 4, horsepower: 90 }, + { name: 'ford fairmont', milesPerGallon: 26.4, cylinders: 4, horsepower: 88 }, + { name: 'amc concord', milesPerGallon: 24.3, cylinders: 4, horsepower: 90 }, + { name: 'dodge aspen', milesPerGallon: 19.1, cylinders: 6, horsepower: 90 }, + { name: 'audi 4000', milesPerGallon: 34.3, cylinders: 4, horsepower: 78 }, + { name: 'toyota corona liftback', milesPerGallon: 29.8, cylinders: 4, horsepower: 90 }, + { name: 'mazda 626', milesPerGallon: 31.3, cylinders: 4, horsepower: 75 }, + { name: 'datsun 510 hatchback', milesPerGallon: 37, cylinders: 4, horsepower: 92 }, + { name: 'toyota corolla', milesPerGallon: 32.2, cylinders: 4, horsepower: 75 }, + { name: 'mazda glc', milesPerGallon: 46.6, cylinders: 4, horsepower: 65 }, + { name: 'dodge colt', milesPerGallon: 27.9, cylinders: 4, horsepower: 105 }, + { name: 'datsun 210', milesPerGallon: 40.8, cylinders: 4, horsepower: 65 }, + { name: 'vw rabbit c (diesel)', milesPerGallon: 44.3, cylinders: 4, horsepower: 48 }, + { name: 'vw dasher (diesel)', milesPerGallon: 43.4, cylinders: 4, horsepower: 48 }, + { name: 'audi 5000s (diesel)', milesPerGallon: 36.4, cylinders: 5, horsepower: 67 }, + { name: 'mercedes-benz 240d', milesPerGallon: 30, cylinders: 4, horsepower: 67 }, + { name: 'honda civic 1500 gl', milesPerGallon: 44.6, cylinders: 4, horsepower: 67 }, + { name: 'renault lecar deluxe', milesPerGallon: 40.9, cylinders: 4, horsepower: 0 }, + { name: 'subaru dl', milesPerGallon: 33.8, cylinders: 4, horsepower: 67 }, + { name: 'vokswagen rabbit', milesPerGallon: 29.8, cylinders: 4, horsepower: 62 }, + { name: 'datsun 280-zx', milesPerGallon: 32.7, cylinders: 6, horsepower: 132 }, + { name: 'mazda rx-7 gs', milesPerGallon: 23.7, cylinders: 3, horsepower: 100 }, + { name: 'triumph tr7 coupe', milesPerGallon: 35, cylinders: 4, horsepower: 88 }, + { name: 'ford mustang cobra', milesPerGallon: 23.6, cylinders: 4, horsepower: 0 }, + { name: 'honda Accelerationord', milesPerGallon: 32.4, cylinders: 4, horsepower: 72 }, + { name: 'plymouth reliant', milesPerGallon: 27.2, cylinders: 4, horsepower: 84 }, + { name: 'buick skylark', milesPerGallon: 26.6, cylinders: 4, horsepower: 84 }, + { name: 'dodge aries wagon (sw)', milesPerGallon: 25.8, cylinders: 4, horsepower: 92 }, + { name: 'chevrolet citation', milesPerGallon: 23.5, cylinders: 6, horsepower: 110 }, + { name: 'plymouth reliant', milesPerGallon: 30, cylinders: 4, horsepower: 84 }, + { name: 'toyota starlet', milesPerGallon: 39.1, cylinders: 4, horsepower: 58 }, + { name: 'plymouth champ', milesPerGallon: 39, cylinders: 4, horsepower: 64 }, + { name: 'honda civic 1300', milesPerGallon: 35.1, cylinders: 4, horsepower: 60 }, + { name: 'subaru', milesPerGallon: 32.3, cylinders: 4, horsepower: 67 }, + { name: 'datsun 210', milesPerGallon: 37, cylinders: 4, horsepower: 65 }, + { name: 'toyota tercel', milesPerGallon: 37.7, cylinders: 4, horsepower: 62 }, + { name: 'mazda glc 4', milesPerGallon: 34.1, cylinders: 4, horsepower: 68 }, + { name: 'plymouth horizon 4', milesPerGallon: 34.7, cylinders: 4, horsepower: 63 }, + { name: 'ford escort 4w', milesPerGallon: 34.4, cylinders: 4, horsepower: 65 }, + { name: 'ford escort 2h', milesPerGallon: 29.9, cylinders: 4, horsepower: 65 }, + { name: 'volkswagen jetta', milesPerGallon: 33, cylinders: 4, horsepower: 74 }, + { name: 'renault 18i', milesPerGallon: 34.5, cylinders: 4, horsepower: 0 }, + { name: 'honda prelude', milesPerGallon: 33.7, cylinders: 4, horsepower: 75 }, + { name: 'toyota corolla', milesPerGallon: 32.4, cylinders: 4, horsepower: 75 }, + { name: 'datsun 200sx', milesPerGallon: 32.9, cylinders: 4, horsepower: 100 }, + { name: 'mazda 626', milesPerGallon: 31.6, cylinders: 4, horsepower: 74 }, + { name: 'peugeot 505s turbo diesel', milesPerGallon: 28.1, cylinders: 4, horsepower: 80 }, + { name: 'saab 900s', milesPerGallon: 0, cylinders: 4, horsepower: 110 }, + { name: 'volvo diesel', milesPerGallon: 30.7, cylinders: 6, horsepower: 76 }, + { name: 'toyota cressida', milesPerGallon: 25.4, cylinders: 6, horsepower: 116 }, + { name: 'datsun 810 maxima', milesPerGallon: 24.2, cylinders: 6, horsepower: 120 }, + { name: 'buick century', milesPerGallon: 22.4, cylinders: 6, horsepower: 110 }, + { name: 'oldsmobile cutlass ls', milesPerGallon: 26.6, cylinders: 8, horsepower: 105 }, + { name: 'ford granada gl', milesPerGallon: 20.2, cylinders: 6, horsepower: 88 }, + { name: 'chrysler lebaron salon', milesPerGallon: 17.6, cylinders: 6, horsepower: 85 }, + { name: 'chevrolet cavalier', milesPerGallon: 28, cylinders: 4, horsepower: 88 }, + { name: 'chevrolet cavalier wagon', milesPerGallon: 27, cylinders: 4, horsepower: 88 }, + { name: 'chevrolet cavalier 2-door', milesPerGallon: 34, cylinders: 4, horsepower: 88 }, + { name: 'pontiac j2000 se hatchback', milesPerGallon: 31, cylinders: 4, horsepower: 85 }, + { name: 'dodge aries se', milesPerGallon: 29, cylinders: 4, horsepower: 84 }, + { name: 'pontiac phoenix', milesPerGallon: 27, cylinders: 4, horsepower: 90 }, + { name: 'ford fairmont futura', milesPerGallon: 24, cylinders: 4, horsepower: 92 }, + { name: 'amc concord dl', milesPerGallon: 23, cylinders: 4, horsepower: 0 }, + { name: 'volkswagen rabbit l', milesPerGallon: 36, cylinders: 4, horsepower: 74 }, + { name: 'mazda glc custom l', milesPerGallon: 37, cylinders: 4, horsepower: 68 }, + { name: 'mazda glc custom', milesPerGallon: 31, cylinders: 4, horsepower: 68 }, + { name: 'plymouth horizon miser', milesPerGallon: 38, cylinders: 4, horsepower: 63 }, + { name: 'mercury lynx l', milesPerGallon: 36, cylinders: 4, horsepower: 70 }, + { name: 'nissan stanza xe', milesPerGallon: 36, cylinders: 4, horsepower: 88 }, + { name: 'honda Accelerationord', milesPerGallon: 36, cylinders: 4, horsepower: 75 }, + { name: 'toyota corolla', milesPerGallon: 34, cylinders: 4, horsepower: 70 }, + { name: 'honda civic', milesPerGallon: 38, cylinders: 4, horsepower: 67 }, + { name: 'honda civic (auto)', milesPerGallon: 32, cylinders: 4, horsepower: 67 }, + { name: 'datsun 310 gx', milesPerGallon: 38, cylinders: 4, horsepower: 67 }, + { name: 'buick century limited', milesPerGallon: 25, cylinders: 6, horsepower: 110 }, + { name: 'oldsmobile cutlass ciera (diesel)', milesPerGallon: 38, cylinders: 6, horsepower: 85 }, + { name: 'chrysler lebaron medallion', milesPerGallon: 26, cylinders: 4, horsepower: 92 }, + { name: 'ford granada l', milesPerGallon: 22, cylinders: 6, horsepower: 112 }, + { name: 'toyota celica gt', milesPerGallon: 32, cylinders: 4, horsepower: 96 }, + { name: 'dodge charger 2.2', milesPerGallon: 36, cylinders: 4, horsepower: 84 }, + { name: 'chevrolet camaro', milesPerGallon: 27, cylinders: 4, horsepower: 90 }, + { name: 'ford mustang gl', milesPerGallon: 27, cylinders: 4, horsepower: 86 }, + { name: 'vw pickup', milesPerGallon: 44, cylinders: 4, horsepower: 52 }, + { name: 'dodge rampage', milesPerGallon: 32, cylinders: 4, horsepower: 84 }, + { name: 'ford ranger', milesPerGallon: 28, cylinders: 4, horsepower: 79 }, + { name: 'chevy s-10', milesPerGallon: 31, cylinders: 4, horsepower: 82 } +]; + +// 图表配置 +const spec = { + type: 'common', + series: [ + { + type: 'scatter', + xField: 'milesPerGallon', + yField: 'horsepower', + point: { + state: { + hover: { + scaleX: 1.2, + scaleY: 1.2 + } + }, + style: { + fillOpacity: 0.25 + } + } + } + ], + tooltip: { + dimension: { + visible: true + }, + mark: { + title: true, + content: [ + { + key: d => d.name, + value: d => d.y + } + ] + } + }, + crosshair: { + yField: { + visible: true, + line: { + visible: true, + type: 'line' + }, + label: { + visible: true // label 默认关闭 + } + }, + xField: { + visible: true, + line: { + visible: true, + type: 'line' + }, + label: { + visible: true // label 默认关闭 + } + } + }, + axes: [ + { + title: { + visible: true, + text: 'Horse Power' + }, + orient: 'left', + range: { min: 0 }, + type: 'linear' + }, + { + title: { + visible: true, + text: 'Miles Per Gallon' + }, + orient: 'bottom', + label: { visible: true }, + type: 'linear' + } + ], + data: [ + { + id: 'data', + values: data.flat() + } + ] +}; +registerRegressionLine(); +appendScatterRegressionLineConfig(spec, [ + { + type: 'polynomial', // 支持 4 中类型 'linear' | 'logisitc' | 'lowess' | 'polynomial' + polynomialDegree: 3, + color: 'red', + line: { + style: { + lineWidth: 2 + } + }, + confidenceInterval: { + style: { + fillOpacity: 0.2 + } + }, + label: { + text: '3 次多项式回归' + } + }, + { + type: 'linear', + color: 'green', + label: { + text: '线性回归' + } + } +]); +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); + +// Just for the convenience of console debugging, DO NOT COPY! +window['vchart'] = vchart; +``` + +``` + +``` diff --git a/docs/assets/examples/menu.json b/docs/assets/examples/menu.json index 56a82f9080..1979929985 100644 --- a/docs/assets/examples/menu.json +++ b/docs/assets/examples/menu.json @@ -652,6 +652,13 @@ "zh": "轴截断柱图", "en": "Axis Break Column Chart" } + }, + { + "path": "bar-poly-regression-line", + "title": { + "zh": "多项式回归柱状图", + "en": "Bar Chart with Polynomial Regression Line" + } } ] }, @@ -689,6 +696,20 @@ "zh": "水平堆叠直方图", "en": "Horizontal Stacked Histogram" } + }, + { + "path": "histogram-bin", + "title": { + "zh": "使用bin获得分箱数据", + "en": "Obtain binned data using bin" + } + }, + { + "path": "histogram-regression-line", + "title": { + "zh": "直方图和回归线", + "en": "Histogram with Regression Line" + } } ] }, @@ -981,6 +1002,13 @@ "zh": "各种形状的散点图", "en": "Scatter Chart of different shape" } + }, + { + "path": "scatter-regression-line", + "title": { + "zh": "散点图回归线", + "en": "Scatter Chart Regression Line" + } } ] }, diff --git a/docs/assets/examples/zh/bar-chart/bar-poly-regression-line.md b/docs/assets/examples/zh/bar-chart/bar-poly-regression-line.md new file mode 100644 index 0000000000..9571e1fa71 --- /dev/null +++ b/docs/assets/examples/zh/bar-chart/bar-poly-regression-line.md @@ -0,0 +1,174 @@ +--- +category: examples +group: bar chart +title: 基础条形图 +keywords: barChart,comparison,distribution,rank,rectangle +order: 2-7 +cover: https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vchart/preview/bar-chart/bar-regression-line.png +option: barChart +--- + +# 简单柱图+回归线 + +## 关键配置 + +通过在 `appendBarRegressionLineConfig` 方法中传入不同的配置项,可以为柱图添加多条不同阶数和样式的回归线。 + +- `degree`:多项式回归的阶数,如 2 表示二次多项式,3 表示三次多项式。 +- `color`:回归线的颜色。 +- `line.style`:回归线的样式配置,如 `lineWidth` 表示线宽。 +- `confidenceInterval.visible`:是否显示置信区间,布尔值。 +- `confidenceInterval.style`:置信区间的样式配置,如 `fillOpacity` 表示透明度。 +- `label.text`:回归线的标签文本。 + +## 代码演示 + +```javascript livedemo +/** --在业务中使用时请添加以下代码-- */ +// 在业务中使用时, 请额外依赖 @visactor/vchart-extension,包版本保持和vchart一致 +// import { appendBarRegressionLineConfig, registerRegressionLine } from '@visactor/vchart-extension'; +/** --在业务中使用时请添加以上代码-- */ + +/** --在业务中使用时请删除以下代码-- */ +const { appendBarRegressionLineConfig, registerRegressionLine } = VChartExtension; +/** --在业务中使用时请删除以上代码-- */ + +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { + name: 'Apple', + value: 214480 + }, + { + name: 'Google', + value: 155506 + }, + { + name: 'Amazon', + value: 100764 + }, + { + name: 'Microsoft', + value: 92715 + }, + { + name: 'Coca-Cola', + value: 66341 + }, + { + name: 'Samsung', + value: 59890 + }, + { + name: 'Toyota', + value: 53404 + }, + { + name: 'Mercedes-Benz', + value: 48601 + }, + { + name: 'Facebook', + value: 45168 + }, + { + name: "McDonald's", + value: 43417 + }, + { + name: 'Intel', + value: 43293 + }, + { + name: 'IBM', + value: 42972 + }, + { + name: 'BMW', + value: 41006 + }, + { + name: 'Disney', + value: 39874 + }, + { + name: 'Cisco', + value: 34575 + }, + { + name: 'GE', + value: 32757 + }, + { + name: 'Nike', + value: 30120 + }, + { + name: 'Louis Vuitton', + value: 28152 + }, + { + name: 'Oracle', + value: 26133 + }, + { + name: 'Honda', + value: 23682 + } + ] + } + ], + xField: 'name', + yField: 'value' +}; + +registerRegressionLine(); +appendBarRegressionLineConfig(spec, [ + { + degree: 2, + color: 'red', + line: { + style: { + lineWidth: 2 + } + }, + confidenceInterval: { + visible: false + }, + label: { + text: '2次多项式拟合' + } + }, + { + degree: 3, + color: 'green', + line: { + style: { + lineWidth: 2 + } + }, + confidenceInterval: { + style: { + fillOpacity: 0.2 + } + }, + label: { + text: '3次多项式拟合' + } + } +]); + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); + +// Just for the convenience of console debugging, DO NOT COPY! +window['vchart'] = vchart; +``` + +## 相关教程 + +[柱状图](link) diff --git a/docs/assets/examples/zh/histogram-chart/histogram-bin.md b/docs/assets/examples/zh/histogram-chart/histogram-bin.md new file mode 100644 index 0000000000..9619710d3e --- /dev/null +++ b/docs/assets/examples/zh/histogram-chart/histogram-bin.md @@ -0,0 +1,125 @@ +--- +category: examples +group: histogram chart +title: 基础直方图 +keywords: histogram,distribution,rectangle +order: 3-4 +cover: https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vchart/preview/histogram-chart/histogram-bin_2.0.7.png +option: histogramChart +--- + +# 基础直方图 + +本示例展示如何使用 bin 分箱对原始数据进行处理,并生成基础直方图。通过设置 `xField`、`x2Field` 和 `yField`,可以分别指定分箱区间的起始、结束和频数字段。 + +## 关键配置说明 + +- `xField`:指定分箱区间的左端点字段(如 `x0`)。 +- `x2Field`:指定分箱区间的右端点字段(如 `x1`)。 +- `yField`:指定每个分箱的频数字段(如 `frequency`)。 + +通过这些配置,可以将明细数据转化为直方图所需的分箱统计数据,实现数据分布的可视化。 + +## 代码演示 + +```javascript livedemo +const spec = { + data: [ + { + name: 'data1', + transforms: [ + { + type: 'bin', + options: { + step: 2, + field: 'value', + outputNames: { x0: 'x0', x1: 'x1', count: 'frequency' } + } + } + ], + values: [ + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2.3 }, + { value: 2.3 }, + { value: 2.3 }, + { value: 2.3 }, + { value: 2.3 }, + { value: 2.3 }, + { value: 2.3 }, + { value: 4 }, + { value: 4 }, + { value: 4 }, + { value: 4 }, + { value: 4 }, + { value: 7 }, + { value: 7 }, + { value: 7 }, + { value: 7 }, + { value: 7 }, + { value: 7 }, + { value: 7 }, + { value: 7 }, + { value: 7 }, + { value: 7 }, + { value: 7 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 } + ] + } + ], + type: 'histogram', + xField: 'x0', + x2Field: 'x1', + yField: 'frequency', + bar: { + style: { + stroke: 'white', + lineWidth: 1 + } + }, + title: { + text: 'Histogram by bin transform' + }, + tooltip: { + visible: true, + mark: { + title: { + key: 'title', + value: 'frequency' + }, + content: [ + { + key: datum => datum['x0'] + '~' + datum['x1'], + value: datum => datum['frequency'] + } + ] + } + } +}; +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); + +// Just for the convenience of console debugging, DO NOT COPY! +window['vchart'] = vchart; +``` diff --git a/docs/assets/examples/zh/histogram-chart/histogram-regression-line.md b/docs/assets/examples/zh/histogram-chart/histogram-regression-line.md new file mode 100644 index 0000000000..27969091bc --- /dev/null +++ b/docs/assets/examples/zh/histogram-chart/histogram-regression-line.md @@ -0,0 +1,143 @@ +--- +category: examples +group: histogram chart +title: 基础直方图 +keywords: histogram,distribution,rectangle +order: 3-4 +cover: https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vchart/preview/histogram-chart/histogram-regression-line.png +option: histogramChart +--- + +# 直方图回归线 + +## 关键信息 + +- 使用 `bin` 分箱对原始数据进行处理,生成直方图所需的区间和频率数据。 +- 直方图配置中需指定以下字段: + - `xField`:表示每个区间的左端点(如 `x0`)。 + - `x2Field`:表示每个区间的右端点(如 `x1`)。 + - `yField`:表示每个区间的频数(如 `frequency`)。 +- 可通过扩展配置添加回归线(如 KDE 核密度估计和 ECDF 经验累积分布函数)以辅助分析数据分布。 + +## 代码演示 + +```javascript livedemo +/** --在业务中使用时请添加以下代码-- */ +// 在业务中使用时, 请额外依赖 @visactor/vchart-extension,包版本保持和vchart一致 +// import { registerRegressionLine, appendHistogramRegressionLineConfig } from '@visactor/vchart-extension'; +/** --在业务中使用时请添加以上代码-- */ + +/** --在业务中使用时请删除以下代码-- */ +const { registerRegressionLine, appendHistogramRegressionLineConfig } = VChartExtension; +/** --在业务中使用时请删除以上代码-- */ + +function boxMullerRandom() { + let u = 0; + let v = 0; + while (u === 0) { + u = Math.random(); + } + while (v === 0) { + v = Math.random(); + } + return Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v); +} + +function generateGaussian(count, mean = 0, sd = 1) { + const out = []; + for (let i = 0; i < count; i++) { + out.push(mean + boxMullerRandom() * sd); + } + return out; +} + +function generateMixtureGaussianSamples() { + const a = generateGaussian(160, 5, 4, 1); // cluster A + // const b = generateGaussian(80, 2.3, 0.08, 2); // cluster B + // const c = generateGaussian(140, 9.3, 0.35, 3); // cluster C + const outliers = [5.0, 6.2, 3.5, 12.0, 0.5]; + const arr = [...a, ...outliers]; + return arr.map(v => ({ value: v })); +} + +const spec = { + data: [ + { + name: 'data1', + transforms: [ + { + type: 'bin', + options: { + step: 2, + field: 'value', + outputNames: { x0: 'x0', x1: 'x1', count: 'frequency' } + } + } + ], + values: generateMixtureGaussianSamples() + } + ], + type: 'histogram', + xField: 'x0', + x2Field: 'x1', + yField: 'frequency', + bar: { + style: { + stroke: 'white', + lineWidth: 1 + } + }, + title: { + text: 'Histogram of Gaussian data' + }, + tooltip: { + visible: true, + mark: { + title: { + key: 'title', + value: 'frequency' + }, + content: [ + { + key: datum => datum['x0'] + '~' + datum['x1'], + value: datum => datum['frequency'] + } + ] + } + } +}; + +registerRegressionLine(); +appendHistogramRegressionLineConfig(spec, [ + { + type: 'kde', // 支持 'kde' 和 'ecdf' + line: { + style: { + stroke: 'red', + lineWidth: 2 + } + }, + label: { + text: 'KDE核密度估计' + } + }, + { + type: 'ecdf', // 支持 'kde' 和 'ecdf' + line: { + style: { + stroke: 'green', + lineWidth: 2 + } + }, + label: { + text: '经验累积分布函数(ECDF)' + } + } +]); + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); + +// Just for the convenience of console debugging, DO NOT COPY! +window['vchart'] = vchart; +``` diff --git a/docs/assets/examples/zh/scatter-chart/scatter-regression-line.md b/docs/assets/examples/zh/scatter-chart/scatter-regression-line.md new file mode 100644 index 0000000000..1b341fb136 --- /dev/null +++ b/docs/assets/examples/zh/scatter-chart/scatter-regression-line.md @@ -0,0 +1,557 @@ +--- +category: examples +group: extension chart +title: 时序散点图-支持kde背景 +keywords: regression-line, scatterChart +order: +cover: https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vchart/preview/scatter-chart/scatter-regression-line.png +option: scatterChart +--- + +# 散点图支持回归线 + +## 关键配置 + +- 通过 `registerRegressionLine()` 注册回归线扩展 +- 使用 `appendScatterRegressionLineConfig(spec, [...])` 配置多条回归线(如多项式回归、线性回归等) +- 可设置回归线类型(`type: 'linear' | 'logisitc' | 'lowess' | 'polynomial'`)、颜色、阶数(多项式)、置信区间样式和标签等 + +## 代码演示 + +```javascript livedemo +/** --在业务中使用时请添加以下代码-- */ +// 在业务中使用时, 请额外依赖 @visactor/vchart-extension,包版本保持和vchart一致 +// import { registerRegressionLine, appendScatterRegressionLineConfig } from '@visactor/vchart-extension'; +/** --在业务中使用时请添加以上代码-- */ + +/** --在业务中使用时请删除以下代码-- */ +const { registerRegressionLine, appendScatterRegressionLineConfig } = VChartExtension; +/** --在业务中使用时请删除以上代码-- */ + +const data = [ + { name: 'chevrolet chevelle malibu', milesPerGallon: 18, cylinders: 8, horsepower: 130 }, + { name: 'buick skylark 320', milesPerGallon: 15, cylinders: 8, horsepower: 165 }, + { name: 'plymouth satellite', milesPerGallon: 18, cylinders: 8, horsepower: 150 }, + { name: 'amc rebel sst', milesPerGallon: 16, cylinders: 8, horsepower: 150 }, + { name: 'ford torino', milesPerGallon: 17, cylinders: 8, horsepower: 140 }, + { name: 'ford galaxie 500', milesPerGallon: 15, cylinders: 8, horsepower: 198 }, + { name: 'chevrolet impala', milesPerGallon: 14, cylinders: 8, horsepower: 220 }, + { name: 'plymouth fury iii', milesPerGallon: 14, cylinders: 8, horsepower: 215 }, + { name: 'pontiac catalina', milesPerGallon: 14, cylinders: 8, horsepower: 225 }, + { name: 'amc ambassador dpl', milesPerGallon: 15, cylinders: 8, horsepower: 190 }, + { name: 'citroen ds-21 pallas', milesPerGallon: 0, cylinders: 4, horsepower: 115 }, + { name: 'chevrolet chevelle concours (sw)', milesPerGallon: 0, cylinders: 8, horsepower: 165 }, + { name: 'ford torino (sw)', milesPerGallon: 0, cylinders: 8, horsepower: 153 }, + { name: 'plymouth satellite (sw)', milesPerGallon: 0, cylinders: 8, horsepower: 175 }, + { name: 'amc rebel sst (sw)', milesPerGallon: 0, cylinders: 8, horsepower: 175 }, + { name: 'dodge challenger se', milesPerGallon: 15, cylinders: 8, horsepower: 170 }, + { name: "plymouth 'cuda 340", milesPerGallon: 14, cylinders: 8, horsepower: 160 }, + { name: 'ford mustang boss 302', milesPerGallon: 0, cylinders: 8, horsepower: 140 }, + { name: 'chevrolet monte carlo', milesPerGallon: 15, cylinders: 8, horsepower: 150 }, + { name: 'buick estate wagon (sw)', milesPerGallon: 14, cylinders: 8, horsepower: 225 }, + { name: 'toyota corona mark ii', milesPerGallon: 24, cylinders: 4, horsepower: 95 }, + { name: 'plymouth duster', milesPerGallon: 22, cylinders: 6, horsepower: 95 }, + { name: 'amc hornet', milesPerGallon: 18, cylinders: 6, horsepower: 97 }, + { name: 'ford maverick', milesPerGallon: 21, cylinders: 6, horsepower: 85 }, + { name: 'datsun pl510', milesPerGallon: 27, cylinders: 4, horsepower: 88 }, + { name: 'volkswagen 1131 deluxe sedan', milesPerGallon: 26, cylinders: 4, horsepower: 46 }, + { name: 'peugeot 504', milesPerGallon: 25, cylinders: 4, horsepower: 87 }, + { name: 'audi 100 ls', milesPerGallon: 24, cylinders: 4, horsepower: 90 }, + { name: 'saab 99e', milesPerGallon: 25, cylinders: 4, horsepower: 95 }, + { name: 'bmw 2002', milesPerGallon: 26, cylinders: 4, horsepower: 113 }, + { name: 'amc gremlin', milesPerGallon: 21, cylinders: 6, horsepower: 90 }, + { name: 'ford f250', milesPerGallon: 10, cylinders: 8, horsepower: 215 }, + { name: 'chevy c20', milesPerGallon: 10, cylinders: 8, horsepower: 200 }, + { name: 'dodge d200', milesPerGallon: 11, cylinders: 8, horsepower: 210 }, + { name: 'hi 1200d', milesPerGallon: 9, cylinders: 8, horsepower: 193 }, + { name: 'datsun pl510', milesPerGallon: 27, cylinders: 4, horsepower: 88 }, + { name: 'chevrolet vega 2300', milesPerGallon: 28, cylinders: 4, horsepower: 90 }, + { name: 'toyota corona', milesPerGallon: 25, cylinders: 4, horsepower: 95 }, + { name: 'ford pinto', milesPerGallon: 25, cylinders: 4, horsepower: 0 }, + { name: 'volkswagen super beetle 117', milesPerGallon: 0, cylinders: 4, horsepower: 48 }, + { name: 'amc gremlin', milesPerGallon: 19, cylinders: 6, horsepower: 100 }, + { name: 'plymouth satellite custom', milesPerGallon: 16, cylinders: 6, horsepower: 105 }, + { name: 'chevrolet chevelle malibu', milesPerGallon: 17, cylinders: 6, horsepower: 100 }, + { name: 'ford torino 500', milesPerGallon: 19, cylinders: 6, horsepower: 88 }, + { name: 'amc matador', milesPerGallon: 18, cylinders: 6, horsepower: 100 }, + { name: 'chevrolet impala', milesPerGallon: 14, cylinders: 8, horsepower: 165 }, + { name: 'pontiac catalina brougham', milesPerGallon: 14, cylinders: 8, horsepower: 175 }, + { name: 'ford galaxie 500', milesPerGallon: 14, cylinders: 8, horsepower: 153 }, + { name: 'plymouth fury iii', milesPerGallon: 14, cylinders: 8, horsepower: 150 }, + { name: 'dodge monaco (sw)', milesPerGallon: 12, cylinders: 8, horsepower: 180 }, + { name: 'ford country squire (sw)', milesPerGallon: 13, cylinders: 8, horsepower: 170 }, + { name: 'pontiac safari (sw)', milesPerGallon: 13, cylinders: 8, horsepower: 175 }, + { name: 'amc hornet sportabout (sw)', milesPerGallon: 18, cylinders: 6, horsepower: 110 }, + { name: 'chevrolet vega (sw)', milesPerGallon: 22, cylinders: 4, horsepower: 72 }, + { name: 'pontiac firebird', milesPerGallon: 19, cylinders: 6, horsepower: 100 }, + { name: 'ford mustang', milesPerGallon: 18, cylinders: 6, horsepower: 88 }, + { name: 'mercury capri 2000', milesPerGallon: 23, cylinders: 4, horsepower: 86 }, + { name: 'opel 1900', milesPerGallon: 28, cylinders: 4, horsepower: 90 }, + { name: 'peugeot 304', milesPerGallon: 30, cylinders: 4, horsepower: 70 }, + { name: 'fiat 124b', milesPerGallon: 30, cylinders: 4, horsepower: 76 }, + { name: 'toyota corolla 1200', milesPerGallon: 31, cylinders: 4, horsepower: 65 }, + { name: 'datsun 1200', milesPerGallon: 35, cylinders: 4, horsepower: 69 }, + { name: 'volkswagen model 111', milesPerGallon: 27, cylinders: 4, horsepower: 60 }, + { name: 'plymouth cricket', milesPerGallon: 26, cylinders: 4, horsepower: 70 }, + { name: 'toyota corona hardtop', milesPerGallon: 24, cylinders: 4, horsepower: 95 }, + { name: 'dodge colt hardtop', milesPerGallon: 25, cylinders: 4, horsepower: 80 }, + { name: 'volkswagen type 3', milesPerGallon: 23, cylinders: 4, horsepower: 54 }, + { name: 'chevrolet vega', milesPerGallon: 20, cylinders: 4, horsepower: 90 }, + { name: 'ford pinto runabout', milesPerGallon: 21, cylinders: 4, horsepower: 86 }, + { name: 'chevrolet impala', milesPerGallon: 13, cylinders: 8, horsepower: 165 }, + { name: 'pontiac catalina', milesPerGallon: 14, cylinders: 8, horsepower: 175 }, + { name: 'plymouth fury iii', milesPerGallon: 15, cylinders: 8, horsepower: 150 }, + { name: 'ford galaxie 500', milesPerGallon: 14, cylinders: 8, horsepower: 153 }, + { name: 'amc ambassador sst', milesPerGallon: 17, cylinders: 8, horsepower: 150 }, + { name: 'mercury marquis', milesPerGallon: 11, cylinders: 8, horsepower: 208 }, + { name: 'buick lesabre custom', milesPerGallon: 13, cylinders: 8, horsepower: 155 }, + { name: 'oldsmobile delta 88 royale', milesPerGallon: 12, cylinders: 8, horsepower: 160 }, + { name: 'chrysler newport royal', milesPerGallon: 13, cylinders: 8, horsepower: 190 }, + { name: 'mazda rx2 coupe', milesPerGallon: 19, cylinders: 3, horsepower: 97 }, + { name: 'amc matador (sw)', milesPerGallon: 15, cylinders: 8, horsepower: 150 }, + { name: 'chevrolet chevelle concours (sw)', milesPerGallon: 13, cylinders: 8, horsepower: 130 }, + { name: 'ford gran torino (sw)', milesPerGallon: 13, cylinders: 8, horsepower: 140 }, + { name: 'plymouth satellite custom (sw)', milesPerGallon: 14, cylinders: 8, horsepower: 150 }, + { name: 'volvo 145e (sw)', milesPerGallon: 18, cylinders: 4, horsepower: 112 }, + { name: 'volkswagen 411 (sw)', milesPerGallon: 22, cylinders: 4, horsepower: 76 }, + { name: 'peugeot 504 (sw)', milesPerGallon: 21, cylinders: 4, horsepower: 87 }, + { name: 'renault 12 (sw)', milesPerGallon: 26, cylinders: 4, horsepower: 69 }, + { name: 'ford pinto (sw)', milesPerGallon: 22, cylinders: 4, horsepower: 86 }, + { name: 'datsun 510 (sw)', milesPerGallon: 28, cylinders: 4, horsepower: 92 }, + { name: 'toyouta corona mark ii (sw)', milesPerGallon: 23, cylinders: 4, horsepower: 97 }, + { name: 'dodge colt (sw)', milesPerGallon: 28, cylinders: 4, horsepower: 80 }, + { name: 'toyota corolla 1600 (sw)', milesPerGallon: 27, cylinders: 4, horsepower: 88 }, + { name: 'buick century 350', milesPerGallon: 13, cylinders: 8, horsepower: 175 }, + { name: 'amc matador', milesPerGallon: 14, cylinders: 8, horsepower: 150 }, + { name: 'chevrolet malibu', milesPerGallon: 13, cylinders: 8, horsepower: 145 }, + { name: 'ford gran torino', milesPerGallon: 14, cylinders: 8, horsepower: 137 }, + { name: 'dodge coronet custom', milesPerGallon: 15, cylinders: 8, horsepower: 150 }, + { name: 'mercury marquis brougham', milesPerGallon: 12, cylinders: 8, horsepower: 198 }, + { name: 'chevrolet caprice classic', milesPerGallon: 13, cylinders: 8, horsepower: 150 }, + { name: 'ford ltd', milesPerGallon: 13, cylinders: 8, horsepower: 158 }, + { name: 'plymouth fury gran sedan', milesPerGallon: 14, cylinders: 8, horsepower: 150 }, + { name: 'chrysler new yorker brougham', milesPerGallon: 13, cylinders: 8, horsepower: 215 }, + { name: 'buick electra 225 custom', milesPerGallon: 12, cylinders: 8, horsepower: 225 }, + { name: 'amc ambassador brougham', milesPerGallon: 13, cylinders: 8, horsepower: 175 }, + { name: 'plymouth valiant', milesPerGallon: 18, cylinders: 6, horsepower: 105 }, + { name: 'chevrolet nova custom', milesPerGallon: 16, cylinders: 6, horsepower: 100 }, + { name: 'amc hornet', milesPerGallon: 18, cylinders: 6, horsepower: 100 }, + { name: 'ford maverick', milesPerGallon: 18, cylinders: 6, horsepower: 88 }, + { name: 'plymouth duster', milesPerGallon: 23, cylinders: 6, horsepower: 95 }, + { name: 'volkswagen super beetle', milesPerGallon: 26, cylinders: 4, horsepower: 46 }, + { name: 'chevrolet impala', milesPerGallon: 11, cylinders: 8, horsepower: 150 }, + { name: 'ford country', milesPerGallon: 12, cylinders: 8, horsepower: 167 }, + { name: 'plymouth custom suburb', milesPerGallon: 13, cylinders: 8, horsepower: 170 }, + { name: 'oldsmobile vista cruiser', milesPerGallon: 12, cylinders: 8, horsepower: 180 }, + { name: 'amc gremlin', milesPerGallon: 18, cylinders: 6, horsepower: 100 }, + { name: 'toyota carina', milesPerGallon: 20, cylinders: 4, horsepower: 88 }, + { name: 'chevrolet vega', milesPerGallon: 21, cylinders: 4, horsepower: 72 }, + { name: 'datsun 610', milesPerGallon: 22, cylinders: 4, horsepower: 94 }, + { name: 'maxda rx3', milesPerGallon: 18, cylinders: 3, horsepower: 90 }, + { name: 'ford pinto', milesPerGallon: 19, cylinders: 4, horsepower: 85 }, + { name: 'mercury capri v6', milesPerGallon: 21, cylinders: 6, horsepower: 107 }, + { name: 'fiat 124 sport coupe', milesPerGallon: 26, cylinders: 4, horsepower: 90 }, + { name: 'chevrolet monte carlo s', milesPerGallon: 15, cylinders: 8, horsepower: 145 }, + { name: 'pontiac grand prix', milesPerGallon: 16, cylinders: 8, horsepower: 230 }, + { name: 'fiat 128', milesPerGallon: 29, cylinders: 4, horsepower: 49 }, + { name: 'opel manta', milesPerGallon: 24, cylinders: 4, horsepower: 75 }, + { name: 'audi 100ls', milesPerGallon: 20, cylinders: 4, horsepower: 91 }, + { name: 'volvo 144ea', milesPerGallon: 19, cylinders: 4, horsepower: 112 }, + { name: 'dodge dart custom', milesPerGallon: 15, cylinders: 8, horsepower: 150 }, + { name: 'saab 99le', milesPerGallon: 24, cylinders: 4, horsepower: 110 }, + { name: 'toyota mark ii', milesPerGallon: 20, cylinders: 6, horsepower: 122 }, + { name: 'oldsmobile omega', milesPerGallon: 11, cylinders: 8, horsepower: 180 }, + { name: 'plymouth duster', milesPerGallon: 20, cylinders: 6, horsepower: 95 }, + { name: 'ford maverick', milesPerGallon: 21, cylinders: 6, horsepower: 0 }, + { name: 'amc hornet', milesPerGallon: 19, cylinders: 6, horsepower: 100 }, + { name: 'chevrolet nova', milesPerGallon: 15, cylinders: 6, horsepower: 100 }, + { name: 'datsun b210', milesPerGallon: 31, cylinders: 4, horsepower: 67 }, + { name: 'ford pinto', milesPerGallon: 26, cylinders: 4, horsepower: 80 }, + { name: 'toyota corolla 1200', milesPerGallon: 32, cylinders: 4, horsepower: 65 }, + { name: 'chevrolet vega', milesPerGallon: 25, cylinders: 4, horsepower: 75 }, + { name: 'chevrolet chevelle malibu classic', milesPerGallon: 16, cylinders: 6, horsepower: 100 }, + { name: 'amc matador', milesPerGallon: 16, cylinders: 6, horsepower: 110 }, + { name: 'plymouth satellite sebring', milesPerGallon: 18, cylinders: 6, horsepower: 105 }, + { name: 'ford gran torino', milesPerGallon: 16, cylinders: 8, horsepower: 140 }, + { name: 'buick century luxus (sw)', milesPerGallon: 13, cylinders: 8, horsepower: 150 }, + { name: 'dodge coronet custom (sw)', milesPerGallon: 14, cylinders: 8, horsepower: 150 }, + { name: 'ford gran torino (sw)', milesPerGallon: 14, cylinders: 8, horsepower: 140 }, + { name: 'amc matador (sw)', milesPerGallon: 14, cylinders: 8, horsepower: 150 }, + { name: 'audi fox', milesPerGallon: 29, cylinders: 4, horsepower: 83 }, + { name: 'volkswagen dasher', milesPerGallon: 26, cylinders: 4, horsepower: 67 }, + { name: 'opel manta', milesPerGallon: 26, cylinders: 4, horsepower: 78 }, + { name: 'toyota corona', milesPerGallon: 31, cylinders: 4, horsepower: 52 }, + { name: 'datsun 710', milesPerGallon: 32, cylinders: 4, horsepower: 61 }, + { name: 'dodge colt', milesPerGallon: 28, cylinders: 4, horsepower: 75 }, + { name: 'fiat 128', milesPerGallon: 24, cylinders: 4, horsepower: 75 }, + { name: 'fiat 124 tc', milesPerGallon: 26, cylinders: 4, horsepower: 75 }, + { name: 'honda civic', milesPerGallon: 24, cylinders: 4, horsepower: 97 }, + { name: 'subaru', milesPerGallon: 26, cylinders: 4, horsepower: 93 }, + { name: 'fiat x1.9', milesPerGallon: 31, cylinders: 4, horsepower: 67 }, + { name: 'plymouth valiant custom', milesPerGallon: 19, cylinders: 6, horsepower: 95 }, + { name: 'chevrolet nova', milesPerGallon: 18, cylinders: 6, horsepower: 105 }, + { name: 'mercury monarch', milesPerGallon: 15, cylinders: 6, horsepower: 72 }, + { name: 'ford maverick', milesPerGallon: 15, cylinders: 6, horsepower: 72 }, + { name: 'pontiac catalina', milesPerGallon: 16, cylinders: 8, horsepower: 170 }, + { name: 'chevrolet bel air', milesPerGallon: 15, cylinders: 8, horsepower: 145 }, + { name: 'plymouth grand fury', milesPerGallon: 16, cylinders: 8, horsepower: 150 }, + { name: 'ford ltd', milesPerGallon: 14, cylinders: 8, horsepower: 148 }, + { name: 'buick century', milesPerGallon: 17, cylinders: 6, horsepower: 110 }, + { name: 'chevroelt chevelle malibu', milesPerGallon: 16, cylinders: 6, horsepower: 105 }, + { name: 'amc matador', milesPerGallon: 15, cylinders: 6, horsepower: 110 }, + { name: 'plymouth fury', milesPerGallon: 18, cylinders: 6, horsepower: 95 }, + { name: 'buick skyhawk', milesPerGallon: 21, cylinders: 6, horsepower: 110 }, + { name: 'chevrolet monza 2+2', milesPerGallon: 20, cylinders: 8, horsepower: 110 }, + { name: 'ford mustang ii', milesPerGallon: 13, cylinders: 8, horsepower: 129 }, + { name: 'toyota corolla', milesPerGallon: 29, cylinders: 4, horsepower: 75 }, + { name: 'ford pinto', milesPerGallon: 23, cylinders: 4, horsepower: 83 }, + { name: 'amc gremlin', milesPerGallon: 20, cylinders: 6, horsepower: 100 }, + { name: 'pontiac astro', milesPerGallon: 23, cylinders: 4, horsepower: 78 }, + { name: 'toyota corona', milesPerGallon: 24, cylinders: 4, horsepower: 96 }, + { name: 'volkswagen dasher', milesPerGallon: 25, cylinders: 4, horsepower: 71 }, + { name: 'datsun 710', milesPerGallon: 24, cylinders: 4, horsepower: 97 }, + { name: 'ford pinto', milesPerGallon: 18, cylinders: 6, horsepower: 97 }, + { name: 'volkswagen rabbit', milesPerGallon: 29, cylinders: 4, horsepower: 70 }, + { name: 'amc pacer', milesPerGallon: 19, cylinders: 6, horsepower: 90 }, + { name: 'audi 100ls', milesPerGallon: 23, cylinders: 4, horsepower: 95 }, + { name: 'peugeot 504', milesPerGallon: 23, cylinders: 4, horsepower: 88 }, + { name: 'volvo 244dl', milesPerGallon: 22, cylinders: 4, horsepower: 98 }, + { name: 'saab 99le', milesPerGallon: 25, cylinders: 4, horsepower: 115 }, + { name: 'honda civic cvcc', milesPerGallon: 33, cylinders: 4, horsepower: 53 }, + { name: 'fiat 131', milesPerGallon: 28, cylinders: 4, horsepower: 86 }, + { name: 'opel 1900', milesPerGallon: 25, cylinders: 4, horsepower: 81 }, + { name: 'capri ii', milesPerGallon: 25, cylinders: 4, horsepower: 92 }, + { name: 'dodge colt', milesPerGallon: 26, cylinders: 4, horsepower: 79 }, + { name: 'renault 12tl', milesPerGallon: 27, cylinders: 4, horsepower: 83 }, + { name: 'chevrolet chevelle malibu classic', milesPerGallon: 17.5, cylinders: 8, horsepower: 140 }, + { name: 'dodge coronet brougham', milesPerGallon: 16, cylinders: 8, horsepower: 150 }, + { name: 'amc matador', milesPerGallon: 15.5, cylinders: 8, horsepower: 120 }, + { name: 'ford gran torino', milesPerGallon: 14.5, cylinders: 8, horsepower: 152 }, + { name: 'plymouth valiant', milesPerGallon: 22, cylinders: 6, horsepower: 100 }, + { name: 'chevrolet nova', milesPerGallon: 22, cylinders: 6, horsepower: 105 }, + { name: 'ford maverick', milesPerGallon: 24, cylinders: 6, horsepower: 81 }, + { name: 'amc hornet', milesPerGallon: 22.5, cylinders: 6, horsepower: 90 }, + { name: 'chevrolet chevette', milesPerGallon: 29, cylinders: 4, horsepower: 52 }, + { name: 'chevrolet woody', milesPerGallon: 24.5, cylinders: 4, horsepower: 60 }, + { name: 'vw rabbit', milesPerGallon: 29, cylinders: 4, horsepower: 70 }, + { name: 'honda civic', milesPerGallon: 33, cylinders: 4, horsepower: 53 }, + { name: 'dodge aspen se', milesPerGallon: 20, cylinders: 6, horsepower: 100 }, + { name: 'ford granada ghia', milesPerGallon: 18, cylinders: 6, horsepower: 78 }, + { name: 'pontiac ventura sj', milesPerGallon: 18.5, cylinders: 6, horsepower: 110 }, + { name: 'amc pacer d/l', milesPerGallon: 17.5, cylinders: 6, horsepower: 95 }, + { name: 'volkswagen rabbit', milesPerGallon: 29.5, cylinders: 4, horsepower: 71 }, + { name: 'datsun b-210', milesPerGallon: 32, cylinders: 4, horsepower: 70 }, + { name: 'toyota corolla', milesPerGallon: 28, cylinders: 4, horsepower: 75 }, + { name: 'ford pinto', milesPerGallon: 26.5, cylinders: 4, horsepower: 72 }, + { name: 'volvo 245', milesPerGallon: 20, cylinders: 4, horsepower: 102 }, + { name: 'plymouth volare premier v8', milesPerGallon: 13, cylinders: 8, horsepower: 150 }, + { name: 'peugeot 504', milesPerGallon: 19, cylinders: 4, horsepower: 88 }, + { name: 'toyota mark ii', milesPerGallon: 19, cylinders: 6, horsepower: 108 }, + { name: 'mercedes-benz 280s', milesPerGallon: 16.5, cylinders: 6, horsepower: 120 }, + { name: 'cadillac seville', milesPerGallon: 16.5, cylinders: 8, horsepower: 180 }, + { name: 'chevy c10', milesPerGallon: 13, cylinders: 8, horsepower: 145 }, + { name: 'ford f108', milesPerGallon: 13, cylinders: 8, horsepower: 130 }, + { name: 'dodge d100', milesPerGallon: 13, cylinders: 8, horsepower: 150 }, + { name: 'honda Accelerationord cvcc', milesPerGallon: 31.5, cylinders: 4, horsepower: 68 }, + { name: 'buick opel isuzu deluxe', milesPerGallon: 30, cylinders: 4, horsepower: 80 }, + { name: 'renault 5 gtl', milesPerGallon: 36, cylinders: 4, horsepower: 58 }, + { name: 'plymouth arrow gs', milesPerGallon: 25.5, cylinders: 4, horsepower: 96 }, + { name: 'datsun f-10 hatchback', milesPerGallon: 33.5, cylinders: 4, horsepower: 70 }, + { name: 'chevrolet caprice classic', milesPerGallon: 17.5, cylinders: 8, horsepower: 145 }, + { name: 'oldsmobile cutlass supreme', milesPerGallon: 17, cylinders: 8, horsepower: 110 }, + { name: 'dodge monaco brougham', milesPerGallon: 15.5, cylinders: 8, horsepower: 145 }, + { name: 'mercury cougar brougham', milesPerGallon: 15, cylinders: 8, horsepower: 130 }, + { name: 'chevrolet concours', milesPerGallon: 17.5, cylinders: 6, horsepower: 110 }, + { name: 'buick skylark', milesPerGallon: 20.5, cylinders: 6, horsepower: 105 }, + { name: 'plymouth volare custom', milesPerGallon: 19, cylinders: 6, horsepower: 100 }, + { name: 'ford granada', milesPerGallon: 18.5, cylinders: 6, horsepower: 98 }, + { name: 'pontiac grand prix lj', milesPerGallon: 16, cylinders: 8, horsepower: 180 }, + { name: 'chevrolet monte carlo landau', milesPerGallon: 15.5, cylinders: 8, horsepower: 170 }, + { name: 'chrysler cordoba', milesPerGallon: 15.5, cylinders: 8, horsepower: 190 }, + { name: 'ford thunderbird', milesPerGallon: 16, cylinders: 8, horsepower: 149 }, + { name: 'volkswagen rabbit custom', milesPerGallon: 29, cylinders: 4, horsepower: 78 }, + { name: 'pontiac sunbird coupe', milesPerGallon: 24.5, cylinders: 4, horsepower: 88 }, + { name: 'toyota corolla liftback', milesPerGallon: 26, cylinders: 4, horsepower: 75 }, + { name: 'ford mustang ii 2+2', milesPerGallon: 25.5, cylinders: 4, horsepower: 89 }, + { name: 'chevrolet chevette', milesPerGallon: 30.5, cylinders: 4, horsepower: 63 }, + { name: 'dodge colt m/m', milesPerGallon: 33.5, cylinders: 4, horsepower: 83 }, + { name: 'subaru dl', milesPerGallon: 30, cylinders: 4, horsepower: 67 }, + { name: 'volkswagen dasher', milesPerGallon: 30.5, cylinders: 4, horsepower: 78 }, + { name: 'datsun 810', milesPerGallon: 22, cylinders: 6, horsepower: 97 }, + { name: 'bmw 320i', milesPerGallon: 21.5, cylinders: 4, horsepower: 110 }, + { name: 'mazda rx-4', milesPerGallon: 21.5, cylinders: 3, horsepower: 110 }, + { name: 'volkswagen rabbit custom diesel', milesPerGallon: 43.1, cylinders: 4, horsepower: 48 }, + { name: 'ford fiesta', milesPerGallon: 36.1, cylinders: 4, horsepower: 66 }, + { name: 'mazda glc deluxe', milesPerGallon: 32.8, cylinders: 4, horsepower: 52 }, + { name: 'datsun b210 gx', milesPerGallon: 39.4, cylinders: 4, horsepower: 70 }, + { name: 'honda civic cvcc', milesPerGallon: 36.1, cylinders: 4, horsepower: 60 }, + { name: 'oldsmobile cutlass salon brougham', milesPerGallon: 19.9, cylinders: 8, horsepower: 110 }, + { name: 'dodge diplomat', milesPerGallon: 19.4, cylinders: 8, horsepower: 140 }, + { name: 'mercury monarch ghia', milesPerGallon: 20.2, cylinders: 8, horsepower: 139 }, + { name: 'pontiac phoenix lj', milesPerGallon: 19.2, cylinders: 6, horsepower: 105 }, + { name: 'chevrolet malibu', milesPerGallon: 20.5, cylinders: 6, horsepower: 95 }, + { name: 'ford fairmont (auto)', milesPerGallon: 20.2, cylinders: 6, horsepower: 85 }, + { name: 'ford fairmont (man)', milesPerGallon: 25.1, cylinders: 4, horsepower: 88 }, + { name: 'plymouth volare', milesPerGallon: 20.5, cylinders: 6, horsepower: 100 }, + { name: 'amc concord', milesPerGallon: 19.4, cylinders: 6, horsepower: 90 }, + { name: 'buick century special', milesPerGallon: 20.6, cylinders: 6, horsepower: 105 }, + { name: 'mercury zephyr', milesPerGallon: 20.8, cylinders: 6, horsepower: 85 }, + { name: 'dodge aspen', milesPerGallon: 18.6, cylinders: 6, horsepower: 110 }, + { name: 'amc concord d/l', milesPerGallon: 18.1, cylinders: 6, horsepower: 120 }, + { name: 'chevrolet monte carlo landau', milesPerGallon: 19.2, cylinders: 8, horsepower: 145 }, + { name: 'buick regal sport coupe (turbo)', milesPerGallon: 17.7, cylinders: 6, horsepower: 165 }, + { name: 'ford futura', milesPerGallon: 18.1, cylinders: 8, horsepower: 139 }, + { name: 'dodge magnum xe', milesPerGallon: 17.5, cylinders: 8, horsepower: 140 }, + { name: 'chevrolet chevette', milesPerGallon: 30, cylinders: 4, horsepower: 68 }, + { name: 'toyota corona', milesPerGallon: 27.5, cylinders: 4, horsepower: 95 }, + { name: 'datsun 510', milesPerGallon: 27.2, cylinders: 4, horsepower: 97 }, + { name: 'dodge omni', milesPerGallon: 30.9, cylinders: 4, horsepower: 75 }, + { name: 'toyota celica gt liftback', milesPerGallon: 21.1, cylinders: 4, horsepower: 95 }, + { name: 'plymouth sapporo', milesPerGallon: 23.2, cylinders: 4, horsepower: 105 }, + { name: 'oldsmobile starfire sx', milesPerGallon: 23.8, cylinders: 4, horsepower: 85 }, + { name: 'datsun 200-sx', milesPerGallon: 23.9, cylinders: 4, horsepower: 97 }, + { name: 'audi 5000', milesPerGallon: 20.3, cylinders: 5, horsepower: 103 }, + { name: 'volvo 264gl', milesPerGallon: 17, cylinders: 6, horsepower: 125 }, + { name: 'saab 99gle', milesPerGallon: 21.6, cylinders: 4, horsepower: 115 }, + { name: 'peugeot 604sl', milesPerGallon: 16.2, cylinders: 6, horsepower: 133 }, + { name: 'volkswagen scirocco', milesPerGallon: 31.5, cylinders: 4, horsepower: 71 }, + { name: 'honda Accelerationord lx', milesPerGallon: 29.5, cylinders: 4, horsepower: 68 }, + { name: 'pontiac lemans v6', milesPerGallon: 21.5, cylinders: 6, horsepower: 115 }, + { name: 'mercury zephyr 6', milesPerGallon: 19.8, cylinders: 6, horsepower: 85 }, + { name: 'ford fairmont 4', milesPerGallon: 22.3, cylinders: 4, horsepower: 88 }, + { name: 'amc concord dl 6', milesPerGallon: 20.2, cylinders: 6, horsepower: 90 }, + { name: 'dodge aspen 6', milesPerGallon: 20.6, cylinders: 6, horsepower: 110 }, + { name: 'chevrolet caprice classic', milesPerGallon: 17, cylinders: 8, horsepower: 130 }, + { name: 'ford ltd landau', milesPerGallon: 17.6, cylinders: 8, horsepower: 129 }, + { name: 'mercury grand marquis', milesPerGallon: 16.5, cylinders: 8, horsepower: 138 }, + { name: 'dodge st. regis', milesPerGallon: 18.2, cylinders: 8, horsepower: 135 }, + { name: 'buick estate wagon (sw)', milesPerGallon: 16.9, cylinders: 8, horsepower: 155 }, + { name: 'ford country squire (sw)', milesPerGallon: 15.5, cylinders: 8, horsepower: 142 }, + { name: 'chevrolet malibu classic (sw)', milesPerGallon: 19.2, cylinders: 8, horsepower: 125 }, + { name: 'chrysler lebaron town @ country (sw)', milesPerGallon: 18.5, cylinders: 8, horsepower: 150 }, + { name: 'vw rabbit custom', milesPerGallon: 31.9, cylinders: 4, horsepower: 71 }, + { name: 'maxda glc deluxe', milesPerGallon: 34.1, cylinders: 4, horsepower: 65 }, + { name: 'dodge colt hatchback custom', milesPerGallon: 35.7, cylinders: 4, horsepower: 80 }, + { name: 'amc spirit dl', milesPerGallon: 27.4, cylinders: 4, horsepower: 80 }, + { name: 'mercedes benz 300d', milesPerGallon: 25.4, cylinders: 5, horsepower: 77 }, + { name: 'cadillac eldorado', milesPerGallon: 23, cylinders: 8, horsepower: 125 }, + { name: 'peugeot 504', milesPerGallon: 27.2, cylinders: 4, horsepower: 71 }, + { name: 'oldsmobile cutlass salon brougham', milesPerGallon: 23.9, cylinders: 8, horsepower: 90 }, + { name: 'plymouth horizon', milesPerGallon: 34.2, cylinders: 4, horsepower: 70 }, + { name: 'plymouth horizon tc3', milesPerGallon: 34.5, cylinders: 4, horsepower: 70 }, + { name: 'datsun 210', milesPerGallon: 31.8, cylinders: 4, horsepower: 65 }, + { name: 'fiat strada custom', milesPerGallon: 37.3, cylinders: 4, horsepower: 69 }, + { name: 'buick skylark limited', milesPerGallon: 28.4, cylinders: 4, horsepower: 90 }, + { name: 'chevrolet citation', milesPerGallon: 28.8, cylinders: 6, horsepower: 115 }, + { name: 'oldsmobile omega brougham', milesPerGallon: 26.8, cylinders: 6, horsepower: 115 }, + { name: 'pontiac phoenix', milesPerGallon: 33.5, cylinders: 4, horsepower: 90 }, + { name: 'vw rabbit', milesPerGallon: 41.5, cylinders: 4, horsepower: 76 }, + { name: 'toyota corolla tercel', milesPerGallon: 38.1, cylinders: 4, horsepower: 60 }, + { name: 'chevrolet chevette', milesPerGallon: 32.1, cylinders: 4, horsepower: 70 }, + { name: 'datsun 310', milesPerGallon: 37.2, cylinders: 4, horsepower: 65 }, + { name: 'chevrolet citation', milesPerGallon: 28, cylinders: 4, horsepower: 90 }, + { name: 'ford fairmont', milesPerGallon: 26.4, cylinders: 4, horsepower: 88 }, + { name: 'amc concord', milesPerGallon: 24.3, cylinders: 4, horsepower: 90 }, + { name: 'dodge aspen', milesPerGallon: 19.1, cylinders: 6, horsepower: 90 }, + { name: 'audi 4000', milesPerGallon: 34.3, cylinders: 4, horsepower: 78 }, + { name: 'toyota corona liftback', milesPerGallon: 29.8, cylinders: 4, horsepower: 90 }, + { name: 'mazda 626', milesPerGallon: 31.3, cylinders: 4, horsepower: 75 }, + { name: 'datsun 510 hatchback', milesPerGallon: 37, cylinders: 4, horsepower: 92 }, + { name: 'toyota corolla', milesPerGallon: 32.2, cylinders: 4, horsepower: 75 }, + { name: 'mazda glc', milesPerGallon: 46.6, cylinders: 4, horsepower: 65 }, + { name: 'dodge colt', milesPerGallon: 27.9, cylinders: 4, horsepower: 105 }, + { name: 'datsun 210', milesPerGallon: 40.8, cylinders: 4, horsepower: 65 }, + { name: 'vw rabbit c (diesel)', milesPerGallon: 44.3, cylinders: 4, horsepower: 48 }, + { name: 'vw dasher (diesel)', milesPerGallon: 43.4, cylinders: 4, horsepower: 48 }, + { name: 'audi 5000s (diesel)', milesPerGallon: 36.4, cylinders: 5, horsepower: 67 }, + { name: 'mercedes-benz 240d', milesPerGallon: 30, cylinders: 4, horsepower: 67 }, + { name: 'honda civic 1500 gl', milesPerGallon: 44.6, cylinders: 4, horsepower: 67 }, + { name: 'renault lecar deluxe', milesPerGallon: 40.9, cylinders: 4, horsepower: 0 }, + { name: 'subaru dl', milesPerGallon: 33.8, cylinders: 4, horsepower: 67 }, + { name: 'vokswagen rabbit', milesPerGallon: 29.8, cylinders: 4, horsepower: 62 }, + { name: 'datsun 280-zx', milesPerGallon: 32.7, cylinders: 6, horsepower: 132 }, + { name: 'mazda rx-7 gs', milesPerGallon: 23.7, cylinders: 3, horsepower: 100 }, + { name: 'triumph tr7 coupe', milesPerGallon: 35, cylinders: 4, horsepower: 88 }, + { name: 'ford mustang cobra', milesPerGallon: 23.6, cylinders: 4, horsepower: 0 }, + { name: 'honda Accelerationord', milesPerGallon: 32.4, cylinders: 4, horsepower: 72 }, + { name: 'plymouth reliant', milesPerGallon: 27.2, cylinders: 4, horsepower: 84 }, + { name: 'buick skylark', milesPerGallon: 26.6, cylinders: 4, horsepower: 84 }, + { name: 'dodge aries wagon (sw)', milesPerGallon: 25.8, cylinders: 4, horsepower: 92 }, + { name: 'chevrolet citation', milesPerGallon: 23.5, cylinders: 6, horsepower: 110 }, + { name: 'plymouth reliant', milesPerGallon: 30, cylinders: 4, horsepower: 84 }, + { name: 'toyota starlet', milesPerGallon: 39.1, cylinders: 4, horsepower: 58 }, + { name: 'plymouth champ', milesPerGallon: 39, cylinders: 4, horsepower: 64 }, + { name: 'honda civic 1300', milesPerGallon: 35.1, cylinders: 4, horsepower: 60 }, + { name: 'subaru', milesPerGallon: 32.3, cylinders: 4, horsepower: 67 }, + { name: 'datsun 210', milesPerGallon: 37, cylinders: 4, horsepower: 65 }, + { name: 'toyota tercel', milesPerGallon: 37.7, cylinders: 4, horsepower: 62 }, + { name: 'mazda glc 4', milesPerGallon: 34.1, cylinders: 4, horsepower: 68 }, + { name: 'plymouth horizon 4', milesPerGallon: 34.7, cylinders: 4, horsepower: 63 }, + { name: 'ford escort 4w', milesPerGallon: 34.4, cylinders: 4, horsepower: 65 }, + { name: 'ford escort 2h', milesPerGallon: 29.9, cylinders: 4, horsepower: 65 }, + { name: 'volkswagen jetta', milesPerGallon: 33, cylinders: 4, horsepower: 74 }, + { name: 'renault 18i', milesPerGallon: 34.5, cylinders: 4, horsepower: 0 }, + { name: 'honda prelude', milesPerGallon: 33.7, cylinders: 4, horsepower: 75 }, + { name: 'toyota corolla', milesPerGallon: 32.4, cylinders: 4, horsepower: 75 }, + { name: 'datsun 200sx', milesPerGallon: 32.9, cylinders: 4, horsepower: 100 }, + { name: 'mazda 626', milesPerGallon: 31.6, cylinders: 4, horsepower: 74 }, + { name: 'peugeot 505s turbo diesel', milesPerGallon: 28.1, cylinders: 4, horsepower: 80 }, + { name: 'saab 900s', milesPerGallon: 0, cylinders: 4, horsepower: 110 }, + { name: 'volvo diesel', milesPerGallon: 30.7, cylinders: 6, horsepower: 76 }, + { name: 'toyota cressida', milesPerGallon: 25.4, cylinders: 6, horsepower: 116 }, + { name: 'datsun 810 maxima', milesPerGallon: 24.2, cylinders: 6, horsepower: 120 }, + { name: 'buick century', milesPerGallon: 22.4, cylinders: 6, horsepower: 110 }, + { name: 'oldsmobile cutlass ls', milesPerGallon: 26.6, cylinders: 8, horsepower: 105 }, + { name: 'ford granada gl', milesPerGallon: 20.2, cylinders: 6, horsepower: 88 }, + { name: 'chrysler lebaron salon', milesPerGallon: 17.6, cylinders: 6, horsepower: 85 }, + { name: 'chevrolet cavalier', milesPerGallon: 28, cylinders: 4, horsepower: 88 }, + { name: 'chevrolet cavalier wagon', milesPerGallon: 27, cylinders: 4, horsepower: 88 }, + { name: 'chevrolet cavalier 2-door', milesPerGallon: 34, cylinders: 4, horsepower: 88 }, + { name: 'pontiac j2000 se hatchback', milesPerGallon: 31, cylinders: 4, horsepower: 85 }, + { name: 'dodge aries se', milesPerGallon: 29, cylinders: 4, horsepower: 84 }, + { name: 'pontiac phoenix', milesPerGallon: 27, cylinders: 4, horsepower: 90 }, + { name: 'ford fairmont futura', milesPerGallon: 24, cylinders: 4, horsepower: 92 }, + { name: 'amc concord dl', milesPerGallon: 23, cylinders: 4, horsepower: 0 }, + { name: 'volkswagen rabbit l', milesPerGallon: 36, cylinders: 4, horsepower: 74 }, + { name: 'mazda glc custom l', milesPerGallon: 37, cylinders: 4, horsepower: 68 }, + { name: 'mazda glc custom', milesPerGallon: 31, cylinders: 4, horsepower: 68 }, + { name: 'plymouth horizon miser', milesPerGallon: 38, cylinders: 4, horsepower: 63 }, + { name: 'mercury lynx l', milesPerGallon: 36, cylinders: 4, horsepower: 70 }, + { name: 'nissan stanza xe', milesPerGallon: 36, cylinders: 4, horsepower: 88 }, + { name: 'honda Accelerationord', milesPerGallon: 36, cylinders: 4, horsepower: 75 }, + { name: 'toyota corolla', milesPerGallon: 34, cylinders: 4, horsepower: 70 }, + { name: 'honda civic', milesPerGallon: 38, cylinders: 4, horsepower: 67 }, + { name: 'honda civic (auto)', milesPerGallon: 32, cylinders: 4, horsepower: 67 }, + { name: 'datsun 310 gx', milesPerGallon: 38, cylinders: 4, horsepower: 67 }, + { name: 'buick century limited', milesPerGallon: 25, cylinders: 6, horsepower: 110 }, + { name: 'oldsmobile cutlass ciera (diesel)', milesPerGallon: 38, cylinders: 6, horsepower: 85 }, + { name: 'chrysler lebaron medallion', milesPerGallon: 26, cylinders: 4, horsepower: 92 }, + { name: 'ford granada l', milesPerGallon: 22, cylinders: 6, horsepower: 112 }, + { name: 'toyota celica gt', milesPerGallon: 32, cylinders: 4, horsepower: 96 }, + { name: 'dodge charger 2.2', milesPerGallon: 36, cylinders: 4, horsepower: 84 }, + { name: 'chevrolet camaro', milesPerGallon: 27, cylinders: 4, horsepower: 90 }, + { name: 'ford mustang gl', milesPerGallon: 27, cylinders: 4, horsepower: 86 }, + { name: 'vw pickup', milesPerGallon: 44, cylinders: 4, horsepower: 52 }, + { name: 'dodge rampage', milesPerGallon: 32, cylinders: 4, horsepower: 84 }, + { name: 'ford ranger', milesPerGallon: 28, cylinders: 4, horsepower: 79 }, + { name: 'chevy s-10', milesPerGallon: 31, cylinders: 4, horsepower: 82 } +]; + +// 图表配置 +const spec = { + type: 'common', + series: [ + { + type: 'scatter', + xField: 'milesPerGallon', + yField: 'horsepower', + point: { + state: { + hover: { + scaleX: 1.2, + scaleY: 1.2 + } + }, + style: { + fillOpacity: 0.25 + } + } + } + ], + tooltip: { + dimension: { + visible: true + }, + mark: { + title: true, + content: [ + { + key: d => d.name, + value: d => d.y + } + ] + } + }, + crosshair: { + yField: { + visible: true, + line: { + visible: true, + type: 'line' + }, + label: { + visible: true // label 默认关闭 + } + }, + xField: { + visible: true, + line: { + visible: true, + type: 'line' + }, + label: { + visible: true // label 默认关闭 + } + } + }, + axes: [ + { + title: { + visible: true, + text: 'Horse Power' + }, + orient: 'left', + range: { min: 0 }, + type: 'linear' + }, + { + title: { + visible: true, + text: 'Miles Per Gallon' + }, + orient: 'bottom', + label: { visible: true }, + type: 'linear' + } + ], + data: [ + { + id: 'data', + values: data.flat() + } + ] +}; +registerRegressionLine(); +appendScatterRegressionLineConfig(spec, [ + { + type: 'polynomial', // 支持4中类型 'linear' | 'logisitc' | 'lowess' | 'polynomial' + polynomialDegree: 3, + color: 'red', + line: { + style: { + lineWidth: 2 + } + }, + confidenceInterval: { + style: { + fillOpacity: 0.2 + } + }, + label: { + text: '3次多项式回归' + } + }, + { + type: 'linear', + color: 'green', + label: { + text: '线性回归' + } + } +]); +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); + +// Just for the convenience of console debugging, DO NOT COPY! +window['vchart'] = vchart; +``` diff --git a/docs/assets/guide/en/tutorial_docs/Chart_Extensions/regression_line.md b/docs/assets/guide/en/tutorial_docs/Chart_Extensions/regression_line.md new file mode 100644 index 0000000000..3d77b352cc --- /dev/null +++ b/docs/assets/guide/en/tutorial_docs/Chart_Extensions/regression_line.md @@ -0,0 +1,614 @@ +# Regression Line Extension Guide + +Regression lines are commonly used in statistical scenarios. The `vchart-extensions` package supports regression line extensions, including calculation and display of common regression lines (polynomial regression, kernel density estimation (KDE), empirical cumulative distribution function (ECDF), etc.). + +## Registering the Extension + +The regression line component is located in the extension package. You need to register the component before use: + +```js +import VChart from '@visactor/vchart'; +import { + registerRegressionLine, + appendBarRegressionLineConfig, + appendHistogramRegressionLineConfig, + appendScatterRegressionLineConfig +} from '@visactor/vchart-extension'; + +registerRegressionLine(); +``` + +If you are using the CDN global variable `VChartExtension`, call `VChartExtension.registerRegressionLine()`. + +## API Overview + +- `registerRegressionLine()` — Registers the regression line component and enables additional configuration methods. +- `appendBarRegressionLineConfig(spec, config)` — Adds regression line configuration to bar chart specs. Note: currently only supports simple bar charts (no grouping, stacking, etc.), and only polynomial regression lines. +- `appendHistogramRegressionLineConfig(spec, config)` — Adds regression overlays to histograms (supports `kde` and `ecdf`). +- `appendScatterRegressionLineConfig(spec, config)` — Adds regression lines to scatter plots. + +## Bar Chart Regression Line + +### Example + +Use `appendBarRegressionLineConfig` to add regression lines to a bar chart: + +```javascript livedemo +/** --Add the following code in your business usage-- */ +// When using in your project, make sure to install @visactor/vchart-extension with the same version as vchart +// import { appendBarRegressionLineConfig, registerRegressionLine } from '@visactor/vchart-extension'; +/** --Add the above code in your business usage-- */ + +/** --Remove the following code in your business usage-- */ +const { appendBarRegressionLineConfig, registerRegressionLine } = VChartExtension; +/** --Remove the above code in your business usage-- */ + +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { name: 'Apple', value: 214480 }, + { name: 'Google', value: 155506 }, + { name: 'Amazon', value: 100764 }, + { name: 'Microsoft', value: 92715 }, + { name: 'Coca-Cola', value: 66341 }, + { name: 'Samsung', value: 59890 }, + { name: 'Toyota', value: 53404 }, + { name: 'Mercedes-Benz', value: 48601 }, + { name: 'Facebook', value: 45168 }, + { name: "McDonald's", value: 43417 }, + { name: 'Intel', value: 43293 }, + { name: 'IBM', value: 42972 }, + { name: 'BMW', value: 41006 }, + { name: 'Disney', value: 39874 }, + { name: 'Cisco', value: 34575 }, + { name: 'GE', value: 32757 }, + { name: 'Nike', value: 30120 }, + { name: 'Louis Vuitton', value: 28152 }, + { name: 'Oracle', value: 26133 }, + { name: 'Honda', value: 23682 } + ] + } + ], + xField: 'name', + yField: 'value' +}; + +registerRegressionLine(); +appendBarRegressionLineConfig(spec, [ + { + degree: 2, + color: 'red', + line: { + style: { + lineWidth: 2 + } + }, + confidenceInterval: { + visible: false + }, + label: { + text: '2nd Degree Polynomial Fit' + } + }, + { + degree: 3, + color: 'green', + line: { + style: { + lineWidth: 2 + } + }, + confidenceInterval: { + style: { + fillOpacity: 0.2 + } + }, + label: { + text: '3rd Degree Polynomial Fit' + } + } +]); + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); + +// Just for the convenience of console debugging, DO NOT COPY! +window['vchart'] = vchart; +``` + +### Configuration Type Definition + +The regression line configuration type is defined as follows: + +```ts +{ + /** + * Degree of the polynomial + */ + degree?: number; + /** + * Color value + */ + color?: string; + /** + * Regression line configuration + */ + line?: { + /** + * Whether to show the series label + * @default true + */ + visible?: boolean; + /** + * Line style + */ + style?: ILineGraphicAttribute; + }; + /** + * Regression line formula label + */ + label?: { + /** + * Whether to show the label + */ + visible?: boolean; + /** + * Label text + */ + text: string; + /** + * Label style + */ + style?: ITextGraphicAttribute; + }; + /** + * Confidence interval + */ + confidenceInterval?: { + visible?: boolean; + style?: IAreaGraphicAttribute; + }; +} +``` + +## Histogram Example (KDE / ECDF) + +### Example + +Histogram regression supports overlaying KDE or ECDF curves on histograms. Make sure your data has been transformed with `bin`, and that `xField/x2Field/yField` are configured correctly. + +```javascript livedemo +/** --Add the following code in your business usage-- */ +// When using in your project, make sure to install @visactor/vchart-extension with the same version as vchart +// import { registerRegressionLine, appendHistogramRegressionLineConfig } from '@visactor/vchart-extension'; +/** --Add the above code in your business usage-- */ + +/** --Remove the following code in your business usage-- */ +const { registerRegressionLine, appendHistogramRegressionLineConfig } = VChartExtension; +/** --Remove the above code in your business usage-- */ + +function boxMullerRandom() { + let u = 0; + let v = 0; + while (u === 0) { + u = Math.random(); + } + while (v === 0) { + v = Math.random(); + } + return Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v); +} + +function generateGaussian(count, mean = 0, sd = 1) { + const out = []; + for (let i = 0; i < count; i++) { + out.push(mean + boxMullerRandom() * sd); + } + return out; +} + +function generateMixtureGaussianSamples() { + const a = generateGaussian(160, 5, 4, 1); // cluster A + // const b = generateGaussian(80, 2.3, 0.08, 2); // cluster B + // const c = generateGaussian(140, 9.3, 0.35, 3); // cluster C + const outliers = [5.0, 6.2, 3.5, 12.0, 0.5]; + const arr = [...a, ...outliers]; + return arr.map(v => ({ value: v })); +} + +const spec = { + data: [ + { + name: 'data1', + transforms: [ + { + type: 'bin', + options: { + step: 2, + field: 'value', + outputNames: { x0: 'x0', x1: 'x1', count: 'frequency' } + } + } + ], + values: generateMixtureGaussianSamples() + } + ], + type: 'histogram', + xField: 'x0', + x2Field: 'x1', + yField: 'frequency', + bar: { + style: { + stroke: 'white', + lineWidth: 1 + } + }, + title: { + text: 'Histogram of Gaussian data' + }, + tooltip: { + visible: true, + mark: { + title: { + key: 'title', + value: 'frequency' + }, + content: [ + { + key: datum => datum['x0'] + '~' + datum['x1'], + value: datum => datum['frequency'] + } + ] + } + } +}; + +registerRegressionLine(); +appendHistogramRegressionLineConfig(spec, [ + { + type: 'kde', // supports 'kde' and 'ecdf' + line: { + style: { + // const b = generateGaussian(80, 2.3, 0.08, 2); // cluster B + // const c = generateGaussian(140, 9.3, 0.35, 3); // cluster C + const outliers = [5.0, 6.2, 3.5, 12.0, 0.5]; + const arr = [...a, ...outliers]; + return arr.map(v => ({ value: v })); +} + +const spec = { + data: [ + { + name: 'data1', + transforms: [ + { + type: 'bin', + options: { + step: 2, + field: 'value', + outputNames: { x0: 'x0', x1: 'x1', count: 'frequency' } + } + } + ], + values: generateMixtureGaussianSamples() + } + ], + type: 'histogram', + xField: 'x0', + x2Field: 'x1', + yField: 'frequency', + bar: { + style: { + stroke: 'white', + lineWidth: 1 + } + }, + title: { + text: 'Histogram of Gaussian data' + }, + tooltip: { + visible: true, + mark: { + title: { + key: 'title', + value: 'frequency' + }, + content: [ + { + key: datum => datum['x0'] + '~' + datum['x1'], + value: datum => datum['frequency'] + } + ] + } + } +}; + +registerRegressionLine(); +appendHistogramRegressionLineConfig(spec, [ + { + type: 'kde', // 支持 'kde' 和 'ecdf' + line: { + style: { + stroke: 'red', + lineWidth: 2 + } + }, + label: { + text: 'KDE核密度估计' + } + }, + { + type: 'ecdf', // 支持 'kde' 和 'ecdf' + line: { + style: { + stroke: 'green', + lineWidth: 2 + } + }, + label: { + text: '经验累积分布函数(ECDF)' + } + } +]); + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); + +// Just for the convenience of console debugging, DO NOT COPY! +window['vchart'] = vchart; +``` + +### Configuration Type Definition + +The regression line configuration type is defined as follows: + +```ts +{ + /** + * Type of regression line + */ + type: 'kde' | 'ecdf'; + /** + * Color value + */ + color?: string; + /** + * Regression line configuration + */ + line?: { + /** + * Whether to show the series label + * @default true + */ + visible?: boolean; + /** + * Line style + */ + style?: ILineGraphicAttribute; + }; + /** + * Regression line formula label + */ + label?: { + /** + * Whether to show the label + */ + visible?: boolean; + /** + * Label text + */ + text: string; + /** + * Label style + */ + style?: ITextGraphicAttribute; + }; +} +``` + +## Scatter Plot / Series Example + +### Example + +Use `appendScatterRegressionLineConfig` to add regression overlays to scatter plots. You can configure `degree`, `type`, styles, and more: + +```javascript livedemo +/** --Add the following code in your business usage-- */ +// When using in your project, make sure to install @visactor/vchart-extension with the same version as vchart +// import { registerRegressionLine, appendScatterRegressionLineConfig } from '@visactor/vchart-extension'; +/** --Add the above code in your business usage-- */ + +/** --Remove the following code in your business usage-- */ +const { registerRegressionLine, appendScatterRegressionLineConfig } = VChartExtension; +/** --Remove the above code in your business usage-- */ + +const data = [ + // ... (data omitted for brevity) +]; + +// Chart configuration +const spec = { + type: 'common', + series: [ + { + type: 'scatter', + xField: 'milesPerGallon', + yField: 'horsepower', + point: { + state: { + hover: { + scaleX: 1.2, + scaleY: 1.2 + } + }, + style: { + fillOpacity: 0.25 + } + } + } + ], + tooltip: { + dimension: { + visible: true + }, + mark: { + title: true, + content: [ + { + key: d => d.name, + value: d => d.y + } + ] + } + }, + crosshair: { + yField: { + visible: true, + line: { + visible: true, + type: 'line' + }, + label: { + visible: true // label is off by default + } + }, + xField: { + visible: true, + line: { + visible: true, + type: 'line' + }, + label: { + visible: true // label is off by default + } + } + }, + axes: [ + { + title: { + visible: true, + text: 'Horse Power' + }, + orient: 'left', + range: { min: 0 }, + type: 'linear' + }, + { + title: { + visible: true, + text: 'Miles Per Gallon' + }, + orient: 'bottom', + label: { visible: true }, + type: 'linear' + } + ], + data: [ + { + id: 'data', + values: data.flat() + } + ] +}; +registerRegressionLine(); +appendScatterRegressionLineConfig(spec, [ + { + type: 'polynomial', // Supports 4 types: 'linear' | 'logisitc' | 'lowess' | 'polynomial' + polynomialDegree: 3, + color: 'red', + line: { + style: { + lineWidth: 2 + } + }, + confidenceInterval: { + style: { + fillOpacity: 0.2 + } + }, + label: { + text: '3rd Degree Polynomial Regression' + } + }, + { + type: 'linear', + color: 'green', + label: { + text: 'Linear Regression' + } + } +]); +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); + +// Just for the convenience of console debugging, DO NOT COPY! +window['vchart'] = vchart; +``` + +### Configuration Type Definition + +The regression line configuration type is defined as follows: + +```ts +{ + /** + * Type of regression line + */ + type: 'linear' | 'logisitc' | 'lowess' | 'polynomial'; + /** + * Degree of polynomial regression, only valid when type is polynomial + */ + polynomialDegree?: number; + /** + * Color value + */ + color?: string; + /** + * Regression line configuration + */ + line?: { + /** + * Whether to show the series label + * @default true + */ + visible?: boolean; + /** + * Line style + */ + style?: ILineGraphicAttribute; + }; + /** + * Regression line formula label + */ + label?: { + /** + * Whether to show the label + */ + visible?: boolean; + /** + * Label text + */ + text: string; + /** + * Label style + */ + style?: ITextGraphicAttribute; + }; + /** + * Confidence interval + */ + confidenceInterval?: { + visible?: boolean; + style?: IAreaGraphicAttribute; + }; +} +``` + +## Notes and Recommendations + +- Histogram regression relies on bin output fields (such as `x0/x1/count`). Make sure the `outputNames` in the `bin` transform match what the regression component expects. +- Confidence interval calculation incurs extra overhead. For large datasets or interactive updates, it is recommended to turn it off. +- The `append*` methods directly modify the input `spec`. If you need to keep the original spec, deep copy it before applying changes. diff --git a/docs/assets/guide/en/tutorial_docs/Chart_Types/Histogram.md b/docs/assets/guide/en/tutorial_docs/Chart_Types/Histogram.md index 07a458d410..99589d607b 100644 --- a/docs/assets/guide/en/tutorial_docs/Chart_Types/Histogram.md +++ b/docs/assets/guide/en/tutorial_docs/Chart_Types/Histogram.md @@ -865,6 +865,130 @@ vchart.renderSync(); window['vchart'] = vchart; ``` +### Generating Histogram Data Using the `bin` Transform + +Since version `2.0.7`, histograms support the `bin` transform. When your data is in a detailed (raw) format, you can use this transform to generate standard histogram data. + +```javascript livedemo +const spec = { + data: [ + { + name: 'data1', + transforms: [ + { + type: 'bin', + options: { + bins: 10, + field: 'value' + } + } + ], + values: [ + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2.3 }, + { value: 2.3 }, + { value: 2.3 }, + { value: 2.3 }, + { value: 2.3 }, + { value: 2.3 }, + { value: 2.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 } + ] + } + ], + type: 'histogram', + xField: 'x0', + x2Field: 'x1', + yField: 'count', + bar: { + style: { + stroke: 'white', + lineWidth: 1 + } + }, + title: { + text: 'Arrival Time Histogram' + }, + tooltip: { + visible: true, + mark: { + title: { + key: 'title', + value: 'count' + }, + content: [ + { + key: datum => datum['x0'] + '~' + datum['x1'], + value: datum => datum['count'] + } + ] + } + } +}; +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); + +// For debugging purposes only, do not copy +window['vchart'] = vchart; +``` + +The `bin` transform supports the following configuration options: + +```ts +interface IBinOptions { + /** + * The numeric field to be binned + */ + field: string; + /** + * Number of bins (default is 10) + */ + bins?: number; + /** + * Explicitly specified array of bin boundaries + */ + thresholds?: number[]; + /** + * Fixed bin width (interval step); overrides bins if set + */ + step?: number; + /** + * Specify the minimum and maximum values for binning [min, max]; otherwise, calculated automatically from the data + */ + extent?: [number, number]; + /** + * Whether to retain original data items in each bin + */ + includeValues?: boolean; + /** + * Field name mapping for the output data + */ + outputNames?: { x0?: string; x1?: string; count?: string; values?: string }; +} +``` + ## Chart Layout ### Stacked Histogram diff --git a/docs/assets/guide/menu.json b/docs/assets/guide/menu.json index 9842484bc3..7ed9cfcc8d 100644 --- a/docs/assets/guide/menu.json +++ b/docs/assets/guide/menu.json @@ -926,6 +926,13 @@ "zh": "地图标签组件", "en": "Map Label" } + }, + { + "path": "regression_line", + "title": { + "zh": "回归线组件", + "en": "Regression Line" + } } ] } diff --git a/docs/assets/guide/zh/tutorial_docs/Chart_Extensions/regression_line.md b/docs/assets/guide/zh/tutorial_docs/Chart_Extensions/regression_line.md new file mode 100644 index 0000000000..70607de14e --- /dev/null +++ b/docs/assets/guide/zh/tutorial_docs/Chart_Extensions/regression_line.md @@ -0,0 +1,1019 @@ +# 回归线扩展指南 + +回归线在统计场景下经常出现,vchart-extensions 支持回归线的扩展功能,支持常用回归线(多项式回归、核密度估计 KDE、经验累积分布 ECDF 等)的计算和显示 + +## 注册扩展 + +回归线组件位于扩展包中,使用前需先注册组件: + +```js +import VChart from '@visactor/vchart'; +import { + registerRegressionLine, + appendBarRegressionLineConfig, + appendHistogramRegressionLineConfig, + appendScatterRegressionLineConfig +} from '@visactor/vchart-extension'; + +registerRegressionLine(); +``` + +如果使用 CDN 打包的全局变量 `VChartExtension`,请调用 `VChartExtension.registerRegressionLine()`。 + +## API 概览 + +- `registerRegressionLine()` — 注册回归线组件并启用附加配置方法 +- `appendBarRegressionLineConfig(spec, config)` — 在柱图配置中增加回归线配置,注意现在仅简单柱图(即没有分组、堆积等计算)中支持回归线,仅支持多项式回归线 +- `appendHistogramRegressionLineConfig(spec, config)` — 在直方图上附加回归叠加(支持 `kde` 和 `ecdf`) +- `appendScatterRegressionLineConfig(spec, config)` — 在散点图上附加回归线 + +## 柱图回归线 + +### 示例 + +使用 `appendBarRegressionLineConfig` 为柱图添加回归线: + +```javascript livedemo +/** --在业务中使用时请添加以下代码-- */ +// 在业务中使用时, 请额外依赖 @visactor/vchart-extension,包版本保持和vchart一致 +// import { appendBarRegressionLineConfig, registerRegressionLine } from '@visactor/vchart-extension'; +/** --在业务中使用时请添加以上代码-- */ + +/** --在业务中使用时请删除以下代码-- */ +const { appendBarRegressionLineConfig, registerRegressionLine } = VChartExtension; +/** --在业务中使用时请删除以上代码-- */ + +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { + name: 'Apple', + value: 214480 + }, + { + name: 'Google', + value: 155506 + }, + { + name: 'Amazon', + value: 100764 + }, + { + name: 'Microsoft', + value: 92715 + }, + { + name: 'Coca-Cola', + value: 66341 + }, + { + name: 'Samsung', + value: 59890 + }, + { + name: 'Toyota', + value: 53404 + }, + { + name: 'Mercedes-Benz', + value: 48601 + }, + { + name: 'Facebook', + value: 45168 + }, + { + name: "McDonald's", + value: 43417 + }, + { + name: 'Intel', + value: 43293 + }, + { + name: 'IBM', + value: 42972 + }, + { + name: 'BMW', + value: 41006 + }, + { + name: 'Disney', + value: 39874 + }, + { + name: 'Cisco', + value: 34575 + }, + { + name: 'GE', + value: 32757 + }, + { + name: 'Nike', + value: 30120 + }, + { + name: 'Louis Vuitton', + value: 28152 + }, + { + name: 'Oracle', + value: 26133 + }, + { + name: 'Honda', + value: 23682 + } + ] + } + ], + xField: 'name', + yField: 'value' +}; + +registerRegressionLine(); +appendBarRegressionLineConfig(spec, [ + { + degree: 2, + color: 'red', + line: { + style: { + lineWidth: 2 + } + }, + confidenceInterval: { + visible: false + }, + label: { + text: '2次多项式拟合' + } + }, + { + degree: 3, + color: 'green', + line: { + style: { + lineWidth: 2 + } + }, + confidenceInterval: { + style: { + fillOpacity: 0.2 + } + }, + label: { + text: '3次多项式拟合' + } + } +]); + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); + +// Just for the convenience of console debugging, DO NOT COPY! +window['vchart'] = vchart; +``` + +### 配置类型定义 + +其中回归线配置的类型定义如下: + +```ts +{ + /** + * 多项式的阶数 + */ + degree?: number; + /** + * 颜色值 + */ + color?: string; + /** + * 回归线配置 + */ + line?: { + /** + * 是否显示系列标签 + * @default true + */ + visible?: boolean; + /** + * 线样式 + */ + style?: ILineGraphicAttribute; + }; + /** + * 回归线公式标签 + */ + label?: { + /** + * 是否显示标签 + */ + visible?: boolean; + /** + * 标签文本 + */ + text: string; + /** + * 标签样式 + */ + style?: ITextGraphicAttribute; + }; + /** + * 置信区间 + */ + confidenceInterval?: { + visible?: boolean; + style?: IAreaGraphicAttribute; + }; +} +``` + +## 直方图示例(KDE / ECDF) + +### 示例 + +直方图回归支持在直方图上叠加 KDE 或 ECDF 曲线。请确保数据经过 `bin` 变换,且正确配置 `xField/x2Field/yField`。 + +```javascript livedemo +/** --在业务中使用时请添加以下代码-- */ +// 在业务中使用时, 请额外依赖 @visactor/vchart-extension,包版本保持和vchart一致 +// import { registerRegressionLine, appendHistogramRegressionLineConfig } from '@visactor/vchart-extension'; +/** --在业务中使用时请添加以上代码-- */ + +/** --在业务中使用时请删除以下代码-- */ +const { registerRegressionLine, appendHistogramRegressionLineConfig } = VChartExtension; +/** --在业务中使用时请删除以上代码-- */ + +function boxMullerRandom() { + let u = 0; + let v = 0; + while (u === 0) { + u = Math.random(); + } + while (v === 0) { + v = Math.random(); + } + return Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v); +} + +function generateGaussian(count, mean = 0, sd = 1) { + const out = []; + for (let i = 0; i < count; i++) { + out.push(mean + boxMullerRandom() * sd); + } + return out; +} + +function generateMixtureGaussianSamples() { + const a = generateGaussian(160, 5, 4, 1); // cluster A + // const b = generateGaussian(80, 2.3, 0.08, 2); // cluster B + // const c = generateGaussian(140, 9.3, 0.35, 3); // cluster C + const outliers = [5.0, 6.2, 3.5, 12.0, 0.5]; + const arr = [...a, ...outliers]; + return arr.map(v => ({ value: v })); +} + +const spec = { + data: [ + { + name: 'data1', + transforms: [ + { + type: 'bin', + options: { + step: 2, + field: 'value', + outputNames: { x0: 'x0', x1: 'x1', count: 'frequency' } + } + } + ], + values: generateMixtureGaussianSamples() + } + ], + type: 'histogram', + xField: 'x0', + x2Field: 'x1', + yField: 'frequency', + bar: { + style: { + stroke: 'white', + lineWidth: 1 + } + }, + title: { + text: 'Histogram of Gaussian data' + }, + tooltip: { + visible: true, + mark: { + title: { + key: 'title', + value: 'frequency' + }, + content: [ + { + key: datum => datum['x0'] + '~' + datum['x1'], + value: datum => datum['frequency'] + } + ] + } + } +}; + +registerRegressionLine(); +appendHistogramRegressionLineConfig(spec, [ + { + type: 'kde', // 支持 'kde' 和 'ecdf' + line: { + style: { + stroke: 'red', + lineWidth: 2 + } + }, + label: { + text: 'KDE核密度估计' + } + }, + { + type: 'ecdf', // 支持 'kde' 和 'ecdf' + line: { + style: { + stroke: 'green', + lineWidth: 2 + } + }, + label: { + text: '经验累积分布函数(ECDF)' + } + } +]); + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); + +// Just for the convenience of console debugging, DO NOT COPY! +window['vchart'] = vchart; +``` + +### 配置类型定义 + +其中回归线配置的类型定义如下: + +```ts +{ + /** + * 回归线的类型 + */ + type: 'kde' | 'ecdf'; + /** + * 颜色值 + */ + color?: string; + /** + * 回归线配置 + */ + line?: { + /** + * 是否显示系列标签 + * @default true + */ + visible?: boolean; + /** + * 线样式 + */ + style?: ILineGraphicAttribute; + }; + /** + * 回归线公式标签 + */ + label?: { + /** + * 是否显示标签 + */ + visible?: boolean; + /** + * 标签文本 + */ + text: string; + /** + * 标签样式 + */ + style?: ITextGraphicAttribute; + }; +} +``` + +## 散点图/序列示例 + +### 示例 + +使用 `appendScatterRegressionLineConfig` 为散点图添加回归叠加,可配置 `degree`、`type`、样式等: + +```javascript livedemo +/** --在业务中使用时请添加以下代码-- */ +// 在业务中使用时, 请额外依赖 @visactor/vchart-extension,包版本保持和vchart一致 +// import { registerRegressionLine, appendScatterRegressionLineConfig } from '@visactor/vchart-extension'; +/** --在业务中使用时请添加以上代码-- */ + +/** --在业务中使用时请删除以下代码-- */ +const { registerRegressionLine, appendScatterRegressionLineConfig } = VChartExtension; +/** --在业务中使用时请删除以上代码-- */ + +const data = [ + { name: 'chevrolet chevelle malibu', milesPerGallon: 18, cylinders: 8, horsepower: 130 }, + { name: 'buick skylark 320', milesPerGallon: 15, cylinders: 8, horsepower: 165 }, + { name: 'plymouth satellite', milesPerGallon: 18, cylinders: 8, horsepower: 150 }, + { name: 'amc rebel sst', milesPerGallon: 16, cylinders: 8, horsepower: 150 }, + { name: 'ford torino', milesPerGallon: 17, cylinders: 8, horsepower: 140 }, + { name: 'ford galaxie 500', milesPerGallon: 15, cylinders: 8, horsepower: 198 }, + { name: 'chevrolet impala', milesPerGallon: 14, cylinders: 8, horsepower: 220 }, + { name: 'plymouth fury iii', milesPerGallon: 14, cylinders: 8, horsepower: 215 }, + { name: 'pontiac catalina', milesPerGallon: 14, cylinders: 8, horsepower: 225 }, + { name: 'amc ambassador dpl', milesPerGallon: 15, cylinders: 8, horsepower: 190 }, + { name: 'citroen ds-21 pallas', milesPerGallon: 0, cylinders: 4, horsepower: 115 }, + { name: 'chevrolet chevelle concours (sw)', milesPerGallon: 0, cylinders: 8, horsepower: 165 }, + { name: 'ford torino (sw)', milesPerGallon: 0, cylinders: 8, horsepower: 153 }, + { name: 'plymouth satellite (sw)', milesPerGallon: 0, cylinders: 8, horsepower: 175 }, + { name: 'amc rebel sst (sw)', milesPerGallon: 0, cylinders: 8, horsepower: 175 }, + { name: 'dodge challenger se', milesPerGallon: 15, cylinders: 8, horsepower: 170 }, + { name: "plymouth 'cuda 340", milesPerGallon: 14, cylinders: 8, horsepower: 160 }, + { name: 'ford mustang boss 302', milesPerGallon: 0, cylinders: 8, horsepower: 140 }, + { name: 'chevrolet monte carlo', milesPerGallon: 15, cylinders: 8, horsepower: 150 }, + { name: 'buick estate wagon (sw)', milesPerGallon: 14, cylinders: 8, horsepower: 225 }, + { name: 'toyota corona mark ii', milesPerGallon: 24, cylinders: 4, horsepower: 95 }, + { name: 'plymouth duster', milesPerGallon: 22, cylinders: 6, horsepower: 95 }, + { name: 'amc hornet', milesPerGallon: 18, cylinders: 6, horsepower: 97 }, + { name: 'ford maverick', milesPerGallon: 21, cylinders: 6, horsepower: 85 }, + { name: 'datsun pl510', milesPerGallon: 27, cylinders: 4, horsepower: 88 }, + { name: 'volkswagen 1131 deluxe sedan', milesPerGallon: 26, cylinders: 4, horsepower: 46 }, + { name: 'peugeot 504', milesPerGallon: 25, cylinders: 4, horsepower: 87 }, + { name: 'audi 100 ls', milesPerGallon: 24, cylinders: 4, horsepower: 90 }, + { name: 'saab 99e', milesPerGallon: 25, cylinders: 4, horsepower: 95 }, + { name: 'bmw 2002', milesPerGallon: 26, cylinders: 4, horsepower: 113 }, + { name: 'amc gremlin', milesPerGallon: 21, cylinders: 6, horsepower: 90 }, + { name: 'ford f250', milesPerGallon: 10, cylinders: 8, horsepower: 215 }, + { name: 'chevy c20', milesPerGallon: 10, cylinders: 8, horsepower: 200 }, + { name: 'dodge d200', milesPerGallon: 11, cylinders: 8, horsepower: 210 }, + { name: 'hi 1200d', milesPerGallon: 9, cylinders: 8, horsepower: 193 }, + { name: 'datsun pl510', milesPerGallon: 27, cylinders: 4, horsepower: 88 }, + { name: 'chevrolet vega 2300', milesPerGallon: 28, cylinders: 4, horsepower: 90 }, + { name: 'toyota corona', milesPerGallon: 25, cylinders: 4, horsepower: 95 }, + { name: 'ford pinto', milesPerGallon: 25, cylinders: 4, horsepower: 0 }, + { name: 'volkswagen super beetle 117', milesPerGallon: 0, cylinders: 4, horsepower: 48 }, + { name: 'amc gremlin', milesPerGallon: 19, cylinders: 6, horsepower: 100 }, + { name: 'plymouth satellite custom', milesPerGallon: 16, cylinders: 6, horsepower: 105 }, + { name: 'chevrolet chevelle malibu', milesPerGallon: 17, cylinders: 6, horsepower: 100 }, + { name: 'ford torino 500', milesPerGallon: 19, cylinders: 6, horsepower: 88 }, + { name: 'amc matador', milesPerGallon: 18, cylinders: 6, horsepower: 100 }, + { name: 'chevrolet impala', milesPerGallon: 14, cylinders: 8, horsepower: 165 }, + { name: 'pontiac catalina brougham', milesPerGallon: 14, cylinders: 8, horsepower: 175 }, + { name: 'ford galaxie 500', milesPerGallon: 14, cylinders: 8, horsepower: 153 }, + { name: 'plymouth fury iii', milesPerGallon: 14, cylinders: 8, horsepower: 150 }, + { name: 'dodge monaco (sw)', milesPerGallon: 12, cylinders: 8, horsepower: 180 }, + { name: 'ford country squire (sw)', milesPerGallon: 13, cylinders: 8, horsepower: 170 }, + { name: 'pontiac safari (sw)', milesPerGallon: 13, cylinders: 8, horsepower: 175 }, + { name: 'amc hornet sportabout (sw)', milesPerGallon: 18, cylinders: 6, horsepower: 110 }, + { name: 'chevrolet vega (sw)', milesPerGallon: 22, cylinders: 4, horsepower: 72 }, + { name: 'pontiac firebird', milesPerGallon: 19, cylinders: 6, horsepower: 100 }, + { name: 'ford mustang', milesPerGallon: 18, cylinders: 6, horsepower: 88 }, + { name: 'mercury capri 2000', milesPerGallon: 23, cylinders: 4, horsepower: 86 }, + { name: 'opel 1900', milesPerGallon: 28, cylinders: 4, horsepower: 90 }, + { name: 'peugeot 304', milesPerGallon: 30, cylinders: 4, horsepower: 70 }, + { name: 'fiat 124b', milesPerGallon: 30, cylinders: 4, horsepower: 76 }, + { name: 'toyota corolla 1200', milesPerGallon: 31, cylinders: 4, horsepower: 65 }, + { name: 'datsun 1200', milesPerGallon: 35, cylinders: 4, horsepower: 69 }, + { name: 'volkswagen model 111', milesPerGallon: 27, cylinders: 4, horsepower: 60 }, + { name: 'plymouth cricket', milesPerGallon: 26, cylinders: 4, horsepower: 70 }, + { name: 'toyota corona hardtop', milesPerGallon: 24, cylinders: 4, horsepower: 95 }, + { name: 'dodge colt hardtop', milesPerGallon: 25, cylinders: 4, horsepower: 80 }, + { name: 'volkswagen type 3', milesPerGallon: 23, cylinders: 4, horsepower: 54 }, + { name: 'chevrolet vega', milesPerGallon: 20, cylinders: 4, horsepower: 90 }, + { name: 'ford pinto runabout', milesPerGallon: 21, cylinders: 4, horsepower: 86 }, + { name: 'chevrolet impala', milesPerGallon: 13, cylinders: 8, horsepower: 165 }, + { name: 'pontiac catalina', milesPerGallon: 14, cylinders: 8, horsepower: 175 }, + { name: 'plymouth fury iii', milesPerGallon: 15, cylinders: 8, horsepower: 150 }, + { name: 'ford galaxie 500', milesPerGallon: 14, cylinders: 8, horsepower: 153 }, + { name: 'amc ambassador sst', milesPerGallon: 17, cylinders: 8, horsepower: 150 }, + { name: 'mercury marquis', milesPerGallon: 11, cylinders: 8, horsepower: 208 }, + { name: 'buick lesabre custom', milesPerGallon: 13, cylinders: 8, horsepower: 155 }, + { name: 'oldsmobile delta 88 royale', milesPerGallon: 12, cylinders: 8, horsepower: 160 }, + { name: 'chrysler newport royal', milesPerGallon: 13, cylinders: 8, horsepower: 190 }, + { name: 'mazda rx2 coupe', milesPerGallon: 19, cylinders: 3, horsepower: 97 }, + { name: 'amc matador (sw)', milesPerGallon: 15, cylinders: 8, horsepower: 150 }, + { name: 'chevrolet chevelle concours (sw)', milesPerGallon: 13, cylinders: 8, horsepower: 130 }, + { name: 'ford gran torino (sw)', milesPerGallon: 13, cylinders: 8, horsepower: 140 }, + { name: 'plymouth satellite custom (sw)', milesPerGallon: 14, cylinders: 8, horsepower: 150 }, + { name: 'volvo 145e (sw)', milesPerGallon: 18, cylinders: 4, horsepower: 112 }, + { name: 'volkswagen 411 (sw)', milesPerGallon: 22, cylinders: 4, horsepower: 76 }, + { name: 'peugeot 504 (sw)', milesPerGallon: 21, cylinders: 4, horsepower: 87 }, + { name: 'renault 12 (sw)', milesPerGallon: 26, cylinders: 4, horsepower: 69 }, + { name: 'ford pinto (sw)', milesPerGallon: 22, cylinders: 4, horsepower: 86 }, + { name: 'datsun 510 (sw)', milesPerGallon: 28, cylinders: 4, horsepower: 92 }, + { name: 'toyouta corona mark ii (sw)', milesPerGallon: 23, cylinders: 4, horsepower: 97 }, + { name: 'dodge colt (sw)', milesPerGallon: 28, cylinders: 4, horsepower: 80 }, + { name: 'toyota corolla 1600 (sw)', milesPerGallon: 27, cylinders: 4, horsepower: 88 }, + { name: 'buick century 350', milesPerGallon: 13, cylinders: 8, horsepower: 175 }, + { name: 'amc matador', milesPerGallon: 14, cylinders: 8, horsepower: 150 }, + { name: 'chevrolet malibu', milesPerGallon: 13, cylinders: 8, horsepower: 145 }, + { name: 'ford gran torino', milesPerGallon: 14, cylinders: 8, horsepower: 137 }, + { name: 'dodge coronet custom', milesPerGallon: 15, cylinders: 8, horsepower: 150 }, + { name: 'mercury marquis brougham', milesPerGallon: 12, cylinders: 8, horsepower: 198 }, + { name: 'chevrolet caprice classic', milesPerGallon: 13, cylinders: 8, horsepower: 150 }, + { name: 'ford ltd', milesPerGallon: 13, cylinders: 8, horsepower: 158 }, + { name: 'plymouth fury gran sedan', milesPerGallon: 14, cylinders: 8, horsepower: 150 }, + { name: 'chrysler new yorker brougham', milesPerGallon: 13, cylinders: 8, horsepower: 215 }, + { name: 'buick electra 225 custom', milesPerGallon: 12, cylinders: 8, horsepower: 225 }, + { name: 'amc ambassador brougham', milesPerGallon: 13, cylinders: 8, horsepower: 175 }, + { name: 'plymouth valiant', milesPerGallon: 18, cylinders: 6, horsepower: 105 }, + { name: 'chevrolet nova custom', milesPerGallon: 16, cylinders: 6, horsepower: 100 }, + { name: 'amc hornet', milesPerGallon: 18, cylinders: 6, horsepower: 100 }, + { name: 'ford maverick', milesPerGallon: 18, cylinders: 6, horsepower: 88 }, + { name: 'plymouth duster', milesPerGallon: 23, cylinders: 6, horsepower: 95 }, + { name: 'volkswagen super beetle', milesPerGallon: 26, cylinders: 4, horsepower: 46 }, + { name: 'chevrolet impala', milesPerGallon: 11, cylinders: 8, horsepower: 150 }, + { name: 'ford country', milesPerGallon: 12, cylinders: 8, horsepower: 167 }, + { name: 'plymouth custom suburb', milesPerGallon: 13, cylinders: 8, horsepower: 170 }, + { name: 'oldsmobile vista cruiser', milesPerGallon: 12, cylinders: 8, horsepower: 180 }, + { name: 'amc gremlin', milesPerGallon: 18, cylinders: 6, horsepower: 100 }, + { name: 'toyota carina', milesPerGallon: 20, cylinders: 4, horsepower: 88 }, + { name: 'chevrolet vega', milesPerGallon: 21, cylinders: 4, horsepower: 72 }, + { name: 'datsun 610', milesPerGallon: 22, cylinders: 4, horsepower: 94 }, + { name: 'maxda rx3', milesPerGallon: 18, cylinders: 3, horsepower: 90 }, + { name: 'ford pinto', milesPerGallon: 19, cylinders: 4, horsepower: 85 }, + { name: 'mercury capri v6', milesPerGallon: 21, cylinders: 6, horsepower: 107 }, + { name: 'fiat 124 sport coupe', milesPerGallon: 26, cylinders: 4, horsepower: 90 }, + { name: 'chevrolet monte carlo s', milesPerGallon: 15, cylinders: 8, horsepower: 145 }, + { name: 'pontiac grand prix', milesPerGallon: 16, cylinders: 8, horsepower: 230 }, + { name: 'fiat 128', milesPerGallon: 29, cylinders: 4, horsepower: 49 }, + { name: 'opel manta', milesPerGallon: 24, cylinders: 4, horsepower: 75 }, + { name: 'audi 100ls', milesPerGallon: 20, cylinders: 4, horsepower: 91 }, + { name: 'volvo 144ea', milesPerGallon: 19, cylinders: 4, horsepower: 112 }, + { name: 'dodge dart custom', milesPerGallon: 15, cylinders: 8, horsepower: 150 }, + { name: 'saab 99le', milesPerGallon: 24, cylinders: 4, horsepower: 110 }, + { name: 'toyota mark ii', milesPerGallon: 20, cylinders: 6, horsepower: 122 }, + { name: 'oldsmobile omega', milesPerGallon: 11, cylinders: 8, horsepower: 180 }, + { name: 'plymouth duster', milesPerGallon: 20, cylinders: 6, horsepower: 95 }, + { name: 'ford maverick', milesPerGallon: 21, cylinders: 6, horsepower: 0 }, + { name: 'amc hornet', milesPerGallon: 19, cylinders: 6, horsepower: 100 }, + { name: 'chevrolet nova', milesPerGallon: 15, cylinders: 6, horsepower: 100 }, + { name: 'datsun b210', milesPerGallon: 31, cylinders: 4, horsepower: 67 }, + { name: 'ford pinto', milesPerGallon: 26, cylinders: 4, horsepower: 80 }, + { name: 'toyota corolla 1200', milesPerGallon: 32, cylinders: 4, horsepower: 65 }, + { name: 'chevrolet vega', milesPerGallon: 25, cylinders: 4, horsepower: 75 }, + { name: 'chevrolet chevelle malibu classic', milesPerGallon: 16, cylinders: 6, horsepower: 100 }, + { name: 'amc matador', milesPerGallon: 16, cylinders: 6, horsepower: 110 }, + { name: 'plymouth satellite sebring', milesPerGallon: 18, cylinders: 6, horsepower: 105 }, + { name: 'ford gran torino', milesPerGallon: 16, cylinders: 8, horsepower: 140 }, + { name: 'buick century luxus (sw)', milesPerGallon: 13, cylinders: 8, horsepower: 150 }, + { name: 'dodge coronet custom (sw)', milesPerGallon: 14, cylinders: 8, horsepower: 150 }, + { name: 'ford gran torino (sw)', milesPerGallon: 14, cylinders: 8, horsepower: 140 }, + { name: 'amc matador (sw)', milesPerGallon: 14, cylinders: 8, horsepower: 150 }, + { name: 'audi fox', milesPerGallon: 29, cylinders: 4, horsepower: 83 }, + { name: 'volkswagen dasher', milesPerGallon: 26, cylinders: 4, horsepower: 67 }, + { name: 'opel manta', milesPerGallon: 26, cylinders: 4, horsepower: 78 }, + { name: 'toyota corona', milesPerGallon: 31, cylinders: 4, horsepower: 52 }, + { name: 'datsun 710', milesPerGallon: 32, cylinders: 4, horsepower: 61 }, + { name: 'dodge colt', milesPerGallon: 28, cylinders: 4, horsepower: 75 }, + { name: 'fiat 128', milesPerGallon: 24, cylinders: 4, horsepower: 75 }, + { name: 'fiat 124 tc', milesPerGallon: 26, cylinders: 4, horsepower: 75 }, + { name: 'honda civic', milesPerGallon: 24, cylinders: 4, horsepower: 97 }, + { name: 'subaru', milesPerGallon: 26, cylinders: 4, horsepower: 93 }, + { name: 'fiat x1.9', milesPerGallon: 31, cylinders: 4, horsepower: 67 }, + { name: 'plymouth valiant custom', milesPerGallon: 19, cylinders: 6, horsepower: 95 }, + { name: 'chevrolet nova', milesPerGallon: 18, cylinders: 6, horsepower: 105 }, + { name: 'mercury monarch', milesPerGallon: 15, cylinders: 6, horsepower: 72 }, + { name: 'ford maverick', milesPerGallon: 15, cylinders: 6, horsepower: 72 }, + { name: 'pontiac catalina', milesPerGallon: 16, cylinders: 8, horsepower: 170 }, + { name: 'chevrolet bel air', milesPerGallon: 15, cylinders: 8, horsepower: 145 }, + { name: 'plymouth grand fury', milesPerGallon: 16, cylinders: 8, horsepower: 150 }, + { name: 'ford ltd', milesPerGallon: 14, cylinders: 8, horsepower: 148 }, + { name: 'buick century', milesPerGallon: 17, cylinders: 6, horsepower: 110 }, + { name: 'chevroelt chevelle malibu', milesPerGallon: 16, cylinders: 6, horsepower: 105 }, + { name: 'amc matador', milesPerGallon: 15, cylinders: 6, horsepower: 110 }, + { name: 'plymouth fury', milesPerGallon: 18, cylinders: 6, horsepower: 95 }, + { name: 'buick skyhawk', milesPerGallon: 21, cylinders: 6, horsepower: 110 }, + { name: 'chevrolet monza 2+2', milesPerGallon: 20, cylinders: 8, horsepower: 110 }, + { name: 'ford mustang ii', milesPerGallon: 13, cylinders: 8, horsepower: 129 }, + { name: 'toyota corolla', milesPerGallon: 29, cylinders: 4, horsepower: 75 }, + { name: 'ford pinto', milesPerGallon: 23, cylinders: 4, horsepower: 83 }, + { name: 'amc gremlin', milesPerGallon: 20, cylinders: 6, horsepower: 100 }, + { name: 'pontiac astro', milesPerGallon: 23, cylinders: 4, horsepower: 78 }, + { name: 'toyota corona', milesPerGallon: 24, cylinders: 4, horsepower: 96 }, + { name: 'volkswagen dasher', milesPerGallon: 25, cylinders: 4, horsepower: 71 }, + { name: 'datsun 710', milesPerGallon: 24, cylinders: 4, horsepower: 97 }, + { name: 'ford pinto', milesPerGallon: 18, cylinders: 6, horsepower: 97 }, + { name: 'volkswagen rabbit', milesPerGallon: 29, cylinders: 4, horsepower: 70 }, + { name: 'amc pacer', milesPerGallon: 19, cylinders: 6, horsepower: 90 }, + { name: 'audi 100ls', milesPerGallon: 23, cylinders: 4, horsepower: 95 }, + { name: 'peugeot 504', milesPerGallon: 23, cylinders: 4, horsepower: 88 }, + { name: 'volvo 244dl', milesPerGallon: 22, cylinders: 4, horsepower: 98 }, + { name: 'saab 99le', milesPerGallon: 25, cylinders: 4, horsepower: 115 }, + { name: 'honda civic cvcc', milesPerGallon: 33, cylinders: 4, horsepower: 53 }, + { name: 'fiat 131', milesPerGallon: 28, cylinders: 4, horsepower: 86 }, + { name: 'opel 1900', milesPerGallon: 25, cylinders: 4, horsepower: 81 }, + { name: 'capri ii', milesPerGallon: 25, cylinders: 4, horsepower: 92 }, + { name: 'dodge colt', milesPerGallon: 26, cylinders: 4, horsepower: 79 }, + { name: 'renault 12tl', milesPerGallon: 27, cylinders: 4, horsepower: 83 }, + { name: 'chevrolet chevelle malibu classic', milesPerGallon: 17.5, cylinders: 8, horsepower: 140 }, + { name: 'dodge coronet brougham', milesPerGallon: 16, cylinders: 8, horsepower: 150 }, + { name: 'amc matador', milesPerGallon: 15.5, cylinders: 8, horsepower: 120 }, + { name: 'ford gran torino', milesPerGallon: 14.5, cylinders: 8, horsepower: 152 }, + { name: 'plymouth valiant', milesPerGallon: 22, cylinders: 6, horsepower: 100 }, + { name: 'chevrolet nova', milesPerGallon: 22, cylinders: 6, horsepower: 105 }, + { name: 'ford maverick', milesPerGallon: 24, cylinders: 6, horsepower: 81 }, + { name: 'amc hornet', milesPerGallon: 22.5, cylinders: 6, horsepower: 90 }, + { name: 'chevrolet chevette', milesPerGallon: 29, cylinders: 4, horsepower: 52 }, + { name: 'chevrolet woody', milesPerGallon: 24.5, cylinders: 4, horsepower: 60 }, + { name: 'vw rabbit', milesPerGallon: 29, cylinders: 4, horsepower: 70 }, + { name: 'honda civic', milesPerGallon: 33, cylinders: 4, horsepower: 53 }, + { name: 'dodge aspen se', milesPerGallon: 20, cylinders: 6, horsepower: 100 }, + { name: 'ford granada ghia', milesPerGallon: 18, cylinders: 6, horsepower: 78 }, + { name: 'pontiac ventura sj', milesPerGallon: 18.5, cylinders: 6, horsepower: 110 }, + { name: 'amc pacer d/l', milesPerGallon: 17.5, cylinders: 6, horsepower: 95 }, + { name: 'volkswagen rabbit', milesPerGallon: 29.5, cylinders: 4, horsepower: 71 }, + { name: 'datsun b-210', milesPerGallon: 32, cylinders: 4, horsepower: 70 }, + { name: 'toyota corolla', milesPerGallon: 28, cylinders: 4, horsepower: 75 }, + { name: 'ford pinto', milesPerGallon: 26.5, cylinders: 4, horsepower: 72 }, + { name: 'volvo 245', milesPerGallon: 20, cylinders: 4, horsepower: 102 }, + { name: 'plymouth volare premier v8', milesPerGallon: 13, cylinders: 8, horsepower: 150 }, + { name: 'peugeot 504', milesPerGallon: 19, cylinders: 4, horsepower: 88 }, + { name: 'toyota mark ii', milesPerGallon: 19, cylinders: 6, horsepower: 108 }, + { name: 'mercedes-benz 280s', milesPerGallon: 16.5, cylinders: 6, horsepower: 120 }, + { name: 'cadillac seville', milesPerGallon: 16.5, cylinders: 8, horsepower: 180 }, + { name: 'chevy c10', milesPerGallon: 13, cylinders: 8, horsepower: 145 }, + { name: 'ford f108', milesPerGallon: 13, cylinders: 8, horsepower: 130 }, + { name: 'dodge d100', milesPerGallon: 13, cylinders: 8, horsepower: 150 }, + { name: 'honda Accelerationord cvcc', milesPerGallon: 31.5, cylinders: 4, horsepower: 68 }, + { name: 'buick opel isuzu deluxe', milesPerGallon: 30, cylinders: 4, horsepower: 80 }, + { name: 'renault 5 gtl', milesPerGallon: 36, cylinders: 4, horsepower: 58 }, + { name: 'plymouth arrow gs', milesPerGallon: 25.5, cylinders: 4, horsepower: 96 }, + { name: 'datsun f-10 hatchback', milesPerGallon: 33.5, cylinders: 4, horsepower: 70 }, + { name: 'chevrolet caprice classic', milesPerGallon: 17.5, cylinders: 8, horsepower: 145 }, + { name: 'oldsmobile cutlass supreme', milesPerGallon: 17, cylinders: 8, horsepower: 110 }, + { name: 'dodge monaco brougham', milesPerGallon: 15.5, cylinders: 8, horsepower: 145 }, + { name: 'mercury cougar brougham', milesPerGallon: 15, cylinders: 8, horsepower: 130 }, + { name: 'chevrolet concours', milesPerGallon: 17.5, cylinders: 6, horsepower: 110 }, + { name: 'buick skylark', milesPerGallon: 20.5, cylinders: 6, horsepower: 105 }, + { name: 'plymouth volare custom', milesPerGallon: 19, cylinders: 6, horsepower: 100 }, + { name: 'ford granada', milesPerGallon: 18.5, cylinders: 6, horsepower: 98 }, + { name: 'pontiac grand prix lj', milesPerGallon: 16, cylinders: 8, horsepower: 180 }, + { name: 'chevrolet monte carlo landau', milesPerGallon: 15.5, cylinders: 8, horsepower: 170 }, + { name: 'chrysler cordoba', milesPerGallon: 15.5, cylinders: 8, horsepower: 190 }, + { name: 'ford thunderbird', milesPerGallon: 16, cylinders: 8, horsepower: 149 }, + { name: 'volkswagen rabbit custom', milesPerGallon: 29, cylinders: 4, horsepower: 78 }, + { name: 'pontiac sunbird coupe', milesPerGallon: 24.5, cylinders: 4, horsepower: 88 }, + { name: 'toyota corolla liftback', milesPerGallon: 26, cylinders: 4, horsepower: 75 }, + { name: 'ford mustang ii 2+2', milesPerGallon: 25.5, cylinders: 4, horsepower: 89 }, + { name: 'chevrolet chevette', milesPerGallon: 30.5, cylinders: 4, horsepower: 63 }, + { name: 'dodge colt m/m', milesPerGallon: 33.5, cylinders: 4, horsepower: 83 }, + { name: 'subaru dl', milesPerGallon: 30, cylinders: 4, horsepower: 67 }, + { name: 'volkswagen dasher', milesPerGallon: 30.5, cylinders: 4, horsepower: 78 }, + { name: 'datsun 810', milesPerGallon: 22, cylinders: 6, horsepower: 97 }, + { name: 'bmw 320i', milesPerGallon: 21.5, cylinders: 4, horsepower: 110 }, + { name: 'mazda rx-4', milesPerGallon: 21.5, cylinders: 3, horsepower: 110 }, + { name: 'volkswagen rabbit custom diesel', milesPerGallon: 43.1, cylinders: 4, horsepower: 48 }, + { name: 'ford fiesta', milesPerGallon: 36.1, cylinders: 4, horsepower: 66 }, + { name: 'mazda glc deluxe', milesPerGallon: 32.8, cylinders: 4, horsepower: 52 }, + { name: 'datsun b210 gx', milesPerGallon: 39.4, cylinders: 4, horsepower: 70 }, + { name: 'honda civic cvcc', milesPerGallon: 36.1, cylinders: 4, horsepower: 60 }, + { name: 'oldsmobile cutlass salon brougham', milesPerGallon: 19.9, cylinders: 8, horsepower: 110 }, + { name: 'dodge diplomat', milesPerGallon: 19.4, cylinders: 8, horsepower: 140 }, + { name: 'mercury monarch ghia', milesPerGallon: 20.2, cylinders: 8, horsepower: 139 }, + { name: 'pontiac phoenix lj', milesPerGallon: 19.2, cylinders: 6, horsepower: 105 }, + { name: 'chevrolet malibu', milesPerGallon: 20.5, cylinders: 6, horsepower: 95 }, + { name: 'ford fairmont (auto)', milesPerGallon: 20.2, cylinders: 6, horsepower: 85 }, + { name: 'ford fairmont (man)', milesPerGallon: 25.1, cylinders: 4, horsepower: 88 }, + { name: 'plymouth volare', milesPerGallon: 20.5, cylinders: 6, horsepower: 100 }, + { name: 'amc concord', milesPerGallon: 19.4, cylinders: 6, horsepower: 90 }, + { name: 'buick century special', milesPerGallon: 20.6, cylinders: 6, horsepower: 105 }, + { name: 'mercury zephyr', milesPerGallon: 20.8, cylinders: 6, horsepower: 85 }, + { name: 'dodge aspen', milesPerGallon: 18.6, cylinders: 6, horsepower: 110 }, + { name: 'amc concord d/l', milesPerGallon: 18.1, cylinders: 6, horsepower: 120 }, + { name: 'chevrolet monte carlo landau', milesPerGallon: 19.2, cylinders: 8, horsepower: 145 }, + { name: 'buick regal sport coupe (turbo)', milesPerGallon: 17.7, cylinders: 6, horsepower: 165 }, + { name: 'ford futura', milesPerGallon: 18.1, cylinders: 8, horsepower: 139 }, + { name: 'dodge magnum xe', milesPerGallon: 17.5, cylinders: 8, horsepower: 140 }, + { name: 'chevrolet chevette', milesPerGallon: 30, cylinders: 4, horsepower: 68 }, + { name: 'toyota corona', milesPerGallon: 27.5, cylinders: 4, horsepower: 95 }, + { name: 'datsun 510', milesPerGallon: 27.2, cylinders: 4, horsepower: 97 }, + { name: 'dodge omni', milesPerGallon: 30.9, cylinders: 4, horsepower: 75 }, + { name: 'toyota celica gt liftback', milesPerGallon: 21.1, cylinders: 4, horsepower: 95 }, + { name: 'plymouth sapporo', milesPerGallon: 23.2, cylinders: 4, horsepower: 105 }, + { name: 'oldsmobile starfire sx', milesPerGallon: 23.8, cylinders: 4, horsepower: 85 }, + { name: 'datsun 200-sx', milesPerGallon: 23.9, cylinders: 4, horsepower: 97 }, + { name: 'audi 5000', milesPerGallon: 20.3, cylinders: 5, horsepower: 103 }, + { name: 'volvo 264gl', milesPerGallon: 17, cylinders: 6, horsepower: 125 }, + { name: 'saab 99gle', milesPerGallon: 21.6, cylinders: 4, horsepower: 115 }, + { name: 'peugeot 604sl', milesPerGallon: 16.2, cylinders: 6, horsepower: 133 }, + { name: 'volkswagen scirocco', milesPerGallon: 31.5, cylinders: 4, horsepower: 71 }, + { name: 'honda Accelerationord lx', milesPerGallon: 29.5, cylinders: 4, horsepower: 68 }, + { name: 'pontiac lemans v6', milesPerGallon: 21.5, cylinders: 6, horsepower: 115 }, + { name: 'mercury zephyr 6', milesPerGallon: 19.8, cylinders: 6, horsepower: 85 }, + { name: 'ford fairmont 4', milesPerGallon: 22.3, cylinders: 4, horsepower: 88 }, + { name: 'amc concord dl 6', milesPerGallon: 20.2, cylinders: 6, horsepower: 90 }, + { name: 'dodge aspen 6', milesPerGallon: 20.6, cylinders: 6, horsepower: 110 }, + { name: 'chevrolet caprice classic', milesPerGallon: 17, cylinders: 8, horsepower: 130 }, + { name: 'ford ltd landau', milesPerGallon: 17.6, cylinders: 8, horsepower: 129 }, + { name: 'mercury grand marquis', milesPerGallon: 16.5, cylinders: 8, horsepower: 138 }, + { name: 'dodge st. regis', milesPerGallon: 18.2, cylinders: 8, horsepower: 135 }, + { name: 'buick estate wagon (sw)', milesPerGallon: 16.9, cylinders: 8, horsepower: 155 }, + { name: 'ford country squire (sw)', milesPerGallon: 15.5, cylinders: 8, horsepower: 142 }, + { name: 'chevrolet malibu classic (sw)', milesPerGallon: 19.2, cylinders: 8, horsepower: 125 }, + { name: 'chrysler lebaron town @ country (sw)', milesPerGallon: 18.5, cylinders: 8, horsepower: 150 }, + { name: 'vw rabbit custom', milesPerGallon: 31.9, cylinders: 4, horsepower: 71 }, + { name: 'maxda glc deluxe', milesPerGallon: 34.1, cylinders: 4, horsepower: 65 }, + { name: 'dodge colt hatchback custom', milesPerGallon: 35.7, cylinders: 4, horsepower: 80 }, + { name: 'amc spirit dl', milesPerGallon: 27.4, cylinders: 4, horsepower: 80 }, + { name: 'mercedes benz 300d', milesPerGallon: 25.4, cylinders: 5, horsepower: 77 }, + { name: 'cadillac eldorado', milesPerGallon: 23, cylinders: 8, horsepower: 125 }, + { name: 'peugeot 504', milesPerGallon: 27.2, cylinders: 4, horsepower: 71 }, + { name: 'oldsmobile cutlass salon brougham', milesPerGallon: 23.9, cylinders: 8, horsepower: 90 }, + { name: 'plymouth horizon', milesPerGallon: 34.2, cylinders: 4, horsepower: 70 }, + { name: 'plymouth horizon tc3', milesPerGallon: 34.5, cylinders: 4, horsepower: 70 }, + { name: 'datsun 210', milesPerGallon: 31.8, cylinders: 4, horsepower: 65 }, + { name: 'fiat strada custom', milesPerGallon: 37.3, cylinders: 4, horsepower: 69 }, + { name: 'buick skylark limited', milesPerGallon: 28.4, cylinders: 4, horsepower: 90 }, + { name: 'chevrolet citation', milesPerGallon: 28.8, cylinders: 6, horsepower: 115 }, + { name: 'oldsmobile omega brougham', milesPerGallon: 26.8, cylinders: 6, horsepower: 115 }, + { name: 'pontiac phoenix', milesPerGallon: 33.5, cylinders: 4, horsepower: 90 }, + { name: 'vw rabbit', milesPerGallon: 41.5, cylinders: 4, horsepower: 76 }, + { name: 'toyota corolla tercel', milesPerGallon: 38.1, cylinders: 4, horsepower: 60 }, + { name: 'chevrolet chevette', milesPerGallon: 32.1, cylinders: 4, horsepower: 70 }, + { name: 'datsun 310', milesPerGallon: 37.2, cylinders: 4, horsepower: 65 }, + { name: 'chevrolet citation', milesPerGallon: 28, cylinders: 4, horsepower: 90 }, + { name: 'ford fairmont', milesPerGallon: 26.4, cylinders: 4, horsepower: 88 }, + { name: 'amc concord', milesPerGallon: 24.3, cylinders: 4, horsepower: 90 }, + { name: 'dodge aspen', milesPerGallon: 19.1, cylinders: 6, horsepower: 90 }, + { name: 'audi 4000', milesPerGallon: 34.3, cylinders: 4, horsepower: 78 }, + { name: 'toyota corona liftback', milesPerGallon: 29.8, cylinders: 4, horsepower: 90 }, + { name: 'mazda 626', milesPerGallon: 31.3, cylinders: 4, horsepower: 75 }, + { name: 'datsun 510 hatchback', milesPerGallon: 37, cylinders: 4, horsepower: 92 }, + { name: 'toyota corolla', milesPerGallon: 32.2, cylinders: 4, horsepower: 75 }, + { name: 'mazda glc', milesPerGallon: 46.6, cylinders: 4, horsepower: 65 }, + { name: 'dodge colt', milesPerGallon: 27.9, cylinders: 4, horsepower: 105 }, + { name: 'datsun 210', milesPerGallon: 40.8, cylinders: 4, horsepower: 65 }, + { name: 'vw rabbit c (diesel)', milesPerGallon: 44.3, cylinders: 4, horsepower: 48 }, + { name: 'vw dasher (diesel)', milesPerGallon: 43.4, cylinders: 4, horsepower: 48 }, + { name: 'audi 5000s (diesel)', milesPerGallon: 36.4, cylinders: 5, horsepower: 67 }, + { name: 'mercedes-benz 240d', milesPerGallon: 30, cylinders: 4, horsepower: 67 }, + { name: 'honda civic 1500 gl', milesPerGallon: 44.6, cylinders: 4, horsepower: 67 }, + { name: 'renault lecar deluxe', milesPerGallon: 40.9, cylinders: 4, horsepower: 0 }, + { name: 'subaru dl', milesPerGallon: 33.8, cylinders: 4, horsepower: 67 }, + { name: 'vokswagen rabbit', milesPerGallon: 29.8, cylinders: 4, horsepower: 62 }, + { name: 'datsun 280-zx', milesPerGallon: 32.7, cylinders: 6, horsepower: 132 }, + { name: 'mazda rx-7 gs', milesPerGallon: 23.7, cylinders: 3, horsepower: 100 }, + { name: 'triumph tr7 coupe', milesPerGallon: 35, cylinders: 4, horsepower: 88 }, + { name: 'ford mustang cobra', milesPerGallon: 23.6, cylinders: 4, horsepower: 0 }, + { name: 'honda Accelerationord', milesPerGallon: 32.4, cylinders: 4, horsepower: 72 }, + { name: 'plymouth reliant', milesPerGallon: 27.2, cylinders: 4, horsepower: 84 }, + { name: 'buick skylark', milesPerGallon: 26.6, cylinders: 4, horsepower: 84 }, + { name: 'dodge aries wagon (sw)', milesPerGallon: 25.8, cylinders: 4, horsepower: 92 }, + { name: 'chevrolet citation', milesPerGallon: 23.5, cylinders: 6, horsepower: 110 }, + { name: 'plymouth reliant', milesPerGallon: 30, cylinders: 4, horsepower: 84 }, + { name: 'toyota starlet', milesPerGallon: 39.1, cylinders: 4, horsepower: 58 }, + { name: 'plymouth champ', milesPerGallon: 39, cylinders: 4, horsepower: 64 }, + { name: 'honda civic 1300', milesPerGallon: 35.1, cylinders: 4, horsepower: 60 }, + { name: 'subaru', milesPerGallon: 32.3, cylinders: 4, horsepower: 67 }, + { name: 'datsun 210', milesPerGallon: 37, cylinders: 4, horsepower: 65 }, + { name: 'toyota tercel', milesPerGallon: 37.7, cylinders: 4, horsepower: 62 }, + { name: 'mazda glc 4', milesPerGallon: 34.1, cylinders: 4, horsepower: 68 }, + { name: 'plymouth horizon 4', milesPerGallon: 34.7, cylinders: 4, horsepower: 63 }, + { name: 'ford escort 4w', milesPerGallon: 34.4, cylinders: 4, horsepower: 65 }, + { name: 'ford escort 2h', milesPerGallon: 29.9, cylinders: 4, horsepower: 65 }, + { name: 'volkswagen jetta', milesPerGallon: 33, cylinders: 4, horsepower: 74 }, + { name: 'renault 18i', milesPerGallon: 34.5, cylinders: 4, horsepower: 0 }, + { name: 'honda prelude', milesPerGallon: 33.7, cylinders: 4, horsepower: 75 }, + { name: 'toyota corolla', milesPerGallon: 32.4, cylinders: 4, horsepower: 75 }, + { name: 'datsun 200sx', milesPerGallon: 32.9, cylinders: 4, horsepower: 100 }, + { name: 'mazda 626', milesPerGallon: 31.6, cylinders: 4, horsepower: 74 }, + { name: 'peugeot 505s turbo diesel', milesPerGallon: 28.1, cylinders: 4, horsepower: 80 }, + { name: 'saab 900s', milesPerGallon: 0, cylinders: 4, horsepower: 110 }, + { name: 'volvo diesel', milesPerGallon: 30.7, cylinders: 6, horsepower: 76 }, + { name: 'toyota cressida', milesPerGallon: 25.4, cylinders: 6, horsepower: 116 }, + { name: 'datsun 810 maxima', milesPerGallon: 24.2, cylinders: 6, horsepower: 120 }, + { name: 'buick century', milesPerGallon: 22.4, cylinders: 6, horsepower: 110 }, + { name: 'oldsmobile cutlass ls', milesPerGallon: 26.6, cylinders: 8, horsepower: 105 }, + { name: 'ford granada gl', milesPerGallon: 20.2, cylinders: 6, horsepower: 88 }, + { name: 'chrysler lebaron salon', milesPerGallon: 17.6, cylinders: 6, horsepower: 85 }, + { name: 'chevrolet cavalier', milesPerGallon: 28, cylinders: 4, horsepower: 88 }, + { name: 'chevrolet cavalier wagon', milesPerGallon: 27, cylinders: 4, horsepower: 88 }, + { name: 'chevrolet cavalier 2-door', milesPerGallon: 34, cylinders: 4, horsepower: 88 }, + { name: 'pontiac j2000 se hatchback', milesPerGallon: 31, cylinders: 4, horsepower: 85 }, + { name: 'dodge aries se', milesPerGallon: 29, cylinders: 4, horsepower: 84 }, + { name: 'pontiac phoenix', milesPerGallon: 27, cylinders: 4, horsepower: 90 }, + { name: 'ford fairmont futura', milesPerGallon: 24, cylinders: 4, horsepower: 92 }, + { name: 'amc concord dl', milesPerGallon: 23, cylinders: 4, horsepower: 0 }, + { name: 'volkswagen rabbit l', milesPerGallon: 36, cylinders: 4, horsepower: 74 }, + { name: 'mazda glc custom l', milesPerGallon: 37, cylinders: 4, horsepower: 68 }, + { name: 'mazda glc custom', milesPerGallon: 31, cylinders: 4, horsepower: 68 }, + { name: 'plymouth horizon miser', milesPerGallon: 38, cylinders: 4, horsepower: 63 }, + { name: 'mercury lynx l', milesPerGallon: 36, cylinders: 4, horsepower: 70 }, + { name: 'nissan stanza xe', milesPerGallon: 36, cylinders: 4, horsepower: 88 }, + { name: 'honda Accelerationord', milesPerGallon: 36, cylinders: 4, horsepower: 75 }, + { name: 'toyota corolla', milesPerGallon: 34, cylinders: 4, horsepower: 70 }, + { name: 'honda civic', milesPerGallon: 38, cylinders: 4, horsepower: 67 }, + { name: 'honda civic (auto)', milesPerGallon: 32, cylinders: 4, horsepower: 67 }, + { name: 'datsun 310 gx', milesPerGallon: 38, cylinders: 4, horsepower: 67 }, + { name: 'buick century limited', milesPerGallon: 25, cylinders: 6, horsepower: 110 }, + { name: 'oldsmobile cutlass ciera (diesel)', milesPerGallon: 38, cylinders: 6, horsepower: 85 }, + { name: 'chrysler lebaron medallion', milesPerGallon: 26, cylinders: 4, horsepower: 92 }, + { name: 'ford granada l', milesPerGallon: 22, cylinders: 6, horsepower: 112 }, + { name: 'toyota celica gt', milesPerGallon: 32, cylinders: 4, horsepower: 96 }, + { name: 'dodge charger 2.2', milesPerGallon: 36, cylinders: 4, horsepower: 84 }, + { name: 'chevrolet camaro', milesPerGallon: 27, cylinders: 4, horsepower: 90 }, + { name: 'ford mustang gl', milesPerGallon: 27, cylinders: 4, horsepower: 86 }, + { name: 'vw pickup', milesPerGallon: 44, cylinders: 4, horsepower: 52 }, + { name: 'dodge rampage', milesPerGallon: 32, cylinders: 4, horsepower: 84 }, + { name: 'ford ranger', milesPerGallon: 28, cylinders: 4, horsepower: 79 }, + { name: 'chevy s-10', milesPerGallon: 31, cylinders: 4, horsepower: 82 } +]; + +// 图表配置 +const spec = { + type: 'common', + series: [ + { + type: 'scatter', + xField: 'milesPerGallon', + yField: 'horsepower', + point: { + state: { + hover: { + scaleX: 1.2, + scaleY: 1.2 + } + }, + style: { + fillOpacity: 0.25 + } + } + } + ], + tooltip: { + dimension: { + visible: true + }, + mark: { + title: true, + content: [ + { + key: d => d.name, + value: d => d.y + } + ] + } + }, + crosshair: { + yField: { + visible: true, + line: { + visible: true, + type: 'line' + }, + label: { + visible: true // label 默认关闭 + } + }, + xField: { + visible: true, + line: { + visible: true, + type: 'line' + }, + label: { + visible: true // label 默认关闭 + } + } + }, + axes: [ + { + title: { + visible: true, + text: 'Horse Power' + }, + orient: 'left', + range: { min: 0 }, + type: 'linear' + }, + { + title: { + visible: true, + text: 'Miles Per Gallon' + }, + orient: 'bottom', + label: { visible: true }, + type: 'linear' + } + ], + data: [ + { + id: 'data', + values: data.flat() + } + ] +}; +registerRegressionLine(); +appendScatterRegressionLineConfig(spec, [ + { + type: 'polynomial', // 支持4中类型 'linear' | 'logisitc' | 'lowess' | 'polynomial' + polynomialDegree: 3, + color: 'red', + line: { + style: { + lineWidth: 2 + } + }, + confidenceInterval: { + style: { + fillOpacity: 0.2 + } + }, + label: { + text: '3次多项式回归' + } + }, + { + type: 'linear', + color: 'green', + label: { + text: '线性回归' + } + } +]); +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); + +// Just for the convenience of console debugging, DO NOT COPY! +window['vchart'] = vchart; +``` + +### 配置类型定义 + +其中回归线配置的类型定义如下: + +```ts +{ + /** + * 回归线的类型 + */ + type: 'linear' | 'logisitc' | 'lowess' | 'polynomial'; + /** + * 多项式回归的阶数,仅当 type 为 polynomial 时有效 + */ + polynomialDegree?: number; + /** + * 颜色值 + */ + color?: string; + /** + * 回归线配置 + */ + line?: { + /** + * 是否显示系列标签 + * @default true + */ + visible?: boolean; + /** + * 线样式 + */ + style?: ILineGraphicAttribute; + }; + /** + * 回归线公式标签 + */ + label?: { + /** + * 是否显示标签 + */ + visible?: boolean; + /** + * 标签文本 + */ + text: string; + /** + * 标签样式 + */ + style?: ITextGraphicAttribute; + }; + /** + * 置信区间 + */ + confidenceInterval?: { + visible?: boolean; + style?: IAreaGraphicAttribute; + }; +} +``` + +## 注意事项与建议 + +- 直方图回归依赖 bin 输出字段(例如 `x0/x1/count`),确保 `transforms` 中 `bin` 的 `outputNames` 与回归组件期望一致。 +- 置信区间计算会带来额外开销,大数据集或交互更新时建议关闭。 +- `append*` 方法会直接修改传入的 `spec`,如需保留原始 spec,请先深拷贝后再操作。 diff --git a/docs/assets/guide/zh/tutorial_docs/Chart_Types/Histogram.md b/docs/assets/guide/zh/tutorial_docs/Chart_Types/Histogram.md index 1fa8b19d67..becf79bf35 100644 --- a/docs/assets/guide/zh/tutorial_docs/Chart_Types/Histogram.md +++ b/docs/assets/guide/zh/tutorial_docs/Chart_Types/Histogram.md @@ -866,6 +866,130 @@ vchart.renderSync(); window['vchart'] = vchart; ``` +### 使用 `bin` transform 生成直方图数据 + +自 `2.0.7` 版本开始,直方图支持了`bin` transform,当数据为明细数据的时候,可以通过该变换,获得标准的直方图数据 + +```javascript livedemo +const spec = { + data: [ + { + name: 'data1', + transforms: [ + { + type: 'bin', + options: { + bins: 10, + field: 'value' + } + } + ], + values: [ + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2 }, + { value: 2.3 }, + { value: 2.3 }, + { value: 2.3 }, + { value: 2.3 }, + { value: 2.3 }, + { value: 2.3 }, + { value: 2.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 }, + { value: 9.3 } + ] + } + ], + type: 'histogram', + xField: 'x0', + x2Field: 'x1', + yField: 'count', + bar: { + style: { + stroke: 'white', + lineWidth: 1 + } + }, + title: { + text: 'Arrival Time Histogram' + }, + tooltip: { + visible: true, + mark: { + title: { + key: 'title', + value: 'count' + }, + content: [ + { + key: datum => datum['x0'] + '~' + datum['x1'], + value: datum => datum['count'] + } + ] + } + } +}; +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); + +// 只为了方便控制台调试用,不要拷贝 +window['vchart'] = vchart; +``` + +其中 bin transform 支持如下配置: + +```ts +interface IBinOptions { + /** + * 需要分箱的数值字段 + */ + field: string; + /** + * 分箱数量(默认 10) + */ + bins?: number; + /** + * 显式指定的分箱边界数组 + */ + thresholds?: number[]; + /** + * 固定的分箱宽度(区间步长),如设置则覆盖 bins + */ + step?: number; + /** + * 指定分箱的最小值和最大值 [min, max],否则自动根据数据计算 + */ + extent?: [number, number]; + /** + * 是否在每个分箱中保留原始数据项 + */ + includeValues?: boolean; + /** + * 输出数据的字段名映射 + */ + outputNames?: { x0?: string; x1?: string; count?: string; values?: string }; +} +``` + ## 图表布局 ### 堆叠直方图 diff --git a/docs/package.json b/docs/package.json index a644da1ab9..354ca6ec3b 100644 --- a/docs/package.json +++ b/docs/package.json @@ -18,7 +18,7 @@ "@visactor/vchart-extension": "workspace:2.0.6", "@visactor/vchart-theme": "~1.6.6", "@visactor/vmind": "1.2.4-alpha.5", - "@visactor/vutils": "~1.0.6", + "@visactor/vutils": "~1.0.11", "@visactor/vrender": "~1.0.18", "@visactor/vrender-kits": "~1.0.18", "@visactor/vtable": "1.19.0-alpha.0", @@ -58,4 +58,4 @@ "react-device-detect": "^2.2.2", "minimist": "1.2.8" } -} +} \ No newline at end of file diff --git a/packages/openinula-vchart/package.json b/packages/openinula-vchart/package.json index 03d0ccc3b1..3a06dc870c 100644 --- a/packages/openinula-vchart/package.json +++ b/packages/openinula-vchart/package.json @@ -29,7 +29,7 @@ }, "dependencies": { "@visactor/vchart": "workspace:2.0.6", - "@visactor/vutils": "~1.0.6", + "@visactor/vutils": "~1.0.11", "@visactor/vrender-core": "~1.0.18", "@visactor/vrender-kits": "~1.0.18", "react-is": "^18.2.0" @@ -78,4 +78,4 @@ "access": "public", "registry": "https://registry.npmjs.org/" } -} +} \ No newline at end of file diff --git a/packages/react-vchart/package.json b/packages/react-vchart/package.json index dd86b5e04f..e0f69375e4 100644 --- a/packages/react-vchart/package.json +++ b/packages/react-vchart/package.json @@ -30,7 +30,7 @@ "dependencies": { "@visactor/vchart": "workspace:2.0.6", "@visactor/vchart-extension": "workspace:2.0.6", - "@visactor/vutils": "~1.0.6", + "@visactor/vutils": "~1.0.11", "@visactor/vrender-core": "~1.0.18", "@visactor/vrender-kits": "~1.0.18", "react-is": "^18.2.0" @@ -83,4 +83,4 @@ "access": "public", "registry": "https://registry.npmjs.org/" } -} +} \ No newline at end of file diff --git a/packages/vchart-extension/__tests__/runtime/browser/test-page/bar-regression-line/poly.ts b/packages/vchart-extension/__tests__/runtime/browser/test-page/bar-regression-line/poly.ts new file mode 100644 index 0000000000..74e8d7a2b4 --- /dev/null +++ b/packages/vchart-extension/__tests__/runtime/browser/test-page/bar-regression-line/poly.ts @@ -0,0 +1,53 @@ +import { registerRegressionLine } from '../../../../../src/components/regression-line/regression-line'; +import { appendBarRegressionLineConfig } from './../../../../../src/components/bar-regression-line'; +import { default as VChart } from '@visactor/vchart'; + +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { month: 'Monday', sales: 22 }, + { month: 'Tuesday', sales: 13 }, + { month: 'Wednesday', sales: 25 }, + { month: 'Thursday', sales: 29 }, + { month: 'Friday', sales: 38 } + ] + } + ], + xField: 'month', + yField: 'sales' +}; + +const run = () => { + registerRegressionLine(); + appendBarRegressionLineConfig(spec, { + degree: 3, + line: { + style: { + stroke: 'red', + lineWidth: 2 + } + }, + confidenceInterval: { + style: { + fill: 'red', + fillOpacity: 0.2 + } + } + }); + + const cs = new VChart(spec, { + dom: document.getElementById('chart') as HTMLElement, + //theme: 'dark', + onError: err => { + console.error(err); + } + }); + + cs.renderSync(); + + window['vchart'] = cs; +}; +run(); diff --git a/packages/vchart-extension/__tests__/runtime/browser/test-page/histogram-regression-line/kde.ts b/packages/vchart-extension/__tests__/runtime/browser/test-page/histogram-regression-line/kde.ts new file mode 100644 index 0000000000..dc0b39de07 --- /dev/null +++ b/packages/vchart-extension/__tests__/runtime/browser/test-page/histogram-regression-line/kde.ts @@ -0,0 +1,133 @@ +import { registerRegressionLine } from '../../../../../src/components/regression-line/regression-line'; +import { appendHistogramRegressionLineConfig } from './../../../../../src/components/histogram-regression-line'; +import { default as VChart } from '@visactor/vchart'; + +// expose vchart on window for debugging in tests +declare global { + interface Window { + vchart?: unknown; + } +} + +// --- gaussian generators (reproducible) --- +function mulberry32(seed: number) { + return function () { + let t = (seed += 0x6d2b79f5); + t = Math.imul(t ^ (t >>> 15), t | 1); + t ^= t + Math.imul(t ^ (t >>> 7), t | 61); + return ((t ^ (t >>> 14)) >>> 0) / 4294967296; + }; +} + +function boxMullerRandom(rng: () => number) { + let u = 0; + let v = 0; + while (u === 0) { + u = rng(); + } + while (v === 0) { + v = rng(); + } + return Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v); +} + +function generateGaussian(count: number, mean = 0, sd = 1, seed?: number) { + const rng = seed === undefined ? Math.random : mulberry32(seed); + const out: number[] = []; + for (let i = 0; i < count; i++) { + out.push(mean + boxMullerRandom(rng) * sd); + } + return out; +} + +function generateMixtureGaussianSamples() { + const a = generateGaussian(160, 5, 4, 1); // cluster A + // const b = generateGaussian(80, 2.3, 0.08, 2); // cluster B + // const c = generateGaussian(140, 9.3, 0.35, 3); // cluster C + const outliers = [5.0, 6.2, 3.5, 12.0, 0.5]; + const arr = [...a, ...outliers]; + return arr.map(v => ({ value: v })); +} + +const spec = { + data: [ + { + name: 'data1', + transforms: [ + { + type: 'bin', + options: { + bins: 5, + step: 2, + field: 'value' + } + } + ], + values: generateMixtureGaussianSamples() + } + ], + type: 'histogram', + xField: 'x0', + x2Field: 'x1', + yField: 'count', + bar: { + style: { + stroke: 'white', + lineWidth: 1 + } + }, + title: { + text: 'Arrival Time Histogram', + textStyle: { + height: 50, + lineWidth: 3, + fill: '#333', + fontSize: 25, + fontFamily: 'Times New Roman' + } + }, + tooltip: { + visible: true, + mark: { + title: { + key: 'title', + value: 'count' + }, + content: [ + { + key: (datum: Record) => + String(datum['x0'] as unknown) + '~' + String(datum['x1'] as unknown), + value: (datum: Record) => Number(datum['count'] as unknown) + } + ] + } + } +}; + +const run = () => { + registerRegressionLine(); + appendHistogramRegressionLineConfig(spec, { + type: 'kde', + line: { + style: { + stroke: 'red', + lineWidth: 2 + } + } + }); + + const cs = new VChart(spec, { + dom: document.getElementById('chart') as HTMLElement, + //theme: 'dark', + onError: (err: unknown) => { + // eslint-disable-next-line no-console + console.error(err); + } + }); + + cs.renderSync(); + + // expose for debugging in tests + window.vchart = cs; +}; +run(); diff --git a/packages/vchart-extension/__tests__/runtime/browser/test-page/scatter-regression-line/linear.ts b/packages/vchart-extension/__tests__/runtime/browser/test-page/scatter-regression-line/linear.ts new file mode 100644 index 0000000000..66d451d323 --- /dev/null +++ b/packages/vchart-extension/__tests__/runtime/browser/test-page/scatter-regression-line/linear.ts @@ -0,0 +1,554 @@ +import { registerRegressionLine } from '../../../../../src/components/regression-line/regression-line'; +import { appendScatterRegressionLineConfig } from './../../../../../src/components/scatter-regression-line'; +import { default as VChart } from '@visactor/vchart'; + +const data = [ + { name: 'chevrolet chevelle malibu', milesPerGallon: 18, cylinders: 8, horsepower: 130 }, + { name: 'buick skylark 320', milesPerGallon: 15, cylinders: 8, horsepower: 165 }, + { name: 'plymouth satellite', milesPerGallon: 18, cylinders: 8, horsepower: 150 }, + { name: 'amc rebel sst', milesPerGallon: 16, cylinders: 8, horsepower: 150 }, + { name: 'ford torino', milesPerGallon: 17, cylinders: 8, horsepower: 140 }, + { name: 'ford galaxie 500', milesPerGallon: 15, cylinders: 8, horsepower: 198 }, + { name: 'chevrolet impala', milesPerGallon: 14, cylinders: 8, horsepower: 220 }, + { name: 'plymouth fury iii', milesPerGallon: 14, cylinders: 8, horsepower: 215 }, + { name: 'pontiac catalina', milesPerGallon: 14, cylinders: 8, horsepower: 225 }, + { name: 'amc ambassador dpl', milesPerGallon: 15, cylinders: 8, horsepower: 190 }, + { name: 'citroen ds-21 pallas', milesPerGallon: 0, cylinders: 4, horsepower: 115 }, + { name: 'chevrolet chevelle concours (sw)', milesPerGallon: 0, cylinders: 8, horsepower: 165 }, + { name: 'ford torino (sw)', milesPerGallon: 0, cylinders: 8, horsepower: 153 }, + { name: 'plymouth satellite (sw)', milesPerGallon: 0, cylinders: 8, horsepower: 175 }, + { name: 'amc rebel sst (sw)', milesPerGallon: 0, cylinders: 8, horsepower: 175 }, + { name: 'dodge challenger se', milesPerGallon: 15, cylinders: 8, horsepower: 170 }, + { name: "plymouth 'cuda 340", milesPerGallon: 14, cylinders: 8, horsepower: 160 }, + { name: 'ford mustang boss 302', milesPerGallon: 0, cylinders: 8, horsepower: 140 }, + { name: 'chevrolet monte carlo', milesPerGallon: 15, cylinders: 8, horsepower: 150 }, + { name: 'buick estate wagon (sw)', milesPerGallon: 14, cylinders: 8, horsepower: 225 }, + { name: 'toyota corona mark ii', milesPerGallon: 24, cylinders: 4, horsepower: 95 }, + { name: 'plymouth duster', milesPerGallon: 22, cylinders: 6, horsepower: 95 }, + { name: 'amc hornet', milesPerGallon: 18, cylinders: 6, horsepower: 97 }, + { name: 'ford maverick', milesPerGallon: 21, cylinders: 6, horsepower: 85 }, + { name: 'datsun pl510', milesPerGallon: 27, cylinders: 4, horsepower: 88 }, + { name: 'volkswagen 1131 deluxe sedan', milesPerGallon: 26, cylinders: 4, horsepower: 46 }, + { name: 'peugeot 504', milesPerGallon: 25, cylinders: 4, horsepower: 87 }, + { name: 'audi 100 ls', milesPerGallon: 24, cylinders: 4, horsepower: 90 }, + { name: 'saab 99e', milesPerGallon: 25, cylinders: 4, horsepower: 95 }, + { name: 'bmw 2002', milesPerGallon: 26, cylinders: 4, horsepower: 113 }, + { name: 'amc gremlin', milesPerGallon: 21, cylinders: 6, horsepower: 90 }, + { name: 'ford f250', milesPerGallon: 10, cylinders: 8, horsepower: 215 }, + { name: 'chevy c20', milesPerGallon: 10, cylinders: 8, horsepower: 200 }, + { name: 'dodge d200', milesPerGallon: 11, cylinders: 8, horsepower: 210 }, + { name: 'hi 1200d', milesPerGallon: 9, cylinders: 8, horsepower: 193 }, + { name: 'datsun pl510', milesPerGallon: 27, cylinders: 4, horsepower: 88 }, + { name: 'chevrolet vega 2300', milesPerGallon: 28, cylinders: 4, horsepower: 90 }, + { name: 'toyota corona', milesPerGallon: 25, cylinders: 4, horsepower: 95 }, + { name: 'ford pinto', milesPerGallon: 25, cylinders: 4, horsepower: 0 }, + { name: 'volkswagen super beetle 117', milesPerGallon: 0, cylinders: 4, horsepower: 48 }, + { name: 'amc gremlin', milesPerGallon: 19, cylinders: 6, horsepower: 100 }, + { name: 'plymouth satellite custom', milesPerGallon: 16, cylinders: 6, horsepower: 105 }, + { name: 'chevrolet chevelle malibu', milesPerGallon: 17, cylinders: 6, horsepower: 100 }, + { name: 'ford torino 500', milesPerGallon: 19, cylinders: 6, horsepower: 88 }, + { name: 'amc matador', milesPerGallon: 18, cylinders: 6, horsepower: 100 }, + { name: 'chevrolet impala', milesPerGallon: 14, cylinders: 8, horsepower: 165 }, + { name: 'pontiac catalina brougham', milesPerGallon: 14, cylinders: 8, horsepower: 175 }, + { name: 'ford galaxie 500', milesPerGallon: 14, cylinders: 8, horsepower: 153 }, + { name: 'plymouth fury iii', milesPerGallon: 14, cylinders: 8, horsepower: 150 }, + { name: 'dodge monaco (sw)', milesPerGallon: 12, cylinders: 8, horsepower: 180 }, + { name: 'ford country squire (sw)', milesPerGallon: 13, cylinders: 8, horsepower: 170 }, + { name: 'pontiac safari (sw)', milesPerGallon: 13, cylinders: 8, horsepower: 175 }, + { name: 'amc hornet sportabout (sw)', milesPerGallon: 18, cylinders: 6, horsepower: 110 }, + { name: 'chevrolet vega (sw)', milesPerGallon: 22, cylinders: 4, horsepower: 72 }, + { name: 'pontiac firebird', milesPerGallon: 19, cylinders: 6, horsepower: 100 }, + { name: 'ford mustang', milesPerGallon: 18, cylinders: 6, horsepower: 88 }, + { name: 'mercury capri 2000', milesPerGallon: 23, cylinders: 4, horsepower: 86 }, + { name: 'opel 1900', milesPerGallon: 28, cylinders: 4, horsepower: 90 }, + { name: 'peugeot 304', milesPerGallon: 30, cylinders: 4, horsepower: 70 }, + { name: 'fiat 124b', milesPerGallon: 30, cylinders: 4, horsepower: 76 }, + { name: 'toyota corolla 1200', milesPerGallon: 31, cylinders: 4, horsepower: 65 }, + { name: 'datsun 1200', milesPerGallon: 35, cylinders: 4, horsepower: 69 }, + { name: 'volkswagen model 111', milesPerGallon: 27, cylinders: 4, horsepower: 60 }, + { name: 'plymouth cricket', milesPerGallon: 26, cylinders: 4, horsepower: 70 }, + { name: 'toyota corona hardtop', milesPerGallon: 24, cylinders: 4, horsepower: 95 }, + { name: 'dodge colt hardtop', milesPerGallon: 25, cylinders: 4, horsepower: 80 }, + { name: 'volkswagen type 3', milesPerGallon: 23, cylinders: 4, horsepower: 54 }, + { name: 'chevrolet vega', milesPerGallon: 20, cylinders: 4, horsepower: 90 }, + { name: 'ford pinto runabout', milesPerGallon: 21, cylinders: 4, horsepower: 86 }, + { name: 'chevrolet impala', milesPerGallon: 13, cylinders: 8, horsepower: 165 }, + { name: 'pontiac catalina', milesPerGallon: 14, cylinders: 8, horsepower: 175 }, + { name: 'plymouth fury iii', milesPerGallon: 15, cylinders: 8, horsepower: 150 }, + { name: 'ford galaxie 500', milesPerGallon: 14, cylinders: 8, horsepower: 153 }, + { name: 'amc ambassador sst', milesPerGallon: 17, cylinders: 8, horsepower: 150 }, + { name: 'mercury marquis', milesPerGallon: 11, cylinders: 8, horsepower: 208 }, + { name: 'buick lesabre custom', milesPerGallon: 13, cylinders: 8, horsepower: 155 }, + { name: 'oldsmobile delta 88 royale', milesPerGallon: 12, cylinders: 8, horsepower: 160 }, + { name: 'chrysler newport royal', milesPerGallon: 13, cylinders: 8, horsepower: 190 }, + { name: 'mazda rx2 coupe', milesPerGallon: 19, cylinders: 3, horsepower: 97 }, + { name: 'amc matador (sw)', milesPerGallon: 15, cylinders: 8, horsepower: 150 }, + { name: 'chevrolet chevelle concours (sw)', milesPerGallon: 13, cylinders: 8, horsepower: 130 }, + { name: 'ford gran torino (sw)', milesPerGallon: 13, cylinders: 8, horsepower: 140 }, + { name: 'plymouth satellite custom (sw)', milesPerGallon: 14, cylinders: 8, horsepower: 150 }, + { name: 'volvo 145e (sw)', milesPerGallon: 18, cylinders: 4, horsepower: 112 }, + { name: 'volkswagen 411 (sw)', milesPerGallon: 22, cylinders: 4, horsepower: 76 }, + { name: 'peugeot 504 (sw)', milesPerGallon: 21, cylinders: 4, horsepower: 87 }, + { name: 'renault 12 (sw)', milesPerGallon: 26, cylinders: 4, horsepower: 69 }, + { name: 'ford pinto (sw)', milesPerGallon: 22, cylinders: 4, horsepower: 86 }, + { name: 'datsun 510 (sw)', milesPerGallon: 28, cylinders: 4, horsepower: 92 }, + { name: 'toyouta corona mark ii (sw)', milesPerGallon: 23, cylinders: 4, horsepower: 97 }, + { name: 'dodge colt (sw)', milesPerGallon: 28, cylinders: 4, horsepower: 80 }, + { name: 'toyota corolla 1600 (sw)', milesPerGallon: 27, cylinders: 4, horsepower: 88 }, + { name: 'buick century 350', milesPerGallon: 13, cylinders: 8, horsepower: 175 }, + { name: 'amc matador', milesPerGallon: 14, cylinders: 8, horsepower: 150 }, + { name: 'chevrolet malibu', milesPerGallon: 13, cylinders: 8, horsepower: 145 }, + { name: 'ford gran torino', milesPerGallon: 14, cylinders: 8, horsepower: 137 }, + { name: 'dodge coronet custom', milesPerGallon: 15, cylinders: 8, horsepower: 150 }, + { name: 'mercury marquis brougham', milesPerGallon: 12, cylinders: 8, horsepower: 198 }, + { name: 'chevrolet caprice classic', milesPerGallon: 13, cylinders: 8, horsepower: 150 }, + { name: 'ford ltd', milesPerGallon: 13, cylinders: 8, horsepower: 158 }, + { name: 'plymouth fury gran sedan', milesPerGallon: 14, cylinders: 8, horsepower: 150 }, + { name: 'chrysler new yorker brougham', milesPerGallon: 13, cylinders: 8, horsepower: 215 }, + { name: 'buick electra 225 custom', milesPerGallon: 12, cylinders: 8, horsepower: 225 }, + { name: 'amc ambassador brougham', milesPerGallon: 13, cylinders: 8, horsepower: 175 }, + { name: 'plymouth valiant', milesPerGallon: 18, cylinders: 6, horsepower: 105 }, + { name: 'chevrolet nova custom', milesPerGallon: 16, cylinders: 6, horsepower: 100 }, + { name: 'amc hornet', milesPerGallon: 18, cylinders: 6, horsepower: 100 }, + { name: 'ford maverick', milesPerGallon: 18, cylinders: 6, horsepower: 88 }, + { name: 'plymouth duster', milesPerGallon: 23, cylinders: 6, horsepower: 95 }, + { name: 'volkswagen super beetle', milesPerGallon: 26, cylinders: 4, horsepower: 46 }, + { name: 'chevrolet impala', milesPerGallon: 11, cylinders: 8, horsepower: 150 }, + { name: 'ford country', milesPerGallon: 12, cylinders: 8, horsepower: 167 }, + { name: 'plymouth custom suburb', milesPerGallon: 13, cylinders: 8, horsepower: 170 }, + { name: 'oldsmobile vista cruiser', milesPerGallon: 12, cylinders: 8, horsepower: 180 }, + { name: 'amc gremlin', milesPerGallon: 18, cylinders: 6, horsepower: 100 }, + { name: 'toyota carina', milesPerGallon: 20, cylinders: 4, horsepower: 88 }, + { name: 'chevrolet vega', milesPerGallon: 21, cylinders: 4, horsepower: 72 }, + { name: 'datsun 610', milesPerGallon: 22, cylinders: 4, horsepower: 94 }, + { name: 'maxda rx3', milesPerGallon: 18, cylinders: 3, horsepower: 90 }, + { name: 'ford pinto', milesPerGallon: 19, cylinders: 4, horsepower: 85 }, + { name: 'mercury capri v6', milesPerGallon: 21, cylinders: 6, horsepower: 107 }, + { name: 'fiat 124 sport coupe', milesPerGallon: 26, cylinders: 4, horsepower: 90 }, + { name: 'chevrolet monte carlo s', milesPerGallon: 15, cylinders: 8, horsepower: 145 }, + { name: 'pontiac grand prix', milesPerGallon: 16, cylinders: 8, horsepower: 230 }, + { name: 'fiat 128', milesPerGallon: 29, cylinders: 4, horsepower: 49 }, + { name: 'opel manta', milesPerGallon: 24, cylinders: 4, horsepower: 75 }, + { name: 'audi 100ls', milesPerGallon: 20, cylinders: 4, horsepower: 91 }, + { name: 'volvo 144ea', milesPerGallon: 19, cylinders: 4, horsepower: 112 }, + { name: 'dodge dart custom', milesPerGallon: 15, cylinders: 8, horsepower: 150 }, + { name: 'saab 99le', milesPerGallon: 24, cylinders: 4, horsepower: 110 }, + { name: 'toyota mark ii', milesPerGallon: 20, cylinders: 6, horsepower: 122 }, + { name: 'oldsmobile omega', milesPerGallon: 11, cylinders: 8, horsepower: 180 }, + { name: 'plymouth duster', milesPerGallon: 20, cylinders: 6, horsepower: 95 }, + { name: 'ford maverick', milesPerGallon: 21, cylinders: 6, horsepower: 0 }, + { name: 'amc hornet', milesPerGallon: 19, cylinders: 6, horsepower: 100 }, + { name: 'chevrolet nova', milesPerGallon: 15, cylinders: 6, horsepower: 100 }, + { name: 'datsun b210', milesPerGallon: 31, cylinders: 4, horsepower: 67 }, + { name: 'ford pinto', milesPerGallon: 26, cylinders: 4, horsepower: 80 }, + { name: 'toyota corolla 1200', milesPerGallon: 32, cylinders: 4, horsepower: 65 }, + { name: 'chevrolet vega', milesPerGallon: 25, cylinders: 4, horsepower: 75 }, + { name: 'chevrolet chevelle malibu classic', milesPerGallon: 16, cylinders: 6, horsepower: 100 }, + { name: 'amc matador', milesPerGallon: 16, cylinders: 6, horsepower: 110 }, + { name: 'plymouth satellite sebring', milesPerGallon: 18, cylinders: 6, horsepower: 105 }, + { name: 'ford gran torino', milesPerGallon: 16, cylinders: 8, horsepower: 140 }, + { name: 'buick century luxus (sw)', milesPerGallon: 13, cylinders: 8, horsepower: 150 }, + { name: 'dodge coronet custom (sw)', milesPerGallon: 14, cylinders: 8, horsepower: 150 }, + { name: 'ford gran torino (sw)', milesPerGallon: 14, cylinders: 8, horsepower: 140 }, + { name: 'amc matador (sw)', milesPerGallon: 14, cylinders: 8, horsepower: 150 }, + { name: 'audi fox', milesPerGallon: 29, cylinders: 4, horsepower: 83 }, + { name: 'volkswagen dasher', milesPerGallon: 26, cylinders: 4, horsepower: 67 }, + { name: 'opel manta', milesPerGallon: 26, cylinders: 4, horsepower: 78 }, + { name: 'toyota corona', milesPerGallon: 31, cylinders: 4, horsepower: 52 }, + { name: 'datsun 710', milesPerGallon: 32, cylinders: 4, horsepower: 61 }, + { name: 'dodge colt', milesPerGallon: 28, cylinders: 4, horsepower: 75 }, + { name: 'fiat 128', milesPerGallon: 24, cylinders: 4, horsepower: 75 }, + { name: 'fiat 124 tc', milesPerGallon: 26, cylinders: 4, horsepower: 75 }, + { name: 'honda civic', milesPerGallon: 24, cylinders: 4, horsepower: 97 }, + { name: 'subaru', milesPerGallon: 26, cylinders: 4, horsepower: 93 }, + { name: 'fiat x1.9', milesPerGallon: 31, cylinders: 4, horsepower: 67 }, + { name: 'plymouth valiant custom', milesPerGallon: 19, cylinders: 6, horsepower: 95 }, + { name: 'chevrolet nova', milesPerGallon: 18, cylinders: 6, horsepower: 105 }, + { name: 'mercury monarch', milesPerGallon: 15, cylinders: 6, horsepower: 72 }, + { name: 'ford maverick', milesPerGallon: 15, cylinders: 6, horsepower: 72 }, + { name: 'pontiac catalina', milesPerGallon: 16, cylinders: 8, horsepower: 170 }, + { name: 'chevrolet bel air', milesPerGallon: 15, cylinders: 8, horsepower: 145 }, + { name: 'plymouth grand fury', milesPerGallon: 16, cylinders: 8, horsepower: 150 }, + { name: 'ford ltd', milesPerGallon: 14, cylinders: 8, horsepower: 148 }, + { name: 'buick century', milesPerGallon: 17, cylinders: 6, horsepower: 110 }, + { name: 'chevroelt chevelle malibu', milesPerGallon: 16, cylinders: 6, horsepower: 105 }, + { name: 'amc matador', milesPerGallon: 15, cylinders: 6, horsepower: 110 }, + { name: 'plymouth fury', milesPerGallon: 18, cylinders: 6, horsepower: 95 }, + { name: 'buick skyhawk', milesPerGallon: 21, cylinders: 6, horsepower: 110 }, + { name: 'chevrolet monza 2+2', milesPerGallon: 20, cylinders: 8, horsepower: 110 }, + { name: 'ford mustang ii', milesPerGallon: 13, cylinders: 8, horsepower: 129 }, + { name: 'toyota corolla', milesPerGallon: 29, cylinders: 4, horsepower: 75 }, + { name: 'ford pinto', milesPerGallon: 23, cylinders: 4, horsepower: 83 }, + { name: 'amc gremlin', milesPerGallon: 20, cylinders: 6, horsepower: 100 }, + { name: 'pontiac astro', milesPerGallon: 23, cylinders: 4, horsepower: 78 }, + { name: 'toyota corona', milesPerGallon: 24, cylinders: 4, horsepower: 96 }, + { name: 'volkswagen dasher', milesPerGallon: 25, cylinders: 4, horsepower: 71 }, + { name: 'datsun 710', milesPerGallon: 24, cylinders: 4, horsepower: 97 }, + { name: 'ford pinto', milesPerGallon: 18, cylinders: 6, horsepower: 97 }, + { name: 'volkswagen rabbit', milesPerGallon: 29, cylinders: 4, horsepower: 70 }, + { name: 'amc pacer', milesPerGallon: 19, cylinders: 6, horsepower: 90 }, + { name: 'audi 100ls', milesPerGallon: 23, cylinders: 4, horsepower: 95 }, + { name: 'peugeot 504', milesPerGallon: 23, cylinders: 4, horsepower: 88 }, + { name: 'volvo 244dl', milesPerGallon: 22, cylinders: 4, horsepower: 98 }, + { name: 'saab 99le', milesPerGallon: 25, cylinders: 4, horsepower: 115 }, + { name: 'honda civic cvcc', milesPerGallon: 33, cylinders: 4, horsepower: 53 }, + { name: 'fiat 131', milesPerGallon: 28, cylinders: 4, horsepower: 86 }, + { name: 'opel 1900', milesPerGallon: 25, cylinders: 4, horsepower: 81 }, + { name: 'capri ii', milesPerGallon: 25, cylinders: 4, horsepower: 92 }, + { name: 'dodge colt', milesPerGallon: 26, cylinders: 4, horsepower: 79 }, + { name: 'renault 12tl', milesPerGallon: 27, cylinders: 4, horsepower: 83 }, + { name: 'chevrolet chevelle malibu classic', milesPerGallon: 17.5, cylinders: 8, horsepower: 140 }, + { name: 'dodge coronet brougham', milesPerGallon: 16, cylinders: 8, horsepower: 150 }, + { name: 'amc matador', milesPerGallon: 15.5, cylinders: 8, horsepower: 120 }, + { name: 'ford gran torino', milesPerGallon: 14.5, cylinders: 8, horsepower: 152 }, + { name: 'plymouth valiant', milesPerGallon: 22, cylinders: 6, horsepower: 100 }, + { name: 'chevrolet nova', milesPerGallon: 22, cylinders: 6, horsepower: 105 }, + { name: 'ford maverick', milesPerGallon: 24, cylinders: 6, horsepower: 81 }, + { name: 'amc hornet', milesPerGallon: 22.5, cylinders: 6, horsepower: 90 }, + { name: 'chevrolet chevette', milesPerGallon: 29, cylinders: 4, horsepower: 52 }, + { name: 'chevrolet woody', milesPerGallon: 24.5, cylinders: 4, horsepower: 60 }, + { name: 'vw rabbit', milesPerGallon: 29, cylinders: 4, horsepower: 70 }, + { name: 'honda civic', milesPerGallon: 33, cylinders: 4, horsepower: 53 }, + { name: 'dodge aspen se', milesPerGallon: 20, cylinders: 6, horsepower: 100 }, + { name: 'ford granada ghia', milesPerGallon: 18, cylinders: 6, horsepower: 78 }, + { name: 'pontiac ventura sj', milesPerGallon: 18.5, cylinders: 6, horsepower: 110 }, + { name: 'amc pacer d/l', milesPerGallon: 17.5, cylinders: 6, horsepower: 95 }, + { name: 'volkswagen rabbit', milesPerGallon: 29.5, cylinders: 4, horsepower: 71 }, + { name: 'datsun b-210', milesPerGallon: 32, cylinders: 4, horsepower: 70 }, + { name: 'toyota corolla', milesPerGallon: 28, cylinders: 4, horsepower: 75 }, + { name: 'ford pinto', milesPerGallon: 26.5, cylinders: 4, horsepower: 72 }, + { name: 'volvo 245', milesPerGallon: 20, cylinders: 4, horsepower: 102 }, + { name: 'plymouth volare premier v8', milesPerGallon: 13, cylinders: 8, horsepower: 150 }, + { name: 'peugeot 504', milesPerGallon: 19, cylinders: 4, horsepower: 88 }, + { name: 'toyota mark ii', milesPerGallon: 19, cylinders: 6, horsepower: 108 }, + { name: 'mercedes-benz 280s', milesPerGallon: 16.5, cylinders: 6, horsepower: 120 }, + { name: 'cadillac seville', milesPerGallon: 16.5, cylinders: 8, horsepower: 180 }, + { name: 'chevy c10', milesPerGallon: 13, cylinders: 8, horsepower: 145 }, + { name: 'ford f108', milesPerGallon: 13, cylinders: 8, horsepower: 130 }, + { name: 'dodge d100', milesPerGallon: 13, cylinders: 8, horsepower: 150 }, + { name: 'honda Accelerationord cvcc', milesPerGallon: 31.5, cylinders: 4, horsepower: 68 }, + { name: 'buick opel isuzu deluxe', milesPerGallon: 30, cylinders: 4, horsepower: 80 }, + { name: 'renault 5 gtl', milesPerGallon: 36, cylinders: 4, horsepower: 58 }, + { name: 'plymouth arrow gs', milesPerGallon: 25.5, cylinders: 4, horsepower: 96 }, + { name: 'datsun f-10 hatchback', milesPerGallon: 33.5, cylinders: 4, horsepower: 70 }, + { name: 'chevrolet caprice classic', milesPerGallon: 17.5, cylinders: 8, horsepower: 145 }, + { name: 'oldsmobile cutlass supreme', milesPerGallon: 17, cylinders: 8, horsepower: 110 }, + { name: 'dodge monaco brougham', milesPerGallon: 15.5, cylinders: 8, horsepower: 145 }, + { name: 'mercury cougar brougham', milesPerGallon: 15, cylinders: 8, horsepower: 130 }, + { name: 'chevrolet concours', milesPerGallon: 17.5, cylinders: 6, horsepower: 110 }, + { name: 'buick skylark', milesPerGallon: 20.5, cylinders: 6, horsepower: 105 }, + { name: 'plymouth volare custom', milesPerGallon: 19, cylinders: 6, horsepower: 100 }, + { name: 'ford granada', milesPerGallon: 18.5, cylinders: 6, horsepower: 98 }, + { name: 'pontiac grand prix lj', milesPerGallon: 16, cylinders: 8, horsepower: 180 }, + { name: 'chevrolet monte carlo landau', milesPerGallon: 15.5, cylinders: 8, horsepower: 170 }, + { name: 'chrysler cordoba', milesPerGallon: 15.5, cylinders: 8, horsepower: 190 }, + { name: 'ford thunderbird', milesPerGallon: 16, cylinders: 8, horsepower: 149 }, + { name: 'volkswagen rabbit custom', milesPerGallon: 29, cylinders: 4, horsepower: 78 }, + { name: 'pontiac sunbird coupe', milesPerGallon: 24.5, cylinders: 4, horsepower: 88 }, + { name: 'toyota corolla liftback', milesPerGallon: 26, cylinders: 4, horsepower: 75 }, + { name: 'ford mustang ii 2+2', milesPerGallon: 25.5, cylinders: 4, horsepower: 89 }, + { name: 'chevrolet chevette', milesPerGallon: 30.5, cylinders: 4, horsepower: 63 }, + { name: 'dodge colt m/m', milesPerGallon: 33.5, cylinders: 4, horsepower: 83 }, + { name: 'subaru dl', milesPerGallon: 30, cylinders: 4, horsepower: 67 }, + { name: 'volkswagen dasher', milesPerGallon: 30.5, cylinders: 4, horsepower: 78 }, + { name: 'datsun 810', milesPerGallon: 22, cylinders: 6, horsepower: 97 }, + { name: 'bmw 320i', milesPerGallon: 21.5, cylinders: 4, horsepower: 110 }, + { name: 'mazda rx-4', milesPerGallon: 21.5, cylinders: 3, horsepower: 110 }, + { name: 'volkswagen rabbit custom diesel', milesPerGallon: 43.1, cylinders: 4, horsepower: 48 }, + { name: 'ford fiesta', milesPerGallon: 36.1, cylinders: 4, horsepower: 66 }, + { name: 'mazda glc deluxe', milesPerGallon: 32.8, cylinders: 4, horsepower: 52 }, + { name: 'datsun b210 gx', milesPerGallon: 39.4, cylinders: 4, horsepower: 70 }, + { name: 'honda civic cvcc', milesPerGallon: 36.1, cylinders: 4, horsepower: 60 }, + { name: 'oldsmobile cutlass salon brougham', milesPerGallon: 19.9, cylinders: 8, horsepower: 110 }, + { name: 'dodge diplomat', milesPerGallon: 19.4, cylinders: 8, horsepower: 140 }, + { name: 'mercury monarch ghia', milesPerGallon: 20.2, cylinders: 8, horsepower: 139 }, + { name: 'pontiac phoenix lj', milesPerGallon: 19.2, cylinders: 6, horsepower: 105 }, + { name: 'chevrolet malibu', milesPerGallon: 20.5, cylinders: 6, horsepower: 95 }, + { name: 'ford fairmont (auto)', milesPerGallon: 20.2, cylinders: 6, horsepower: 85 }, + { name: 'ford fairmont (man)', milesPerGallon: 25.1, cylinders: 4, horsepower: 88 }, + { name: 'plymouth volare', milesPerGallon: 20.5, cylinders: 6, horsepower: 100 }, + { name: 'amc concord', milesPerGallon: 19.4, cylinders: 6, horsepower: 90 }, + { name: 'buick century special', milesPerGallon: 20.6, cylinders: 6, horsepower: 105 }, + { name: 'mercury zephyr', milesPerGallon: 20.8, cylinders: 6, horsepower: 85 }, + { name: 'dodge aspen', milesPerGallon: 18.6, cylinders: 6, horsepower: 110 }, + { name: 'amc concord d/l', milesPerGallon: 18.1, cylinders: 6, horsepower: 120 }, + { name: 'chevrolet monte carlo landau', milesPerGallon: 19.2, cylinders: 8, horsepower: 145 }, + { name: 'buick regal sport coupe (turbo)', milesPerGallon: 17.7, cylinders: 6, horsepower: 165 }, + { name: 'ford futura', milesPerGallon: 18.1, cylinders: 8, horsepower: 139 }, + { name: 'dodge magnum xe', milesPerGallon: 17.5, cylinders: 8, horsepower: 140 }, + { name: 'chevrolet chevette', milesPerGallon: 30, cylinders: 4, horsepower: 68 }, + { name: 'toyota corona', milesPerGallon: 27.5, cylinders: 4, horsepower: 95 }, + { name: 'datsun 510', milesPerGallon: 27.2, cylinders: 4, horsepower: 97 }, + { name: 'dodge omni', milesPerGallon: 30.9, cylinders: 4, horsepower: 75 }, + { name: 'toyota celica gt liftback', milesPerGallon: 21.1, cylinders: 4, horsepower: 95 }, + { name: 'plymouth sapporo', milesPerGallon: 23.2, cylinders: 4, horsepower: 105 }, + { name: 'oldsmobile starfire sx', milesPerGallon: 23.8, cylinders: 4, horsepower: 85 }, + { name: 'datsun 200-sx', milesPerGallon: 23.9, cylinders: 4, horsepower: 97 }, + { name: 'audi 5000', milesPerGallon: 20.3, cylinders: 5, horsepower: 103 }, + { name: 'volvo 264gl', milesPerGallon: 17, cylinders: 6, horsepower: 125 }, + { name: 'saab 99gle', milesPerGallon: 21.6, cylinders: 4, horsepower: 115 }, + { name: 'peugeot 604sl', milesPerGallon: 16.2, cylinders: 6, horsepower: 133 }, + { name: 'volkswagen scirocco', milesPerGallon: 31.5, cylinders: 4, horsepower: 71 }, + { name: 'honda Accelerationord lx', milesPerGallon: 29.5, cylinders: 4, horsepower: 68 }, + { name: 'pontiac lemans v6', milesPerGallon: 21.5, cylinders: 6, horsepower: 115 }, + { name: 'mercury zephyr 6', milesPerGallon: 19.8, cylinders: 6, horsepower: 85 }, + { name: 'ford fairmont 4', milesPerGallon: 22.3, cylinders: 4, horsepower: 88 }, + { name: 'amc concord dl 6', milesPerGallon: 20.2, cylinders: 6, horsepower: 90 }, + { name: 'dodge aspen 6', milesPerGallon: 20.6, cylinders: 6, horsepower: 110 }, + { name: 'chevrolet caprice classic', milesPerGallon: 17, cylinders: 8, horsepower: 130 }, + { name: 'ford ltd landau', milesPerGallon: 17.6, cylinders: 8, horsepower: 129 }, + { name: 'mercury grand marquis', milesPerGallon: 16.5, cylinders: 8, horsepower: 138 }, + { name: 'dodge st. regis', milesPerGallon: 18.2, cylinders: 8, horsepower: 135 }, + { name: 'buick estate wagon (sw)', milesPerGallon: 16.9, cylinders: 8, horsepower: 155 }, + { name: 'ford country squire (sw)', milesPerGallon: 15.5, cylinders: 8, horsepower: 142 }, + { name: 'chevrolet malibu classic (sw)', milesPerGallon: 19.2, cylinders: 8, horsepower: 125 }, + { name: 'chrysler lebaron town @ country (sw)', milesPerGallon: 18.5, cylinders: 8, horsepower: 150 }, + { name: 'vw rabbit custom', milesPerGallon: 31.9, cylinders: 4, horsepower: 71 }, + { name: 'maxda glc deluxe', milesPerGallon: 34.1, cylinders: 4, horsepower: 65 }, + { name: 'dodge colt hatchback custom', milesPerGallon: 35.7, cylinders: 4, horsepower: 80 }, + { name: 'amc spirit dl', milesPerGallon: 27.4, cylinders: 4, horsepower: 80 }, + { name: 'mercedes benz 300d', milesPerGallon: 25.4, cylinders: 5, horsepower: 77 }, + { name: 'cadillac eldorado', milesPerGallon: 23, cylinders: 8, horsepower: 125 }, + { name: 'peugeot 504', milesPerGallon: 27.2, cylinders: 4, horsepower: 71 }, + { name: 'oldsmobile cutlass salon brougham', milesPerGallon: 23.9, cylinders: 8, horsepower: 90 }, + { name: 'plymouth horizon', milesPerGallon: 34.2, cylinders: 4, horsepower: 70 }, + { name: 'plymouth horizon tc3', milesPerGallon: 34.5, cylinders: 4, horsepower: 70 }, + { name: 'datsun 210', milesPerGallon: 31.8, cylinders: 4, horsepower: 65 }, + { name: 'fiat strada custom', milesPerGallon: 37.3, cylinders: 4, horsepower: 69 }, + { name: 'buick skylark limited', milesPerGallon: 28.4, cylinders: 4, horsepower: 90 }, + { name: 'chevrolet citation', milesPerGallon: 28.8, cylinders: 6, horsepower: 115 }, + { name: 'oldsmobile omega brougham', milesPerGallon: 26.8, cylinders: 6, horsepower: 115 }, + { name: 'pontiac phoenix', milesPerGallon: 33.5, cylinders: 4, horsepower: 90 }, + { name: 'vw rabbit', milesPerGallon: 41.5, cylinders: 4, horsepower: 76 }, + { name: 'toyota corolla tercel', milesPerGallon: 38.1, cylinders: 4, horsepower: 60 }, + { name: 'chevrolet chevette', milesPerGallon: 32.1, cylinders: 4, horsepower: 70 }, + { name: 'datsun 310', milesPerGallon: 37.2, cylinders: 4, horsepower: 65 }, + { name: 'chevrolet citation', milesPerGallon: 28, cylinders: 4, horsepower: 90 }, + { name: 'ford fairmont', milesPerGallon: 26.4, cylinders: 4, horsepower: 88 }, + { name: 'amc concord', milesPerGallon: 24.3, cylinders: 4, horsepower: 90 }, + { name: 'dodge aspen', milesPerGallon: 19.1, cylinders: 6, horsepower: 90 }, + { name: 'audi 4000', milesPerGallon: 34.3, cylinders: 4, horsepower: 78 }, + { name: 'toyota corona liftback', milesPerGallon: 29.8, cylinders: 4, horsepower: 90 }, + { name: 'mazda 626', milesPerGallon: 31.3, cylinders: 4, horsepower: 75 }, + { name: 'datsun 510 hatchback', milesPerGallon: 37, cylinders: 4, horsepower: 92 }, + { name: 'toyota corolla', milesPerGallon: 32.2, cylinders: 4, horsepower: 75 }, + { name: 'mazda glc', milesPerGallon: 46.6, cylinders: 4, horsepower: 65 }, + { name: 'dodge colt', milesPerGallon: 27.9, cylinders: 4, horsepower: 105 }, + { name: 'datsun 210', milesPerGallon: 40.8, cylinders: 4, horsepower: 65 }, + { name: 'vw rabbit c (diesel)', milesPerGallon: 44.3, cylinders: 4, horsepower: 48 }, + { name: 'vw dasher (diesel)', milesPerGallon: 43.4, cylinders: 4, horsepower: 48 }, + { name: 'audi 5000s (diesel)', milesPerGallon: 36.4, cylinders: 5, horsepower: 67 }, + { name: 'mercedes-benz 240d', milesPerGallon: 30, cylinders: 4, horsepower: 67 }, + { name: 'honda civic 1500 gl', milesPerGallon: 44.6, cylinders: 4, horsepower: 67 }, + { name: 'renault lecar deluxe', milesPerGallon: 40.9, cylinders: 4, horsepower: 0 }, + { name: 'subaru dl', milesPerGallon: 33.8, cylinders: 4, horsepower: 67 }, + { name: 'vokswagen rabbit', milesPerGallon: 29.8, cylinders: 4, horsepower: 62 }, + { name: 'datsun 280-zx', milesPerGallon: 32.7, cylinders: 6, horsepower: 132 }, + { name: 'mazda rx-7 gs', milesPerGallon: 23.7, cylinders: 3, horsepower: 100 }, + { name: 'triumph tr7 coupe', milesPerGallon: 35, cylinders: 4, horsepower: 88 }, + { name: 'ford mustang cobra', milesPerGallon: 23.6, cylinders: 4, horsepower: 0 }, + { name: 'honda Accelerationord', milesPerGallon: 32.4, cylinders: 4, horsepower: 72 }, + { name: 'plymouth reliant', milesPerGallon: 27.2, cylinders: 4, horsepower: 84 }, + { name: 'buick skylark', milesPerGallon: 26.6, cylinders: 4, horsepower: 84 }, + { name: 'dodge aries wagon (sw)', milesPerGallon: 25.8, cylinders: 4, horsepower: 92 }, + { name: 'chevrolet citation', milesPerGallon: 23.5, cylinders: 6, horsepower: 110 }, + { name: 'plymouth reliant', milesPerGallon: 30, cylinders: 4, horsepower: 84 }, + { name: 'toyota starlet', milesPerGallon: 39.1, cylinders: 4, horsepower: 58 }, + { name: 'plymouth champ', milesPerGallon: 39, cylinders: 4, horsepower: 64 }, + { name: 'honda civic 1300', milesPerGallon: 35.1, cylinders: 4, horsepower: 60 }, + { name: 'subaru', milesPerGallon: 32.3, cylinders: 4, horsepower: 67 }, + { name: 'datsun 210', milesPerGallon: 37, cylinders: 4, horsepower: 65 }, + { name: 'toyota tercel', milesPerGallon: 37.7, cylinders: 4, horsepower: 62 }, + { name: 'mazda glc 4', milesPerGallon: 34.1, cylinders: 4, horsepower: 68 }, + { name: 'plymouth horizon 4', milesPerGallon: 34.7, cylinders: 4, horsepower: 63 }, + { name: 'ford escort 4w', milesPerGallon: 34.4, cylinders: 4, horsepower: 65 }, + { name: 'ford escort 2h', milesPerGallon: 29.9, cylinders: 4, horsepower: 65 }, + { name: 'volkswagen jetta', milesPerGallon: 33, cylinders: 4, horsepower: 74 }, + { name: 'renault 18i', milesPerGallon: 34.5, cylinders: 4, horsepower: 0 }, + { name: 'honda prelude', milesPerGallon: 33.7, cylinders: 4, horsepower: 75 }, + { name: 'toyota corolla', milesPerGallon: 32.4, cylinders: 4, horsepower: 75 }, + { name: 'datsun 200sx', milesPerGallon: 32.9, cylinders: 4, horsepower: 100 }, + { name: 'mazda 626', milesPerGallon: 31.6, cylinders: 4, horsepower: 74 }, + { name: 'peugeot 505s turbo diesel', milesPerGallon: 28.1, cylinders: 4, horsepower: 80 }, + { name: 'saab 900s', milesPerGallon: 0, cylinders: 4, horsepower: 110 }, + { name: 'volvo diesel', milesPerGallon: 30.7, cylinders: 6, horsepower: 76 }, + { name: 'toyota cressida', milesPerGallon: 25.4, cylinders: 6, horsepower: 116 }, + { name: 'datsun 810 maxima', milesPerGallon: 24.2, cylinders: 6, horsepower: 120 }, + { name: 'buick century', milesPerGallon: 22.4, cylinders: 6, horsepower: 110 }, + { name: 'oldsmobile cutlass ls', milesPerGallon: 26.6, cylinders: 8, horsepower: 105 }, + { name: 'ford granada gl', milesPerGallon: 20.2, cylinders: 6, horsepower: 88 }, + { name: 'chrysler lebaron salon', milesPerGallon: 17.6, cylinders: 6, horsepower: 85 }, + { name: 'chevrolet cavalier', milesPerGallon: 28, cylinders: 4, horsepower: 88 }, + { name: 'chevrolet cavalier wagon', milesPerGallon: 27, cylinders: 4, horsepower: 88 }, + { name: 'chevrolet cavalier 2-door', milesPerGallon: 34, cylinders: 4, horsepower: 88 }, + { name: 'pontiac j2000 se hatchback', milesPerGallon: 31, cylinders: 4, horsepower: 85 }, + { name: 'dodge aries se', milesPerGallon: 29, cylinders: 4, horsepower: 84 }, + { name: 'pontiac phoenix', milesPerGallon: 27, cylinders: 4, horsepower: 90 }, + { name: 'ford fairmont futura', milesPerGallon: 24, cylinders: 4, horsepower: 92 }, + { name: 'amc concord dl', milesPerGallon: 23, cylinders: 4, horsepower: 0 }, + { name: 'volkswagen rabbit l', milesPerGallon: 36, cylinders: 4, horsepower: 74 }, + { name: 'mazda glc custom l', milesPerGallon: 37, cylinders: 4, horsepower: 68 }, + { name: 'mazda glc custom', milesPerGallon: 31, cylinders: 4, horsepower: 68 }, + { name: 'plymouth horizon miser', milesPerGallon: 38, cylinders: 4, horsepower: 63 }, + { name: 'mercury lynx l', milesPerGallon: 36, cylinders: 4, horsepower: 70 }, + { name: 'nissan stanza xe', milesPerGallon: 36, cylinders: 4, horsepower: 88 }, + { name: 'honda Accelerationord', milesPerGallon: 36, cylinders: 4, horsepower: 75 }, + { name: 'toyota corolla', milesPerGallon: 34, cylinders: 4, horsepower: 70 }, + { name: 'honda civic', milesPerGallon: 38, cylinders: 4, horsepower: 67 }, + { name: 'honda civic (auto)', milesPerGallon: 32, cylinders: 4, horsepower: 67 }, + { name: 'datsun 310 gx', milesPerGallon: 38, cylinders: 4, horsepower: 67 }, + { name: 'buick century limited', milesPerGallon: 25, cylinders: 6, horsepower: 110 }, + { name: 'oldsmobile cutlass ciera (diesel)', milesPerGallon: 38, cylinders: 6, horsepower: 85 }, + { name: 'chrysler lebaron medallion', milesPerGallon: 26, cylinders: 4, horsepower: 92 }, + { name: 'ford granada l', milesPerGallon: 22, cylinders: 6, horsepower: 112 }, + { name: 'toyota celica gt', milesPerGallon: 32, cylinders: 4, horsepower: 96 }, + { name: 'dodge charger 2.2', milesPerGallon: 36, cylinders: 4, horsepower: 84 }, + { name: 'chevrolet camaro', milesPerGallon: 27, cylinders: 4, horsepower: 90 }, + { name: 'ford mustang gl', milesPerGallon: 27, cylinders: 4, horsepower: 86 }, + { name: 'vw pickup', milesPerGallon: 44, cylinders: 4, horsepower: 52 }, + { name: 'dodge rampage', milesPerGallon: 32, cylinders: 4, horsepower: 84 }, + { name: 'ford ranger', milesPerGallon: 28, cylinders: 4, horsepower: 79 }, + { name: 'chevy s-10', milesPerGallon: 31, cylinders: 4, horsepower: 82 } +]; + +// 图表配置 +const spec = { + type: 'common', + series: [ + { + type: 'scatter', + xField: 'milesPerGallon', + yField: 'horsepower', + point: { + state: { + hover: { + scaleX: 1.2, + scaleY: 1.2 + } + }, + style: { + fillOpacity: 0.25 + } + } + } + ], + tooltip: { + dimension: { + visible: true + }, + mark: { + title: true, + content: [ + { + key: d => d.name, + value: d => d.y + } + ] + } + }, + crosshair: { + yField: { + visible: true, + line: { + visible: true, + type: 'line' + }, + label: { + visible: true // label 默认关闭 + } + }, + xField: { + visible: true, + line: { + visible: true, + type: 'line' + }, + label: { + visible: true // label 默认关闭 + } + } + }, + axes: [ + { + title: { + visible: true, + text: 'Horse Power' + }, + orient: 'left', + range: { min: 0 }, + type: 'linear' + }, + { + title: { + visible: true, + text: 'Miles Per Gallon' + }, + orient: 'bottom', + label: { visible: true }, + type: 'linear' + } + ], + data: [ + { + id: 'data', + values: data.flat() + } + ] +}; + +const run = () => { + registerRegressionLine(); + appendScatterRegressionLineConfig(spec, [ + { + type: 'lowess', + polynomialDegree: 3, + line: { + style: { + stroke: 'red', + lineWidth: 2 + } + }, + confidenceInterval: { + style: { + fill: 'red', + fillOpacity: 0.2 + } + }, + label: { + text: 'lowess' + } + }, + { + type: 'linear', + polynomialDegree: 3, + line: { + style: { + stroke: 'green', + lineWidth: 2 + } + }, + confidenceInterval: { + style: { + fill: 'green', + fillOpacity: 0.2 + } + }, + label: { + text: '线性回归' + } + } + ]); + + const cs = new VChart(spec, { + dom: document.getElementById('chart') as HTMLElement, + //theme: 'dark', + onError: err => { + console.error(err); + } + }); + + cs.renderSync(); + + window['vchart'] = cs; +}; +run(); diff --git a/packages/vchart-extension/package.json b/packages/vchart-extension/package.json index 1a91e233b6..a7430fdb22 100644 --- a/packages/vchart-extension/package.json +++ b/packages/vchart-extension/package.json @@ -25,10 +25,10 @@ "@visactor/vrender-kits": "~1.0.18", "@visactor/vrender-components": "~1.0.18", "@visactor/vrender-animate": "~1.0.18", - "@visactor/vutils": "~1.0.6", - "@visactor/vdataset": "~1.0.6", - "@visactor/vlayouts": "~1.0.6", - "@visactor/vchart": "workspace:2.0.6" + "@visactor/vchart": "workspace:2.0.6", + "@visactor/vutils": "~1.0.11", + "@visactor/vdataset": "~1.0.11", + "@visactor/vlayouts": "~1.0.11" }, "devDependencies": { "@internal/bundler": "workspace:*", @@ -61,4 +61,4 @@ "registry": "https://registry.npmjs.org/" }, "license": "MIT" -} +} \ No newline at end of file diff --git a/packages/vchart-extension/src/components/bar-regression-line/index.ts b/packages/vchart-extension/src/components/bar-regression-line/index.ts new file mode 100644 index 0000000000..fb9ecc4d5e --- /dev/null +++ b/packages/vchart-extension/src/components/bar-regression-line/index.ts @@ -0,0 +1,108 @@ +/** + * @description vchart 自定义组件,用于实现柱图、线图以及面积图的系列标签 + * @author zhangweixing + */ +import { array, get, regressionPolynomial } from '@visactor/vutils'; +import type { Datum, ICartesianSeries, ISpec } from '@visactor/vchart'; +import { Direction, SeriesTypeEnum } from '@visactor/vchart'; +import type { BarRegressionLineSpec } from './type'; +import type { RegressionLineData } from '../regression-line/type'; +import { REGRESSION_LINE } from '../regression-line/regression-line'; + +/** + * 获取系列标签的 spec 配置 + * @param position 显示位置 + * @param config 系列标签的样式配置 + * @returns + */ +export function getBarRegressionLineConfig(config: Omit) { + const { color, line, confidenceInterval, label } = config; + return { + type: 'component', + componentType: REGRESSION_LINE, + interactive: false, + zIndex: 500, // 高于柱子 + style: { + data: (datum: any, ctx: any) => { + const vchart = ctx.vchart; + const chart = vchart.getChart(); + const series = chart.getAllSeries().filter((s: any) => s.type === SeriesTypeEnum.bar) as ICartesianSeries[]; + const regressionData: RegressionLineData[] = []; + + // 必须存在散点图系列 + if (series && series.length) { + series.forEach(s => { + const region = s.getRegion().getLayoutStartPoint(); + + const data = s.getViewData().latestData; + const fieldX = s.fieldX?.[0]; + const fieldY = s.fieldY?.[0]; + const isHorizontal = s.direction === Direction.horizontal; + const groups = s.getRawDataStatisticsByField(fieldX).values; + + if (isHorizontal || !fieldX || !fieldY || !data || data.length <= 2 || groups.length <= 2) { + return; + } + const { evaluateGrid, confidenceInterval } = regressionPolynomial( + data, + (datum: Datum) => groups.indexOf(datum?.[fieldX]), + (datum: Datum) => datum?.[fieldY], + { degree: config.degree } + ); + const N = groups.length; + const lineData = evaluateGrid(N); + const confidenceData = confidenceInterval(N); + const halfBandWidth = s.getXAxisHelper().getBandwidth(0) / 2; + + regressionData.push({ + line: lineData.map((ld: Datum) => { + const d = { [fieldX]: groups[ld.x], [fieldY]: ld.y }; + return { + x: s.dataToPositionX(d) + region.x + halfBandWidth, + y: s.dataToPositionY(d) + region.y + }; + }), + area: confidenceData.map((c: Datum) => { + const d = { [fieldX]: groups[c.x], [fieldY]: c.lower }; + return { + x: s.dataToPositionX(d) + region.x + halfBandWidth, + y: s.dataToPositionY(d) + region.y, + y1: s.dataToPositionY({ [fieldY]: c.upper }) + region.y + }; + }) + }); + }); + } + + return regressionData; + }, + color, + line, + confidenceInterval, + label + } + }; +} + +export function appendBarRegressionLineConfig(chartSpec: ISpec, spec?: BarRegressionLineSpec) { + if (!spec) { + spec = + get(chartSpec, REGRESSION_LINE) ?? + get( + chartSpec.series?.find(s => s.type === SeriesTypeEnum.bar), + REGRESSION_LINE + ); + } + const specs = array(spec); + + specs.forEach((s: BarRegressionLineSpec) => { + if (s.visible !== false) { + if (!(chartSpec as any).customMark) { + (chartSpec as any).customMark = []; + } + + const { visible, ...rest } = s; + (chartSpec as any).customMark.push(getBarRegressionLineConfig(rest)); + } + }); +} diff --git a/packages/vchart-extension/src/components/bar-regression-line/type.ts b/packages/vchart-extension/src/components/bar-regression-line/type.ts new file mode 100644 index 0000000000..0e33085d64 --- /dev/null +++ b/packages/vchart-extension/src/components/bar-regression-line/type.ts @@ -0,0 +1,13 @@ +import type { RegressionLineAttrs } from '../regression-line/type'; + +export interface BarRegressionLineAttrs extends RegressionLineAttrs { + /** + * 多项式回归的阶数,仅当 type 为 polynomial 时有效 + */ + degree?: number; +} + +export interface BarRegressionLineSpec + extends Partial> { + visible?: boolean; +} diff --git a/packages/vchart-extension/src/components/histogram-regression-line/index.ts b/packages/vchart-extension/src/components/histogram-regression-line/index.ts new file mode 100644 index 0000000000..310f2a08b7 --- /dev/null +++ b/packages/vchart-extension/src/components/histogram-regression-line/index.ts @@ -0,0 +1,130 @@ +/** + * @description vchart 自定义组件,用于实现柱图、线图以及面积图的系列标签 + * @author zhangweixing + */ + +import { array, get, kde, ecdf, last } from '@visactor/vutils'; +import type { Datum, ICartesianSeries, ISpec } from '@visactor/vchart'; +import { SeriesTypeEnum } from '@visactor/vchart'; +import type { HistogramRegressionLineSpec } from './type'; +import type { RegressionLineData } from '../regression-line/type'; +import { REGRESSION_LINE } from '../regression-line/regression-line'; + +const getRegressionByType = (type: 'kde' | 'ecdf', data: number[], kdeOptions?: any) => { + switch (type) { + case 'kde': + return kde(data, kdeOptions); + case 'ecdf': + return ecdf(data); + } +}; + +/** + * 获取系列标签的 spec 配置 + * @param position 显示位置 + * @param config 系列标签的样式配置 + * @returns + */ +export function getHistogramRegressionLineConfig( + type: 'kde' | 'ecdf', + config: Omit +) { + const { line, label, color } = config; + return { + type: 'component', + componentType: REGRESSION_LINE, + interactive: false, + zIndex: 500, // 高于柱子 + style: { + data: (datum: any, ctx: any) => { + const vchart = ctx.vchart; + const chart = vchart.getChart(); + const series = chart.getAllSeries().filter((s: any) => s.type === SeriesTypeEnum.bar) as ICartesianSeries[]; + const regressionData: RegressionLineData[] = []; + + // 必须存在散点图系列 + if (series && series.length) { + series.forEach(s => { + const region = s.getRegion().getLayoutStartPoint(); + + const rawData = (s as any)._rawData; + const data = rawData?.rawData; + const binTransformOptions = rawData.transformsArr?.find((t: any) => t.type === 'bin')?.options; + const fieldX = s.fieldX?.[0]; + const scaleY = s.getYAxisHelper().getScale(0); + const viewData = s.getViewData().latestData; + + if (!data || !data.length || !binTransformOptions?.field || !scaleY || !viewData || !viewData.length) { + return; + } + const simpleData = data.map((entry: Datum) => entry[binTransformOptions.field]); + const res = getRegressionByType( + type, + simpleData, + type === 'kde' + ? { + bandwidth: + viewData[0][binTransformOptions.outputNames?.x1 ?? 'x1'] - + viewData[0][binTransformOptions.outputNames?.x0 ?? 'x0'] + } + : null + ); + const N = Math.max(3, Math.floor(simpleData.length / 4)); + const lineData = res.evaluateGrid(N); + const yRange = scaleY.range(); + const y0 = yRange[0]; + const y1 = last(yRange); + const scaleR = + type === 'kde' + ? (k: number) => { + return scaleY.scale(k * data.length * res.bandwidth); + } + : (e: number) => { + return y0 + (y1 - y0) * e; + }; + + regressionData.push({ + line: lineData.map((ld: Datum) => { + const d = { [fieldX]: ld.x }; + return { + x: s.dataToPositionX(d) + region.x, + y: scaleR(ld.y) + region.y + }; + }) + }); + }); + } + + return regressionData; + }, + color, + line, + label + } + }; +} + +export function appendHistogramRegressionLineConfig( + chartSpec: ISpec, + spec?: HistogramRegressionLineSpec | HistogramRegressionLineSpec[] +) { + if (!spec) { + spec = + get(chartSpec, REGRESSION_LINE) ?? + get( + chartSpec.series?.find(s => s.type === SeriesTypeEnum.bar), + REGRESSION_LINE + ); + } + const specs = array(spec); + + specs.forEach((s: HistogramRegressionLineSpec) => { + if (s.visible !== false) { + if (!(chartSpec as any).customMark) { + (chartSpec as any).customMark = []; + } + const { type, ...rest } = s; + (chartSpec as any).customMark.push(getHistogramRegressionLineConfig(type, rest)); + } + }); +} diff --git a/packages/vchart-extension/src/components/histogram-regression-line/type.ts b/packages/vchart-extension/src/components/histogram-regression-line/type.ts new file mode 100644 index 0000000000..a885eee55f --- /dev/null +++ b/packages/vchart-extension/src/components/histogram-regression-line/type.ts @@ -0,0 +1,10 @@ +import type { RegressionLineAttrs } from '../regression-line/type'; + +export interface HistogramRegressionLineAttrs extends Omit { + type: 'kde' | 'ecdf'; +} + +export interface HistogramRegressionLineSpec + extends Partial> { + visible?: boolean; +} diff --git a/packages/vchart-extension/src/components/regression-line/index.ts b/packages/vchart-extension/src/components/regression-line/index.ts new file mode 100644 index 0000000000..64007f29d6 --- /dev/null +++ b/packages/vchart-extension/src/components/regression-line/index.ts @@ -0,0 +1,2 @@ +export * from './regression-line'; +export * from './type'; diff --git a/packages/vchart-extension/src/components/regression-line/regression-line.ts b/packages/vchart-extension/src/components/regression-line/regression-line.ts new file mode 100644 index 0000000000..ad7972f026 --- /dev/null +++ b/packages/vchart-extension/src/components/regression-line/regression-line.ts @@ -0,0 +1,69 @@ +import { AbstractComponent } from '@visactor/vrender-components'; +import { isEmpty, isValid, last } from '@visactor/vutils'; +import { Factory } from '@visactor/vchart'; +import { type IGraphic, createText, createLine, createArea } from '@visactor/vrender-core'; +import type { RegressionLineAttrs } from '../regression-line/type'; + +export const REGRESSION_LINE = 'regressionLine'; + +export class RegressionLine extends AbstractComponent> { + name = REGRESSION_LINE; + protected render() { + this.removeAllChild(); + const { + data, + line = {}, + label, + name = 'regression-line', + confidenceInterval, + color + } = this.attribute as RegressionLineAttrs; + if (isEmpty(data)) { + return; + } + + data.forEach(d => { + if (d.area && confidenceInterval?.visible !== false) { + const areaShape = createArea({ + points: d.area, + ...(isValid(color) ? { fill: color, fillOpacity: 0.12 } : null), + ...confidenceInterval?.style + }); + areaShape.name = 'scatter-regression-area'; + this.add(areaShape); + } + + if (d.line && line?.visible !== false) { + const lineShape = createLine({ + points: d.line, + lineWidth: 1, + ...(isValid(color) ? { stroke: color } : null), + ...line?.style + }); + lineShape.name = `${name}-curve`; + this.add(lineShape); + } + + const lastPoint = last(d.line); + + if (label && label.visible !== false && label.text && lastPoint) { + const tag = createText({ + ...lastPoint, + text: label.text, + textAlign: 'end', + textBaseline: 'middle', + ...label.style + }); + tag.name = `${name}-label`; + this.add(tag); + } + }); + } +} + +export const registerRegressionLine = () => { + Factory.registerGraphicComponent( + REGRESSION_LINE, + (attrs: Required) => new RegressionLine(attrs) as unknown as IGraphic + ); +}; diff --git a/packages/vchart-extension/src/components/regression-line/type.ts b/packages/vchart-extension/src/components/regression-line/type.ts new file mode 100644 index 0000000000..813e322161 --- /dev/null +++ b/packages/vchart-extension/src/components/regression-line/type.ts @@ -0,0 +1,62 @@ +import type { + IAreaGraphicAttribute, + IGroupGraphicAttribute, + ILineGraphicAttribute, + ITextGraphicAttribute +} from '@visactor/vrender-core'; + +export interface RegressionLineData { + line: { x: number; y: number }[]; + area?: { x: number; y: number; y1: number }[]; +} + +export interface RegressionLineAttrs extends IGroupGraphicAttribute { + /** + * 用于区分的名称 + */ + name?: string; + /** + * 颜色值 + */ + color?: string; + /** + * 回归线配置 + */ + line?: { + /** + * 是否显示系列标签 + * @default true + */ + visible?: boolean; + /** + * 线样式 + */ + style?: ILineGraphicAttribute; + }; + /** + * 回归线公式标签 + */ + label?: { + /** + * 是否显示标签 + */ + visible?: boolean; + /** + * 标签文本 + */ + text: string; + /** + * 标签样式 + */ + style?: ITextGraphicAttribute; + }; + /** + * 置信区间 + */ + confidenceInterval?: { + visible?: boolean; + style?: IAreaGraphicAttribute; + }; + + data: RegressionLineData[]; +} diff --git a/packages/vchart-extension/src/components/scatter-regression-line/index.ts b/packages/vchart-extension/src/components/scatter-regression-line/index.ts new file mode 100644 index 0000000000..016f09b26d --- /dev/null +++ b/packages/vchart-extension/src/components/scatter-regression-line/index.ts @@ -0,0 +1,141 @@ +/** + * @description vchart 自定义组件,用于实现柱图、线图以及面积图的系列标签 + * @author zhangweixing + */ + +import { AbstractComponent } from '@visactor/vrender-components'; +import { + array, + get, + isEmpty, + regressionLinear, + regressionLogistic, + regressionLowess, + regressionPolynomial +} from '@visactor/vutils'; +import type { Datum, ICartesianSeries, ISpec } from '@visactor/vchart'; +import { SeriesTypeEnum } from '@visactor/vchart'; +import type { ScatterRegressionLineSpec } from './type'; +import type { RegressionLineData } from '../regression-line/type'; +import { REGRESSION_LINE } from '../regression-line/regression-line'; + +const getRegressionByType = ( + type: 'linear' | 'logisitc' | 'lowess' | 'polynomial', + data: any[], + x: (d: any) => number = d => d.x, + y: (d: any) => number = d => d.y, + degree?: number +) => { + switch (type) { + case 'logisitc': + return regressionLogistic(data, x, y); + case 'lowess': + return regressionLowess(data, x, y); + case 'polynomial': + return regressionPolynomial(data, x, y, { degree }); + default: + return regressionLinear(data, x, y); + } +}; + +/** + * 获取系列标签的 spec 配置 + * @param position 显示位置 + * @param config 系列标签的样式配置 + * @returns + */ +export function getScatterRegressionLineConfig( + type: 'linear' | 'logisitc' | 'lowess' | 'polynomial', + config: Omit +) { + const { color, line, confidenceInterval, label } = config; + return { + type: 'component', + componentType: REGRESSION_LINE, + interactive: false, + style: { + data: (datum: any, ctx: any) => { + const vchart = ctx.vchart; + const chart = vchart.getChart(); + const series = chart.getAllSeries().filter((s: any) => s.type === SeriesTypeEnum.scatter) as ICartesianSeries[]; + const regressionData: RegressionLineData[] = []; + + // 必须存在散点图系列 + if (series && series.length) { + series.forEach(s => { + const region = s.getRegion().getLayoutStartPoint(); + + const data = s.getViewData().latestData; + const fieldX = s.fieldX?.[0]; + const fieldY = s.fieldY?.[0]; + + if (!fieldX || !fieldY || !data || data.length <= 2) { + return; + } + const { evaluateGrid, confidenceInterval } = getRegressionByType( + type, + data, + (datum: Datum) => datum?.[fieldX], + (datum: Datum) => datum?.[fieldY], + config.polynomialDegree + ); + const N = Math.min(3, Math.floor(data.length / 4)); + const lineData = evaluateGrid(N); + const confidenceData = confidenceInterval(N); + + regressionData.push({ + line: lineData.map((ld: Datum) => { + const d = { [fieldX]: ld.x, [fieldY]: ld.y }; + return { + x: s.dataToPositionX(d) + region.x, + y: s.dataToPositionY(d) + region.y + }; + }), + area: confidenceData.map((c: Datum) => { + const d = { [fieldX]: c.x, [fieldY]: c.lower }; + return { + x: s.dataToPositionX(d) + region.x, + y: s.dataToPositionY(d) + region.y, + y1: s.dataToPositionY({ [fieldY]: c.upper }) + region.y + }; + }) + }); + }); + } + + return regressionData; + }, + line, + confidenceInterval, + label, + color + } + }; +} + +export function appendScatterRegressionLineConfig( + chartSpec: ISpec, + spec?: ScatterRegressionLineSpec | ScatterRegressionLineSpec[] +) { + if (!spec) { + spec = + get(chartSpec, REGRESSION_LINE) ?? + get( + chartSpec.series?.find(s => s.type === SeriesTypeEnum.scatter), + REGRESSION_LINE + ); + } + + const specs = array(spec); + + specs.forEach((s: ScatterRegressionLineSpec) => { + if (s.visible !== false) { + if (!(chartSpec as any).customMark) { + (chartSpec as any).customMark = []; + } + + const { type, ...rest } = s; + (chartSpec as any).customMark.push(getScatterRegressionLineConfig(type, rest)); + } + }); +} diff --git a/packages/vchart-extension/src/components/scatter-regression-line/type.ts b/packages/vchart-extension/src/components/scatter-regression-line/type.ts new file mode 100644 index 0000000000..4bbeaeaf54 --- /dev/null +++ b/packages/vchart-extension/src/components/scatter-regression-line/type.ts @@ -0,0 +1,16 @@ +import type { RegressionLineAttrs } from '../regression-line/type'; + +export interface ScatterRegressionLineAttrs extends RegressionLineAttrs { + type: 'linear' | 'logisitc' | 'lowess' | 'polynomial'; + /** + * 多项式回归的阶数,仅当 type 为 polynomial 时有效 + */ + polynomialDegree?: number; +} + +export interface ScatterRegressionLineSpec + extends Partial< + Pick + > { + visible?: boolean; +} diff --git a/packages/vchart-extension/src/index.ts b/packages/vchart-extension/src/index.ts index 27617b4164..6db81fb8fe 100644 --- a/packages/vchart-extension/src/index.ts +++ b/packages/vchart-extension/src/index.ts @@ -22,3 +22,7 @@ export * from './components/series-break'; export * from './components/bar-link'; export * from './components/series-label'; export * from './components/map-label'; +export * from './components/regression-line'; +export * from './components/scatter-regression-line'; +export * from './components/bar-regression-line'; +export * from './components/histogram-regression-line'; diff --git a/packages/vchart/package.json b/packages/vchart/package.json index b0f479fcb1..ceebf9faa3 100644 --- a/packages/vchart/package.json +++ b/packages/vchart/package.json @@ -118,10 +118,10 @@ "cross-env": "^7.0.3" }, "dependencies": { - "@visactor/vutils": "~1.0.6", - "@visactor/vdataset": "~1.0.6", - "@visactor/vscale": "~1.0.6", - "@visactor/vlayouts": "~1.0.6", + "@visactor/vutils": "~1.0.11", + "@visactor/vdataset": "~1.0.11", + "@visactor/vscale": "~1.0.11", + "@visactor/vlayouts": "~1.0.11", "@visactor/vrender-core": "~1.0.18", "@visactor/vrender-kits": "~1.0.18", "@visactor/vrender-components": "~1.0.18", @@ -132,4 +132,4 @@ "access": "public", "registry": "https://registry.npmjs.org/" } -} +} \ No newline at end of file diff --git a/packages/vchart/src/chart/histogram/histogram.ts b/packages/vchart/src/chart/histogram/histogram.ts index e2f8bbe91e..7fa82d7e90 100644 --- a/packages/vchart/src/chart/histogram/histogram.ts +++ b/packages/vchart/src/chart/histogram/histogram.ts @@ -12,6 +12,7 @@ import { getCartesianCrosshairRect } from '../../component/crosshair/utils/carte import { registerDimensionTooltipProcessor } from '../../component/tooltip/processor/dimension-tooltip'; import { registerMarkTooltipProcessor } from '../../component/tooltip/processor/mark-tooltip'; import { registerGroupTooltipProcessor } from '../../component/tooltip/processor/group-tooltip'; +import { bin } from '@visactor/vdataset'; export class HistogramChart extends BaseHistogramChart { static readonly type: string = ChartTypeEnum.histogram; @@ -35,5 +36,6 @@ export const registerHistogramChart = () => { registerDimensionEvents(); registerDimensionHover(); registerBarSeries(); + Factory.registerTransform('bin', bin); Factory.registerChart(HistogramChart.type, HistogramChart); }; diff --git a/packages/vchart/src/series/index.ts b/packages/vchart/src/series/index.ts index 2be7d5ffb8..6832ac8366 100644 --- a/packages/vchart/src/series/index.ts +++ b/packages/vchart/src/series/index.ts @@ -71,7 +71,7 @@ import type { IMosaicSeriesSpec } from './mosaic/interface'; import { MosaicSeries, registerMosaicSeries } from './mosaic/mosaic'; import type { ISeries, ICartesianSeries, IPolarSeries, IGeoSeries } from './interface'; -import { barGrowIn, barGrowOut, barPresetAnimation } from './bar/animation'; +import { barGrowIn, barGrowOut, barPresetAnimation, registerBarAnimation } from './bar/animation'; import { BaseWordCloudSeries } from './word-cloud/base'; import { RangeColumnSeriesSpecTransformer } from './range-column/range-column-transformer'; import { pieDisappear, pieEnter, pieExit, piePresetAnimation } from './pie/animation/animation'; @@ -143,6 +143,7 @@ export { export { registerAreaSeries, registerBarSeries, + registerBarAnimation, registerBoxplotSeries, registerCirclePackingSeries, registerCircularProgressSeries, diff --git a/packages/vstory/package.json b/packages/vstory/package.json index d7dc0863d3..f7e0fa645c 100644 --- a/packages/vstory/package.json +++ b/packages/vstory/package.json @@ -24,7 +24,7 @@ "@visactor/vrender-core": "~1.0.18", "@visactor/vrender-kits": "~1.0.18", "@visactor/vrender-components": "~1.0.18", - "@visactor/vutils": "~1.0.6" + "@visactor/vutils": "~1.0.11" }, "devDependencies": { "@internal/bundler": "workspace:*", @@ -42,4 +42,4 @@ "vite": "3.2.6", "typescript": "4.9.5" } -} +} \ No newline at end of file diff --git a/packages/vutils-extension/package.json b/packages/vutils-extension/package.json index dcb57f39f8..bc03cc70f1 100644 --- a/packages/vutils-extension/package.json +++ b/packages/vutils-extension/package.json @@ -25,8 +25,8 @@ "test-watch": "DEBUG_MODE=1 jest --watch" }, "dependencies": { - "@visactor/vutils": "~1.0.6", - "@visactor/vdataset": "~1.0.6" + "@visactor/vutils": "~1.0.11", + "@visactor/vdataset": "~1.0.11" }, "devDependencies": { "@internal/bundler": "workspace:*", @@ -67,4 +67,4 @@ "url": "https://www.visactor.io/" }, "license": "MIT" -} +} \ No newline at end of file diff --git a/tools/story-player/package.json b/tools/story-player/package.json index 7a58dfdfaf..5d327db48b 100644 --- a/tools/story-player/package.json +++ b/tools/story-player/package.json @@ -60,6 +60,6 @@ "@visactor/vrender-kits": "~1.0.18", "@visactor/vchart": "workspace:2.0.6", "@visactor/vrender": "~1.0.18", - "@visactor/vutils": "~1.0.6" + "@visactor/vutils": "~1.0.11" } -} +} \ No newline at end of file