From 1b9c1999367930408db9a73ba21c934344677f21 Mon Sep 17 00:00:00 2001 From: Silviya Geo Date: Fri, 5 Aug 2022 09:53:45 +0200 Subject: [PATCH 01/22] Added the heatmap to the index of the echarts --- packages/echarts-demo/public/svg/heatmap.html | 26 +++++++++++++++++++ packages/echarts-demo/src/heatmap.js | 0 packages/echarts-demo/src/index.js | 17 +++++++----- packages/echarts/src/heatmap.ts | 0 4 files changed, 36 insertions(+), 7 deletions(-) create mode 100644 packages/echarts-demo/public/svg/heatmap.html create mode 100644 packages/echarts-demo/src/heatmap.js create mode 100644 packages/echarts/src/heatmap.ts diff --git a/packages/echarts-demo/public/svg/heatmap.html b/packages/echarts-demo/public/svg/heatmap.html new file mode 100644 index 00000000..54cd50a0 --- /dev/null +++ b/packages/echarts-demo/public/svg/heatmap.html @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + VisAhoi - ECharts - Heatmap + + +
+ + Show onboarding + +
+

VisAhoi Demo: ECharts - Heatmap

+
+ + + diff --git a/packages/echarts-demo/src/heatmap.js b/packages/echarts-demo/src/heatmap.js new file mode 100644 index 00000000..e69de29b diff --git a/packages/echarts-demo/src/index.js b/packages/echarts-demo/src/index.js index bb4cb131..e425017c 100644 --- a/packages/echarts-demo/src/index.js +++ b/packages/echarts-demo/src/index.js @@ -1,25 +1,28 @@ - const demos = [ { title: 'Bar Chart', - link: './svg/bar-chart.html' + link: './svg/bar-chart.html', }, { title: 'Change Matrix', - link: './svg/change-matrix.html' + link: './svg/change-matrix.html', }, { title: 'Horizon Graph', - link: './svg/horizon-graph.html' + link: './svg/horizon-graph.html', }, { title: 'Scatterplot', - link: './svg/scatterplot.html' + link: './svg/scatterplot.html', }, { title: 'Treemap', - link: './svg/treemap.html' - } + link: './svg/treemap.html', + }, + { + title: 'Heatmap', + link: './svg/heatmap.html', + }, // { // title: 'Bar Chart Canvas', // link: './canvas/bar-chart.html' diff --git a/packages/echarts/src/heatmap.ts b/packages/echarts/src/heatmap.ts new file mode 100644 index 00000000..e69de29b From 4bc6a219aeac214e6dd902ef96e8443e997f8270 Mon Sep 17 00:00:00 2001 From: Silviya Geo Date: Fri, 5 Aug 2022 11:47:52 +0200 Subject: [PATCH 02/22] Added data to heatmap --- packages/echarts-demo/src/heatmap.js | 148 +++++++++++++++++++++++ packages/echarts-demo/src/svg/heatmap.js | 2 + 2 files changed, 150 insertions(+) create mode 100644 packages/echarts-demo/src/svg/heatmap.js diff --git a/packages/echarts-demo/src/heatmap.js b/packages/echarts-demo/src/heatmap.js index e69de29b..d0e3344c 100644 --- a/packages/echarts-demo/src/heatmap.js +++ b/packages/echarts-demo/src/heatmap.js @@ -0,0 +1,148 @@ +import * as echarts from 'echarts'; +// import { +// generateBasicAnnotations, +// ahoi, +// EVisualizationType, +// } from '@visahoi/plotly'; +import debounce from 'lodash.debounce'; + +let chart = null; +let showOnboarding = false; +let onboardingUI = null; + +// const debouncedResize = debounce((event) => { +// onboardingUI?.updateOnboarding(getAhoiConfig()); +// }, 250); + +const render = () => { + chart = createPlot(); + window.addEventListener('resize', debouncedResize); +}; + +const createPlot = () => { + const day = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']; + const dayTime = ['Morning', 'Afternoon', 'Evening']; + const data = [ + { + z: [ + [0, 0, 1], + [0, 1, 0], + [0, 2, 30], + [0, 3, 50], + [0, 4, 1], + [1, 0, 20], + [1, 1, 1], + [1, 2, 60], + [1, 3, 80], + [1, 4, 30], + [2, 0, 30], + [2, 1, 60], + [2, 2, 1], + [2, 3, -10], + [2, 4, 20], + ].map(function (item) { + return [item[1], item[0], item[2] || '-']; + }), + }, + ]; + + const options = { + tooltip: { + position: 'top', + }, + grid: { + height: '50%', + top: '10%', + }, + xAxis: { + type: 'category', + data: dayTime, + splitArea: { + show: true, + }, + }, + yAxis: { + type: 'category', + data: day, + splitArea: { + show: true, + }, + }, + visualMap: { + min: 0, + max: 10, + calculable: true, + orient: 'horizontal', + left: 'center', + bottom: '15%', + }, + series: [ + { + name: 'Punch Card', + type: 'heatmap', + data: data, + label: { + show: true, + }, + emphasis: { + itemStyle: { + shadowBlur: 10, + shadowColor: 'rgba(0, 0, 0, 0.5)', + }, + }, + }, + ], + }; + + const config = { + responsive: true, + }; + + chart.setOption(options); + return chart; +}; + +// const getAhoiConfig = () => { +// const defaultOnboardingMessages = generateBasicAnnotations( +// EVisualizationType.HEATMAP, +// chart, +// ); +// const extendedOnboardingMessages = defaultOnboardingMessages.map((d) => ({ +// ...d, +// text: 'test123', +// })); +// const ahoiConfig = { +// onboardingMessages: defaultOnboardingMessages, +// }; +// return ahoiConfig; +// }; + +const registerEventListener = () => { + showOnboarding = !showOnboarding; + const helpIcon = document.getElementById('show-onboarding'); + if (!helpIcon) { + return; + } + helpIcon.addEventListener('click', async () => { + showOnboarding = !showOnboarding; + if (showOnboarding) { + onboardingUI = await ahoi( + EVisualizationType.HEATMAP, + chart, + getAhoiConfig(), + ); + } else { + onboardingUI?.removeOnboarding(); + } + }); +}; + +const createChart = (renderer = 'svg') => { + const vis = document.getElementById('vis'); + chart = echarts.init(vis, null, { renderer }); + window.addEventListener('resize', () => chart.resize()); + // registerEventListener(); + render(); +}; + +export default createChart; diff --git a/packages/echarts-demo/src/svg/heatmap.js b/packages/echarts-demo/src/svg/heatmap.js new file mode 100644 index 00000000..cfd978a2 --- /dev/null +++ b/packages/echarts-demo/src/svg/heatmap.js @@ -0,0 +1,2 @@ +import createChart from '../heatmap'; +createChart('svg'); From e7f89a45b6e3313c19da0ec7e36f30bd1886d22c Mon Sep 17 00:00:00 2001 From: Silviya Geo Date: Fri, 12 Aug 2022 09:28:12 +0200 Subject: [PATCH 03/22] Added heatmap to echarts and it shows the data --- packages/echarts-demo/src/heatmap.js | 87 ++++++++++------------------ 1 file changed, 32 insertions(+), 55 deletions(-) diff --git a/packages/echarts-demo/src/heatmap.js b/packages/echarts-demo/src/heatmap.js index d0e3344c..dbb5deac 100644 --- a/packages/echarts-demo/src/heatmap.js +++ b/packages/echarts-demo/src/heatmap.js @@ -10,9 +10,9 @@ let chart = null; let showOnboarding = false; let onboardingUI = null; -// const debouncedResize = debounce((event) => { -// onboardingUI?.updateOnboarding(getAhoiConfig()); -// }, 250); +const debouncedResize = debounce((event) => { + onboardingUI?.updateOnboarding(getAhoiConfig()); +}, 250); const render = () => { chart = createPlot(); @@ -23,47 +23,42 @@ const createPlot = () => { const day = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']; const dayTime = ['Morning', 'Afternoon', 'Evening']; const data = [ - { - z: [ - [0, 0, 1], - [0, 1, 0], - [0, 2, 30], - [0, 3, 50], - [0, 4, 1], - [1, 0, 20], - [1, 1, 1], - [1, 2, 60], - [1, 3, 80], - [1, 4, 30], - [2, 0, 30], - [2, 1, 60], - [2, 2, 1], - [2, 3, -10], - [2, 4, 20], - ].map(function (item) { - return [item[1], item[0], item[2] || '-']; - }), - }, - ]; - - const options = { + [0, 0, 1], + [0, 1, 0], + [0, 2, 30], + [0, 3, 50], + [0, 4, 1], + [1, 0, 20], + [1, 1, 1], + [1, 2, 60], + [1, 3, 80], + [1, 4, 30], + [2, 0, 30], + [2, 1, 60], + [2, 2, 1], + [2, 3, -10], + [2, 4, 20], + ].map(function (item) { + return [item[1], item[0], item[2] || '-']; + }); + const option = { tooltip: { - position: 'top', + position: 'right', }, grid: { - height: '50%', - top: '10%', + height: '70%', + top: '5%', }, xAxis: { type: 'category', - data: dayTime, + data: day, splitArea: { show: true, }, }, yAxis: { type: 'category', - data: day, + data: dayTime, splitArea: { show: true, }, @@ -72,9 +67,10 @@ const createPlot = () => { min: 0, max: 10, calculable: true, - orient: 'horizontal', - left: 'center', - bottom: '15%', + orient: 'vertical', + right: '3%', + bottom: '50%', + height: '80%', }, series: [ { @@ -94,29 +90,10 @@ const createPlot = () => { ], }; - const config = { - responsive: true, - }; - - chart.setOption(options); + chart.setOption(option); return chart; }; -// const getAhoiConfig = () => { -// const defaultOnboardingMessages = generateBasicAnnotations( -// EVisualizationType.HEATMAP, -// chart, -// ); -// const extendedOnboardingMessages = defaultOnboardingMessages.map((d) => ({ -// ...d, -// text: 'test123', -// })); -// const ahoiConfig = { -// onboardingMessages: defaultOnboardingMessages, -// }; -// return ahoiConfig; -// }; - const registerEventListener = () => { showOnboarding = !showOnboarding; const helpIcon = document.getElementById('show-onboarding'); From cc124b161e0c9a7a50a9b17b232cea4f2ca1e827 Mon Sep 17 00:00:00 2001 From: Silviya Geo Date: Fri, 12 Aug 2022 10:56:41 +0200 Subject: [PATCH 04/22] Changed the label and tooltip styles --- packages/echarts-demo/src/heatmap.js | 30 +++++-- packages/echarts-demo/src/treemap.js | 128 +++++++++++++++------------ 2 files changed, 93 insertions(+), 65 deletions(-) diff --git a/packages/echarts-demo/src/heatmap.js b/packages/echarts-demo/src/heatmap.js index dbb5deac..f3430d37 100644 --- a/packages/echarts-demo/src/heatmap.js +++ b/packages/echarts-demo/src/heatmap.js @@ -42,27 +42,43 @@ const createPlot = () => { return [item[1], item[0], item[2] || '-']; }); const option = { + title: { + text: 'Average temperature in a week', + left: 'center', + }, tooltip: { position: 'right', }, grid: { height: '70%', - top: '5%', + top: '10%', }, xAxis: { + name: 'Weekday', type: 'category', data: day, splitArea: { show: true, }, + nameLocation: 'middle', + nameGap: 35, }, yAxis: { + name: 'Average temperature per day', type: 'category', data: dayTime, splitArea: { show: true, }, + nameLocation: 'middle', + nameGap: 75, + axisName: { + fontWeight: 'bold', + }, }, + // labelLayout: { + // fontSize: '30px', + // }, visualMap: { min: 0, max: 10, @@ -72,9 +88,9 @@ const createPlot = () => { bottom: '50%', height: '80%', }, + itemStyle: {}, series: [ { - name: 'Punch Card', type: 'heatmap', data: data, label: { @@ -82,8 +98,9 @@ const createPlot = () => { }, emphasis: { itemStyle: { - shadowBlur: 10, - shadowColor: 'rgba(0, 0, 0, 0.5)', + fontWeight: 'bold', + // shadowBlur: 10, + // shadowColor: 'rgba(0, 0, 0, 0.5)', }, }, }, @@ -95,7 +112,6 @@ const createPlot = () => { }; const registerEventListener = () => { - showOnboarding = !showOnboarding; const helpIcon = document.getElementById('show-onboarding'); if (!helpIcon) { return; @@ -104,7 +120,7 @@ const registerEventListener = () => { showOnboarding = !showOnboarding; if (showOnboarding) { onboardingUI = await ahoi( - EVisualizationType.HEATMAP, + EVisualizationType.TREEMAP, chart, getAhoiConfig(), ); @@ -118,7 +134,7 @@ const createChart = (renderer = 'svg') => { const vis = document.getElementById('vis'); chart = echarts.init(vis, null, { renderer }); window.addEventListener('resize', () => chart.resize()); - // registerEventListener(); + registerEventListener(); render(); }; diff --git a/packages/echarts-demo/src/treemap.js b/packages/echarts-demo/src/treemap.js index 97ec77f9..a90fc2fc 100644 --- a/packages/echarts-demo/src/treemap.js +++ b/packages/echarts-demo/src/treemap.js @@ -1,37 +1,43 @@ import * as echarts from 'echarts'; -import debounce from "lodash.debounce"; -import { generateBasicAnnotations, ahoi, EVisualizationType } from '@visahoi/echarts'; +import debounce from 'lodash.debounce'; +import { + generateBasicAnnotations, + ahoi, + EVisualizationType, +} from '@visahoi/echarts'; let chart = null; let showOnboarding = false; let onboardingUI = null; const debouncedResize = debounce((event) => { - onboardingUI?.updateOnboarding(getAhoiConfig()) + onboardingUI?.updateOnboarding(getAhoiConfig()); }, 250); -const render = async() => { - fetch("../data/jobsplan.json").then(response => response.json()).then(data => { - const value = processData(data); - chart = createPlot(value); - window.addEventListener("resize", debouncedResize); - }); -} +const render = async () => { + fetch('../data/jobsplan.json') + .then((response) => response.json()) + .then((data) => { + const value = processData(data); + chart = createPlot(value); + window.addEventListener('resize', debouncedResize); + }); +}; -const processData = (data) => { +const processData = (data) => { const dataArr = []; const obj = {}; - if(data.children.length > 0) { - data.children.map((child,i) => { - obj[i] = child; - obj[i].itemStyle = { - color: child.color, - } - dataArr.push(obj[i]); - }) - } + if (data.children.length > 0) { + data.children.map((child, i) => { + obj[i] = child; + obj[i].itemStyle = { + color: child.color, + }; + dataArr.push(obj[i]); + }); + } return dataArr; -} +}; const getLevelOption = () => { return [ @@ -40,82 +46,88 @@ const getLevelOption = () => { borderColor: 'white', borderWidth: 0, gapWidth: 1, - color: 'black' + color: 'black', }, upperLabel: { - show: false - } + show: false, + }, }, { itemStyle: { borderColor: 'white', borderWidth: 2, - gapWidth: 1, - }, + gapWidth: 1, + }, upperLabel: { show: true, fontWeight: 'bold', - fontSize: 15, - }, + fontSize: 15, + }, }, - ]; -} +}; const createPlot = (data) => { - const options = { + const options = { series: [ { type: 'treemap', - name: "American Jobs Plan", + name: 'American Jobs Plan', data: data, - levels: getLevelOption(), - } + levels: getLevelOption(), + }, ], tooltip: {}, // textStyle: { // color: 'black', - // // fontWeight: 'bold', + // // fontWeight: 'bold', // } - - } + }; -chart.setOption(options); -return chart; -} + chart.setOption(options); + return chart; +}; const getAhoiConfig = () => { - const defaultOnboardingMessages = generateBasicAnnotations(EVisualizationType.TREEMAP, chart); + const defaultOnboardingMessages = generateBasicAnnotations( + EVisualizationType.TREEMAP, + chart, + ); const extendedOnboardingMessages = defaultOnboardingMessages.map((d) => ({ ...d, - text: "test123" + text: 'test123', })); const ahoiConfig = { onboardingMessages: defaultOnboardingMessages, - } + }; return ahoiConfig; -} +}; -const registerEventListener = () => { - const helpIcon = document.getElementById("show-onboarding"); - if(!helpIcon) { return; } +const registerEventListener = () => { + const helpIcon = document.getElementById('show-onboarding'); + if (!helpIcon) { + return; + } helpIcon.addEventListener('click', async () => { showOnboarding = !showOnboarding; - if(showOnboarding) { - onboardingUI = await ahoi(EVisualizationType.TREEMAP, chart, getAhoiConfig()); + if (showOnboarding) { + onboardingUI = await ahoi( + EVisualizationType.TREEMAP, + chart, + getAhoiConfig(), + ); } else { onboardingUI?.removeOnboarding(); - } - }) -} - + } + }); +}; -const createChart = (renderer = 'svg') => { - const vis = document.getElementById("vis"); - chart = echarts.init(vis, null, {renderer}); - window.addEventListener("resize", () => chart.resize()); +const createChart = (renderer = 'svg') => { + const vis = document.getElementById('vis'); + chart = echarts.init(vis, null, { renderer }); + window.addEventListener('resize', () => chart.resize()); registerEventListener(); render(); -} +}; export default createChart; From 55afecadf6a55f583dd382411f0bce4325815e52 Mon Sep 17 00:00:00 2001 From: Silviya Geo Date: Tue, 16 Aug 2022 11:31:09 +0200 Subject: [PATCH 05/22] Add onboarding to heatmap(WIP) --- packages/echarts-demo/public/svg/heatmap.html | 4 +- packages/echarts-demo/src/heatmap.js | 28 +++- packages/echarts/src/heatmap.ts | 121 ++++++++++++++++++ packages/echarts/src/index.ts | 51 ++++++-- 4 files changed, 183 insertions(+), 21 deletions(-) diff --git a/packages/echarts-demo/public/svg/heatmap.html b/packages/echarts-demo/public/svg/heatmap.html index 54cd50a0..1939c1ef 100644 --- a/packages/echarts-demo/public/svg/heatmap.html +++ b/packages/echarts-demo/public/svg/heatmap.html @@ -16,7 +16,9 @@
- Show onboarding + + + Show onboarding

VisAhoi Demo: ECharts - Heatmap

diff --git a/packages/echarts-demo/src/heatmap.js b/packages/echarts-demo/src/heatmap.js index f3430d37..f9386afc 100644 --- a/packages/echarts-demo/src/heatmap.js +++ b/packages/echarts-demo/src/heatmap.js @@ -1,9 +1,9 @@ import * as echarts from 'echarts'; -// import { -// generateBasicAnnotations, -// ahoi, -// EVisualizationType, -// } from '@visahoi/plotly'; +import { + generateBasicAnnotations, + ahoi, + EVisualizationType, +} from '@visahoi/echarts'; import debounce from 'lodash.debounce'; let chart = null; @@ -111,6 +111,21 @@ const createPlot = () => { return chart; }; +const getAhoiConfig = () => { + const defaultOnboardingMessages = generateBasicAnnotations( + EVisualizationType.HEATMAP, + chart, + ); + const extendedOnboardingMessages = defaultOnboardingMessages.map((d) => ({ + ...d, + text: 'test123', + })); + const ahoiConfig = { + onboardingMessages: defaultOnboardingMessages, + }; + return ahoiConfig; +}; + const registerEventListener = () => { const helpIcon = document.getElementById('show-onboarding'); if (!helpIcon) { @@ -118,9 +133,10 @@ const registerEventListener = () => { } helpIcon.addEventListener('click', async () => { showOnboarding = !showOnboarding; + console.log(showOnboarding, 'Show onboarding'); if (showOnboarding) { onboardingUI = await ahoi( - EVisualizationType.TREEMAP, + EVisualizationType.HEATMAP, chart, getAhoiConfig(), ); diff --git a/packages/echarts/src/heatmap.ts b/packages/echarts/src/heatmap.ts index e69de29b..0a97b22a 100644 --- a/packages/echarts/src/heatmap.ts +++ b/packages/echarts/src/heatmap.ts @@ -0,0 +1,121 @@ +import { + EVisualizationType, + IOnboardingMessage, + generateMessages, +} from "@visahoi/core"; +import { IOnboardingHeatmapSpec } from "@visahoi/core/src/heatmap"; + +function extractOnboardingSpec(chart, coords): IOnboardingHeatmapSpec { + console.log(chart.data, "Chart detail"); + // const options = chart._model?.option?.series[0]; + // const childrenData = chart._model?.option?.series[0].data[0].children; + // const childrenArr = [chart._model.option.series[0].data[0].children]; + + // let maxValue: number | null = null; + // let minValue: number | null = null; + // let maxChildName: string = ""; + // let minChildName: string = ""; + + // childrenArr.map((child) => { + // maxValue = Math.max(...child.map((d) => d.value)); + // minValue = Math.min(...child.map((d) => d.value)); + // }); + + // childrenData.map((child) => { + // if(child.value === maxValue) { + // maxChildName = child.name + // } else if (child.value === minValue) { + // minChildName = child.name + // } + // }); + + debugger; + return { + chartTitle: { + value: "Average temperature in a week", + anchor: { + findDomNodeByValue: true, + offset: { left: -20, top: 10 }, + }, + }, + + // desc: { + // value: options?.data[0]?.name, + // anchor: { + // findDomNodeByValue: true, + // offset: {left: -20, top: 20} + // } + // }, + + // subDesc: { + // value: options?.data[0]?.children[0]?.name, + // anchor: { + // findDomNodeByValue: true, + // offset: {left: -20, top:-20} + // } + // }, + + // gapDesc: { + // value: (options?.data[0]?.children[1]?.name) ? options?.data[0]?.children[1]?.name : options?.data[0]?.children[0]?.name , + // anchor: { + // findDomNodeByValue: true, + // offset: {left: -40, top:-40} + // } + // }, + + // otherDesc: { + // value: (options?.data[0]?.children[2]?.name) ? options?.data[0]?.children[2]?.name : options?.data[0]?.children[1]?.name ? options?.data[0]?.children[1]?.name : options?.data[0]?.children[0]?.name, + // anchor: { + // findDomNodeByValue: true, + // offset: {left: -60, top: -30} + // } + // }, + + // interactingDesc:{ + // value: options?.data[0]?.children[0]?.name, + // anchor: { + // findDomNodeByValue: true, + // offset: {left: -20, top: -30} + // } + // }, + + // maxValueDesc: { + // value: maxChildName, + // anchor: { + // findDomNodeByValue: true, + // offset: {left: -20, top: -30} + // } + // }, + + // minValueDesc: { + // value: minChildName, + // anchor: { + // findDomNodeByValue: true, + // offset: {left: -20, top: -10} + // } + // }, + + // maxValue: { + // value: maxValue, + // }, + + // minValue: { + // value: minValue + // } + + // }; + }; +} + +export function heatmapFactory( + chart, + coords, + visElementId: Element +): IOnboardingMessage[] { + const onbordingSpec = extractOnboardingSpec(chart, coords); + return generateMessages( + EVisualizationType.HEATMAP, + onbordingSpec, + visElementId + ); +} diff --git a/packages/echarts/src/index.ts b/packages/echarts/src/index.ts index ba51fcbf..f3d8bef7 100644 --- a/packages/echarts/src/index.ts +++ b/packages/echarts/src/index.ts @@ -1,9 +1,16 @@ -import { defaultOnboardingStages, EVisualizationType, IAhoiConfig, injectOnboarding, IOnboardingMessage } from '@visahoi/core'; -import { barChartFactory } from './bar-chart'; -import { changeMatrixFactory } from './change-matrix'; -import { horizonGraphFactory } from './horizon-graph'; -import { scatterplotFactory } from './scatterplot'; -import { treemapFactory } from './treemap'; +import { + defaultOnboardingStages, + EVisualizationType, + IAhoiConfig, + injectOnboarding, + IOnboardingMessage, +} from "@visahoi/core"; +import { barChartFactory } from "./bar-chart"; +import { changeMatrixFactory } from "./change-matrix"; +import { heatmapFactory } from "./heatmap"; +import { horizonGraphFactory } from "./horizon-graph"; +import { scatterplotFactory } from "./scatterplot"; +import { treemapFactory } from "./treemap"; /** * @@ -11,13 +18,20 @@ import { treemapFactory } from './treemap'; * @param chart runtime object of the visualization * @param onboardingElement ID of the DOM Element where the onboarding Messages should be displayed */ -export const generateBasicAnnotations = (visType: EVisualizationType, chart: any): IOnboardingMessage[] => { +export const generateBasicAnnotations = ( + visType: EVisualizationType, + chart: any +): IOnboardingMessage[] => { const coords = {}; const visElement = chart._dom; // TODO: coords - const chartTitlePosition = chart._componentsMap["_ec_\u0000series\u00000\u00000_title"]?.group.position; - coords['chartTitle'] = chartTitlePosition ? { x: chartTitlePosition[0], y: chartTitlePosition[1] + 20 } : null; + const chartTitlePosition = + chart._componentsMap["_ec_\u0000series\u00000\u00000_title"]?.group + .position; + coords["chartTitle"] = chartTitlePosition + ? { x: chartTitlePosition[0], y: chartTitlePosition[1] + 20 } + : null; let onboardingMessages: IOnboardingMessage[]; @@ -42,12 +56,18 @@ export const generateBasicAnnotations = (visType: EVisualizationType, chart: any onboardingMessages = treemapFactory(chart, coords, visElement); break; + case EVisualizationType.HEATMAP: + debugger; + onboardingMessages = heatmapFactory(chart, coords, visElement); + break; + default: - throw new Error(`No onboarding for visualization type ${visType} available.`); + throw new Error( + `No onboarding for visualization type ${visType} available.` + ); } return onboardingMessages; -} - +}; /** * @@ -55,10 +75,13 @@ export const generateBasicAnnotations = (visType: EVisualizationType, chart: any * @param chart * @param onboardingElement ID of the DOM Element where the onboarding Messages should be displayed */ -export async function ahoi(visType: EVisualizationType, chart: any, ahoiConfig: IAhoiConfig) { +export async function ahoi( + visType: EVisualizationType, + chart: any, + ahoiConfig: IAhoiConfig +) { const visElement = chart._dom; return injectOnboarding(ahoiConfig, visElement, "column"); } - export { EVisualizationType }; From 5c227c4b1a95c871b8ae18828a72c8741eae0d80 Mon Sep 17 00:00:00 2001 From: Silviya Geo Date: Thu, 8 Sep 2022 17:24:52 +0200 Subject: [PATCH 06/22] add onboardings to echart --- packages/echarts-demo/src/heatmap.js | 72 ++++++++++++----- packages/echarts/src/heatmap.ts | 111 ++++++--------------------- 2 files changed, 76 insertions(+), 107 deletions(-) diff --git a/packages/echarts-demo/src/heatmap.js b/packages/echarts-demo/src/heatmap.js index f9386afc..206f7b56 100644 --- a/packages/echarts-demo/src/heatmap.js +++ b/packages/echarts-demo/src/heatmap.js @@ -1,3 +1,5 @@ +/* eslint-disable comma-dangle */ +/* eslint-disable semi */ import * as echarts from 'echarts'; import { generateBasicAnnotations, @@ -22,22 +24,40 @@ const render = () => { const createPlot = () => { const day = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']; const dayTime = ['Morning', 'Afternoon', 'Evening']; + + // const data = [ + // [0, 0, 1], + // [0, 1, 0], + // [0, 2, 30], + // [0, 3, 50], + // [0, 4, 1], + // [1, 0, 20], + // [1, 1, 1], + // [1, 2, 60], + // [1, 3, 80], + // [1, 4, 30], + // [2, 0, 30], + // [2, 1, 60], + // [2, 2, 1], + // [2, 3, -10], + // [2, 4, 20], + // ] const data = [ - [0, 0, 1], + [0, 0, 14], [0, 1, 0], - [0, 2, 30], - [0, 3, 50], - [0, 4, 1], - [1, 0, 20], - [1, 1, 1], - [1, 2, 60], - [1, 3, 80], - [1, 4, 30], - [2, 0, 30], - [2, 1, 60], - [2, 2, 1], - [2, 3, -10], - [2, 4, 20], + [0, 2, 19], + [0, 3, 24], + [0, 4, 16], + [1, 0, 17], + [1, 1, 15], + [1, 2, 28], + [1, 3, 52], + [1, 4, 20], + [2, 0, 19], + [2, 1, 23], + [2, 2, 82], + [2, 3, 18], + [2, 4, 18], ].map(function (item) { return [item[1], item[0], item[2] || '-']; }); @@ -61,6 +81,10 @@ const createPlot = () => { show: true, }, nameLocation: 'middle', + nameTextStyle: { + fontWeight: 'bold', + fontSize: '13', + }, nameGap: 35, }, yAxis: { @@ -71,17 +95,29 @@ const createPlot = () => { show: true, }, nameLocation: 'middle', - nameGap: 75, - axisName: { + nameTextStyle: { fontWeight: 'bold', + fontSize: '13', }, + nameGap: 75, + // axisName: { + // fontWeight: 'bold', + // }, }, // labelLayout: { // fontSize: '30px', // }, visualMap: { - min: 0, - max: 10, + min: 10, + max: 100, + // inRange: { + // color: ['#337ab7', '#f5f5f5', '#ec6836'], //From smaller to bigger value -> + // }, + // colorscale: [ + // [0, '#337ab7'], + // [0.5, '#f5f5f5'], + // [1, '#ec6836'], + // ], calculable: true, orient: 'vertical', right: '3%', diff --git a/packages/echarts/src/heatmap.ts b/packages/echarts/src/heatmap.ts index 0a97b22a..f37db626 100644 --- a/packages/echarts/src/heatmap.ts +++ b/packages/echarts/src/heatmap.ts @@ -1,3 +1,7 @@ +/* eslint-disable space-before-function-paren */ +/* eslint-disable semi */ +/* eslint-disable quotes */ +/* eslint-disable comma-dangle */ import { EVisualizationType, IOnboardingMessage, @@ -6,112 +10,41 @@ import { import { IOnboardingHeatmapSpec } from "@visahoi/core/src/heatmap"; function extractOnboardingSpec(chart, coords): IOnboardingHeatmapSpec { - console.log(chart.data, "Chart detail"); - // const options = chart._model?.option?.series[0]; - // const childrenData = chart._model?.option?.series[0].data[0].children; - // const childrenArr = [chart._model.option.series[0].data[0].children]; + const data = chart?._model.option; + console.log(data, "Chart detail-1"); - // let maxValue: number | null = null; - // let minValue: number | null = null; - // let maxChildName: string = ""; - // let minChildName: string = ""; - - // childrenArr.map((child) => { - // maxValue = Math.max(...child.map((d) => d.value)); - // minValue = Math.min(...child.map((d) => d.value)); - // }); - - // childrenData.map((child) => { - // if(child.value === maxValue) { - // maxChildName = child.name - // } else if (child.value === minValue) { - // minChildName = child.name - // } - // }); - - debugger; return { chartTitle: { - value: "Average temperature in a week", + value: data.title[0].text, anchor: { findDomNodeByValue: true, offset: { left: -20, top: 10 }, }, }, + axisDescription: { + value: data?.yAxis[0].name, + anchor: { + findDomNodeByValue: true, + offset: { right: -40, top: -320 }, + }, + }, - // desc: { - // value: options?.data[0]?.name, - // anchor: { - // findDomNodeByValue: true, - // offset: {left: -20, top: 20} - // } - // }, - - // subDesc: { - // value: options?.data[0]?.children[0]?.name, - // anchor: { - // findDomNodeByValue: true, - // offset: {left: -20, top:-20} - // } - // }, - - // gapDesc: { - // value: (options?.data[0]?.children[1]?.name) ? options?.data[0]?.children[1]?.name : options?.data[0]?.children[0]?.name , - // anchor: { - // findDomNodeByValue: true, - // offset: {left: -40, top:-40} - // } - // }, - - // otherDesc: { - // value: (options?.data[0]?.children[2]?.name) ? options?.data[0]?.children[2]?.name : options?.data[0]?.children[1]?.name ? options?.data[0]?.children[1]?.name : options?.data[0]?.children[0]?.name, - // anchor: { - // findDomNodeByValue: true, - // offset: {left: -60, top: -30} - // } - // }, - - // interactingDesc:{ - // value: options?.data[0]?.children[0]?.name, - // anchor: { - // findDomNodeByValue: true, - // offset: {left: -20, top: -30} - // } - // }, - - // maxValueDesc: { - // value: maxChildName, - // anchor: { - // findDomNodeByValue: true, - // offset: {left: -20, top: -30} - // } - // }, - - // minValueDesc: { - // value: minChildName, - // anchor: { - // findDomNodeByValue: true, - // offset: {left: -20, top: -10} - // } - // }, - - // maxValue: { - // value: maxValue, - // }, - - // minValue: { - // value: minValue - // } - - // }; + xAxis: { + value: data?.xAxis[0].name, + }, + yAxis: { + value: data?.yAxis[0].name, + }, }; } +// eslint-disable-next-line space-before-function-paren export function heatmapFactory( chart, coords, visElementId: Element ): IOnboardingMessage[] { + console.log(chart, "Chart"); const onbordingSpec = extractOnboardingSpec(chart, coords); return generateMessages( EVisualizationType.HEATMAP, From ae5d71ba1eb763ea7edd6a7f504a3b387f190ace Mon Sep 17 00:00:00 2001 From: Silviya Geo Date: Fri, 9 Sep 2022 09:19:37 +0200 Subject: [PATCH 07/22] WIP --- packages/echarts-demo/src/heatmap.js | 12 +-- packages/echarts/src/heatmap.ts | 16 +++- packages/plotly-demo/src/treeMap.js | 108 +++++++++++++------------- packages/plotly/src/heatmap.ts | 56 +++++++------- packages/plotly/src/treemap.ts | 110 +++++++++++++-------------- 5 files changed, 158 insertions(+), 144 deletions(-) diff --git a/packages/echarts-demo/src/heatmap.js b/packages/echarts-demo/src/heatmap.js index 206f7b56..4205fa30 100644 --- a/packages/echarts-demo/src/heatmap.js +++ b/packages/echarts-demo/src/heatmap.js @@ -51,11 +51,11 @@ const createPlot = () => { [1, 0, 17], [1, 1, 15], [1, 2, 28], - [1, 3, 52], + [1, 3, 44], [1, 4, 20], [2, 0, 19], [2, 1, 23], - [2, 2, 82], + [2, 2, 48], [2, 3, 18], [2, 4, 18], ].map(function (item) { @@ -109,10 +109,10 @@ const createPlot = () => { // }, visualMap: { min: 10, - max: 100, - // inRange: { - // color: ['#337ab7', '#f5f5f5', '#ec6836'], //From smaller to bigger value -> - // }, + max: 50, + inRange: { + color: ['#337ab7', '#f5f5f5', '#ec6836'], //From smaller to bigger value -> + }, // colorscale: [ // [0, '#337ab7'], // [0.5, '#f5f5f5'], diff --git a/packages/echarts/src/heatmap.ts b/packages/echarts/src/heatmap.ts index f37db626..13fe0805 100644 --- a/packages/echarts/src/heatmap.ts +++ b/packages/echarts/src/heatmap.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-debugger */ /* eslint-disable space-before-function-paren */ /* eslint-disable semi */ /* eslint-disable quotes */ @@ -11,7 +12,13 @@ import { IOnboardingHeatmapSpec } from "@visahoi/core/src/heatmap"; function extractOnboardingSpec(chart, coords): IOnboardingHeatmapSpec { const data = chart?._model.option; - console.log(data, "Chart detail-1"); + console.log(data, "Chart detail-5"); + console.log(data.visualMap[0].max, "max value"); + const dataArr: number[] = []; + data.series[0].data.map((d) => dataArr.push(d[d.length - 1])); + console.log(dataArr); + const maxValue: number = Math.max.apply(Math, dataArr); + const minValue: number = Math.min.apply(Math, dataArr) return { chartTitle: { @@ -35,6 +42,13 @@ function extractOnboardingSpec(chart, coords): IOnboardingHeatmapSpec { yAxis: { value: data?.yAxis[0].name, }, + legendDescription: { + value: data.visualMap[0].max, + anchor: { + findDomNodeByValue: true, + offset: { left: -40, top: 20 }, + }, + }, }; } diff --git a/packages/plotly-demo/src/treeMap.js b/packages/plotly-demo/src/treeMap.js index 59a0d61b..f366804b 100644 --- a/packages/plotly-demo/src/treeMap.js +++ b/packages/plotly-demo/src/treeMap.js @@ -1,42 +1,42 @@ -import Plotly from 'plotly.js-dist'; +import Plotly from 'plotly.js-dist' import { generateBasicAnnotations, ahoi, - EVisualizationType, -} from '@visahoi/plotly'; -import debounce from 'lodash.debounce'; -import { importCsv } from './util'; + EVisualizationType +} from '@visahoi/plotly' +import debounce from 'lodash.debounce' +import { importCsv } from './util' -let chart = null; -let showOnboarding = false; -let onboardingUI = null; +let chart = null +let showOnboarding = false +let onboardingUI = null const debouncedResize = debounce((event) => { - onboardingUI?.updateOnboarding(getAhoiConfig()); -}, 250); + onboardingUI?.updateOnboarding(getAhoiConfig()) +}, 250) const render = async () => { - const data = await importCsv('./data/jobsPlan.csv'); - const { label, parent, value, color } = processData(data); - chart = await makePlotly(label, parent, value, color); - window.addEventListener('resize', debouncedResize); -}; + const data = await importCsv('./data/jobsPlan.csv') + const { label, parent, value, color } = processData(data) + chart = await makePlotly(label, parent, value, color) + window.addEventListener('resize', debouncedResize) +} const processData = (data) => { - const label = []; - const parent = []; - const value = []; - const color = []; + const label = [] + const parent = [] + const value = [] + const color = [] data.map((d) => { - label.push(d.Label); - parent.push(d.Parent); - value.push(d.Value); - color.push(d.Color); - }); + label.push(d.Label) + parent.push(d.Parent) + value.push(d.Value) + color.push(d.Color) + }) - return { label, parent, value, color }; -}; + return { label, parent, value, color } +} const makePlotly = (label, parent, value, color) => { const traces = [ @@ -47,54 +47,54 @@ const makePlotly = (label, parent, value, color) => { parents: parent, values: value, marker: { - colors: color, + colors: color // colorscale: 'Greys', - }, - }, - ]; + } + } + ] const config = { - responsive: true, - }; + responsive: true + } const layout = { - title: 'Jobs Plan', - }; - return Plotly.newPlot('vis', traces, layout, config); -}; + title: 'Jobs Plan' + } + return Plotly.newPlot('vis', traces, layout, config) +} const getAhoiConfig = () => { const defaultOnboardingMessages = generateBasicAnnotations( EVisualizationType.TREEMAP, - chart, - ); + chart + ) const extendedOnboardingMessages = defaultOnboardingMessages.map((d) => ({ ...d, - text: 'test123', - })); + text: 'test123' + })) const ahoiConfig = { onboardingMessages: defaultOnboardingMessages, - showHelpCloseText: false, - }; - return ahoiConfig; -}; + showHelpCloseText: false + } + return ahoiConfig +} const registerEventListener = () => { - const helpIcon = document.getElementById('show-onboarding'); + const helpIcon = document.getElementById('show-onboarding') if (!helpIcon) { - return; + return } helpIcon.addEventListener('click', async () => { - showOnboarding = !showOnboarding; + showOnboarding = !showOnboarding if (showOnboarding) { onboardingUI = await ahoi( EVisualizationType.TREEMAP, chart, - getAhoiConfig(), - ); + getAhoiConfig() + ) } else { - onboardingUI?.removeOnboarding(); + onboardingUI?.removeOnboarding() } - }); -}; + }) +} -registerEventListener(); -render(); +registerEventListener() +render() diff --git a/packages/plotly/src/heatmap.ts b/packages/plotly/src/heatmap.ts index 133b1733..e64c7a79 100644 --- a/packages/plotly/src/heatmap.ts +++ b/packages/plotly/src/heatmap.ts @@ -1,70 +1,70 @@ import { EVisualizationType, IOnboardingMessage, - generateMessages, -} from "@visahoi/core"; -import { IOnboardingScatterplotSpec } from "@visahoi/core/src/scatterplot"; + generateMessages +} from '@visahoi/core' +import { IOnboardingScatterplotSpec } from '@visahoi/core/src/scatterplot' -function extractOnboardingSpec(chart: any, coords): IOnboardingScatterplotSpec { +function extractOnboardingSpec (chart: any, coords): IOnboardingScatterplotSpec { const heatmapData = (( - Array.from(chart.querySelectorAll(".hm"))[0] - )).__data__; - const t = heatmapData[0].trace; + Array.from(chart.querySelectorAll('.hm'))[0] + )).__data__ + const t = heatmapData[0].trace return { chartTitle: { value: chart.layout.title.text, anchor: { findDomNodeByValue: true, - offset: { left: -20, top: 10 }, - }, + offset: { left: -20, top: 10 } + } }, heatmapDescription: { value: t.type, anchor: { - sel: ".heatmaplayer > .hm > image", - offset: { left: -50, top: -30 }, - }, + sel: '.heatmaplayer > .hm > image', + offset: { left: -50, top: -30 } + } }, legendDescription: { value: t.colorbar.title.text, anchor: { - sel: ".infolayer > .colorbar", - offset: { top: -10 }, - }, + sel: '.infolayer > .colorbar', + offset: { top: -10 } + } }, axisDescription: { value: t?.yaxis?.title?.text, anchor: { - sel: ".infolayer > .g-ytitle", - offset: { bottom: -320, left: -50 }, - }, + sel: '.infolayer > .g-ytitle', + offset: { bottom: -320, left: -50 } + } }, xAxis: { - value: chart.layout.xaxis.title.text, + value: chart.layout.xaxis.title.text }, yAxis: { - value: chart.layout.yaxis.title.text, + value: chart.layout.yaxis.title.text }, hoverDescription: { value: t?.xaxis?.title?.text, anchor: { - sel: ".cartesianlayer", - offset: { top: -50, left: -120 }, - }, - }, - }; + sel: '.cartesianlayer', + offset: { top: -50, left: -120 } + } + } + } } -export function heatmapFactory( +export function heatmapFactory ( chart: Element, coords, visElementId: Element ): IOnboardingMessage[] { - const onbordingSpec = extractOnboardingSpec(chart, coords); + const onbordingSpec = extractOnboardingSpec(chart, coords) return generateMessages( EVisualizationType.HEATMAP, onbordingSpec, visElementId - ); + ) } diff --git a/packages/plotly/src/treemap.ts b/packages/plotly/src/treemap.ts index ddaa3cd7..1322603e 100644 --- a/packages/plotly/src/treemap.ts +++ b/packages/plotly/src/treemap.ts @@ -2,89 +2,89 @@ import { EVisualizationType, IOnboardingMessage, IOnboardingTreemapSpec, - generateMessages, -} from "@visahoi/core"; + generateMessages +} from '@visahoi/core' -function extractOnboardingSpec(chart: any, coords): IOnboardingTreemapSpec { - let indexArr: number[] = []; - let valArr: number[] = []; - let childArr: any = []; - let maxIndex: number; - let minIndex: number; - let maxLabel: string = ""; - let minLabel: string = ""; - let parentLabel: string = ""; +function extractOnboardingSpec (chart: any, coords): IOnboardingTreemapSpec { + const indexArr: number[] = [] + const valArr: number[] = [] + const childArr: any = [] + let maxIndex: number + let minIndex: number + let maxLabel: string = '' + let minLabel: string = '' + let parentLabel: string = '' // set the parent for getting the max and min values of the sub-category chart.data.map((d) => { if (d.parents.length > 1) { - if (d.parents[0] === "" && d.parents.length > 2) { - parentLabel = d.parents[1]; + if (d.parents[0] === '' && d.parents.length > 2) { + parentLabel = d.parents[1] } else { - parentLabel = d.parents[0]; + parentLabel = d.parents[0] } } - }); + }) // To get the min and max values and corresponding labels in each sub-category chart.data.map((dat: any, i: number) => { dat.parents.map((parent: any, j: number) => { if (parent === parentLabel) { - indexArr.push(j); + indexArr.push(j) } - }); + }) dat.values.map((value: number, id: number) => { if (indexArr) { indexArr.map((d) => { if (d === id) { - childArr.push({ value: value, index: id }); - valArr.push(value); + childArr.push({ value: value, index: id }) + valArr.push(value) } - }); + }) } - }); - }); + }) + }) - const maxVal = Math.max.apply(Math, valArr); - const minVal = Math.min.apply(Math, valArr); + const maxVal = Math.max.apply(Math, valArr) + const minVal = Math.min.apply(Math, valArr) childArr.map((dd: any, i: number) => { if (parseInt(dd.value) === maxVal) { - maxIndex = dd.index; + maxIndex = dd.index } if (parseInt(dd.value) === minVal) { - minIndex = dd.index; + minIndex = dd.index } - }); + }) chart.data.map((d: any) => d.labels.map((label: string, i: number) => { if (i === maxIndex) { - maxLabel = label; + maxLabel = label } if (i === minIndex) { - minLabel = label; + minLabel = label } }) - ); + ) return { chartTitle: { value: chart?.layout?.title?.text, anchor: { findDomNodeByValue: true, - offset: { left: -20, top: 10 }, - }, + offset: { left: -20, top: 10 } + } }, desc: { value: chart.data[0].labels[0], anchor: { findDomNodeByValue: true, - offset: { left: -20, top: 20 }, - }, + offset: { left: -20, top: 20 } + } }, subDesc: { @@ -94,8 +94,8 @@ function extractOnboardingSpec(chart: any, coords): IOnboardingTreemapSpec { : chart.data[0].labels[0], anchor: { findDomNodeByValue: true, - offset: { left: -40, top: -30 }, - }, + offset: { left: -40, top: -30 } + } }, gapDesc: { @@ -104,60 +104,60 @@ function extractOnboardingSpec(chart: any, coords): IOnboardingTreemapSpec { : chart.data[0].labels[0], anchor: { findDomNodeByValue: true, - offset: { left: -40, top: -60 }, - }, + offset: { left: -40, top: -60 } + } }, otherDesc: { value: chart.data[0].labels[2] ? chart.data[0].labels[2] : chart.data[0].labels[1] - ? chart.data[0].labels[1] - : chart.data[0].labels[0], + ? chart.data[0].labels[1] + : chart.data[0].labels[0], anchor: { findDomNodeByValue: true, - offset: { left: -80, top: -30 }, - }, + offset: { left: -80, top: -30 } + } }, interactingDesc: { value: chart.data[0].labels[0], anchor: { findDomNodeByValue: true, - offset: { left: -20, top: -30 }, - }, + offset: { left: -20, top: -30 } + } }, maxValueDesc: { value: maxLabel, anchor: { findDomNodeByValue: true, - offset: { left: -20, top: -30 }, - }, + offset: { left: -20, top: -30 } + } }, minValueDesc: { value: minLabel, anchor: { findDomNodeByValue: true, - offset: { left: -20, top: -20 }, - }, + offset: { left: -20, top: -20 } + } }, maxValue: { - value: maxVal, + value: maxVal }, minValue: { - value: minVal, - }, - }; + value: minVal + } + } } -export function treemapFactory( +export function treemapFactory ( chart: Element, coords, visElementId: Element ): IOnboardingMessage[] { - const onbordingSpec = extractOnboardingSpec(chart, coords); + const onbordingSpec = extractOnboardingSpec(chart, coords) return generateMessages( EVisualizationType.TREEMAP, onbordingSpec, visElementId - ); + ) } From 4d45bb8f2430ee543d65abe4366781a1099d39cc Mon Sep 17 00:00:00 2001 From: Silviya Geo Date: Fri, 9 Sep 2022 14:35:22 +0200 Subject: [PATCH 08/22] Added onboarding to echart heatmap --- packages/core/src/heatmap.ts | 103 ++++++++++------ packages/core/src/treemap.ts | 110 +++++++++--------- packages/echarts-demo/public/svg/heatmap.html | 4 +- packages/echarts-demo/src/heatmap.js | 43 ++----- packages/echarts/src/heatmap.ts | 82 ++++++++----- packages/echarts/src/index.ts | 73 ++++++------ 6 files changed, 216 insertions(+), 199 deletions(-) diff --git a/packages/core/src/heatmap.ts b/packages/core/src/heatmap.ts index 93855b2f..c0eac799 100644 --- a/packages/core/src/heatmap.ts +++ b/packages/core/src/heatmap.ts @@ -4,9 +4,9 @@ import { IOnboardingMessage, defaultOnboardingStages, EDefaultOnboardingStages, - IOnboardingStage, -} from "./interfaces"; -import { getAnchor } from "./utils"; + IOnboardingStage +} from './interfaces' +import { getAnchor } from './utils' export interface IOnboardingHeatmapSpec extends IOnboardingSpec { chartTitle?: ISpecProp; @@ -17,88 +17,115 @@ export interface IOnboardingHeatmapSpec extends IOnboardingSpec { yAxis?: ISpecProp; hoverDescription?: ISpecProp; missingDataDescription?: ISpecProp; + maxValue?: ISpecProp; + minValue?: ISpecProp; } -function generateMessages( +function generateMessages ( spec: IOnboardingHeatmapSpec, visElement: Element ): IOnboardingMessage[] { const reading = defaultOnboardingStages.get( EDefaultOnboardingStages.READING - ) as IOnboardingStage; + ) as IOnboardingStage const interacting = defaultOnboardingStages.get( EDefaultOnboardingStages.USING - ) as IOnboardingStage; + ) as IOnboardingStage + const analyzing = defaultOnboardingStages.get( + EDefaultOnboardingStages.ANALYZING + ) as IOnboardingStage const messages = [ { anchor: getAnchor(spec.chartTitle, visElement), - requires: ["chartTitle"], + requires: ['chartTitle'], text: `The chart shows the ${spec.chartTitle?.value}.`, - title: "Reading the chart", + title: 'Reading the chart', onboardingStage: reading, marker: { - id: "unique-marker-id-1", + id: 'unique-marker-id-1' }, - id: "unique-message-id-2", - order: 1, + id: 'unique-message-id-2', + order: 1 }, { anchor: getAnchor(spec.heatmapDescription, visElement), - requires: ["heatmapDescription"], - text: "It is based on colored cells.", - title: "Reading the chart", + requires: ['heatmapDescription'], + text: 'It is based on colored cells.', + title: 'Reading the chart', onboardingStage: reading, marker: { - id: "unique-marker-id-2", + id: 'unique-marker-id-2' }, - id: "unique-message-id-2", - order: 2, + id: 'unique-message-id-2', + order: 2 }, { anchor: getAnchor(spec.legendDescription, visElement), - requires: ["legendDescription"], - text: "A deep red color indicates a high temperature whereas a deep blue color indicates a low temperature. Medium values are visualized by a neutral light gray.", - title: "Reading the chart", + requires: ['legendDescription'], + text: 'A deep red color indicates a high temperature whereas a deep blue color indicates a low temperature. Medium values are visualized by a neutral light gray.', + title: 'Reading the chart', onboardingStage: reading, marker: { - id: "unique-marker-id-3", + id: 'unique-marker-id-3' }, - id: "unique-message-id-3", - order: 3, + id: 'unique-message-id-3', + order: 3 }, { anchor: getAnchor(spec.axisDescription, visElement), - requires: ["xAxis", "yAxis"], + requires: ['xAxis', 'yAxis'], text: `${spec.yAxis?.value} is plotted in rows and the ${spec.xAxis?.value} in columns.`, - title: "Reading the chart", + title: 'Reading the chart', onboardingStage: reading, marker: { - id: "unique-marker-id-4", + id: 'unique-marker-id-4' }, - id: "unique-message-id-4", - order: 4, + id: 'unique-message-id-4', + order: 4 }, { anchor: getAnchor(spec.hoverDescription, visElement), - requires: ["hoverDescription"], - text: "Hover over the chart to get the dedicated value for each cell.", - title: "Interacting with the chart", + requires: ['hoverDescription'], + text: 'Hover over the chart to get the dedicated value for each cell.', + title: 'Interacting with the chart', onboardingStage: interacting, marker: { - id: "unique-marker-id-5", + id: 'unique-marker-id-5' }, - id: "unique-message-id-5", - order: 1, + id: 'unique-message-id-5', + order: 1 }, - ]; + { + anchor: getAnchor(spec.maxValue, visElement), + requires: ['maxValue'], + text: `The deep red color rectangle holds the maximum value in the heatmap. In this heatmap ${spec.maxValue?.value} is the maximum value.`, + title: 'Analyzing the chart', + onboardingStage: analyzing, + marker: { + id: 'unique-marker-id-6' + }, + id: 'unique-message-id-6' + }, + { + anchor: getAnchor(spec.minValue, visElement), + requires: ['minValue'], + text: `The deep blue color rectangle holds the minimum value in the heatmap. In this heatmap ${spec.minValue?.value} is the minimum value.`, + title: 'Analyzing the chart', + onboardingStage: analyzing, + marker: { + id: 'unique-marker-id-7' + }, + id: 'unique-message-id-7' + } + ] // Filter for messages where all template variables are available in the spec return messages.filter((message) => message.requires.every((tplVars) => spec[tplVars]) - ); + ) } export const heatmap = { - generateMessages, -}; + generateMessages +} diff --git a/packages/core/src/treemap.ts b/packages/core/src/treemap.ts index 76284170..c1a8f9d4 100644 --- a/packages/core/src/treemap.ts +++ b/packages/core/src/treemap.ts @@ -4,9 +4,9 @@ import { IOnboardingMessage, defaultOnboardingStages, EDefaultOnboardingStages, - IOnboardingStage, -} from "./interfaces"; -import { getAnchor } from "./utils"; + IOnboardingStage +} from './interfaces' +import { getAnchor } from './utils' export interface IOnboardingTreemapSpec extends IOnboardingSpec { chartTitle?: ISpecProp; @@ -21,129 +21,129 @@ export interface IOnboardingTreemapSpec extends IOnboardingSpec { maxValue?: ISpecProp; } -function generateMessages( +function generateMessages ( spec: IOnboardingTreemapSpec, visElement: Element ): IOnboardingMessage[] { const analyzing = defaultOnboardingStages.get( EDefaultOnboardingStages.ANALYZING - ) as IOnboardingStage; + ) as IOnboardingStage const reading = defaultOnboardingStages.get( EDefaultOnboardingStages.READING - ) as IOnboardingStage; + ) as IOnboardingStage const interacting = defaultOnboardingStages.get( EDefaultOnboardingStages.USING - ) as IOnboardingStage; + ) as IOnboardingStage const messages: IOnboardingMessage[] = [ { anchor: getAnchor(spec.desc, visElement), - requires: ["desc"], - text: `The treemap visualization shows the breakdown of hierarchical data level by level. The size of each rectangle represents a quantitative value associated with each element in the hierarchy.`, - title: "Reading the chart", + requires: ['desc'], + text: 'The treemap visualization shows the breakdown of hierarchical data level by level. The size of each rectangle represents a quantitative value associated with each element in the hierarchy.', + title: 'Reading the chart', onboardingStage: reading, marker: { - id: "unique-marker-id-2", + id: 'unique-marker-id-2' }, - id: "unique-message-id-2", - order: 1, + id: 'unique-message-id-2', + order: 1 }, { anchor: getAnchor(spec.subDesc, visElement), - requires: ["subDesc"], - text: `The area covered by the whole treemap is subdivided recursively into sub-categories according to their quantitative values, level by level.`, - title: "Reading the chart", + requires: ['subDesc'], + text: 'The area covered by the whole treemap is subdivided recursively into sub-categories according to their quantitative values, level by level.', + title: 'Reading the chart', onboardingStage: reading, marker: { - id: "unique-marker-id-3", + id: 'unique-marker-id-3' }, - id: "unique-message-id-3", - order: 3, + id: 'unique-message-id-3', + order: 3 }, { anchor: getAnchor(spec.otherDesc, visElement), - requires: ["otherDesc"], - text: `Items on the bottom level that belong to the same sub-category are visually represented by using the same color.`, - title: "Reading the chart", + requires: ['otherDesc'], + text: 'Items on the bottom level that belong to the same sub-category are visually represented by using the same color.', + title: 'Reading the chart', onboardingStage: reading, marker: { - id: "unique-marker-id-4", + id: 'unique-marker-id-4' }, - id: "unique-message-id-4", - order: 4, + id: 'unique-message-id-4', + order: 4 }, { anchor: getAnchor(spec.gapDesc, visElement), - requires: ["gapDesc"], - text: `Items within a sub-category are represented by rectangles that are closely packed together with increasingly larger gaps to the neighboring categories.`, - title: "Reading the chart", + requires: ['gapDesc'], + text: 'Items within a sub-category are represented by rectangles that are closely packed together with increasingly larger gaps to the neighboring categories.', + title: 'Reading the chart', onboardingStage: reading, marker: { - id: "unique-marker-id-5", + id: 'unique-marker-id-5' }, - id: "unique-message-id-5", - order: 5, + id: 'unique-message-id-5', + order: 5 }, { anchor: getAnchor(spec.interactingDesc, visElement), - requires: ["interactingDesc"], - text: `Hover over the rectangles to get the dedicated value of the sub-category and further information.`, - title: "Interacting with the chart", + requires: ['interactingDesc'], + text: 'Hover over the rectangles to get the dedicated value of the sub-category and further information.', + title: 'Interacting with the chart', onboardingStage: interacting, marker: { - id: "unique-marker-id-6", + id: 'unique-marker-id-6' }, - id: "unique-message-id-6", + id: 'unique-message-id-6' }, { anchor: getAnchor(spec.maxValueDesc, visElement), - requires: ["maxValueDesc", "maxValue"], + requires: ['maxValueDesc', 'maxValue'], text: `The largest rectangle holds the maximum value in the sub-category. In this sub-category ${spec.maxValue?.value} is the maximum value.`, - title: "Analyzing the chart", + title: 'Analyzing the chart', onboardingStage: analyzing, marker: { - id: "unique-marker-id-7", + id: 'unique-marker-id-7' }, - id: "unique-message-id-7", + id: 'unique-message-id-7' }, { anchor: getAnchor(spec.minValueDesc, visElement), - requires: ["minValueDesc", "minValue"], + requires: ['minValueDesc', 'minValue'], text: ` The smallest rectangle holds the minimum value in the sub-category. In this sub-category ${spec.minValue?.value} is the minimum value.`, - title: "Analyzing the chart", + title: 'Analyzing the chart', onboardingStage: analyzing, marker: { - id: "unique-marker-id-8", + id: 'unique-marker-id-8' }, - id: "unique-message-id-8", - }, - ]; + id: 'unique-message-id-8' + } + ] if (spec.chartTitle?.value !== undefined) { messages.unshift({ anchor: getAnchor(spec.chartTitle, visElement), - requires: ["chartTitle"], + requires: ['chartTitle'], text: `The chart shows the ${spec.chartTitle?.value}.`, - title: "Reading the chart", + title: 'Reading the chart', onboardingStage: reading, marker: { - id: "unique-marker-id-1", + id: 'unique-marker-id-1' }, - id: "unique-message-id-1", - order: 2, - }); + id: 'unique-message-id-1', + order: 2 + }) } // Filter for messages where all template variables are available in the spec return messages.filter((message) => message.requires.every((tplVars) => spec[tplVars]) - ); + ) } export const treemap = { - generateMessages, -}; + generateMessages +} diff --git a/packages/echarts-demo/public/svg/heatmap.html b/packages/echarts-demo/public/svg/heatmap.html index 1939c1ef..5a3d913c 100644 --- a/packages/echarts-demo/public/svg/heatmap.html +++ b/packages/echarts-demo/public/svg/heatmap.html @@ -16,8 +16,8 @@
- - + + Show onboarding
diff --git a/packages/echarts-demo/src/heatmap.js b/packages/echarts-demo/src/heatmap.js index 4205fa30..04aa2390 100644 --- a/packages/echarts-demo/src/heatmap.js +++ b/packages/echarts-demo/src/heatmap.js @@ -25,23 +25,6 @@ const createPlot = () => { const day = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']; const dayTime = ['Morning', 'Afternoon', 'Evening']; - // const data = [ - // [0, 0, 1], - // [0, 1, 0], - // [0, 2, 30], - // [0, 3, 50], - // [0, 4, 1], - // [1, 0, 20], - // [1, 1, 1], - // [1, 2, 60], - // [1, 3, 80], - // [1, 4, 30], - // [2, 0, 30], - // [2, 1, 60], - // [2, 2, 1], - // [2, 3, -10], - // [2, 4, 20], - // ] const data = [ [0, 0, 14], [0, 1, 0], @@ -100,24 +83,15 @@ const createPlot = () => { fontSize: '13', }, nameGap: 75, - // axisName: { - // fontWeight: 'bold', - // }, }, - // labelLayout: { - // fontSize: '30px', - // }, + visualMap: { min: 10, max: 50, inRange: { - color: ['#337ab7', '#f5f5f5', '#ec6836'], //From smaller to bigger value -> + color: ['#337ab7', '#f5f5f5', '#ec6836'], // From smaller to bigger value -> }, - // colorscale: [ - // [0, '#337ab7'], - // [0.5, '#f5f5f5'], - // [1, '#ec6836'], - // ], + calculable: true, orient: 'vertical', right: '3%', @@ -135,8 +109,6 @@ const createPlot = () => { emphasis: { itemStyle: { fontWeight: 'bold', - // shadowBlur: 10, - // shadowColor: 'rgba(0, 0, 0, 0.5)', }, }, }, @@ -152,10 +124,10 @@ const getAhoiConfig = () => { EVisualizationType.HEATMAP, chart, ); - const extendedOnboardingMessages = defaultOnboardingMessages.map((d) => ({ - ...d, - text: 'test123', - })); + // const extendedOnboardingMessages = defaultOnboardingMessages.map((d) => ({ + // ...d, + // text: 'test123', + // })); const ahoiConfig = { onboardingMessages: defaultOnboardingMessages, }; @@ -169,7 +141,6 @@ const registerEventListener = () => { } helpIcon.addEventListener('click', async () => { showOnboarding = !showOnboarding; - console.log(showOnboarding, 'Show onboarding'); if (showOnboarding) { onboardingUI = await ahoi( EVisualizationType.HEATMAP, diff --git a/packages/echarts/src/heatmap.ts b/packages/echarts/src/heatmap.ts index 13fe0805..e687612e 100644 --- a/packages/echarts/src/heatmap.ts +++ b/packages/echarts/src/heatmap.ts @@ -1,68 +1,88 @@ -/* eslint-disable no-debugger */ -/* eslint-disable space-before-function-paren */ -/* eslint-disable semi */ -/* eslint-disable quotes */ -/* eslint-disable comma-dangle */ + import { EVisualizationType, IOnboardingMessage, - generateMessages, -} from "@visahoi/core"; -import { IOnboardingHeatmapSpec } from "@visahoi/core/src/heatmap"; + generateMessages +} from '@visahoi/core' +import { IOnboardingHeatmapSpec } from '@visahoi/core/src/heatmap' + +function extractOnboardingSpec (chart, coords): IOnboardingHeatmapSpec { + const data = chart?._model.option + + const dataArr: number[] = [] + data.series[0].data.map((d) => dataArr.push(d[d.length - 1])) + + // The 0 value is indicated as '-'. Remove this from the data array. + const index = dataArr.indexOf('-') -function extractOnboardingSpec(chart, coords): IOnboardingHeatmapSpec { - const data = chart?._model.option; - console.log(data, "Chart detail-5"); - console.log(data.visualMap[0].max, "max value"); - const dataArr: number[] = []; - data.series[0].data.map((d) => dataArr.push(d[d.length - 1])); - console.log(dataArr); - const maxValue: number = Math.max.apply(Math, dataArr); - const minValue: number = Math.min.apply(Math, dataArr) + if (index !== -1) { + dataArr.splice(index, 1) + } + const maxValue: number = Math.max(...dataArr) + const minValue: number = Math.min(...dataArr) return { chartTitle: { value: data.title[0].text, anchor: { findDomNodeByValue: true, - offset: { left: -20, top: 10 }, - }, + offset: { left: -20, top: 10 } + } }, axisDescription: { value: data?.yAxis[0].name, anchor: { findDomNodeByValue: true, - offset: { right: -40, top: -320 }, - }, + offset: { right: -40, top: -320 } + } }, xAxis: { - value: data?.xAxis[0].name, + value: data?.xAxis[0].name }, yAxis: { - value: data?.yAxis[0].name, + value: data?.yAxis[0].name }, legendDescription: { value: data.visualMap[0].max, anchor: { findDomNodeByValue: true, - offset: { left: -40, top: 20 }, - }, + offset: { left: -40, top: 20 } + } }, - }; + hoverDescription: { + value: dataArr[0], + anchor: { + findDomNodeByValue: true, + offset: { left: 10, top: -10 } + } + }, + maxValue: { + value: maxValue, + anchor: { + findDomNodeByValue: true, + offset: { left: 20, top: -20 } + } + }, + minValue: { + value: minValue, + anchor: { + findDomNodeByValue: true, + offset: { left: 20, top: -20 } + } + } + } } -// eslint-disable-next-line space-before-function-paren -export function heatmapFactory( +export function heatmapFactory ( chart, coords, visElementId: Element ): IOnboardingMessage[] { - console.log(chart, "Chart"); - const onbordingSpec = extractOnboardingSpec(chart, coords); + const onbordingSpec = extractOnboardingSpec(chart, coords) return generateMessages( EVisualizationType.HEATMAP, onbordingSpec, visElementId - ); + ) } diff --git a/packages/echarts/src/index.ts b/packages/echarts/src/index.ts index d80cfbc1..d8f50907 100644 --- a/packages/echarts/src/index.ts +++ b/packages/echarts/src/index.ts @@ -11,14 +11,14 @@ import { getOnboardingStages, setEditMode, setOnboardingMessage, - setOnboardingStage, -} from "@visahoi/core"; -import { barChartFactory } from "./bar-chart"; -import { changeMatrixFactory } from "./change-matrix"; -import { heatmapFactory } from "./heatmap"; -import { horizonGraphFactory } from "./horizon-graph"; -import { scatterplotFactory } from "./scatterplot"; -import { treemapFactory } from "./treemap"; + setOnboardingStage +} from '@visahoi/core' +import { barChartFactory } from './bar-chart' +import { changeMatrixFactory } from './change-matrix' +import { heatmapFactory } from './heatmap' +import { horizonGraphFactory } from './horizon-graph' +import { scatterplotFactory } from './scatterplot' +import { treemapFactory } from './treemap' // just pass them through export { @@ -29,8 +29,8 @@ export { deleteOnboardingStage, setOnboardingStage, setOnboardingMessage, - setEditMode, -}; + setEditMode +} /** * @@ -42,52 +42,51 @@ export const generateBasicAnnotations = ( visType: EVisualizationType, chart: any ): IOnboardingMessage[] => { - const coords = {}; - const visElement = chart._dom; + const coords = {} + const visElement = chart._dom // TODO: coords const chartTitlePosition = - chart._componentsMap["_ec_\u0000series\u00000\u00000_title"]?.group - .position; - coords["chartTitle"] = chartTitlePosition + chart._componentsMap['_ec_\u0000series\u00000\u00000_title']?.group + .position + coords.chartTitle = chartTitlePosition ? { x: chartTitlePosition[0], y: chartTitlePosition[1] + 20 } - : null; + : null - let onboardingMessages: IOnboardingMessage[]; + let onboardingMessages: IOnboardingMessage[] switch (visType) { case EVisualizationType.BAR_CHART: - onboardingMessages = barChartFactory(chart, coords, visElement); - break; + onboardingMessages = barChartFactory(chart, coords, visElement) + break case EVisualizationType.CHANGE_MATRIX: - onboardingMessages = changeMatrixFactory(chart, coords, visElement); - break; + onboardingMessages = changeMatrixFactory(chart, coords, visElement) + break case EVisualizationType.HORIZON_GRAPH: - onboardingMessages = horizonGraphFactory(chart, coords, visElement); - break; + onboardingMessages = horizonGraphFactory(chart, coords, visElement) + break case EVisualizationType.SCATTERPLOT: - onboardingMessages = scatterplotFactory(chart, coords, visElement); - break; + onboardingMessages = scatterplotFactory(chart, coords, visElement) + break case EVisualizationType.TREEMAP: - onboardingMessages = treemapFactory(chart, coords, visElement); - break; + onboardingMessages = treemapFactory(chart, coords, visElement) + break case EVisualizationType.HEATMAP: - debugger; - onboardingMessages = heatmapFactory(chart, coords, visElement); - break; + onboardingMessages = heatmapFactory(chart, coords, visElement) + break default: throw new Error( `No onboarding for visualization type ${visType} available.` - ); + ) } - return onboardingMessages; -}; + return onboardingMessages +} /** * @@ -95,13 +94,13 @@ export const generateBasicAnnotations = ( * @param chart * @param onboardingElement ID of the DOM Element where the onboarding Messages should be displayed */ -export async function ahoi( +export async function ahoi ( visType: EVisualizationType, chart: any, ahoiConfig: IAhoiConfig ) { - const visElement = chart._dom; - return injectOnboarding(ahoiConfig, visElement, "column"); + const visElement = chart._dom + return injectOnboarding(ahoiConfig, visElement, 'column') } -export { EVisualizationType }; +export { EVisualizationType } From 29300957b96b026dc4e50029ad2be38d9c1d9021 Mon Sep 17 00:00:00 2001 From: Silviya Geo Date: Sun, 11 Sep 2022 06:58:04 +0200 Subject: [PATCH 09/22] Added heatmap to vegalite --- packages/vega-demo/public/data/carsData.json | 4468 ++++++++++++++++++ packages/vega-demo/public/heatmap.html | 26 + packages/vega-demo/src/change-matrix.js | 62 +- packages/vega-demo/src/heatmap.js | 43 + packages/vega-demo/src/horizon-graph.js | 62 +- packages/vega-demo/src/index.js | 18 +- packages/vega-demo/src/scatterplot.js | 62 +- packages/vega-demo/src/treemap.js | 84 +- 8 files changed, 4683 insertions(+), 142 deletions(-) create mode 100644 packages/vega-demo/public/data/carsData.json create mode 100644 packages/vega-demo/public/heatmap.html create mode 100644 packages/vega-demo/src/heatmap.js diff --git a/packages/vega-demo/public/data/carsData.json b/packages/vega-demo/public/data/carsData.json new file mode 100644 index 00000000..66ca6f8f --- /dev/null +++ b/packages/vega-demo/public/data/carsData.json @@ -0,0 +1,4468 @@ +[ + { + "Name": "chevrolet chevelle malibu", + "Miles_per_Gallon": 18, + "Cylinders": 8, + "Displacement": 307, + "Horsepower": 130, + "Weight_in_lbs": 3504, + "Acceleration": 12, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "buick skylark 320", + "Miles_per_Gallon": 15, + "Cylinders": 8, + "Displacement": 350, + "Horsepower": 165, + "Weight_in_lbs": 3693, + "Acceleration": 11.5, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "plymouth satellite", + "Miles_per_Gallon": 18, + "Cylinders": 8, + "Displacement": 318, + "Horsepower": 150, + "Weight_in_lbs": 3436, + "Acceleration": 11, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "amc rebel sst", + "Miles_per_Gallon": 16, + "Cylinders": 8, + "Displacement": 304, + "Horsepower": 150, + "Weight_in_lbs": 3433, + "Acceleration": 12, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "ford torino", + "Miles_per_Gallon": 17, + "Cylinders": 8, + "Displacement": 302, + "Horsepower": 140, + "Weight_in_lbs": 3449, + "Acceleration": 10.5, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "ford galaxie 500", + "Miles_per_Gallon": 15, + "Cylinders": 8, + "Displacement": 429, + "Horsepower": 198, + "Weight_in_lbs": 4341, + "Acceleration": 10, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet impala", + "Miles_per_Gallon": 14, + "Cylinders": 8, + "Displacement": 454, + "Horsepower": 220, + "Weight_in_lbs": 4354, + "Acceleration": 9, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "plymouth fury iii", + "Miles_per_Gallon": 14, + "Cylinders": 8, + "Displacement": 440, + "Horsepower": 215, + "Weight_in_lbs": 4312, + "Acceleration": 8.5, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "pontiac catalina", + "Miles_per_Gallon": 14, + "Cylinders": 8, + "Displacement": 455, + "Horsepower": 225, + "Weight_in_lbs": 4425, + "Acceleration": 10, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "amc ambassador dpl", + "Miles_per_Gallon": 15, + "Cylinders": 8, + "Displacement": 390, + "Horsepower": 190, + "Weight_in_lbs": 3850, + "Acceleration": 8.5, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "citroen ds-21 pallas", + "Miles_per_Gallon": null, + "Cylinders": 4, + "Displacement": 133, + "Horsepower": 115, + "Weight_in_lbs": 3090, + "Acceleration": 17.5, + "Year": "1970-01-01", + "Origin": "Europe" + }, + { + "Name": "chevrolet chevelle concours (sw)", + "Miles_per_Gallon": null, + "Cylinders": 8, + "Displacement": 350, + "Horsepower": 165, + "Weight_in_lbs": 4142, + "Acceleration": 11.5, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "ford torino (sw)", + "Miles_per_Gallon": null, + "Cylinders": 8, + "Displacement": 351, + "Horsepower": 153, + "Weight_in_lbs": 4034, + "Acceleration": 11, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "plymouth satellite (sw)", + "Miles_per_Gallon": null, + "Cylinders": 8, + "Displacement": 383, + "Horsepower": 175, + "Weight_in_lbs": 4166, + "Acceleration": 10.5, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "amc rebel sst (sw)", + "Miles_per_Gallon": null, + "Cylinders": 8, + "Displacement": 360, + "Horsepower": 175, + "Weight_in_lbs": 3850, + "Acceleration": 11, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "dodge challenger se", + "Miles_per_Gallon": 15, + "Cylinders": 8, + "Displacement": 383, + "Horsepower": 170, + "Weight_in_lbs": 3563, + "Acceleration": 10, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "plymouth 'cuda 340", + "Miles_per_Gallon": 14, + "Cylinders": 8, + "Displacement": 340, + "Horsepower": 160, + "Weight_in_lbs": 3609, + "Acceleration": 8, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "ford mustang boss 302", + "Miles_per_Gallon": null, + "Cylinders": 8, + "Displacement": 302, + "Horsepower": 140, + "Weight_in_lbs": 3353, + "Acceleration": 8, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet monte carlo", + "Miles_per_Gallon": 15, + "Cylinders": 8, + "Displacement": 400, + "Horsepower": 150, + "Weight_in_lbs": 3761, + "Acceleration": 9.5, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "buick estate wagon (sw)", + "Miles_per_Gallon": 14, + "Cylinders": 8, + "Displacement": 455, + "Horsepower": 225, + "Weight_in_lbs": 3086, + "Acceleration": 10, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "toyota corona mark ii", + "Miles_per_Gallon": 24, + "Cylinders": 4, + "Displacement": 113, + "Horsepower": 95, + "Weight_in_lbs": 2372, + "Acceleration": 15, + "Year": "1970-01-01", + "Origin": "Japan" + }, + { + "Name": "plymouth duster", + "Miles_per_Gallon": 22, + "Cylinders": 6, + "Displacement": 198, + "Horsepower": 95, + "Weight_in_lbs": 2833, + "Acceleration": 15.5, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "amc hornet", + "Miles_per_Gallon": 18, + "Cylinders": 6, + "Displacement": 199, + "Horsepower": 97, + "Weight_in_lbs": 2774, + "Acceleration": 15.5, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "ford maverick", + "Miles_per_Gallon": 21, + "Cylinders": 6, + "Displacement": 200, + "Horsepower": 85, + "Weight_in_lbs": 2587, + "Acceleration": 16, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "datsun pl510", + "Miles_per_Gallon": 27, + "Cylinders": 4, + "Displacement": 97, + "Horsepower": 88, + "Weight_in_lbs": 2130, + "Acceleration": 14.5, + "Year": "1970-01-01", + "Origin": "Japan" + }, + { + "Name": "volkswagen 1131 deluxe sedan", + "Miles_per_Gallon": 26, + "Cylinders": 4, + "Displacement": 97, + "Horsepower": 46, + "Weight_in_lbs": 1835, + "Acceleration": 20.5, + "Year": "1970-01-01", + "Origin": "Europe" + }, + { + "Name": "peugeot 504", + "Miles_per_Gallon": 25, + "Cylinders": 4, + "Displacement": 110, + "Horsepower": 87, + "Weight_in_lbs": 2672, + "Acceleration": 17.5, + "Year": "1970-01-01", + "Origin": "Europe" + }, + { + "Name": "audi 100 ls", + "Miles_per_Gallon": 24, + "Cylinders": 4, + "Displacement": 107, + "Horsepower": 90, + "Weight_in_lbs": 2430, + "Acceleration": 14.5, + "Year": "1970-01-01", + "Origin": "Europe" + }, + { + "Name": "saab 99e", + "Miles_per_Gallon": 25, + "Cylinders": 4, + "Displacement": 104, + "Horsepower": 95, + "Weight_in_lbs": 2375, + "Acceleration": 17.5, + "Year": "1970-01-01", + "Origin": "Europe" + }, + { + "Name": "bmw 2002", + "Miles_per_Gallon": 26, + "Cylinders": 4, + "Displacement": 121, + "Horsepower": 113, + "Weight_in_lbs": 2234, + "Acceleration": 12.5, + "Year": "1970-01-01", + "Origin": "Europe" + }, + { + "Name": "amc gremlin", + "Miles_per_Gallon": 21, + "Cylinders": 6, + "Displacement": 199, + "Horsepower": 90, + "Weight_in_lbs": 2648, + "Acceleration": 15, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "ford f250", + "Miles_per_Gallon": 10, + "Cylinders": 8, + "Displacement": 360, + "Horsepower": 215, + "Weight_in_lbs": 4615, + "Acceleration": 14, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "chevy c20", + "Miles_per_Gallon": 10, + "Cylinders": 8, + "Displacement": 307, + "Horsepower": 200, + "Weight_in_lbs": 4376, + "Acceleration": 15, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "dodge d200", + "Miles_per_Gallon": 11, + "Cylinders": 8, + "Displacement": 318, + "Horsepower": 210, + "Weight_in_lbs": 4382, + "Acceleration": 13.5, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "hi 1200d", + "Miles_per_Gallon": 9, + "Cylinders": 8, + "Displacement": 304, + "Horsepower": 193, + "Weight_in_lbs": 4732, + "Acceleration": 18.5, + "Year": "1970-01-01", + "Origin": "USA" + }, + { + "Name": "datsun pl510", + "Miles_per_Gallon": 27, + "Cylinders": 4, + "Displacement": 97, + "Horsepower": 88, + "Weight_in_lbs": 2130, + "Acceleration": 14.5, + "Year": "1971-01-01", + "Origin": "Japan" + }, + { + "Name": "chevrolet vega 2300", + "Miles_per_Gallon": 28, + "Cylinders": 4, + "Displacement": 140, + "Horsepower": 90, + "Weight_in_lbs": 2264, + "Acceleration": 15.5, + "Year": "1971-01-01", + "Origin": "USA" + }, + { + "Name": "toyota corona", + "Miles_per_Gallon": 25, + "Cylinders": 4, + "Displacement": 113, + "Horsepower": 95, + "Weight_in_lbs": 2228, + "Acceleration": 14, + "Year": "1971-01-01", + "Origin": "Japan" + }, + { + "Name": "ford pinto", + "Miles_per_Gallon": 25, + "Cylinders": 4, + "Displacement": 98, + "Horsepower": 80, + "Weight_in_lbs": 2046, + "Acceleration": 19, + "Year": "1971-01-01", + "Origin": "USA" + }, + { + "Name": "volkswagen super beetle 117", + "Miles_per_Gallon": null, + "Cylinders": 4, + "Displacement": 97, + "Horsepower": 48, + "Weight_in_lbs": 1978, + "Acceleration": 20, + "Year": "1971-01-01", + "Origin": "Europe" + }, + { + "Name": "amc gremlin", + "Miles_per_Gallon": 19, + "Cylinders": 6, + "Displacement": 232, + "Horsepower": 100, + "Weight_in_lbs": 2634, + "Acceleration": 13, + "Year": "1971-01-01", + "Origin": "USA" + }, + { + "Name": "plymouth satellite custom", + "Miles_per_Gallon": 16, + "Cylinders": 6, + "Displacement": 225, + "Horsepower": 105, + "Weight_in_lbs": 3439, + "Acceleration": 15.5, + "Year": "1971-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet chevelle malibu", + "Miles_per_Gallon": 17, + "Cylinders": 6, + "Displacement": 250, + "Horsepower": 100, + "Weight_in_lbs": 3329, + "Acceleration": 15.5, + "Year": "1971-01-01", + "Origin": "USA" + }, + { + "Name": "ford torino 500", + "Miles_per_Gallon": 19, + "Cylinders": 6, + "Displacement": 250, + "Horsepower": 88, + "Weight_in_lbs": 3302, + "Acceleration": 15.5, + "Year": "1971-01-01", + "Origin": "USA" + }, + { + "Name": "amc matador", + "Miles_per_Gallon": 18, + "Cylinders": 6, + "Displacement": 232, + "Horsepower": 100, + "Weight_in_lbs": 3288, + "Acceleration": 15.5, + "Year": "1971-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet impala", + "Miles_per_Gallon": 14, + "Cylinders": 8, + "Displacement": 350, + "Horsepower": 165, + "Weight_in_lbs": 4209, + "Acceleration": 12, + "Year": "1971-01-01", + "Origin": "USA" + }, + { + "Name": "pontiac catalina brougham", + "Miles_per_Gallon": 14, + "Cylinders": 8, + "Displacement": 400, + "Horsepower": 175, + "Weight_in_lbs": 4464, + "Acceleration": 11.5, + "Year": "1971-01-01", + "Origin": "USA" + }, + { + "Name": "ford galaxie 500", + "Miles_per_Gallon": 14, + "Cylinders": 8, + "Displacement": 351, + "Horsepower": 153, + "Weight_in_lbs": 4154, + "Acceleration": 13.5, + "Year": "1971-01-01", + "Origin": "USA" + }, + { + "Name": "plymouth fury iii", + "Miles_per_Gallon": 14, + "Cylinders": 8, + "Displacement": 318, + "Horsepower": 150, + "Weight_in_lbs": 4096, + "Acceleration": 13, + "Year": "1971-01-01", + "Origin": "USA" + }, + { + "Name": "dodge monaco (sw)", + "Miles_per_Gallon": 12, + "Cylinders": 8, + "Displacement": 383, + "Horsepower": 180, + "Weight_in_lbs": 4955, + "Acceleration": 11.5, + "Year": "1971-01-01", + "Origin": "USA" + }, + { + "Name": "ford country squire (sw)", + "Miles_per_Gallon": 13, + "Cylinders": 8, + "Displacement": 400, + "Horsepower": 170, + "Weight_in_lbs": 4746, + "Acceleration": 12, + "Year": "1971-01-01", + "Origin": "USA" + }, + { + "Name": "pontiac safari (sw)", + "Miles_per_Gallon": 13, + "Cylinders": 8, + "Displacement": 400, + "Horsepower": 175, + "Weight_in_lbs": 5140, + "Acceleration": 12, + "Year": "1971-01-01", + "Origin": "USA" + }, + { + "Name": "amc hornet sportabout (sw)", + "Miles_per_Gallon": 18, + "Cylinders": 6, + "Displacement": 258, + "Horsepower": 110, + "Weight_in_lbs": 2962, + "Acceleration": 13.5, + "Year": "1971-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet vega (sw)", + "Miles_per_Gallon": 22, + "Cylinders": 4, + "Displacement": 140, + "Horsepower": 72, + "Weight_in_lbs": 2408, + "Acceleration": 19, + "Year": "1971-01-01", + "Origin": "USA" + }, + { + "Name": "pontiac firebird", + "Miles_per_Gallon": 19, + "Cylinders": 6, + "Displacement": 250, + "Horsepower": 100, + "Weight_in_lbs": 3282, + "Acceleration": 15, + "Year": "1971-01-01", + "Origin": "USA" + }, + { + "Name": "ford mustang", + "Miles_per_Gallon": 18, + "Cylinders": 6, + "Displacement": 250, + "Horsepower": 88, + "Weight_in_lbs": 3139, + "Acceleration": 14.5, + "Year": "1971-01-01", + "Origin": "USA" + }, + { + "Name": "mercury capri 2000", + "Miles_per_Gallon": 23, + "Cylinders": 4, + "Displacement": 122, + "Horsepower": 86, + "Weight_in_lbs": 2220, + "Acceleration": 14, + "Year": "1971-01-01", + "Origin": "USA" + }, + { + "Name": "opel 1900", + "Miles_per_Gallon": 28, + "Cylinders": 4, + "Displacement": 116, + "Horsepower": 90, + "Weight_in_lbs": 2123, + "Acceleration": 14, + "Year": "1971-01-01", + "Origin": "Europe" + }, + { + "Name": "peugeot 304", + "Miles_per_Gallon": 30, + "Cylinders": 4, + "Displacement": 79, + "Horsepower": 70, + "Weight_in_lbs": 2074, + "Acceleration": 19.5, + "Year": "1971-01-01", + "Origin": "Europe" + }, + { + "Name": "fiat 124b", + "Miles_per_Gallon": 30, + "Cylinders": 4, + "Displacement": 88, + "Horsepower": 76, + "Weight_in_lbs": 2065, + "Acceleration": 14.5, + "Year": "1971-01-01", + "Origin": "Europe" + }, + { + "Name": "toyota corolla 1200", + "Miles_per_Gallon": 31, + "Cylinders": 4, + "Displacement": 71, + "Horsepower": 65, + "Weight_in_lbs": 1773, + "Acceleration": 19, + "Year": "1971-01-01", + "Origin": "Japan" + }, + { + "Name": "datsun 1200", + "Miles_per_Gallon": 35, + "Cylinders": 4, + "Displacement": 72, + "Horsepower": 69, + "Weight_in_lbs": 1613, + "Acceleration": 18, + "Year": "1971-01-01", + "Origin": "Japan" + }, + { + "Name": "volkswagen model 111", + "Miles_per_Gallon": 27, + "Cylinders": 4, + "Displacement": 97, + "Horsepower": 60, + "Weight_in_lbs": 1834, + "Acceleration": 19, + "Year": "1971-01-01", + "Origin": "Europe" + }, + { + "Name": "plymouth cricket", + "Miles_per_Gallon": 26, + "Cylinders": 4, + "Displacement": 91, + "Horsepower": 70, + "Weight_in_lbs": 1955, + "Acceleration": 20.5, + "Year": "1971-01-01", + "Origin": "USA" + }, + { + "Name": "toyota corona hardtop", + "Miles_per_Gallon": 24, + "Cylinders": 4, + "Displacement": 113, + "Horsepower": 95, + "Weight_in_lbs": 2278, + "Acceleration": 15.5, + "Year": "1972-01-01", + "Origin": "Japan" + }, + { + "Name": "dodge colt hardtop", + "Miles_per_Gallon": 25, + "Cylinders": 4, + "Displacement": 97.5, + "Horsepower": 80, + "Weight_in_lbs": 2126, + "Acceleration": 17, + "Year": "1972-01-01", + "Origin": "USA" + }, + { + "Name": "volkswagen type 3", + "Miles_per_Gallon": 23, + "Cylinders": 4, + "Displacement": 97, + "Horsepower": 54, + "Weight_in_lbs": 2254, + "Acceleration": 23.5, + "Year": "1972-01-01", + "Origin": "Europe" + }, + { + "Name": "chevrolet vega", + "Miles_per_Gallon": 20, + "Cylinders": 4, + "Displacement": 140, + "Horsepower": 90, + "Weight_in_lbs": 2408, + "Acceleration": 19.5, + "Year": "1972-01-01", + "Origin": "USA" + }, + { + "Name": "ford pinto runabout", + "Miles_per_Gallon": 21, + "Cylinders": 4, + "Displacement": 122, + "Horsepower": 86, + "Weight_in_lbs": 2226, + "Acceleration": 16.5, + "Year": "1972-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet impala", + "Miles_per_Gallon": 13, + "Cylinders": 8, + "Displacement": 350, + "Horsepower": 165, + "Weight_in_lbs": 4274, + "Acceleration": 12, + "Year": "1972-01-01", + "Origin": "USA" + }, + { + "Name": "pontiac catalina", + "Miles_per_Gallon": 14, + "Cylinders": 8, + "Displacement": 400, + "Horsepower": 175, + "Weight_in_lbs": 4385, + "Acceleration": 12, + "Year": "1972-01-01", + "Origin": "USA" + }, + { + "Name": "plymouth fury iii", + "Miles_per_Gallon": 15, + "Cylinders": 8, + "Displacement": 318, + "Horsepower": 150, + "Weight_in_lbs": 4135, + "Acceleration": 13.5, + "Year": "1972-01-01", + "Origin": "USA" + }, + { + "Name": "ford galaxie 500", + "Miles_per_Gallon": 14, + "Cylinders": 8, + "Displacement": 351, + "Horsepower": 153, + "Weight_in_lbs": 4129, + "Acceleration": 13, + "Year": "1972-01-01", + "Origin": "USA" + }, + { + "Name": "amc ambassador sst", + "Miles_per_Gallon": 17, + "Cylinders": 8, + "Displacement": 304, + "Horsepower": 150, + "Weight_in_lbs": 3672, + "Acceleration": 11.5, + "Year": "1972-01-01", + "Origin": "USA" + }, + { + "Name": "mercury marquis", + "Miles_per_Gallon": 11, + "Cylinders": 8, + "Displacement": 429, + "Horsepower": 208, + "Weight_in_lbs": 4633, + "Acceleration": 11, + "Year": "1972-01-01", + "Origin": "USA" + }, + { + "Name": "buick lesabre custom", + "Miles_per_Gallon": 13, + "Cylinders": 8, + "Displacement": 350, + "Horsepower": 155, + "Weight_in_lbs": 4502, + "Acceleration": 13.5, + "Year": "1972-01-01", + "Origin": "USA" + }, + { + "Name": "oldsmobile delta 88 royale", + "Miles_per_Gallon": 12, + "Cylinders": 8, + "Displacement": 350, + "Horsepower": 160, + "Weight_in_lbs": 4456, + "Acceleration": 13.5, + "Year": "1972-01-01", + "Origin": "USA" + }, + { + "Name": "chrysler newport royal", + "Miles_per_Gallon": 13, + "Cylinders": 8, + "Displacement": 400, + "Horsepower": 190, + "Weight_in_lbs": 4422, + "Acceleration": 12.5, + "Year": "1972-01-01", + "Origin": "USA" + }, + { + "Name": "mazda rx2 coupe", + "Miles_per_Gallon": 19, + "Cylinders": 6, + "Displacement": 70, + "Horsepower": 97, + "Weight_in_lbs": 2330, + "Acceleration": 13.5, + "Year": "1972-01-01", + "Origin": "Japan" + }, + { + "Name": "amc matador (sw)", + "Miles_per_Gallon": 15, + "Cylinders": 8, + "Displacement": 304, + "Horsepower": 150, + "Weight_in_lbs": 3892, + "Acceleration": 12.5, + "Year": "1972-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet chevelle concours (sw)", + "Miles_per_Gallon": 13, + "Cylinders": 8, + "Displacement": 307, + "Horsepower": 130, + "Weight_in_lbs": 4098, + "Acceleration": 14, + "Year": "1972-01-01", + "Origin": "USA" + }, + { + "Name": "ford gran torino (sw)", + "Miles_per_Gallon": 13, + "Cylinders": 8, + "Displacement": 302, + "Horsepower": 140, + "Weight_in_lbs": 4294, + "Acceleration": 16, + "Year": "1972-01-01", + "Origin": "USA" + }, + { + "Name": "plymouth satellite custom (sw)", + "Miles_per_Gallon": 14, + "Cylinders": 8, + "Displacement": 318, + "Horsepower": 150, + "Weight_in_lbs": 4077, + "Acceleration": 14, + "Year": "1972-01-01", + "Origin": "USA" + }, + { + "Name": "volvo 145e (sw)", + "Miles_per_Gallon": 18, + "Cylinders": 4, + "Displacement": 121, + "Horsepower": 112, + "Weight_in_lbs": 2933, + "Acceleration": 14.5, + "Year": "1972-01-01", + "Origin": "Europe" + }, + { + "Name": "volkswagen 411 (sw)", + "Miles_per_Gallon": 22, + "Cylinders": 4, + "Displacement": 121, + "Horsepower": 76, + "Weight_in_lbs": 2511, + "Acceleration": 18, + "Year": "1972-01-01", + "Origin": "Europe" + }, + { + "Name": "peugeot 504 (sw)", + "Miles_per_Gallon": 21, + "Cylinders": 4, + "Displacement": 120, + "Horsepower": 87, + "Weight_in_lbs": 2979, + "Acceleration": 19.5, + "Year": "1972-01-01", + "Origin": "Europe" + }, + { + "Name": "renault 12 (sw)", + "Miles_per_Gallon": 26, + "Cylinders": 4, + "Displacement": 96, + "Horsepower": 69, + "Weight_in_lbs": 2189, + "Acceleration": 18, + "Year": "1972-01-01", + "Origin": "Europe" + }, + { + "Name": "ford pinto (sw)", + "Miles_per_Gallon": 22, + "Cylinders": 4, + "Displacement": 122, + "Horsepower": 86, + "Weight_in_lbs": 2395, + "Acceleration": 16, + "Year": "1972-01-01", + "Origin": "USA" + }, + { + "Name": "datsun 510 (sw)", + "Miles_per_Gallon": 28, + "Cylinders": 4, + "Displacement": 97, + "Horsepower": 92, + "Weight_in_lbs": 2288, + "Acceleration": 17, + "Year": "1972-01-01", + "Origin": "Japan" + }, + { + "Name": "toyouta corona mark ii (sw)", + "Miles_per_Gallon": 23, + "Cylinders": 4, + "Displacement": 120, + "Horsepower": 97, + "Weight_in_lbs": 2506, + "Acceleration": 14.5, + "Year": "1972-01-01", + "Origin": "Japan" + }, + { + "Name": "dodge colt (sw)", + "Miles_per_Gallon": 28, + "Cylinders": 4, + "Displacement": 98, + "Horsepower": 80, + "Weight_in_lbs": 2164, + "Acceleration": 15, + "Year": "1972-01-01", + "Origin": "USA" + }, + { + "Name": "toyota corolla 1600 (sw)", + "Miles_per_Gallon": 27, + "Cylinders": 4, + "Displacement": 97, + "Horsepower": 88, + "Weight_in_lbs": 2100, + "Acceleration": 16.5, + "Year": "1972-01-01", + "Origin": "Japan" + }, + { + "Name": "buick century 350", + "Miles_per_Gallon": 13, + "Cylinders": 8, + "Displacement": 350, + "Horsepower": 175, + "Weight_in_lbs": 4100, + "Acceleration": 13, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "amc matador", + "Miles_per_Gallon": 14, + "Cylinders": 8, + "Displacement": 304, + "Horsepower": 150, + "Weight_in_lbs": 3672, + "Acceleration": 11.5, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet malibu", + "Miles_per_Gallon": 13, + "Cylinders": 8, + "Displacement": 350, + "Horsepower": 145, + "Weight_in_lbs": 3988, + "Acceleration": 13, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "ford gran torino", + "Miles_per_Gallon": 14, + "Cylinders": 8, + "Displacement": 302, + "Horsepower": 137, + "Weight_in_lbs": 4042, + "Acceleration": 14.5, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "dodge coronet custom", + "Miles_per_Gallon": 15, + "Cylinders": 8, + "Displacement": 318, + "Horsepower": 150, + "Weight_in_lbs": 3777, + "Acceleration": 12.5, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "mercury marquis brougham", + "Miles_per_Gallon": 12, + "Cylinders": 8, + "Displacement": 429, + "Horsepower": 198, + "Weight_in_lbs": 4952, + "Acceleration": 11.5, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet caprice classic", + "Miles_per_Gallon": 13, + "Cylinders": 8, + "Displacement": 400, + "Horsepower": 150, + "Weight_in_lbs": 4464, + "Acceleration": 12, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "ford ltd", + "Miles_per_Gallon": 13, + "Cylinders": 8, + "Displacement": 351, + "Horsepower": 158, + "Weight_in_lbs": 4363, + "Acceleration": 13, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "plymouth fury gran sedan", + "Miles_per_Gallon": 14, + "Cylinders": 8, + "Displacement": 318, + "Horsepower": 150, + "Weight_in_lbs": 4237, + "Acceleration": 14.5, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "chrysler new yorker brougham", + "Miles_per_Gallon": 13, + "Cylinders": 8, + "Displacement": 440, + "Horsepower": 215, + "Weight_in_lbs": 4735, + "Acceleration": 11, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "buick electra 225 custom", + "Miles_per_Gallon": 12, + "Cylinders": 8, + "Displacement": 455, + "Horsepower": 225, + "Weight_in_lbs": 4951, + "Acceleration": 11, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "amc ambassador brougham", + "Miles_per_Gallon": 13, + "Cylinders": 8, + "Displacement": 360, + "Horsepower": 175, + "Weight_in_lbs": 3821, + "Acceleration": 11, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "plymouth valiant", + "Miles_per_Gallon": 18, + "Cylinders": 6, + "Displacement": 225, + "Horsepower": 105, + "Weight_in_lbs": 3121, + "Acceleration": 16.5, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet nova custom", + "Miles_per_Gallon": 16, + "Cylinders": 6, + "Displacement": 250, + "Horsepower": 100, + "Weight_in_lbs": 3278, + "Acceleration": 18, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "amc hornet", + "Miles_per_Gallon": 18, + "Cylinders": 6, + "Displacement": 232, + "Horsepower": 100, + "Weight_in_lbs": 2945, + "Acceleration": 16, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "ford maverick", + "Miles_per_Gallon": 18, + "Cylinders": 6, + "Displacement": 250, + "Horsepower": 88, + "Weight_in_lbs": 3021, + "Acceleration": 16.5, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "plymouth duster", + "Miles_per_Gallon": 23, + "Cylinders": 6, + "Displacement": 198, + "Horsepower": 95, + "Weight_in_lbs": 2904, + "Acceleration": 16, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "volkswagen super beetle", + "Miles_per_Gallon": 26, + "Cylinders": 4, + "Displacement": 97, + "Horsepower": 46, + "Weight_in_lbs": 1950, + "Acceleration": 21, + "Year": "1973-01-01", + "Origin": "Europe" + }, + { + "Name": "chevrolet impala", + "Miles_per_Gallon": 11, + "Cylinders": 8, + "Displacement": 400, + "Horsepower": 150, + "Weight_in_lbs": 4997, + "Acceleration": 14, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "ford country", + "Miles_per_Gallon": 12, + "Cylinders": 8, + "Displacement": 400, + "Horsepower": 167, + "Weight_in_lbs": 4906, + "Acceleration": 12.5, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "plymouth custom suburb", + "Miles_per_Gallon": 13, + "Cylinders": 8, + "Displacement": 360, + "Horsepower": 170, + "Weight_in_lbs": 4654, + "Acceleration": 13, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "oldsmobile vista cruiser", + "Miles_per_Gallon": 12, + "Cylinders": 8, + "Displacement": 350, + "Horsepower": 180, + "Weight_in_lbs": 4499, + "Acceleration": 12.5, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "amc gremlin", + "Miles_per_Gallon": 18, + "Cylinders": 6, + "Displacement": 232, + "Horsepower": 100, + "Weight_in_lbs": 2789, + "Acceleration": 15, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "toyota carina", + "Miles_per_Gallon": 20, + "Cylinders": 4, + "Displacement": 97, + "Horsepower": 88, + "Weight_in_lbs": 2279, + "Acceleration": 19, + "Year": "1973-01-01", + "Origin": "Japan" + }, + { + "Name": "chevrolet vega", + "Miles_per_Gallon": 21, + "Cylinders": 4, + "Displacement": 140, + "Horsepower": 72, + "Weight_in_lbs": 2401, + "Acceleration": 19.5, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "datsun 610", + "Miles_per_Gallon": 22, + "Cylinders": 4, + "Displacement": 108, + "Horsepower": 94, + "Weight_in_lbs": 2379, + "Acceleration": 16.5, + "Year": "1973-01-01", + "Origin": "Japan" + }, + { + "Name": "maxda rx3", + "Miles_per_Gallon": 18, + "Cylinders": 6, + "Displacement": 70, + "Horsepower": 90, + "Weight_in_lbs": 2124, + "Acceleration": 13.5, + "Year": "1973-01-01", + "Origin": "Japan" + }, + { + "Name": "ford pinto", + "Miles_per_Gallon": 19, + "Cylinders": 4, + "Displacement": 122, + "Horsepower": 85, + "Weight_in_lbs": 2310, + "Acceleration": 18.5, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "mercury capri v6", + "Miles_per_Gallon": 21, + "Cylinders": 6, + "Displacement": 155, + "Horsepower": 107, + "Weight_in_lbs": 2472, + "Acceleration": 14, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "fiat 124 sport coupe", + "Miles_per_Gallon": 26, + "Cylinders": 4, + "Displacement": 98, + "Horsepower": 90, + "Weight_in_lbs": 2265, + "Acceleration": 15.5, + "Year": "1973-01-01", + "Origin": "Europe" + }, + { + "Name": "chevrolet monte carlo s", + "Miles_per_Gallon": 15, + "Cylinders": 8, + "Displacement": 350, + "Horsepower": 145, + "Weight_in_lbs": 4082, + "Acceleration": 13, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "pontiac grand prix", + "Miles_per_Gallon": 16, + "Cylinders": 8, + "Displacement": 400, + "Horsepower": 230, + "Weight_in_lbs": 4278, + "Acceleration": 9.5, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "fiat 128", + "Miles_per_Gallon": 29, + "Cylinders": 4, + "Displacement": 68, + "Horsepower": 49, + "Weight_in_lbs": 1867, + "Acceleration": 19.5, + "Year": "1973-01-01", + "Origin": "Europe" + }, + { + "Name": "opel manta", + "Miles_per_Gallon": 24, + "Cylinders": 4, + "Displacement": 116, + "Horsepower": 75, + "Weight_in_lbs": 2158, + "Acceleration": 15.5, + "Year": "1973-01-01", + "Origin": "Europe" + }, + { + "Name": "audi 100ls", + "Miles_per_Gallon": 20, + "Cylinders": 4, + "Displacement": 114, + "Horsepower": 91, + "Weight_in_lbs": 2582, + "Acceleration": 14, + "Year": "1973-01-01", + "Origin": "Europe" + }, + { + "Name": "volvo 144ea", + "Miles_per_Gallon": 19, + "Cylinders": 4, + "Displacement": 121, + "Horsepower": 112, + "Weight_in_lbs": 2868, + "Acceleration": 15.5, + "Year": "1973-01-01", + "Origin": "Europe" + }, + { + "Name": "dodge dart custom", + "Miles_per_Gallon": 15, + "Cylinders": 8, + "Displacement": 318, + "Horsepower": 150, + "Weight_in_lbs": 3399, + "Acceleration": 11, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "saab 99le", + "Miles_per_Gallon": 24, + "Cylinders": 4, + "Displacement": 121, + "Horsepower": 110, + "Weight_in_lbs": 2660, + "Acceleration": 14, + "Year": "1973-01-01", + "Origin": "Europe" + }, + { + "Name": "toyota mark ii", + "Miles_per_Gallon": 20, + "Cylinders": 6, + "Displacement": 156, + "Horsepower": 122, + "Weight_in_lbs": 2807, + "Acceleration": 13.5, + "Year": "1973-01-01", + "Origin": "Japan" + }, + { + "Name": "oldsmobile omega", + "Miles_per_Gallon": 11, + "Cylinders": 8, + "Displacement": 350, + "Horsepower": 180, + "Weight_in_lbs": 3664, + "Acceleration": 11, + "Year": "1973-01-01", + "Origin": "USA" + }, + { + "Name": "plymouth duster", + "Miles_per_Gallon": 20, + "Cylinders": 6, + "Displacement": 198, + "Horsepower": 95, + "Weight_in_lbs": 3102, + "Acceleration": 16.5, + "Year": "1974-01-01", + "Origin": "USA" + }, + { + "Name": "ford maverick", + "Miles_per_Gallon": 21, + "Cylinders": 6, + "Displacement": 200, + "Horsepower": 76, + "Weight_in_lbs": 2875, + "Acceleration": 17, + "Year": "1974-01-01", + "Origin": "USA" + }, + { + "Name": "amc hornet", + "Miles_per_Gallon": 19, + "Cylinders": 6, + "Displacement": 232, + "Horsepower": 100, + "Weight_in_lbs": 2901, + "Acceleration": 16, + "Year": "1974-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet nova", + "Miles_per_Gallon": 15, + "Cylinders": 6, + "Displacement": 250, + "Horsepower": 100, + "Weight_in_lbs": 3336, + "Acceleration": 17, + "Year": "1974-01-01", + "Origin": "USA" + }, + { + "Name": "datsun b210", + "Miles_per_Gallon": 31, + "Cylinders": 4, + "Displacement": 79, + "Horsepower": 67, + "Weight_in_lbs": 1950, + "Acceleration": 19, + "Year": "1974-01-01", + "Origin": "Japan" + }, + { + "Name": "ford pinto", + "Miles_per_Gallon": 26, + "Cylinders": 4, + "Displacement": 122, + "Horsepower": 80, + "Weight_in_lbs": 2451, + "Acceleration": 16.5, + "Year": "1974-01-01", + "Origin": "USA" + }, + { + "Name": "toyota corolla 1200", + "Miles_per_Gallon": 32, + "Cylinders": 4, + "Displacement": 71, + "Horsepower": 65, + "Weight_in_lbs": 1836, + "Acceleration": 21, + "Year": "1974-01-01", + "Origin": "Japan" + }, + { + "Name": "chevrolet vega", + "Miles_per_Gallon": 25, + "Cylinders": 4, + "Displacement": 140, + "Horsepower": 75, + "Weight_in_lbs": 2542, + "Acceleration": 17, + "Year": "1974-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet chevelle malibu classic", + "Miles_per_Gallon": 16, + "Cylinders": 6, + "Displacement": 250, + "Horsepower": 100, + "Weight_in_lbs": 3781, + "Acceleration": 17, + "Year": "1974-01-01", + "Origin": "USA" + }, + { + "Name": "amc matador", + "Miles_per_Gallon": 16, + "Cylinders": 6, + "Displacement": 258, + "Horsepower": 110, + "Weight_in_lbs": 3632, + "Acceleration": 18, + "Year": "1974-01-01", + "Origin": "USA" + }, + { + "Name": "plymouth satellite sebring", + "Miles_per_Gallon": 18, + "Cylinders": 6, + "Displacement": 225, + "Horsepower": 105, + "Weight_in_lbs": 3613, + "Acceleration": 16.5, + "Year": "1974-01-01", + "Origin": "USA" + }, + { + "Name": "ford gran torino", + "Miles_per_Gallon": 16, + "Cylinders": 8, + "Displacement": 302, + "Horsepower": 140, + "Weight_in_lbs": 4141, + "Acceleration": 14, + "Year": "1974-01-01", + "Origin": "USA" + }, + { + "Name": "buick century luxus (sw)", + "Miles_per_Gallon": 13, + "Cylinders": 8, + "Displacement": 350, + "Horsepower": 150, + "Weight_in_lbs": 4699, + "Acceleration": 14.5, + "Year": "1974-01-01", + "Origin": "USA" + }, + { + "Name": "dodge coronet custom (sw)", + "Miles_per_Gallon": 14, + "Cylinders": 8, + "Displacement": 318, + "Horsepower": 150, + "Weight_in_lbs": 4457, + "Acceleration": 13.5, + "Year": "1974-01-01", + "Origin": "USA" + }, + { + "Name": "ford gran torino (sw)", + "Miles_per_Gallon": 14, + "Cylinders": 8, + "Displacement": 302, + "Horsepower": 140, + "Weight_in_lbs": 4638, + "Acceleration": 16, + "Year": "1974-01-01", + "Origin": "USA" + }, + { + "Name": "amc matador (sw)", + "Miles_per_Gallon": 14, + "Cylinders": 8, + "Displacement": 304, + "Horsepower": 150, + "Weight_in_lbs": 4257, + "Acceleration": 15.5, + "Year": "1974-01-01", + "Origin": "USA" + }, + { + "Name": "audi fox", + "Miles_per_Gallon": 29, + "Cylinders": 4, + "Displacement": 98, + "Horsepower": 83, + "Weight_in_lbs": 2219, + "Acceleration": 16.5, + "Year": "1974-01-01", + "Origin": "Europe" + }, + { + "Name": "volkswagen dasher", + "Miles_per_Gallon": 26, + "Cylinders": 4, + "Displacement": 79, + "Horsepower": 67, + "Weight_in_lbs": 1963, + "Acceleration": 15.5, + "Year": "1974-01-01", + "Origin": "Europe" + }, + { + "Name": "opel manta", + "Miles_per_Gallon": 26, + "Cylinders": 4, + "Displacement": 97, + "Horsepower": 78, + "Weight_in_lbs": 2300, + "Acceleration": 14.5, + "Year": "1974-01-01", + "Origin": "Europe" + }, + { + "Name": "toyota corona", + "Miles_per_Gallon": 31, + "Cylinders": 4, + "Displacement": 76, + "Horsepower": 52, + "Weight_in_lbs": 1649, + "Acceleration": 16.5, + "Year": "1974-01-01", + "Origin": "Japan" + }, + { + "Name": "datsun 710", + "Miles_per_Gallon": 32, + "Cylinders": 4, + "Displacement": 83, + "Horsepower": 61, + "Weight_in_lbs": 2003, + "Acceleration": 19, + "Year": "1974-01-01", + "Origin": "Japan" + }, + { + "Name": "dodge colt", + "Miles_per_Gallon": 28, + "Cylinders": 4, + "Displacement": 90, + "Horsepower": 75, + "Weight_in_lbs": 2125, + "Acceleration": 14.5, + "Year": "1974-01-01", + "Origin": "USA" + }, + { + "Name": "fiat 128", + "Miles_per_Gallon": 24, + "Cylinders": 4, + "Displacement": 90, + "Horsepower": 75, + "Weight_in_lbs": 2108, + "Acceleration": 15.5, + "Year": "1974-01-01", + "Origin": "Europe" + }, + { + "Name": "fiat 124 tc", + "Miles_per_Gallon": 26, + "Cylinders": 4, + "Displacement": 116, + "Horsepower": 75, + "Weight_in_lbs": 2246, + "Acceleration": 14, + "Year": "1974-01-01", + "Origin": "Europe" + }, + { + "Name": "honda civic", + "Miles_per_Gallon": 24, + "Cylinders": 4, + "Displacement": 120, + "Horsepower": 97, + "Weight_in_lbs": 2489, + "Acceleration": 15, + "Year": "1974-01-01", + "Origin": "Japan" + }, + { + "Name": "subaru", + "Miles_per_Gallon": 26, + "Cylinders": 4, + "Displacement": 108, + "Horsepower": 93, + "Weight_in_lbs": 2391, + "Acceleration": 15.5, + "Year": "1974-01-01", + "Origin": "Japan" + }, + { + "Name": "fiat x1.9", + "Miles_per_Gallon": 31, + "Cylinders": 4, + "Displacement": 79, + "Horsepower": 67, + "Weight_in_lbs": 2000, + "Acceleration": 16, + "Year": "1974-01-01", + "Origin": "Europe" + }, + { + "Name": "plymouth valiant custom", + "Miles_per_Gallon": 19, + "Cylinders": 6, + "Displacement": 225, + "Horsepower": 95, + "Weight_in_lbs": 3264, + "Acceleration": 16, + "Year": "1975-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet nova", + "Miles_per_Gallon": 18, + "Cylinders": 6, + "Displacement": 250, + "Horsepower": 105, + "Weight_in_lbs": 3459, + "Acceleration": 16, + "Year": "1975-01-01", + "Origin": "USA" + }, + { + "Name": "mercury monarch", + "Miles_per_Gallon": 15, + "Cylinders": 6, + "Displacement": 250, + "Horsepower": 72, + "Weight_in_lbs": 3432, + "Acceleration": 21, + "Year": "1975-01-01", + "Origin": "USA" + }, + { + "Name": "ford maverick", + "Miles_per_Gallon": 15, + "Cylinders": 6, + "Displacement": 250, + "Horsepower": 72, + "Weight_in_lbs": 3158, + "Acceleration": 19.5, + "Year": "1975-01-01", + "Origin": "USA" + }, + { + "Name": "pontiac catalina", + "Miles_per_Gallon": 16, + "Cylinders": 8, + "Displacement": 400, + "Horsepower": 170, + "Weight_in_lbs": 4668, + "Acceleration": 11.5, + "Year": "1975-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet bel air", + "Miles_per_Gallon": 15, + "Cylinders": 8, + "Displacement": 350, + "Horsepower": 145, + "Weight_in_lbs": 4440, + "Acceleration": 14, + "Year": "1975-01-01", + "Origin": "USA" + }, + { + "Name": "plymouth grand fury", + "Miles_per_Gallon": 16, + "Cylinders": 8, + "Displacement": 318, + "Horsepower": 150, + "Weight_in_lbs": 4498, + "Acceleration": 14.5, + "Year": "1975-01-01", + "Origin": "USA" + }, + { + "Name": "ford ltd", + "Miles_per_Gallon": 14, + "Cylinders": 8, + "Displacement": 351, + "Horsepower": 148, + "Weight_in_lbs": 4657, + "Acceleration": 13.5, + "Year": "1975-01-01", + "Origin": "USA" + }, + { + "Name": "buick century", + "Miles_per_Gallon": 17, + "Cylinders": 6, + "Displacement": 231, + "Horsepower": 110, + "Weight_in_lbs": 3907, + "Acceleration": 21, + "Year": "1975-01-01", + "Origin": "USA" + }, + { + "Name": "chevroelt chevelle malibu", + "Miles_per_Gallon": 16, + "Cylinders": 6, + "Displacement": 250, + "Horsepower": 105, + "Weight_in_lbs": 3897, + "Acceleration": 18.5, + "Year": "1975-01-01", + "Origin": "USA" + }, + { + "Name": "amc matador", + "Miles_per_Gallon": 15, + "Cylinders": 6, + "Displacement": 258, + "Horsepower": 110, + "Weight_in_lbs": 3730, + "Acceleration": 19, + "Year": "1975-01-01", + "Origin": "USA" + }, + { + "Name": "plymouth fury", + "Miles_per_Gallon": 18, + "Cylinders": 6, + "Displacement": 225, + "Horsepower": 95, + "Weight_in_lbs": 3785, + "Acceleration": 19, + "Year": "1975-01-01", + "Origin": "USA" + }, + { + "Name": "buick skyhawk", + "Miles_per_Gallon": 21, + "Cylinders": 6, + "Displacement": 231, + "Horsepower": 110, + "Weight_in_lbs": 3039, + "Acceleration": 15, + "Year": "1975-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet monza 2+2", + "Miles_per_Gallon": 20, + "Cylinders": 8, + "Displacement": 262, + "Horsepower": 110, + "Weight_in_lbs": 3221, + "Acceleration": 13.5, + "Year": "1975-01-01", + "Origin": "USA" + }, + { + "Name": "ford mustang ii", + "Miles_per_Gallon": 13, + "Cylinders": 8, + "Displacement": 302, + "Horsepower": 129, + "Weight_in_lbs": 3169, + "Acceleration": 12, + "Year": "1975-01-01", + "Origin": "USA" + }, + { + "Name": "toyota corolla", + "Miles_per_Gallon": 29, + "Cylinders": 4, + "Displacement": 97, + "Horsepower": 75, + "Weight_in_lbs": 2171, + "Acceleration": 16, + "Year": "1975-01-01", + "Origin": "Japan" + }, + { + "Name": "ford pinto", + "Miles_per_Gallon": 23, + "Cylinders": 4, + "Displacement": 140, + "Horsepower": 83, + "Weight_in_lbs": 2639, + "Acceleration": 17, + "Year": "1975-01-01", + "Origin": "USA" + }, + { + "Name": "amc gremlin", + "Miles_per_Gallon": 20, + "Cylinders": 6, + "Displacement": 232, + "Horsepower": 100, + "Weight_in_lbs": 2914, + "Acceleration": 16, + "Year": "1975-01-01", + "Origin": "USA" + }, + { + "Name": "pontiac astro", + "Miles_per_Gallon": 23, + "Cylinders": 4, + "Displacement": 140, + "Horsepower": 78, + "Weight_in_lbs": 2592, + "Acceleration": 18.5, + "Year": "1975-01-01", + "Origin": "USA" + }, + { + "Name": "toyota corona", + "Miles_per_Gallon": 24, + "Cylinders": 4, + "Displacement": 134, + "Horsepower": 96, + "Weight_in_lbs": 2702, + "Acceleration": 13.5, + "Year": "1975-01-01", + "Origin": "Japan" + }, + { + "Name": "volkswagen dasher", + "Miles_per_Gallon": 25, + "Cylinders": 4, + "Displacement": 90, + "Horsepower": 71, + "Weight_in_lbs": 2223, + "Acceleration": 16.5, + "Year": "1975-01-01", + "Origin": "Europe" + }, + { + "Name": "datsun 710", + "Miles_per_Gallon": 24, + "Cylinders": 4, + "Displacement": 119, + "Horsepower": 97, + "Weight_in_lbs": 2545, + "Acceleration": 17, + "Year": "1975-01-01", + "Origin": "Japan" + }, + { + "Name": "ford pinto", + "Miles_per_Gallon": 18, + "Cylinders": 6, + "Displacement": 171, + "Horsepower": 97, + "Weight_in_lbs": 2984, + "Acceleration": 14.5, + "Year": "1975-01-01", + "Origin": "USA" + }, + { + "Name": "volkswagen rabbit", + "Miles_per_Gallon": 29, + "Cylinders": 4, + "Displacement": 90, + "Horsepower": 70, + "Weight_in_lbs": 1937, + "Acceleration": 14, + "Year": "1975-01-01", + "Origin": "Europe" + }, + { + "Name": "amc pacer", + "Miles_per_Gallon": 19, + "Cylinders": 6, + "Displacement": 232, + "Horsepower": 90, + "Weight_in_lbs": 3211, + "Acceleration": 17, + "Year": "1975-01-01", + "Origin": "USA" + }, + { + "Name": "audi 100ls", + "Miles_per_Gallon": 23, + "Cylinders": 4, + "Displacement": 115, + "Horsepower": 95, + "Weight_in_lbs": 2694, + "Acceleration": 15, + "Year": "1975-01-01", + "Origin": "Europe" + }, + { + "Name": "peugeot 504", + "Miles_per_Gallon": 23, + "Cylinders": 4, + "Displacement": 120, + "Horsepower": 88, + "Weight_in_lbs": 2957, + "Acceleration": 17, + "Year": "1975-01-01", + "Origin": "Europe" + }, + { + "Name": "volvo 244dl", + "Miles_per_Gallon": 22, + "Cylinders": 4, + "Displacement": 121, + "Horsepower": 98, + "Weight_in_lbs": 2945, + "Acceleration": 14.5, + "Year": "1975-01-01", + "Origin": "Europe" + }, + { + "Name": "saab 99le", + "Miles_per_Gallon": 25, + "Cylinders": 4, + "Displacement": 121, + "Horsepower": 115, + "Weight_in_lbs": 2671, + "Acceleration": 13.5, + "Year": "1975-01-01", + "Origin": "Europe" + }, + { + "Name": "honda civic cvcc", + "Miles_per_Gallon": 33, + "Cylinders": 4, + "Displacement": 91, + "Horsepower": 53, + "Weight_in_lbs": 1795, + "Acceleration": 17.5, + "Year": "1975-01-01", + "Origin": "Japan" + }, + { + "Name": "fiat 131", + "Miles_per_Gallon": 28, + "Cylinders": 4, + "Displacement": 107, + "Horsepower": 86, + "Weight_in_lbs": 2464, + "Acceleration": 15.5, + "Year": "1976-01-01", + "Origin": "Europe" + }, + { + "Name": "opel 1900", + "Miles_per_Gallon": 25, + "Cylinders": 4, + "Displacement": 116, + "Horsepower": 81, + "Weight_in_lbs": 2220, + "Acceleration": 16.9, + "Year": "1976-01-01", + "Origin": "Europe" + }, + { + "Name": "capri ii", + "Miles_per_Gallon": 25, + "Cylinders": 4, + "Displacement": 140, + "Horsepower": 92, + "Weight_in_lbs": 2572, + "Acceleration": 14.9, + "Year": "1976-01-01", + "Origin": "USA" + }, + { + "Name": "dodge colt", + "Miles_per_Gallon": 26, + "Cylinders": 4, + "Displacement": 98, + "Horsepower": 79, + "Weight_in_lbs": 2255, + "Acceleration": 17.7, + "Year": "1976-01-01", + "Origin": "USA" + }, + { + "Name": "renault 12tl", + "Miles_per_Gallon": 27, + "Cylinders": 4, + "Displacement": 101, + "Horsepower": 83, + "Weight_in_lbs": 2202, + "Acceleration": 15.3, + "Year": "1976-01-01", + "Origin": "Europe" + }, + { + "Name": "chevrolet chevelle malibu classic", + "Miles_per_Gallon": 17.5, + "Cylinders": 8, + "Displacement": 305, + "Horsepower": 140, + "Weight_in_lbs": 4215, + "Acceleration": 13, + "Year": "1976-01-01", + "Origin": "USA" + }, + { + "Name": "dodge coronet brougham", + "Miles_per_Gallon": 16, + "Cylinders": 8, + "Displacement": 318, + "Horsepower": 150, + "Weight_in_lbs": 4190, + "Acceleration": 13, + "Year": "1976-01-01", + "Origin": "USA" + }, + { + "Name": "amc matador", + "Miles_per_Gallon": 15.5, + "Cylinders": 8, + "Displacement": 304, + "Horsepower": 120, + "Weight_in_lbs": 3962, + "Acceleration": 13.9, + "Year": "1976-01-01", + "Origin": "USA" + }, + { + "Name": "ford gran torino", + "Miles_per_Gallon": 14.5, + "Cylinders": 8, + "Displacement": 351, + "Horsepower": 152, + "Weight_in_lbs": 4215, + "Acceleration": 12.8, + "Year": "1976-01-01", + "Origin": "USA" + }, + { + "Name": "plymouth valiant", + "Miles_per_Gallon": 22, + "Cylinders": 6, + "Displacement": 225, + "Horsepower": 100, + "Weight_in_lbs": 3233, + "Acceleration": 15.4, + "Year": "1976-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet nova", + "Miles_per_Gallon": 22, + "Cylinders": 6, + "Displacement": 250, + "Horsepower": 105, + "Weight_in_lbs": 3353, + "Acceleration": 14.5, + "Year": "1976-01-01", + "Origin": "USA" + }, + { + "Name": "ford maverick", + "Miles_per_Gallon": 24, + "Cylinders": 6, + "Displacement": 200, + "Horsepower": 81, + "Weight_in_lbs": 3012, + "Acceleration": 17.6, + "Year": "1976-01-01", + "Origin": "USA" + }, + { + "Name": "amc hornet", + "Miles_per_Gallon": 22.5, + "Cylinders": 6, + "Displacement": 232, + "Horsepower": 90, + "Weight_in_lbs": 3085, + "Acceleration": 17.6, + "Year": "1976-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet chevette", + "Miles_per_Gallon": 29, + "Cylinders": 4, + "Displacement": 85, + "Horsepower": 52, + "Weight_in_lbs": 2035, + "Acceleration": 22.2, + "Year": "1976-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet woody", + "Miles_per_Gallon": 24.5, + "Cylinders": 4, + "Displacement": 98, + "Horsepower": 60, + "Weight_in_lbs": 2164, + "Acceleration": 22.1, + "Year": "1976-01-01", + "Origin": "USA" + }, + { + "Name": "vw rabbit", + "Miles_per_Gallon": 29, + "Cylinders": 4, + "Displacement": 90, + "Horsepower": 70, + "Weight_in_lbs": 1937, + "Acceleration": 14.2, + "Year": "1976-01-01", + "Origin": "Europe" + }, + { + "Name": "honda civic", + "Miles_per_Gallon": 33, + "Cylinders": 4, + "Displacement": 91, + "Horsepower": 53, + "Weight_in_lbs": 1795, + "Acceleration": 17.4, + "Year": "1976-01-01", + "Origin": "Japan" + }, + { + "Name": "dodge aspen se", + "Miles_per_Gallon": 20, + "Cylinders": 6, + "Displacement": 225, + "Horsepower": 100, + "Weight_in_lbs": 3651, + "Acceleration": 17.7, + "Year": "1976-01-01", + "Origin": "USA" + }, + { + "Name": "ford granada ghia", + "Miles_per_Gallon": 18, + "Cylinders": 6, + "Displacement": 250, + "Horsepower": 78, + "Weight_in_lbs": 3574, + "Acceleration": 21, + "Year": "1976-01-01", + "Origin": "USA" + }, + { + "Name": "pontiac ventura sj", + "Miles_per_Gallon": 18.5, + "Cylinders": 6, + "Displacement": 250, + "Horsepower": 110, + "Weight_in_lbs": 3645, + "Acceleration": 16.2, + "Year": "1976-01-01", + "Origin": "USA" + }, + { + "Name": "amc pacer d/l", + "Miles_per_Gallon": 17.5, + "Cylinders": 6, + "Displacement": 258, + "Horsepower": 95, + "Weight_in_lbs": 3193, + "Acceleration": 17.8, + "Year": "1976-01-01", + "Origin": "USA" + }, + { + "Name": "volkswagen rabbit", + "Miles_per_Gallon": 29.5, + "Cylinders": 4, + "Displacement": 97, + "Horsepower": 71, + "Weight_in_lbs": 1825, + "Acceleration": 12.2, + "Year": "1976-01-01", + "Origin": "Europe" + }, + { + "Name": "datsun b-210", + "Miles_per_Gallon": 32, + "Cylinders": 4, + "Displacement": 85, + "Horsepower": 70, + "Weight_in_lbs": 1990, + "Acceleration": 17, + "Year": "1976-01-01", + "Origin": "Japan" + }, + { + "Name": "toyota corolla", + "Miles_per_Gallon": 28, + "Cylinders": 4, + "Displacement": 97, + "Horsepower": 75, + "Weight_in_lbs": 2155, + "Acceleration": 16.4, + "Year": "1976-01-01", + "Origin": "Japan" + }, + { + "Name": "ford pinto", + "Miles_per_Gallon": 26.5, + "Cylinders": 4, + "Displacement": 140, + "Horsepower": 72, + "Weight_in_lbs": 2565, + "Acceleration": 13.6, + "Year": "1976-01-01", + "Origin": "USA" + }, + { + "Name": "volvo 245", + "Miles_per_Gallon": 20, + "Cylinders": 4, + "Displacement": 130, + "Horsepower": 102, + "Weight_in_lbs": 3150, + "Acceleration": 15.7, + "Year": "1976-01-01", + "Origin": "Europe" + }, + { + "Name": "plymouth volare premier v8", + "Miles_per_Gallon": 13, + "Cylinders": 8, + "Displacement": 318, + "Horsepower": 150, + "Weight_in_lbs": 3940, + "Acceleration": 13.2, + "Year": "1976-01-01", + "Origin": "USA" + }, + { + "Name": "peugeot 504", + "Miles_per_Gallon": 19, + "Cylinders": 4, + "Displacement": 120, + "Horsepower": 88, + "Weight_in_lbs": 3270, + "Acceleration": 21.9, + "Year": "1976-01-01", + "Origin": "Europe" + }, + { + "Name": "toyota mark ii", + "Miles_per_Gallon": 19, + "Cylinders": 6, + "Displacement": 156, + "Horsepower": 108, + "Weight_in_lbs": 2930, + "Acceleration": 15.5, + "Year": "1976-01-01", + "Origin": "Japan" + }, + { + "Name": "mercedes-benz 280s", + "Miles_per_Gallon": 16.5, + "Cylinders": 6, + "Displacement": 168, + "Horsepower": 120, + "Weight_in_lbs": 3820, + "Acceleration": 16.7, + "Year": "1976-01-01", + "Origin": "Europe" + }, + { + "Name": "cadillac seville", + "Miles_per_Gallon": 16.5, + "Cylinders": 8, + "Displacement": 350, + "Horsepower": 180, + "Weight_in_lbs": 4380, + "Acceleration": 12.1, + "Year": "1976-01-01", + "Origin": "USA" + }, + { + "Name": "chevy c10", + "Miles_per_Gallon": 13, + "Cylinders": 8, + "Displacement": 350, + "Horsepower": 145, + "Weight_in_lbs": 4055, + "Acceleration": 12, + "Year": "1976-01-01", + "Origin": "USA" + }, + { + "Name": "ford f108", + "Miles_per_Gallon": 13, + "Cylinders": 8, + "Displacement": 302, + "Horsepower": 130, + "Weight_in_lbs": 3870, + "Acceleration": 15, + "Year": "1976-01-01", + "Origin": "USA" + }, + { + "Name": "dodge d100", + "Miles_per_Gallon": 13, + "Cylinders": 8, + "Displacement": 318, + "Horsepower": 150, + "Weight_in_lbs": 3755, + "Acceleration": 14, + "Year": "1976-01-01", + "Origin": "USA" + }, + { + "Name": "honda Accelerationord cvcc", + "Miles_per_Gallon": 31.5, + "Cylinders": 4, + "Displacement": 98, + "Horsepower": 68, + "Weight_in_lbs": 2045, + "Acceleration": 18.5, + "Year": "1977-01-01", + "Origin": "Japan" + }, + { + "Name": "buick opel isuzu deluxe", + "Miles_per_Gallon": 30, + "Cylinders": 4, + "Displacement": 111, + "Horsepower": 80, + "Weight_in_lbs": 2155, + "Acceleration": 14.8, + "Year": "1977-01-01", + "Origin": "USA" + }, + { + "Name": "renault 5 gtl", + "Miles_per_Gallon": 36, + "Cylinders": 4, + "Displacement": 79, + "Horsepower": 58, + "Weight_in_lbs": 1825, + "Acceleration": 18.6, + "Year": "1977-01-01", + "Origin": "Europe" + }, + { + "Name": "plymouth arrow gs", + "Miles_per_Gallon": 25.5, + "Cylinders": 4, + "Displacement": 122, + "Horsepower": 96, + "Weight_in_lbs": 2300, + "Acceleration": 15.5, + "Year": "1977-01-01", + "Origin": "USA" + }, + { + "Name": "datsun f-10 hatchback", + "Miles_per_Gallon": 33.5, + "Cylinders": 4, + "Displacement": 85, + "Horsepower": 70, + "Weight_in_lbs": 1945, + "Acceleration": 16.8, + "Year": "1977-01-01", + "Origin": "Japan" + }, + { + "Name": "chevrolet caprice classic", + "Miles_per_Gallon": 17.5, + "Cylinders": 8, + "Displacement": 305, + "Horsepower": 145, + "Weight_in_lbs": 3880, + "Acceleration": 12.5, + "Year": "1977-01-01", + "Origin": "USA" + }, + { + "Name": "oldsmobile cutlass supreme", + "Miles_per_Gallon": 17, + "Cylinders": 8, + "Displacement": 260, + "Horsepower": 110, + "Weight_in_lbs": 4060, + "Acceleration": 19, + "Year": "1977-01-01", + "Origin": "USA" + }, + { + "Name": "dodge monaco brougham", + "Miles_per_Gallon": 15.5, + "Cylinders": 8, + "Displacement": 318, + "Horsepower": 145, + "Weight_in_lbs": 4140, + "Acceleration": 13.7, + "Year": "1977-01-01", + "Origin": "USA" + }, + { + "Name": "mercury cougar brougham", + "Miles_per_Gallon": 15, + "Cylinders": 8, + "Displacement": 302, + "Horsepower": 130, + "Weight_in_lbs": 4295, + "Acceleration": 14.9, + "Year": "1977-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet concours", + "Miles_per_Gallon": 17.5, + "Cylinders": 6, + "Displacement": 250, + "Horsepower": 110, + "Weight_in_lbs": 3520, + "Acceleration": 16.4, + "Year": "1977-01-01", + "Origin": "USA" + }, + { + "Name": "buick skylark", + "Miles_per_Gallon": 20.5, + "Cylinders": 6, + "Displacement": 231, + "Horsepower": 105, + "Weight_in_lbs": 3425, + "Acceleration": 16.9, + "Year": "1977-01-01", + "Origin": "USA" + }, + { + "Name": "plymouth volare custom", + "Miles_per_Gallon": 19, + "Cylinders": 6, + "Displacement": 225, + "Horsepower": 100, + "Weight_in_lbs": 3630, + "Acceleration": 17.7, + "Year": "1977-01-01", + "Origin": "USA" + }, + { + "Name": "ford granada", + "Miles_per_Gallon": 18.5, + "Cylinders": 6, + "Displacement": 250, + "Horsepower": 98, + "Weight_in_lbs": 3525, + "Acceleration": 19, + "Year": "1977-01-01", + "Origin": "USA" + }, + { + "Name": "pontiac grand prix lj", + "Miles_per_Gallon": 16, + "Cylinders": 8, + "Displacement": 400, + "Horsepower": 180, + "Weight_in_lbs": 4220, + "Acceleration": 11.1, + "Year": "1977-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet monte carlo landau", + "Miles_per_Gallon": 15.5, + "Cylinders": 8, + "Displacement": 350, + "Horsepower": 170, + "Weight_in_lbs": 4165, + "Acceleration": 11.4, + "Year": "1977-01-01", + "Origin": "USA" + }, + { + "Name": "chrysler cordoba", + "Miles_per_Gallon": 15.5, + "Cylinders": 8, + "Displacement": 400, + "Horsepower": 190, + "Weight_in_lbs": 4325, + "Acceleration": 12.2, + "Year": "1977-01-01", + "Origin": "USA" + }, + { + "Name": "ford thunderbird", + "Miles_per_Gallon": 16, + "Cylinders": 8, + "Displacement": 351, + "Horsepower": 149, + "Weight_in_lbs": 4335, + "Acceleration": 14.5, + "Year": "1977-01-01", + "Origin": "USA" + }, + { + "Name": "volkswagen rabbit custom", + "Miles_per_Gallon": 29, + "Cylinders": 4, + "Displacement": 97, + "Horsepower": 78, + "Weight_in_lbs": 1940, + "Acceleration": 14.5, + "Year": "1977-01-01", + "Origin": "Europe" + }, + { + "Name": "pontiac sunbird coupe", + "Miles_per_Gallon": 24.5, + "Cylinders": 4, + "Displacement": 151, + "Horsepower": 88, + "Weight_in_lbs": 2740, + "Acceleration": 16, + "Year": "1977-01-01", + "Origin": "USA" + }, + { + "Name": "toyota corolla liftback", + "Miles_per_Gallon": 26, + "Cylinders": 4, + "Displacement": 97, + "Horsepower": 75, + "Weight_in_lbs": 2265, + "Acceleration": 18.2, + "Year": "1977-01-01", + "Origin": "Japan" + }, + { + "Name": "ford mustang ii 2+2", + "Miles_per_Gallon": 25.5, + "Cylinders": 4, + "Displacement": 140, + "Horsepower": 89, + "Weight_in_lbs": 2755, + "Acceleration": 15.8, + "Year": "1977-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet chevette", + "Miles_per_Gallon": 30.5, + "Cylinders": 4, + "Displacement": 98, + "Horsepower": 63, + "Weight_in_lbs": 2051, + "Acceleration": 17, + "Year": "1977-01-01", + "Origin": "USA" + }, + { + "Name": "dodge colt m/m", + "Miles_per_Gallon": 33.5, + "Cylinders": 4, + "Displacement": 98, + "Horsepower": 83, + "Weight_in_lbs": 2075, + "Acceleration": 15.9, + "Year": "1977-01-01", + "Origin": "USA" + }, + { + "Name": "subaru dl", + "Miles_per_Gallon": 30, + "Cylinders": 4, + "Displacement": 97, + "Horsepower": 67, + "Weight_in_lbs": 1985, + "Acceleration": 16.4, + "Year": "1977-01-01", + "Origin": "Japan" + }, + { + "Name": "volkswagen dasher", + "Miles_per_Gallon": 30.5, + "Cylinders": 4, + "Displacement": 97, + "Horsepower": 78, + "Weight_in_lbs": 2190, + "Acceleration": 14.1, + "Year": "1977-01-01", + "Origin": "Europe" + }, + { + "Name": "datsun 810", + "Miles_per_Gallon": 22, + "Cylinders": 6, + "Displacement": 146, + "Horsepower": 97, + "Weight_in_lbs": 2815, + "Acceleration": 14.5, + "Year": "1977-01-01", + "Origin": "Japan" + }, + { + "Name": "bmw 320i", + "Miles_per_Gallon": 21.5, + "Cylinders": 4, + "Displacement": 121, + "Horsepower": 110, + "Weight_in_lbs": 2600, + "Acceleration": 12.8, + "Year": "1977-01-01", + "Origin": "Europe" + }, + { + "Name": "mazda rx-4", + "Miles_per_Gallon": 21.5, + "Cylinders": 6, + "Displacement": 80, + "Horsepower": 110, + "Weight_in_lbs": 2720, + "Acceleration": 13.5, + "Year": "1977-01-01", + "Origin": "Japan" + }, + { + "Name": "volkswagen rabbit custom diesel", + "Miles_per_Gallon": 43.1, + "Cylinders": 4, + "Displacement": 90, + "Horsepower": 48, + "Weight_in_lbs": 1985, + "Acceleration": 21.5, + "Year": "1978-01-01", + "Origin": "Europe" + }, + { + "Name": "ford fiesta", + "Miles_per_Gallon": 36.1, + "Cylinders": 4, + "Displacement": 98, + "Horsepower": 66, + "Weight_in_lbs": 1800, + "Acceleration": 14.4, + "Year": "1978-01-01", + "Origin": "USA" + }, + { + "Name": "mazda glc deluxe", + "Miles_per_Gallon": 32.8, + "Cylinders": 4, + "Displacement": 78, + "Horsepower": 52, + "Weight_in_lbs": 1985, + "Acceleration": 19.4, + "Year": "1978-01-01", + "Origin": "Japan" + }, + { + "Name": "datsun b210 gx", + "Miles_per_Gallon": 39.4, + "Cylinders": 4, + "Displacement": 85, + "Horsepower": 70, + "Weight_in_lbs": 2070, + "Acceleration": 18.6, + "Year": "1978-01-01", + "Origin": "Japan" + }, + { + "Name": "honda civic cvcc", + "Miles_per_Gallon": 36.1, + "Cylinders": 4, + "Displacement": 91, + "Horsepower": 60, + "Weight_in_lbs": 1800, + "Acceleration": 16.4, + "Year": "1978-01-01", + "Origin": "Japan" + }, + { + "Name": "oldsmobile cutlass salon brougham", + "Miles_per_Gallon": 19.9, + "Cylinders": 8, + "Displacement": 260, + "Horsepower": 110, + "Weight_in_lbs": 3365, + "Acceleration": 15.5, + "Year": "1978-01-01", + "Origin": "USA" + }, + { + "Name": "dodge diplomat", + "Miles_per_Gallon": 19.4, + "Cylinders": 8, + "Displacement": 318, + "Horsepower": 140, + "Weight_in_lbs": 3735, + "Acceleration": 13.2, + "Year": "1978-01-01", + "Origin": "USA" + }, + { + "Name": "mercury monarch ghia", + "Miles_per_Gallon": 20.2, + "Cylinders": 8, + "Displacement": 302, + "Horsepower": 139, + "Weight_in_lbs": 3570, + "Acceleration": 12.8, + "Year": "1978-01-01", + "Origin": "USA" + }, + { + "Name": "pontiac phoenix lj", + "Miles_per_Gallon": 19.2, + "Cylinders": 6, + "Displacement": 231, + "Horsepower": 105, + "Weight_in_lbs": 3535, + "Acceleration": 19.2, + "Year": "1978-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet malibu", + "Miles_per_Gallon": 20.5, + "Cylinders": 6, + "Displacement": 200, + "Horsepower": 95, + "Weight_in_lbs": 3155, + "Acceleration": 18.2, + "Year": "1978-01-01", + "Origin": "USA" + }, + { + "Name": "ford fairmont (auto)", + "Miles_per_Gallon": 20.2, + "Cylinders": 6, + "Displacement": 200, + "Horsepower": 85, + "Weight_in_lbs": 2965, + "Acceleration": 15.8, + "Year": "1978-01-01", + "Origin": "USA" + }, + { + "Name": "ford fairmont (man)", + "Miles_per_Gallon": 25.1, + "Cylinders": 4, + "Displacement": 140, + "Horsepower": 88, + "Weight_in_lbs": 2720, + "Acceleration": 15.4, + "Year": "1978-01-01", + "Origin": "USA" + }, + { + "Name": "plymouth volare", + "Miles_per_Gallon": 20.5, + "Cylinders": 6, + "Displacement": 225, + "Horsepower": 100, + "Weight_in_lbs": 3430, + "Acceleration": 17.2, + "Year": "1978-01-01", + "Origin": "USA" + }, + { + "Name": "amc concord", + "Miles_per_Gallon": 19.4, + "Cylinders": 6, + "Displacement": 232, + "Horsepower": 90, + "Weight_in_lbs": 3210, + "Acceleration": 17.2, + "Year": "1978-01-01", + "Origin": "USA" + }, + { + "Name": "buick century special", + "Miles_per_Gallon": 20.6, + "Cylinders": 6, + "Displacement": 231, + "Horsepower": 105, + "Weight_in_lbs": 3380, + "Acceleration": 15.8, + "Year": "1978-01-01", + "Origin": "USA" + }, + { + "Name": "mercury zephyr", + "Miles_per_Gallon": 20.8, + "Cylinders": 6, + "Displacement": 200, + "Horsepower": 85, + "Weight_in_lbs": 3070, + "Acceleration": 16.7, + "Year": "1978-01-01", + "Origin": "USA" + }, + { + "Name": "dodge aspen", + "Miles_per_Gallon": 18.6, + "Cylinders": 6, + "Displacement": 225, + "Horsepower": 110, + "Weight_in_lbs": 3620, + "Acceleration": 18.7, + "Year": "1978-01-01", + "Origin": "USA" + }, + { + "Name": "amc concord d/l", + "Miles_per_Gallon": 18.1, + "Cylinders": 6, + "Displacement": 258, + "Horsepower": 120, + "Weight_in_lbs": 3410, + "Acceleration": 15.1, + "Year": "1978-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet monte carlo landau", + "Miles_per_Gallon": 19.2, + "Cylinders": 8, + "Displacement": 305, + "Horsepower": 145, + "Weight_in_lbs": 3425, + "Acceleration": 13.2, + "Year": "1978-01-01", + "Origin": "USA" + }, + { + "Name": "buick regal sport coupe (turbo)", + "Miles_per_Gallon": 17.7, + "Cylinders": 6, + "Displacement": 231, + "Horsepower": 165, + "Weight_in_lbs": 3445, + "Acceleration": 13.4, + "Year": "1978-01-01", + "Origin": "USA" + }, + { + "Name": "ford futura", + "Miles_per_Gallon": 18.1, + "Cylinders": 8, + "Displacement": 302, + "Horsepower": 139, + "Weight_in_lbs": 3205, + "Acceleration": 11.2, + "Year": "1978-01-01", + "Origin": "USA" + }, + { + "Name": "dodge magnum xe", + "Miles_per_Gallon": 17.5, + "Cylinders": 8, + "Displacement": 318, + "Horsepower": 140, + "Weight_in_lbs": 4080, + "Acceleration": 13.7, + "Year": "1978-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet chevette", + "Miles_per_Gallon": 30, + "Cylinders": 4, + "Displacement": 98, + "Horsepower": 68, + "Weight_in_lbs": 2155, + "Acceleration": 16.5, + "Year": "1978-01-01", + "Origin": "USA" + }, + { + "Name": "toyota corona", + "Miles_per_Gallon": 27.5, + "Cylinders": 4, + "Displacement": 134, + "Horsepower": 95, + "Weight_in_lbs": 2560, + "Acceleration": 14.2, + "Year": "1978-01-01", + "Origin": "Japan" + }, + { + "Name": "datsun 510", + "Miles_per_Gallon": 27.2, + "Cylinders": 4, + "Displacement": 119, + "Horsepower": 97, + "Weight_in_lbs": 2300, + "Acceleration": 14.7, + "Year": "1978-01-01", + "Origin": "Japan" + }, + { + "Name": "dodge omni", + "Miles_per_Gallon": 30.9, + "Cylinders": 4, + "Displacement": 105, + "Horsepower": 75, + "Weight_in_lbs": 2230, + "Acceleration": 14.5, + "Year": "1978-01-01", + "Origin": "USA" + }, + { + "Name": "toyota celica gt liftback", + "Miles_per_Gallon": 21.1, + "Cylinders": 4, + "Displacement": 134, + "Horsepower": 95, + "Weight_in_lbs": 2515, + "Acceleration": 14.8, + "Year": "1978-01-01", + "Origin": "Japan" + }, + { + "Name": "plymouth sapporo", + "Miles_per_Gallon": 23.2, + "Cylinders": 4, + "Displacement": 156, + "Horsepower": 105, + "Weight_in_lbs": 2745, + "Acceleration": 16.7, + "Year": "1978-01-01", + "Origin": "USA" + }, + { + "Name": "oldsmobile starfire sx", + "Miles_per_Gallon": 23.8, + "Cylinders": 4, + "Displacement": 151, + "Horsepower": 85, + "Weight_in_lbs": 2855, + "Acceleration": 17.6, + "Year": "1978-01-01", + "Origin": "USA" + }, + { + "Name": "datsun 200-sx", + "Miles_per_Gallon": 23.9, + "Cylinders": 4, + "Displacement": 119, + "Horsepower": 97, + "Weight_in_lbs": 2405, + "Acceleration": 14.9, + "Year": "1978-01-01", + "Origin": "Japan" + }, + { + "Name": "audi 5000", + "Miles_per_Gallon": 20.3, + "Cylinders": 5, + "Displacement": 131, + "Horsepower": 103, + "Weight_in_lbs": 2830, + "Acceleration": 15.9, + "Year": "1978-01-01", + "Origin": "Europe" + }, + { + "Name": "volvo 264gl", + "Miles_per_Gallon": 17, + "Cylinders": 6, + "Displacement": 163, + "Horsepower": 125, + "Weight_in_lbs": 3140, + "Acceleration": 13.6, + "Year": "1978-01-01", + "Origin": "Europe" + }, + { + "Name": "saab 99gle", + "Miles_per_Gallon": 21.6, + "Cylinders": 4, + "Displacement": 121, + "Horsepower": 115, + "Weight_in_lbs": 2795, + "Acceleration": 15.7, + "Year": "1978-01-01", + "Origin": "Europe" + }, + { + "Name": "peugeot 604sl", + "Miles_per_Gallon": 16.2, + "Cylinders": 6, + "Displacement": 163, + "Horsepower": 133, + "Weight_in_lbs": 3410, + "Acceleration": 15.8, + "Year": "1978-01-01", + "Origin": "Europe" + }, + { + "Name": "volkswagen scirocco", + "Miles_per_Gallon": 31.5, + "Cylinders": 4, + "Displacement": 89, + "Horsepower": 71, + "Weight_in_lbs": 1990, + "Acceleration": 14.9, + "Year": "1978-01-01", + "Origin": "Europe" + }, + { + "Name": "honda Accelerationord lx", + "Miles_per_Gallon": 29.5, + "Cylinders": 4, + "Displacement": 98, + "Horsepower": 68, + "Weight_in_lbs": 2135, + "Acceleration": 16.6, + "Year": "1978-01-01", + "Origin": "Japan" + }, + { + "Name": "pontiac lemans v6", + "Miles_per_Gallon": 21.5, + "Cylinders": 6, + "Displacement": 231, + "Horsepower": 115, + "Weight_in_lbs": 3245, + "Acceleration": 15.4, + "Year": "1979-01-01", + "Origin": "USA" + }, + { + "Name": "mercury zephyr 6", + "Miles_per_Gallon": 19.8, + "Cylinders": 6, + "Displacement": 200, + "Horsepower": 85, + "Weight_in_lbs": 2990, + "Acceleration": 18.2, + "Year": "1979-01-01", + "Origin": "USA" + }, + { + "Name": "ford fairmont 4", + "Miles_per_Gallon": 22.3, + "Cylinders": 4, + "Displacement": 140, + "Horsepower": 88, + "Weight_in_lbs": 2890, + "Acceleration": 17.3, + "Year": "1979-01-01", + "Origin": "USA" + }, + { + "Name": "amc concord dl 6", + "Miles_per_Gallon": 20.2, + "Cylinders": 6, + "Displacement": 232, + "Horsepower": 90, + "Weight_in_lbs": 3265, + "Acceleration": 18.2, + "Year": "1979-01-01", + "Origin": "USA" + }, + { + "Name": "dodge aspen 6", + "Miles_per_Gallon": 20.6, + "Cylinders": 6, + "Displacement": 225, + "Horsepower": 110, + "Weight_in_lbs": 3360, + "Acceleration": 16.6, + "Year": "1979-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet caprice classic", + "Miles_per_Gallon": 17, + "Cylinders": 8, + "Displacement": 305, + "Horsepower": 130, + "Weight_in_lbs": 3840, + "Acceleration": 15.4, + "Year": "1979-01-01", + "Origin": "USA" + }, + { + "Name": "ford ltd landau", + "Miles_per_Gallon": 17.6, + "Cylinders": 8, + "Displacement": 302, + "Horsepower": 129, + "Weight_in_lbs": 3725, + "Acceleration": 13.4, + "Year": "1979-01-01", + "Origin": "USA" + }, + { + "Name": "mercury grand marquis", + "Miles_per_Gallon": 16.5, + "Cylinders": 8, + "Displacement": 351, + "Horsepower": 138, + "Weight_in_lbs": 3955, + "Acceleration": 13.2, + "Year": "1979-01-01", + "Origin": "USA" + }, + { + "Name": "dodge st. regis", + "Miles_per_Gallon": 18.2, + "Cylinders": 8, + "Displacement": 318, + "Horsepower": 135, + "Weight_in_lbs": 3830, + "Acceleration": 15.2, + "Year": "1979-01-01", + "Origin": "USA" + }, + { + "Name": "buick estate wagon (sw)", + "Miles_per_Gallon": 16.9, + "Cylinders": 8, + "Displacement": 350, + "Horsepower": 155, + "Weight_in_lbs": 4360, + "Acceleration": 14.9, + "Year": "1979-01-01", + "Origin": "USA" + }, + { + "Name": "ford country squire (sw)", + "Miles_per_Gallon": 15.5, + "Cylinders": 8, + "Displacement": 351, + "Horsepower": 142, + "Weight_in_lbs": 4054, + "Acceleration": 14.3, + "Year": "1979-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet malibu classic (sw)", + "Miles_per_Gallon": 19.2, + "Cylinders": 8, + "Displacement": 267, + "Horsepower": 125, + "Weight_in_lbs": 3605, + "Acceleration": 15, + "Year": "1979-01-01", + "Origin": "USA" + }, + { + "Name": "chrysler lebaron town @ country (sw)", + "Miles_per_Gallon": 18.5, + "Cylinders": 8, + "Displacement": 360, + "Horsepower": 150, + "Weight_in_lbs": 3940, + "Acceleration": 13, + "Year": "1979-01-01", + "Origin": "USA" + }, + { + "Name": "vw rabbit custom", + "Miles_per_Gallon": 31.9, + "Cylinders": 4, + "Displacement": 89, + "Horsepower": 71, + "Weight_in_lbs": 1925, + "Acceleration": 14, + "Year": "1979-01-01", + "Origin": "Europe" + }, + { + "Name": "maxda glc deluxe", + "Miles_per_Gallon": 34.1, + "Cylinders": 4, + "Displacement": 86, + "Horsepower": 65, + "Weight_in_lbs": 1975, + "Acceleration": 15.2, + "Year": "1979-01-01", + "Origin": "Japan" + }, + { + "Name": "dodge colt hatchback custom", + "Miles_per_Gallon": 35.7, + "Cylinders": 4, + "Displacement": 98, + "Horsepower": 80, + "Weight_in_lbs": 1915, + "Acceleration": 14.4, + "Year": "1979-01-01", + "Origin": "USA" + }, + { + "Name": "amc spirit dl", + "Miles_per_Gallon": 27.4, + "Cylinders": 4, + "Displacement": 121, + "Horsepower": 80, + "Weight_in_lbs": 2670, + "Acceleration": 15, + "Year": "1979-01-01", + "Origin": "USA" + }, + { + "Name": "mercedes benz 300d", + "Miles_per_Gallon": 25.4, + "Cylinders": 5, + "Displacement": 183, + "Horsepower": 77, + "Weight_in_lbs": 3530, + "Acceleration": 20.1, + "Year": "1979-01-01", + "Origin": "Europe" + }, + { + "Name": "cadillac eldorado", + "Miles_per_Gallon": 23, + "Cylinders": 8, + "Displacement": 350, + "Horsepower": 125, + "Weight_in_lbs": 3900, + "Acceleration": 17.4, + "Year": "1979-01-01", + "Origin": "USA" + }, + { + "Name": "peugeot 504", + "Miles_per_Gallon": 27.2, + "Cylinders": 4, + "Displacement": 141, + "Horsepower": 71, + "Weight_in_lbs": 3190, + "Acceleration": 24.8, + "Year": "1979-01-01", + "Origin": "Europe" + }, + { + "Name": "oldsmobile cutlass salon brougham", + "Miles_per_Gallon": 23.9, + "Cylinders": 8, + "Displacement": 260, + "Horsepower": 90, + "Weight_in_lbs": 3420, + "Acceleration": 22.2, + "Year": "1979-01-01", + "Origin": "USA" + }, + { + "Name": "plymouth horizon", + "Miles_per_Gallon": 34.2, + "Cylinders": 4, + "Displacement": 105, + "Horsepower": 70, + "Weight_in_lbs": 2200, + "Acceleration": 13.2, + "Year": "1979-01-01", + "Origin": "USA" + }, + { + "Name": "plymouth horizon tc3", + "Miles_per_Gallon": 34.5, + "Cylinders": 4, + "Displacement": 105, + "Horsepower": 70, + "Weight_in_lbs": 2150, + "Acceleration": 14.9, + "Year": "1979-01-01", + "Origin": "USA" + }, + { + "Name": "datsun 210", + "Miles_per_Gallon": 31.8, + "Cylinders": 4, + "Displacement": 85, + "Horsepower": 65, + "Weight_in_lbs": 2020, + "Acceleration": 19.2, + "Year": "1979-01-01", + "Origin": "Japan" + }, + { + "Name": "fiat strada custom", + "Miles_per_Gallon": 37.3, + "Cylinders": 4, + "Displacement": 91, + "Horsepower": 69, + "Weight_in_lbs": 2130, + "Acceleration": 14.7, + "Year": "1979-01-01", + "Origin": "Europe" + }, + { + "Name": "buick skylark limited", + "Miles_per_Gallon": 28.4, + "Cylinders": 4, + "Displacement": 151, + "Horsepower": 90, + "Weight_in_lbs": 2670, + "Acceleration": 16, + "Year": "1979-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet citation", + "Miles_per_Gallon": 28.8, + "Cylinders": 6, + "Displacement": 173, + "Horsepower": 115, + "Weight_in_lbs": 2595, + "Acceleration": 11.3, + "Year": "1979-01-01", + "Origin": "USA" + }, + { + "Name": "oldsmobile omega brougham", + "Miles_per_Gallon": 26.8, + "Cylinders": 6, + "Displacement": 173, + "Horsepower": 115, + "Weight_in_lbs": 2700, + "Acceleration": 12.9, + "Year": "1979-01-01", + "Origin": "USA" + }, + { + "Name": "pontiac phoenix", + "Miles_per_Gallon": 33.5, + "Cylinders": 4, + "Displacement": 151, + "Horsepower": 90, + "Weight_in_lbs": 2556, + "Acceleration": 13.2, + "Year": "1979-01-01", + "Origin": "USA" + }, + { + "Name": "vw rabbit", + "Miles_per_Gallon": 41.5, + "Cylinders": 4, + "Displacement": 98, + "Horsepower": 76, + "Weight_in_lbs": 2144, + "Acceleration": 14.7, + "Year": "1980-01-01", + "Origin": "Europe" + }, + { + "Name": "toyota corolla tercel", + "Miles_per_Gallon": 38.1, + "Cylinders": 4, + "Displacement": 89, + "Horsepower": 60, + "Weight_in_lbs": 1968, + "Acceleration": 18.8, + "Year": "1980-01-01", + "Origin": "Japan" + }, + { + "Name": "chevrolet chevette", + "Miles_per_Gallon": 32.1, + "Cylinders": 4, + "Displacement": 98, + "Horsepower": 70, + "Weight_in_lbs": 2120, + "Acceleration": 15.5, + "Year": "1980-01-01", + "Origin": "USA" + }, + { + "Name": "datsun 310", + "Miles_per_Gallon": 37.2, + "Cylinders": 4, + "Displacement": 86, + "Horsepower": 65, + "Weight_in_lbs": 2019, + "Acceleration": 16.4, + "Year": "1980-01-01", + "Origin": "Japan" + }, + { + "Name": "chevrolet citation", + "Miles_per_Gallon": 28, + "Cylinders": 4, + "Displacement": 151, + "Horsepower": 90, + "Weight_in_lbs": 2678, + "Acceleration": 16.5, + "Year": "1980-01-01", + "Origin": "USA" + }, + { + "Name": "ford fairmont", + "Miles_per_Gallon": 26.4, + "Cylinders": 4, + "Displacement": 140, + "Horsepower": 88, + "Weight_in_lbs": 2870, + "Acceleration": 18.1, + "Year": "1980-01-01", + "Origin": "USA" + }, + { + "Name": "amc concord", + "Miles_per_Gallon": 24.3, + "Cylinders": 4, + "Displacement": 151, + "Horsepower": 90, + "Weight_in_lbs": 3003, + "Acceleration": 20.1, + "Year": "1980-01-01", + "Origin": "USA" + }, + { + "Name": "dodge aspen", + "Miles_per_Gallon": 19.1, + "Cylinders": 6, + "Displacement": 225, + "Horsepower": 90, + "Weight_in_lbs": 3381, + "Acceleration": 18.7, + "Year": "1980-01-01", + "Origin": "USA" + }, + { + "Name": "audi 4000", + "Miles_per_Gallon": 34.3, + "Cylinders": 4, + "Displacement": 97, + "Horsepower": 78, + "Weight_in_lbs": 2188, + "Acceleration": 15.8, + "Year": "1980-01-01", + "Origin": "Europe" + }, + { + "Name": "toyota corona liftback", + "Miles_per_Gallon": 29.8, + "Cylinders": 4, + "Displacement": 134, + "Horsepower": 90, + "Weight_in_lbs": 2711, + "Acceleration": 15.5, + "Year": "1980-01-01", + "Origin": "Japan" + }, + { + "Name": "mazda 626", + "Miles_per_Gallon": 31.3, + "Cylinders": 4, + "Displacement": 120, + "Horsepower": 75, + "Weight_in_lbs": 2542, + "Acceleration": 17.5, + "Year": "1980-01-01", + "Origin": "Japan" + }, + { + "Name": "datsun 510 hatchback", + "Miles_per_Gallon": 37, + "Cylinders": 4, + "Displacement": 119, + "Horsepower": 92, + "Weight_in_lbs": 2434, + "Acceleration": 15, + "Year": "1980-01-01", + "Origin": "Japan" + }, + { + "Name": "toyota corolla", + "Miles_per_Gallon": 32.2, + "Cylinders": 4, + "Displacement": 108, + "Horsepower": 75, + "Weight_in_lbs": 2265, + "Acceleration": 15.2, + "Year": "1980-01-01", + "Origin": "Japan" + }, + { + "Name": "mazda glc", + "Miles_per_Gallon": 46.6, + "Cylinders": 4, + "Displacement": 86, + "Horsepower": 65, + "Weight_in_lbs": 2110, + "Acceleration": 17.9, + "Year": "1980-01-01", + "Origin": "Japan" + }, + { + "Name": "dodge colt", + "Miles_per_Gallon": 27.9, + "Cylinders": 4, + "Displacement": 156, + "Horsepower": 105, + "Weight_in_lbs": 2800, + "Acceleration": 14.4, + "Year": "1980-01-01", + "Origin": "USA" + }, + { + "Name": "datsun 210", + "Miles_per_Gallon": 40.8, + "Cylinders": 4, + "Displacement": 85, + "Horsepower": 65, + "Weight_in_lbs": 2110, + "Acceleration": 19.2, + "Year": "1980-01-01", + "Origin": "Japan" + }, + { + "Name": "vw rabbit c (diesel)", + "Miles_per_Gallon": 44.3, + "Cylinders": 4, + "Displacement": 90, + "Horsepower": 48, + "Weight_in_lbs": 2085, + "Acceleration": 21.7, + "Year": "1980-01-01", + "Origin": "Europe" + }, + { + "Name": "vw dasher (diesel)", + "Miles_per_Gallon": 43.4, + "Cylinders": 4, + "Displacement": 90, + "Horsepower": 48, + "Weight_in_lbs": 2335, + "Acceleration": 23.7, + "Year": "1980-01-01", + "Origin": "Europe" + }, + { + "Name": "audi 5000s (diesel)", + "Miles_per_Gallon": 36.4, + "Cylinders": 5, + "Displacement": 121, + "Horsepower": 67, + "Weight_in_lbs": 2950, + "Acceleration": 19.9, + "Year": "1980-01-01", + "Origin": "Europe" + }, + { + "Name": "mercedes-benz 240d", + "Miles_per_Gallon": 30, + "Cylinders": 4, + "Displacement": 146, + "Horsepower": 67, + "Weight_in_lbs": 3250, + "Acceleration": 21.8, + "Year": "1980-01-01", + "Origin": "Europe" + }, + { + "Name": "honda civic 1500 gl", + "Miles_per_Gallon": 44.6, + "Cylinders": 4, + "Displacement": 91, + "Horsepower": 67, + "Weight_in_lbs": 1850, + "Acceleration": 13.8, + "Year": "1980-01-01", + "Origin": "Japan" + }, + { + "Name": "renault lecar deluxe", + "Miles_per_Gallon": 40.9, + "Cylinders": 4, + "Displacement": 85, + "Horsepower": 75, + "Weight_in_lbs": 1835, + "Acceleration": 17.3, + "Year": "1980-01-01", + "Origin": "Europe" + }, + { + "Name": "subaru dl", + "Miles_per_Gallon": 33.8, + "Cylinders": 4, + "Displacement": 97, + "Horsepower": 67, + "Weight_in_lbs": 2145, + "Acceleration": 18, + "Year": "1980-01-01", + "Origin": "Japan" + }, + { + "Name": "vokswagen rabbit", + "Miles_per_Gallon": 29.8, + "Cylinders": 4, + "Displacement": 89, + "Horsepower": 62, + "Weight_in_lbs": 1845, + "Acceleration": 15.3, + "Year": "1980-01-01", + "Origin": "Europe" + }, + { + "Name": "datsun 280-zx", + "Miles_per_Gallon": 32.7, + "Cylinders": 6, + "Displacement": 168, + "Horsepower": 132, + "Weight_in_lbs": 2910, + "Acceleration": 11.4, + "Year": "1980-01-01", + "Origin": "Japan" + }, + { + "Name": "mazda rx-7 gs", + "Miles_per_Gallon": 23.7, + "Cylinders": 6, + "Displacement": 70, + "Horsepower": 100, + "Weight_in_lbs": 2420, + "Acceleration": 12.5, + "Year": "1980-01-01", + "Origin": "Japan" + }, + { + "Name": "triumph tr7 coupe", + "Miles_per_Gallon": 35, + "Cylinders": 4, + "Displacement": 122, + "Horsepower": 88, + "Weight_in_lbs": 2500, + "Acceleration": 15.1, + "Year": "1980-01-01", + "Origin": "Europe" + }, + { + "Name": "ford mustang cobra", + "Miles_per_Gallon": 23.6, + "Cylinders": 4, + "Displacement": 140, + "Horsepower": 65, + "Weight_in_lbs": 2905, + "Acceleration": 14.3, + "Year": "1980-01-01", + "Origin": "USA" + }, + { + "Name": "honda Accelerationord", + "Miles_per_Gallon": 32.4, + "Cylinders": 4, + "Displacement": 107, + "Horsepower": 72, + "Weight_in_lbs": 2290, + "Acceleration": 17, + "Year": "1980-01-01", + "Origin": "Japan" + }, + { + "Name": "plymouth reliant", + "Miles_per_Gallon": 27.2, + "Cylinders": 4, + "Displacement": 135, + "Horsepower": 84, + "Weight_in_lbs": 2490, + "Acceleration": 15.7, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "buick skylark", + "Miles_per_Gallon": 26.6, + "Cylinders": 4, + "Displacement": 151, + "Horsepower": 84, + "Weight_in_lbs": 2635, + "Acceleration": 16.4, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "dodge aries wagon (sw)", + "Miles_per_Gallon": 25.8, + "Cylinders": 4, + "Displacement": 156, + "Horsepower": 92, + "Weight_in_lbs": 2620, + "Acceleration": 14.4, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet citation", + "Miles_per_Gallon": 23.5, + "Cylinders": 6, + "Displacement": 173, + "Horsepower": 110, + "Weight_in_lbs": 2725, + "Acceleration": 12.6, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "plymouth reliant", + "Miles_per_Gallon": 30, + "Cylinders": 4, + "Displacement": 135, + "Horsepower": 84, + "Weight_in_lbs": 2385, + "Acceleration": 12.9, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "toyota starlet", + "Miles_per_Gallon": 39.1, + "Cylinders": 4, + "Displacement": 79, + "Horsepower": 58, + "Weight_in_lbs": 1755, + "Acceleration": 16.9, + "Year": "1982-01-01", + "Origin": "Japan" + }, + { + "Name": "plymouth champ", + "Miles_per_Gallon": 39, + "Cylinders": 4, + "Displacement": 86, + "Horsepower": 64, + "Weight_in_lbs": 1875, + "Acceleration": 16.4, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "honda civic 1300", + "Miles_per_Gallon": 35.1, + "Cylinders": 4, + "Displacement": 81, + "Horsepower": 60, + "Weight_in_lbs": 1760, + "Acceleration": 16.1, + "Year": "1982-01-01", + "Origin": "Japan" + }, + { + "Name": "subaru", + "Miles_per_Gallon": 32.3, + "Cylinders": 4, + "Displacement": 97, + "Horsepower": 67, + "Weight_in_lbs": 2065, + "Acceleration": 17.8, + "Year": "1982-01-01", + "Origin": "Japan" + }, + { + "Name": "datsun 210", + "Miles_per_Gallon": 37, + "Cylinders": 4, + "Displacement": 85, + "Horsepower": 65, + "Weight_in_lbs": 1975, + "Acceleration": 19.4, + "Year": "1982-01-01", + "Origin": "Japan" + }, + { + "Name": "toyota tercel", + "Miles_per_Gallon": 37.7, + "Cylinders": 4, + "Displacement": 89, + "Horsepower": 62, + "Weight_in_lbs": 2050, + "Acceleration": 17.3, + "Year": "1982-01-01", + "Origin": "Japan" + }, + { + "Name": "mazda glc 4", + "Miles_per_Gallon": 34.1, + "Cylinders": 4, + "Displacement": 91, + "Horsepower": 68, + "Weight_in_lbs": 1985, + "Acceleration": 16, + "Year": "1982-01-01", + "Origin": "Japan" + }, + { + "Name": "plymouth horizon 4", + "Miles_per_Gallon": 34.7, + "Cylinders": 4, + "Displacement": 105, + "Horsepower": 63, + "Weight_in_lbs": 2215, + "Acceleration": 14.9, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "ford escort 4w", + "Miles_per_Gallon": 34.4, + "Cylinders": 4, + "Displacement": 98, + "Horsepower": 65, + "Weight_in_lbs": 2045, + "Acceleration": 16.2, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "ford escort 2h", + "Miles_per_Gallon": 29.9, + "Cylinders": 4, + "Displacement": 98, + "Horsepower": 65, + "Weight_in_lbs": 2380, + "Acceleration": 20.7, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "volkswagen jetta", + "Miles_per_Gallon": 33, + "Cylinders": 4, + "Displacement": 105, + "Horsepower": 74, + "Weight_in_lbs": 2190, + "Acceleration": 14.2, + "Year": "1982-01-01", + "Origin": "Europe" + }, + { + "Name": "renault 18i", + "Miles_per_Gallon": 34.5, + "Cylinders": 4, + "Displacement": 100, + "Horsepower": 78, + "Weight_in_lbs": 2320, + "Acceleration": 15.8, + "Year": "1982-01-01", + "Origin": "Europe" + }, + { + "Name": "honda prelude", + "Miles_per_Gallon": 33.7, + "Cylinders": 4, + "Displacement": 107, + "Horsepower": 75, + "Weight_in_lbs": 2210, + "Acceleration": 14.4, + "Year": "1982-01-01", + "Origin": "Japan" + }, + { + "Name": "toyota corolla", + "Miles_per_Gallon": 32.4, + "Cylinders": 4, + "Displacement": 108, + "Horsepower": 75, + "Weight_in_lbs": 2350, + "Acceleration": 16.8, + "Year": "1982-01-01", + "Origin": "Japan" + }, + { + "Name": "datsun 200sx", + "Miles_per_Gallon": 32.9, + "Cylinders": 4, + "Displacement": 119, + "Horsepower": 100, + "Weight_in_lbs": 2615, + "Acceleration": 14.8, + "Year": "1982-01-01", + "Origin": "Japan" + }, + { + "Name": "mazda 626", + "Miles_per_Gallon": 31.6, + "Cylinders": 4, + "Displacement": 120, + "Horsepower": 74, + "Weight_in_lbs": 2635, + "Acceleration": 18.3, + "Year": "1982-01-01", + "Origin": "Japan" + }, + { + "Name": "peugeot 505s turbo diesel", + "Miles_per_Gallon": 28.1, + "Cylinders": 4, + "Displacement": 141, + "Horsepower": 80, + "Weight_in_lbs": 3230, + "Acceleration": 20.4, + "Year": "1982-01-01", + "Origin": "Europe" + }, + { + "Name": "saab 900s", + "Miles_per_Gallon": null, + "Cylinders": 4, + "Displacement": 121, + "Horsepower": 110, + "Weight_in_lbs": 2800, + "Acceleration": 15.4, + "Year": "1982-01-01", + "Origin": "Europe" + }, + { + "Name": "volvo diesel", + "Miles_per_Gallon": 30.7, + "Cylinders": 6, + "Displacement": 145, + "Horsepower": 76, + "Weight_in_lbs": 3160, + "Acceleration": 19.6, + "Year": "1982-01-01", + "Origin": "Europe" + }, + { + "Name": "toyota cressida", + "Miles_per_Gallon": 25.4, + "Cylinders": 6, + "Displacement": 168, + "Horsepower": 116, + "Weight_in_lbs": 2900, + "Acceleration": 12.6, + "Year": "1982-01-01", + "Origin": "Japan" + }, + { + "Name": "datsun 810 maxima", + "Miles_per_Gallon": 24.2, + "Cylinders": 6, + "Displacement": 146, + "Horsepower": 120, + "Weight_in_lbs": 2930, + "Acceleration": 13.8, + "Year": "1982-01-01", + "Origin": "Japan" + }, + { + "Name": "buick century", + "Miles_per_Gallon": 22.4, + "Cylinders": 6, + "Displacement": 231, + "Horsepower": 110, + "Weight_in_lbs": 3415, + "Acceleration": 15.8, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "oldsmobile cutlass ls", + "Miles_per_Gallon": 26.6, + "Cylinders": 8, + "Displacement": 350, + "Horsepower": 105, + "Weight_in_lbs": 3725, + "Acceleration": 19, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "ford granada gl", + "Miles_per_Gallon": 20.2, + "Cylinders": 6, + "Displacement": 200, + "Horsepower": 88, + "Weight_in_lbs": 3060, + "Acceleration": 17.1, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "chrysler lebaron salon", + "Miles_per_Gallon": 17.6, + "Cylinders": 6, + "Displacement": 225, + "Horsepower": 85, + "Weight_in_lbs": 3465, + "Acceleration": 16.6, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet cavalier", + "Miles_per_Gallon": 28, + "Cylinders": 4, + "Displacement": 112, + "Horsepower": 88, + "Weight_in_lbs": 2605, + "Acceleration": 19.6, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet cavalier wagon", + "Miles_per_Gallon": 27, + "Cylinders": 4, + "Displacement": 112, + "Horsepower": 88, + "Weight_in_lbs": 2640, + "Acceleration": 18.6, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet cavalier 2-door", + "Miles_per_Gallon": 34, + "Cylinders": 4, + "Displacement": 112, + "Horsepower": 88, + "Weight_in_lbs": 2395, + "Acceleration": 18, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "pontiac j2000 se hatchback", + "Miles_per_Gallon": 31, + "Cylinders": 4, + "Displacement": 112, + "Horsepower": 85, + "Weight_in_lbs": 2575, + "Acceleration": 16.2, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "dodge aries se", + "Miles_per_Gallon": 29, + "Cylinders": 4, + "Displacement": 135, + "Horsepower": 84, + "Weight_in_lbs": 2525, + "Acceleration": 16, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "pontiac phoenix", + "Miles_per_Gallon": 27, + "Cylinders": 4, + "Displacement": 151, + "Horsepower": 90, + "Weight_in_lbs": 2735, + "Acceleration": 18, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "ford fairmont futura", + "Miles_per_Gallon": 24, + "Cylinders": 4, + "Displacement": 140, + "Horsepower": 92, + "Weight_in_lbs": 2865, + "Acceleration": 16.4, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "amc concord dl", + "Miles_per_Gallon": 23, + "Cylinders": 4, + "Displacement": 151, + "Horsepower": 80, + "Weight_in_lbs": 3035, + "Acceleration": 20.5, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "volkswagen rabbit l", + "Miles_per_Gallon": 36, + "Cylinders": 4, + "Displacement": 105, + "Horsepower": 74, + "Weight_in_lbs": 1980, + "Acceleration": 15.3, + "Year": "1982-01-01", + "Origin": "Europe" + }, + { + "Name": "mazda glc custom l", + "Miles_per_Gallon": 37, + "Cylinders": 4, + "Displacement": 91, + "Horsepower": 68, + "Weight_in_lbs": 2025, + "Acceleration": 18.2, + "Year": "1982-01-01", + "Origin": "Japan" + }, + { + "Name": "mazda glc custom", + "Miles_per_Gallon": 31, + "Cylinders": 4, + "Displacement": 91, + "Horsepower": 68, + "Weight_in_lbs": 1970, + "Acceleration": 17.6, + "Year": "1982-01-01", + "Origin": "Japan" + }, + { + "Name": "plymouth horizon miser", + "Miles_per_Gallon": 38, + "Cylinders": 4, + "Displacement": 105, + "Horsepower": 63, + "Weight_in_lbs": 2125, + "Acceleration": 14.7, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "mercury lynx l", + "Miles_per_Gallon": 36, + "Cylinders": 4, + "Displacement": 98, + "Horsepower": 70, + "Weight_in_lbs": 2125, + "Acceleration": 17.3, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "nissan stanza xe", + "Miles_per_Gallon": 36, + "Cylinders": 4, + "Displacement": 120, + "Horsepower": 88, + "Weight_in_lbs": 2160, + "Acceleration": 14.5, + "Year": "1982-01-01", + "Origin": "Japan" + }, + { + "Name": "honda Accelerationord", + "Miles_per_Gallon": 36, + "Cylinders": 4, + "Displacement": 107, + "Horsepower": 75, + "Weight_in_lbs": 2205, + "Acceleration": 14.5, + "Year": "1982-01-01", + "Origin": "Japan" + }, + { + "Name": "toyota corolla", + "Miles_per_Gallon": 34, + "Cylinders": 4, + "Displacement": 108, + "Horsepower": 70, + "Weight_in_lbs": 2245, + "Acceleration": 16.9, + "Year": "1982-01-01", + "Origin": "Japan" + }, + { + "Name": "honda civic", + "Miles_per_Gallon": 38, + "Cylinders": 4, + "Displacement": 91, + "Horsepower": 67, + "Weight_in_lbs": 1965, + "Acceleration": 15, + "Year": "1982-01-01", + "Origin": "Japan" + }, + { + "Name": "honda civic (auto)", + "Miles_per_Gallon": 32, + "Cylinders": 4, + "Displacement": 91, + "Horsepower": 67, + "Weight_in_lbs": 1965, + "Acceleration": 15.7, + "Year": "1982-01-01", + "Origin": "Japan" + }, + { + "Name": "datsun 310 gx", + "Miles_per_Gallon": 38, + "Cylinders": 4, + "Displacement": 91, + "Horsepower": 67, + "Weight_in_lbs": 1995, + "Acceleration": 16.2, + "Year": "1982-01-01", + "Origin": "Japan" + }, + { + "Name": "buick century limited", + "Miles_per_Gallon": 25, + "Cylinders": 6, + "Displacement": 181, + "Horsepower": 110, + "Weight_in_lbs": 2945, + "Acceleration": 16.4, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "oldsmobile cutlass ciera (diesel)", + "Miles_per_Gallon": 38, + "Cylinders": 6, + "Displacement": 262, + "Horsepower": 85, + "Weight_in_lbs": 3015, + "Acceleration": 17, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "chrysler lebaron medallion", + "Miles_per_Gallon": 26, + "Cylinders": 4, + "Displacement": 156, + "Horsepower": 92, + "Weight_in_lbs": 2585, + "Acceleration": 14.5, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "ford granada l", + "Miles_per_Gallon": 22, + "Cylinders": 6, + "Displacement": 232, + "Horsepower": 112, + "Weight_in_lbs": 2835, + "Acceleration": 14.7, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "toyota celica gt", + "Miles_per_Gallon": 32, + "Cylinders": 4, + "Displacement": 144, + "Horsepower": 96, + "Weight_in_lbs": 2665, + "Acceleration": 13.9, + "Year": "1982-01-01", + "Origin": "Japan" + }, + { + "Name": "dodge charger 2.2", + "Miles_per_Gallon": 36, + "Cylinders": 4, + "Displacement": 135, + "Horsepower": 84, + "Weight_in_lbs": 2370, + "Acceleration": 13, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "chevrolet camaro", + "Miles_per_Gallon": 27, + "Cylinders": 4, + "Displacement": 151, + "Horsepower": 90, + "Weight_in_lbs": 2950, + "Acceleration": 17.3, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "ford mustang gl", + "Miles_per_Gallon": 27, + "Cylinders": 4, + "Displacement": 140, + "Horsepower": 86, + "Weight_in_lbs": 2790, + "Acceleration": 15.6, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "vw pickup", + "Miles_per_Gallon": 44, + "Cylinders": 4, + "Displacement": 97, + "Horsepower": 52, + "Weight_in_lbs": 2130, + "Acceleration": 24.6, + "Year": "1982-01-01", + "Origin": "Europe" + }, + { + "Name": "dodge rampage", + "Miles_per_Gallon": 32, + "Cylinders": 4, + "Displacement": 135, + "Horsepower": 84, + "Weight_in_lbs": 2295, + "Acceleration": 11.6, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "ford ranger", + "Miles_per_Gallon": 28, + "Cylinders": 4, + "Displacement": 120, + "Horsepower": 79, + "Weight_in_lbs": 2625, + "Acceleration": 18.6, + "Year": "1982-01-01", + "Origin": "USA" + }, + { + "Name": "chevy s-10", + "Miles_per_Gallon": 31, + "Cylinders": 4, + "Displacement": 119, + "Horsepower": 82, + "Weight_in_lbs": 2720, + "Acceleration": 19.4, + "Year": "1982-01-01", + "Origin": "USA" + } + ] \ No newline at end of file diff --git a/packages/vega-demo/public/heatmap.html b/packages/vega-demo/public/heatmap.html new file mode 100644 index 00000000..7a01f32a --- /dev/null +++ b/packages/vega-demo/public/heatmap.html @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + VisAhoi - Vega-Lite - Heatmap + + +
+ + Show onboarding + +
+

VisAhoi Demo: Vega-Lite - Heatmap

+
+ + + \ No newline at end of file diff --git a/packages/vega-demo/src/change-matrix.js b/packages/vega-demo/src/change-matrix.js index bd98f76e..4fc14f23 100644 --- a/packages/vega-demo/src/change-matrix.js +++ b/packages/vega-demo/src/change-matrix.js @@ -1,56 +1,56 @@ -import vegaEmbed from 'vega-embed'; -import { generateBasicAnnotations, ahoi, EVisualizationType } from '@visahoi/vega'; -import debounce from "lodash.debounce"; +import vegaEmbed from 'vega-embed' +import { generateBasicAnnotations, ahoi, EVisualizationType } from '@visahoi/vega' +import debounce from 'lodash.debounce' // Options for the vega embed const opt = { theme: 'default', actions: false, - renderer: 'svg', -}; + renderer: 'svg' +} -let chart = null; -let showOnboarding = false; -let onboardingUI = null; +let chart = null +let showOnboarding = false +let onboardingUI = null const debouncedResize = debounce(async (event) => { - const config = await getAhoiConfig(); + const config = await getAhoiConfig() onboardingUI?.updateOnboarding(config) -}, 250); +}, 250) -async function render() { - const response = await fetch('./data/changeMatrix.json'); - const json = await response.json(); +async function render () { + const response = await fetch('./data/changeMatrix.json') + const json = await response.json() - chart = await vegaEmbed('#vis', json, opt); - window.addEventListener("resize", debouncedResize); + chart = await vegaEmbed('#vis', json, opt) + window.addEventListener('resize', debouncedResize) }; const getAhoiConfig = async () => { - const defaultOnboardingMessages = await generateBasicAnnotations(EVisualizationType.CHANGE_MATRIX, chart); + const defaultOnboardingMessages = await generateBasicAnnotations(EVisualizationType.CHANGE_MATRIX, chart) const extendedOnboardingMessages = defaultOnboardingMessages.map((d) => ({ ...d, - text: "test123" - })); + text: 'test123' + })) const ahoiConfig = { - onboardingMessages: defaultOnboardingMessages, + onboardingMessages: defaultOnboardingMessages } - return ahoiConfig; + return ahoiConfig } -const registerEventListener = () => { - const helpIcon = document.getElementById("show-onboarding"); - if(!helpIcon) { return; } +const registerEventListener = () => { + const helpIcon = document.getElementById('show-onboarding') + if (!helpIcon) { return } helpIcon.addEventListener('click', async () => { - showOnboarding = !showOnboarding; - if(showOnboarding) { - const config = await getAhoiConfig(); - onboardingUI = await ahoi(EVisualizationType.CHANGE_MATRIX, chart, config); + showOnboarding = !showOnboarding + if (showOnboarding) { + const config = await getAhoiConfig() + onboardingUI = await ahoi(EVisualizationType.CHANGE_MATRIX, chart, config) } else { - onboardingUI?.removeOnboarding(); - } + onboardingUI?.removeOnboarding() + } }) } -registerEventListener(); -render(); +registerEventListener() +render() diff --git a/packages/vega-demo/src/heatmap.js b/packages/vega-demo/src/heatmap.js new file mode 100644 index 00000000..1c3415bb --- /dev/null +++ b/packages/vega-demo/src/heatmap.js @@ -0,0 +1,43 @@ +import embed from 'vega-embed' +import debounce from 'lodash.debounce' +import '../public/data/jobsplan.json' + +let chart = null +const onboardingUI = null + +const opt = { +// $schema: 'https://vega.github.io/schema/vega-lite/v5.json', + title: 'Cars origin and their horsepower based on number of cylinders', + description: 'An example of heatmap.', + width: 1200, + height: 600, + padding: { + left: window.innerWidth / 2 - 600, + top: 30 + }, + autosize: 'none', + + data: { url: 'data/carsData.json' }, + mark: 'rect', + encoding: { + y: { field: 'Origin', type: 'nominal', title: 'Origin' }, + x: { field: 'Cylinders', type: 'ordinal', title: 'Cylinders' }, + color: { aggregate: 'mean', field: 'Horsepower' } + }, + config: { + axis: { grid: true } + } + +} + +const debouncedResize = debounce((event) => { + onboardingUI?.updateOnboarding(getAhoiConfig()) +}, 250) + +async function render () { + chart = await embed('#vis', opt) + window.addEventListener('resize', debouncedResize) +} + +// registerEventListener(); +render() diff --git a/packages/vega-demo/src/horizon-graph.js b/packages/vega-demo/src/horizon-graph.js index 068c12ee..ffe41d32 100644 --- a/packages/vega-demo/src/horizon-graph.js +++ b/packages/vega-demo/src/horizon-graph.js @@ -1,56 +1,56 @@ -import vegaEmbed from 'vega-embed'; -import { generateBasicAnnotations, ahoi, EVisualizationType } from '@visahoi/vega'; -import debounce from "lodash.debounce"; +import vegaEmbed from 'vega-embed' +import { generateBasicAnnotations, ahoi, EVisualizationType } from '@visahoi/vega' +import debounce from 'lodash.debounce' // Options for the vega embed const opt = { theme: 'default', actions: false, - renderer: 'svg', -}; + renderer: 'svg' +} -let chart = null; -let showOnboarding = false; -let onboardingUI = null; +let chart = null +let showOnboarding = false +let onboardingUI = null const debouncedResize = debounce(async (event) => { - const config = await getAhoiConfig(); + const config = await getAhoiConfig() onboardingUI?.updateOnboarding(config) -}, 250); +}, 250) -async function render() { - const response = await fetch('./data/horizonGraphOslo2018.json'); - const json = await response.json(); +async function render () { + const response = await fetch('./data/horizonGraphOslo2018.json') + const json = await response.json() - chart = await vegaEmbed('#vis', json, opt); - window.addEventListener("resize", debouncedResize); + chart = await vegaEmbed('#vis', json, opt) + window.addEventListener('resize', debouncedResize) }; const getAhoiConfig = async () => { - const defaultOnboardingMessages = await generateBasicAnnotations(EVisualizationType.HORIZON_GRAPH, chart); + const defaultOnboardingMessages = await generateBasicAnnotations(EVisualizationType.HORIZON_GRAPH, chart) const extendedOnboardingMessages = defaultOnboardingMessages.map((d) => ({ ...d, - text: "test123" - })); + text: 'test123' + })) const ahoiConfig = { - onboardingMessages: defaultOnboardingMessages, + onboardingMessages: defaultOnboardingMessages } - return ahoiConfig; + return ahoiConfig } -const registerEventListener = () => { - const helpIcon = document.getElementById("show-onboarding"); - if(!helpIcon) { return; } +const registerEventListener = () => { + const helpIcon = document.getElementById('show-onboarding') + if (!helpIcon) { return } helpIcon.addEventListener('click', async () => { - showOnboarding = !showOnboarding; - if(showOnboarding) { - const config = await getAhoiConfig(); - onboardingUI = await ahoi(EVisualizationType.HORIZON_GRAPH, chart, config); + showOnboarding = !showOnboarding + if (showOnboarding) { + const config = await getAhoiConfig() + onboardingUI = await ahoi(EVisualizationType.HORIZON_GRAPH, chart, config) } else { - onboardingUI?.removeOnboarding(); - } + onboardingUI?.removeOnboarding() + } }) } -registerEventListener(); -render(); +registerEventListener() +render() diff --git a/packages/vega-demo/src/index.js b/packages/vega-demo/src/index.js index b447eeb1..05f9d116 100644 --- a/packages/vega-demo/src/index.js +++ b/packages/vega-demo/src/index.js @@ -19,15 +19,19 @@ const demos = [ { title: 'Treemap', link: './treemap.html' + }, + { + title: 'Heatmap', + link: './heatmap.html' } -]; +] -const ul = document.createElement('ul'); +const ul = document.createElement('ul') demos.forEach((demo) => { - const li = document.createElement('li'); - li.innerHTML = `${demo.title}`; - ul.append(li); -}); + const li = document.createElement('li') + li.innerHTML = `${demo.title}` + ul.append(li) +}) -document.getElementById('app').append(ul); +document.getElementById('app').append(ul) diff --git a/packages/vega-demo/src/scatterplot.js b/packages/vega-demo/src/scatterplot.js index 08619c69..d0e19310 100644 --- a/packages/vega-demo/src/scatterplot.js +++ b/packages/vega-demo/src/scatterplot.js @@ -1,55 +1,55 @@ -import vegaEmbed from 'vega-embed'; -import { generateBasicAnnotations, ahoi, EVisualizationType } from '@visahoi/vega'; -import debounce from "lodash.debounce"; +import vegaEmbed from 'vega-embed' +import { generateBasicAnnotations, ahoi, EVisualizationType } from '@visahoi/vega' +import debounce from 'lodash.debounce' // Options for the vega embed const opt = { theme: 'default', actions: false, - renderer: 'svg', -}; + renderer: 'svg' +} -let chart = null; -let showOnboarding = false; -let onboardingUI = null; +let chart = null +let showOnboarding = false +let onboardingUI = null const debouncedResize = debounce(async (event) => { - const config = await getAhoiConfig(); + const config = await getAhoiConfig() onboardingUI?.updateOnboarding(config) -}, 250); +}, 250) -async function render() { - const response = await fetch('./data/cars.json'); - const json = await response.json(); - chart = await vegaEmbed('#vis', json, opt); - window.addEventListener("resize", debouncedResize); +async function render () { + const response = await fetch('./data/cars.json') + const json = await response.json() + chart = await vegaEmbed('#vis', json, opt) + window.addEventListener('resize', debouncedResize) }; const getAhoiConfig = async () => { - const defaultOnboardingMessages = await generateBasicAnnotations(EVisualizationType.SCATTERPLOT, chart); + const defaultOnboardingMessages = await generateBasicAnnotations(EVisualizationType.SCATTERPLOT, chart) const extendedOnboardingMessages = defaultOnboardingMessages.map((d) => ({ ...d, - text: "test123" - })); + text: 'test123' + })) const ahoiConfig = { - onboardingMessages: defaultOnboardingMessages, + onboardingMessages: defaultOnboardingMessages } - return ahoiConfig; + return ahoiConfig } -const registerEventListener = () => { - const helpIcon = document.getElementById("show-onboarding"); - if(!helpIcon) { return; } +const registerEventListener = () => { + const helpIcon = document.getElementById('show-onboarding') + if (!helpIcon) { return } helpIcon.addEventListener('click', async () => { - showOnboarding = !showOnboarding; - if(showOnboarding) { - const config = await getAhoiConfig(); - onboardingUI = await ahoi(EVisualizationType.SCATTERPLOT, chart, config); + showOnboarding = !showOnboarding + if (showOnboarding) { + const config = await getAhoiConfig() + onboardingUI = await ahoi(EVisualizationType.SCATTERPLOT, chart, config) } else { - onboardingUI?.removeOnboarding(); - } + onboardingUI?.removeOnboarding() + } }) } -registerEventListener(); -render(); +registerEventListener() +render() diff --git a/packages/vega-demo/src/treemap.js b/packages/vega-demo/src/treemap.js index f7e51c67..9b15a4ac 100644 --- a/packages/vega-demo/src/treemap.js +++ b/packages/vega-demo/src/treemap.js @@ -1,6 +1,6 @@ -import embed from 'vega-embed'; -import debounce from 'lodash.debounce'; -import '../public/data/jobsplan.json'; +import embed from 'vega-embed' +import debounce from 'lodash.debounce' +import '../public/data/jobsplan.json' const opt = { description: 'An example of treemap layout for hierarchical data.', @@ -8,14 +8,14 @@ const opt = { height: 600, padding: { left: window.innerWidth / 2 - 600, - top: 30, + top: 30 }, autosize: 'none', signals: [ { name: 'layout', - value: 'squarify', + value: 'squarify' // "bind": { // "input": "select", // "options": [ @@ -27,9 +27,9 @@ const opt = { }, { name: 'aspectRatio', - value: 1.6, + value: 1.6 // "bind": {"input": "range", "min": 1, "max": 5, "step": 0.1} - }, + } ], data: [ @@ -40,7 +40,7 @@ const opt = { { type: 'stratify', key: 'id', - parentKey: 'parent', + parentKey: 'parent' }, { type: 'treemap', @@ -49,20 +49,20 @@ const opt = { round: true, method: { signal: 'layout' }, ratio: { signal: 'aspectRatio' }, - size: [{ signal: 'width' }, { signal: 'height' }], - }, - ], + size: [{ signal: 'width' }, { signal: 'height' }] + } + ] }, { name: 'nodes', source: 'tree', - transform: [{ type: 'filter', expr: 'datum.children' }], + transform: [{ type: 'filter', expr: 'datum.children' }] }, { name: 'leaves', source: 'tree', - transform: [{ type: 'filter', expr: '!datum.children' }], - }, + transform: [{ type: 'filter', expr: '!datum.children' }] + } ], scales: [ @@ -70,20 +70,20 @@ const opt = { name: 'color', type: 'ordinal', domain: { data: 'nodes', field: 'name' }, - range: ['#80b1d3', '#80b1d3', '#fdb462', '#b3de69', '#fccde5'], + range: ['#80b1d3', '#80b1d3', '#fdb462', '#b3de69', '#fccde5'] }, { name: 'size', type: 'ordinal', domain: [0, 1, 2, 3], - range: [120, 25, 20, 14], + range: [120, 25, 20, 14] }, { name: 'opacity', type: 'ordinal', domain: [0, 1, 2, 3], - range: [0.15, 0.5, 0.8, 1.0], - }, + range: [0.15, 0.5, 0.8, 1.0] + } ], marks: [ @@ -93,15 +93,15 @@ const opt = { interactive: false, encode: { enter: { - fill: { scale: 'color', field: 'name' }, + fill: { scale: 'color', field: 'name' } }, update: { x: { field: 'x0' }, y: { field: 'y0' }, x2: { field: 'x1' }, - y2: { field: 'y1' }, - }, - }, + y2: { field: 'y1' } + } + } }, { type: 'rect', @@ -109,19 +109,19 @@ const opt = { encode: { enter: { stroke: { value: '#fff' }, - tooltip: { signal: "{'title': datum.name, 'value': datum.size}" }, + tooltip: { signal: "{'title': datum.name, 'value': datum.size}" } }, update: { x: { field: 'x0' }, y: { field: 'y0' }, x2: { field: 'x1' }, y2: { field: 'y1' }, - fill: { value: 'transparent' }, + fill: { value: 'transparent' } }, hover: { - fill: { value: 'red' }, - }, - }, + fill: { value: 'red' } + } + } }, { type: 'text', @@ -135,27 +135,27 @@ const opt = { fill: { value: '#000' }, text: { field: 'name' }, fontSize: { scale: 'size', field: 'depth' }, - fillOpacity: { scale: 'opacity', field: 'depth' }, + fillOpacity: { scale: 'opacity', field: 'depth' } }, update: { x: { signal: '0.5 * (datum.x0 + datum.x1)' }, - y: { signal: '0.5 * (datum.y0 + datum.y1)' }, - }, - }, - }, - ], -}; -let chart = null; -let onboardingUI = null; + y: { signal: '0.5 * (datum.y0 + datum.y1)' } + } + } + } + ] +} +let chart = null +const onboardingUI = null const debouncedResize = debounce((event) => { - onboardingUI?.updateOnboarding(getAhoiConfig()); -}, 250); + onboardingUI?.updateOnboarding(getAhoiConfig()) +}, 250) -async function render() { - chart = await embed('#vis', opt); - window.addEventListener('resize', debouncedResize); +async function render () { + chart = await embed('#vis', opt) + window.addEventListener('resize', debouncedResize) } // registerEventListener(); -render(); +render() From d01f71b7debca4ccaa0dd66fdb6aa7269c7bd0d4 Mon Sep 17 00:00:00 2001 From: Silviya Geo Date: Mon, 12 Sep 2022 09:20:49 +0200 Subject: [PATCH 10/22] added heatmap to vega-lite --- packages/vega-demo/src/heatmap.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/vega-demo/src/heatmap.js b/packages/vega-demo/src/heatmap.js index 1c3415bb..d24a6e80 100644 --- a/packages/vega-demo/src/heatmap.js +++ b/packages/vega-demo/src/heatmap.js @@ -18,14 +18,20 @@ const opt = { autosize: 'none', data: { url: 'data/carsData.json' }, - mark: 'rect', + mark: { type: 'rect', tooltip: true }, encoding: { y: { field: 'Origin', type: 'nominal', title: 'Origin' }, x: { field: 'Cylinders', type: 'ordinal', title: 'Cylinders' }, - color: { aggregate: 'mean', field: 'Horsepower' } + // color: { aggregate: 'mean', field: 'Horsepower' } + color: { + field: 'Horsepower', + aggregate: 'max', + type: 'quantitative', + legend: { title: null } + } }, config: { - axis: { grid: true } + axis: { grid: true, labels: true } } } From da19025a9ca0187d11038252de7dac16d5e5f57b Mon Sep 17 00:00:00 2001 From: Silviya Geo Date: Mon, 12 Sep 2022 11:30:35 +0200 Subject: [PATCH 11/22] WIP --- packages/vega-demo/src/heatmap.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/vega-demo/src/heatmap.js b/packages/vega-demo/src/heatmap.js index d24a6e80..84a6a3ec 100644 --- a/packages/vega-demo/src/heatmap.js +++ b/packages/vega-demo/src/heatmap.js @@ -7,8 +7,13 @@ const onboardingUI = null const opt = { // $schema: 'https://vega.github.io/schema/vega-lite/v5.json', - title: 'Cars origin and their horsepower based on number of cylinders', - description: 'An example of heatmap.', + title: { + text: 'Cars origin and their horsepower based on number of cylinders', + + fontSize: 14 + + }, + description: 'An example vega-lite heatmap.', width: 1200, height: 600, padding: { From 840cb18d4302c01a1f4ea84c642d9191361cceee Mon Sep 17 00:00:00 2001 From: Silviya Geo Date: Mon, 12 Sep 2022 14:26:58 +0200 Subject: [PATCH 12/22] Add onboarding messages to vega-lite heatmap (WIP) --- packages/core/src/utils.ts | 61 ++++++++++++------------ packages/vega-demo/src/heatmap.js | 52 +++++++++++++++------ packages/vega/src/heatmap.ts | 32 +++++++++++++ packages/vega/src/index.ts | 78 +++++++++++++++++-------------- 4 files changed, 142 insertions(+), 81 deletions(-) create mode 100644 packages/vega/src/heatmap.ts diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts index d7356f72..a1f6c204 100644 --- a/packages/core/src/utils.ts +++ b/packages/core/src/utils.ts @@ -1,9 +1,9 @@ -import { createPopper } from "@popperjs/core/dist/esm/"; +import { createPopper } from '@popperjs/core/dist/esm/' import { EDefaultOnboardingStages, ISpecProp, - OnboardingAnchor, -} from "./interfaces"; + OnboardingAnchor +} from './interfaces' /** * Returns the dom node which contains the passed text @@ -18,15 +18,15 @@ const getDomNodeByTextContent = ( visElement, // The root node of the chart NodeFilter.SHOW_TEXT, // Look for text nodes only { - acceptNode(node) { + acceptNode (node) { // The filter method of interface NodeFilter return new RegExp(textContent).test(node.textContent as string) // Check if text contains target string ? NodeFilter.FILTER_ACCEPT // Found: accept node - : NodeFilter.FILTER_REJECT; // Not found: reject and continue - }, + : NodeFilter.FILTER_REJECT // Not found: reject and continue + } } ) - .nextNode()!?.parentElement; + .nextNode()!?.parentElement /** * Returns the anchor for the requested onboarding specification. @@ -39,22 +39,22 @@ export const getAnchor = ( ): OnboardingAnchor | undefined => { if (!prop) { // if prop is undefined -> return - return; + } else if (prop.anchor?.findDomNodeByValue) { // the dom node should be found by it's content // TODO: can findDomNodeByValue be removed? const targetDomNode = getDomNodeByTextContent( prop.domNodeValue ? prop.domNodeValue : prop.value, visElement - ); + ) // if no node was found by the given text return undefined, otherwise return the dom node return targetDomNode ? Object.assign({ element: targetDomNode }, prop.anchor || {}) - : undefined; + : undefined } else if (prop.anchor) { - return prop.anchor; + return prop.anchor } -}; +} /** * Returns the color for the specific onboarding stage @@ -63,15 +63,15 @@ export const getAnchor = ( export const getColor = (stage: string) => { switch (stage) { case EDefaultOnboardingStages.ANALYZING: - return "#FE8029"; + return '#FE8029' case EDefaultOnboardingStages.READING: - return "#7B5096"; + return '#7B5096' case EDefaultOnboardingStages.USING: - return "#003D5C"; + return '#003D5C' default: - return "white"; + return 'white' } -}; +} /** * Does the popper function for the given tooltip + anchor @@ -80,15 +80,15 @@ export const getColor = (stage: string) => { */ export const createPopperTooltip = (anchor, tooltip) => { createPopper(anchor, tooltip, { - placement: "top", + placement: 'top', modifiers: [ { - name: "offset", - options: { offset: [0, 8] }, - }, - ], - }); -}; + name: 'offset', + options: { offset: [0, 8] } + } + ] + }) +} /** * returns the markerId with the visahoi prefix @@ -97,9 +97,8 @@ export const createPopperTooltip = (anchor, tooltip) => { * @returns */ export const getMarkerDomId = (id: string): string => { - return `visahoi-marker-${id}`; -}; - + return `visahoi-marker-${id}` +} /** * returns the markerId with the visahoi navigation prefix @@ -107,8 +106,6 @@ export const getMarkerDomId = (id: string): string => { * @param id * @returns */ - export const getNavigationMarkerDomId = (id: string): string => { - return `visahoi-marker-navigation-visahoi-marker-${id}`; -}; - - +export const getNavigationMarkerDomId = (id: string): string => { + return `visahoi-marker-navigation-visahoi-marker-${id}` +} diff --git a/packages/vega-demo/src/heatmap.js b/packages/vega-demo/src/heatmap.js index 84a6a3ec..40fc213b 100644 --- a/packages/vega-demo/src/heatmap.js +++ b/packages/vega-demo/src/heatmap.js @@ -1,26 +1,30 @@ import embed from 'vega-embed' +import { generateBasicAnnotations, ahoi, EVisualizationType } from '@visahoi/vega' import debounce from 'lodash.debounce' import '../public/data/jobsplan.json' let chart = null -const onboardingUI = null +let showOnboarding = false +let onboardingUI = null + +const debouncedResize = debounce((event) => { + onboardingUI?.updateOnboarding(getAhoiConfig()) +}, 250) const opt = { // $schema: 'https://vega.github.io/schema/vega-lite/v5.json', title: { text: 'Cars origin and their horsepower based on number of cylinders', - fontSize: 14 - }, + // actions: false, description: 'An example vega-lite heatmap.', - width: 1200, + width: 'container', height: 600, padding: { - left: window.innerWidth / 2 - 600, + left: 80, top: 30 }, - autosize: 'none', data: { url: 'data/carsData.json' }, mark: { type: 'rect', tooltip: true }, @@ -31,8 +35,8 @@ const opt = { color: { field: 'Horsepower', aggregate: 'max', - type: 'quantitative', - legend: { title: null } + type: 'quantitative' + // legend: { title: 'legend' } } }, config: { @@ -41,14 +45,36 @@ const opt = { } -const debouncedResize = debounce((event) => { - onboardingUI?.updateOnboarding(getAhoiConfig()) -}, 250) +const getAhoiConfig = async () => { + const defaultOnboardingMessages = await generateBasicAnnotations(EVisualizationType.HEATMAP, chart) + const extendedOnboardingMessages = defaultOnboardingMessages.map((d) => ({ + ...d, + text: 'test123' + })) + const ahoiConfig = { + onboardingMessages: defaultOnboardingMessages + } + return ahoiConfig +} async function render () { - chart = await embed('#vis', opt) + chart = await embed('#vis', opt, { actions: false }) window.addEventListener('resize', debouncedResize) } -// registerEventListener(); +const registerEventListener = () => { + const helpIcon = document.getElementById('show-onboarding') + if (!helpIcon) { return } + helpIcon.addEventListener('click', async () => { + showOnboarding = !showOnboarding + if (showOnboarding) { + const config = await getAhoiConfig() + onboardingUI = await ahoi(EVisualizationType.HEATMAP, chart, config) + } else { + onboardingUI?.removeOnboarding() + } + }) +} + +registerEventListener() render() diff --git a/packages/vega/src/heatmap.ts b/packages/vega/src/heatmap.ts new file mode 100644 index 00000000..bad1c398 --- /dev/null +++ b/packages/vega/src/heatmap.ts @@ -0,0 +1,32 @@ +import { EVisualizationType, IOnboardingMessage, generateMessages } from '@visahoi/core' +import { Spec } from 'vega-typings' +import { IOnboardingHeatmapSpec } from '@visahoi/core/src/heatmap' + +function extractOnboardingSpec (vegaSpec: Spec, elems: any[]): IOnboardingHeatmapSpec { + console.log(vegaSpec, 'Vega specification') + + return { + chartTitle: { + // value: vegaSpec.title, + value: 'Cars origin and their horsepower based on number of cylinders', + anchor: { + findDomNodeByValue: true, + offset: { left: -20, top: 5 } + } + }, + legendDescription: { + value: 'Max of Horsepower', + anchor: { + findDomNodeByValue: true + // offset: {} + } + } + + } +} + +export function heatmapFactory (vegaSpec: Spec, elems: any[], visElement: Element): IOnboardingMessage[] { + const onbordingSpec = extractOnboardingSpec(vegaSpec, elems) + console.log(onbordingSpec, 'Onboardidning speex') + return generateMessages(EVisualizationType.HEATMAP, onbordingSpec, visElement) +} diff --git a/packages/vega/src/index.ts b/packages/vega/src/index.ts index 8110a85a..711543ed 100644 --- a/packages/vega/src/index.ts +++ b/packages/vega/src/index.ts @@ -1,4 +1,4 @@ -import { Result } from "vega-embed"; +import { Result } from 'vega-embed' import { createBasicOnboardingMessage, createBasicOnboardingStage, @@ -11,12 +11,13 @@ import { IOnboardingMessage, setEditMode, setOnboardingMessage, - setOnboardingStage, -} from "@visahoi/core"; -import { barChartFactory } from "./bar-chart"; -import { changeMatrixFactory } from "./change-matrix"; -import { horizonGraphFactory } from "./horizon-graph"; -import { scatterplotFactory } from "./scatterplot"; + setOnboardingStage +} from '@visahoi/core' +import { barChartFactory } from './bar-chart' +import { changeMatrixFactory } from './change-matrix' +import { horizonGraphFactory } from './horizon-graph' +import { scatterplotFactory } from './scatterplot' +import { heatmapFactory } from './heatmap' // just pass them through export { createBasicOnboardingMessage, @@ -26,8 +27,8 @@ export { deleteOnboardingStage, setOnboardingStage, setOnboardingMessage, - setEditMode, -}; + setEditMode +} /** * @@ -39,65 +40,70 @@ export const generateBasicAnnotations = async ( visType: EVisualizationType, chart: any ): Promise => { - const evaluated = await chart.view.runAsync(); + const evaluated = await chart.view.runAsync() // Vega-lite spec after all rendering happend and the aggregations - const vegaSpec = chart.vgSpec; - const origSpec = chart.spec; - const visElement: Element = (chart.view as any)._el; + const vegaSpec = chart.vgSpec + const origSpec = chart.spec + const visElement: Element = (chart.view as any)._el // ADDITIONAL (not used) // Get the individual nodes - const nodes = document.querySelectorAll(".role-mark > path"); + const nodes = document.querySelectorAll('.role-mark > path') // Get the data of the individual bars - const d3Data = Array.from(nodes).map((el: any) => el.__data__); + const d3Data = Array.from(nodes).map((el: any) => el.__data__) - let onboardingMessages; + let onboardingMessages switch (visType) { case EVisualizationType.BAR_CHART: // data_0 contains the input, output and values which are the aggregated data values - const { data_0 } = evaluated._runtime.data; + const { data_0 } = evaluated._runtime.data // Use the aggregated data values - const values = data_0.values.value; + const values = data_0.values.value onboardingMessages = barChartFactory( vegaSpec, values, d3Data, visElement - ); - break; + ) + break case EVisualizationType.CHANGE_MATRIX: - onboardingMessages = changeMatrixFactory(vegaSpec, d3Data, visElement); - break; + onboardingMessages = changeMatrixFactory(vegaSpec, d3Data, visElement) + break case EVisualizationType.HORIZON_GRAPH: // data_0 contains the input, output and values which are the aggregated data values - const { data_1 } = evaluated._runtime.data; + const { data_1 } = evaluated._runtime.data // Use the aggregated data values - const aggregatedValues = data_1.values.value; + const aggregatedValues = data_1.values.value onboardingMessages = horizonGraphFactory( vegaSpec, origSpec, d3Data, aggregatedValues, visElement - ); - break; + ) + break case EVisualizationType.SCATTERPLOT: - onboardingMessages = scatterplotFactory(vegaSpec, d3Data, visElement); - break; + onboardingMessages = scatterplotFactory(vegaSpec, d3Data, visElement) + break + + case EVisualizationType.HEATMAP: + onboardingMessages = heatmapFactory(vegaSpec, d3Data, visElement) + console.log(onboardingMessages, 'Onboarding messages') + break default: throw new Error( `No onboarding for visualization type ${visType} available.` - ); + ) } - return onboardingMessages; -}; + return onboardingMessages +} /** * @@ -105,7 +111,7 @@ export const generateBasicAnnotations = async ( * @param chart * @param onboardingElement ID of the DOM Element where the onboarding Messages should be displayed */ -export async function ahoi( +export async function ahoi ( visType: EVisualizationType, chart: any, ahoiConfig: IAhoiConfig @@ -113,9 +119,9 @@ export async function ahoi( ahoiConfig.onboardingMessages = await generateBasicAnnotations( visType, chart - ); - const visElement = chart.view._el; - return injectOnboarding(ahoiConfig, visElement, "column"); + ) + const visElement = chart.view._el + return injectOnboarding(ahoiConfig, visElement, 'column') } -export { EVisualizationType }; +export { EVisualizationType } From aa71141e212b2f5e6fff924deca67426a57644aa Mon Sep 17 00:00:00 2001 From: dvsilviyageo Date: Tue, 20 Sep 2022 10:50:55 +0200 Subject: [PATCH 13/22] Removed console logs --- packages/vega-demo/src/heatmap.js | 2 +- packages/vega/src/heatmap.ts | 3 --- packages/vega/src/index.ts | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/vega-demo/src/heatmap.js b/packages/vega-demo/src/heatmap.js index 40fc213b..c4b86b1e 100644 --- a/packages/vega-demo/src/heatmap.js +++ b/packages/vega-demo/src/heatmap.js @@ -15,7 +15,7 @@ const opt = { // $schema: 'https://vega.github.io/schema/vega-lite/v5.json', title: { text: 'Cars origin and their horsepower based on number of cylinders', - fontSize: 14 + fontSize: 16 }, // actions: false, description: 'An example vega-lite heatmap.', diff --git a/packages/vega/src/heatmap.ts b/packages/vega/src/heatmap.ts index bad1c398..b16f4ee1 100644 --- a/packages/vega/src/heatmap.ts +++ b/packages/vega/src/heatmap.ts @@ -3,8 +3,6 @@ import { Spec } from 'vega-typings' import { IOnboardingHeatmapSpec } from '@visahoi/core/src/heatmap' function extractOnboardingSpec (vegaSpec: Spec, elems: any[]): IOnboardingHeatmapSpec { - console.log(vegaSpec, 'Vega specification') - return { chartTitle: { // value: vegaSpec.title, @@ -27,6 +25,5 @@ function extractOnboardingSpec (vegaSpec: Spec, elems: any[]): IOnboardingHeatma export function heatmapFactory (vegaSpec: Spec, elems: any[], visElement: Element): IOnboardingMessage[] { const onbordingSpec = extractOnboardingSpec(vegaSpec, elems) - console.log(onbordingSpec, 'Onboardidning speex') return generateMessages(EVisualizationType.HEATMAP, onbordingSpec, visElement) } diff --git a/packages/vega/src/index.ts b/packages/vega/src/index.ts index 711543ed..dcebd0b8 100644 --- a/packages/vega/src/index.ts +++ b/packages/vega/src/index.ts @@ -94,7 +94,6 @@ export const generateBasicAnnotations = async ( case EVisualizationType.HEATMAP: onboardingMessages = heatmapFactory(vegaSpec, d3Data, visElement) - console.log(onboardingMessages, 'Onboarding messages') break default: From f32309d431f514ae5596492fa4603179da22fb57 Mon Sep 17 00:00:00 2001 From: dvsilviyageo Date: Sun, 25 Sep 2022 20:48:45 +0200 Subject: [PATCH 14/22] Add onboarding messages --- .../core/src/components/getMarkerInformation.ts | 1 + packages/core/src/heatmap.ts | 2 ++ packages/vega/src/heatmap.ts | 14 ++++++++------ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/core/src/components/getMarkerInformation.ts b/packages/core/src/components/getMarkerInformation.ts index 0772b5b1..11d423a6 100644 --- a/packages/core/src/components/getMarkerInformation.ts +++ b/packages/core/src/components/getMarkerInformation.ts @@ -7,6 +7,7 @@ const h = 30 const textOffset = 5 export function getMarkerInformation (onboardingMessages: IOnboardingMessage[]): IMarkerInformation[] { + console.log(onboardingMessages, 'Onboarding messages') const markerInformation: IMarkerInformation[] = [] onboardingMessages.forEach((message, index) => { if (!message.anchor) { diff --git a/packages/core/src/heatmap.ts b/packages/core/src/heatmap.ts index c0eac799..26a4dc74 100644 --- a/packages/core/src/heatmap.ts +++ b/packages/core/src/heatmap.ts @@ -35,6 +35,8 @@ function generateMessages ( EDefaultOnboardingStages.ANALYZING ) as IOnboardingStage + console.log(spec, 'Spec') + const messages = [ { anchor: getAnchor(spec.chartTitle, visElement), diff --git a/packages/vega/src/heatmap.ts b/packages/vega/src/heatmap.ts index b16f4ee1..2f86becc 100644 --- a/packages/vega/src/heatmap.ts +++ b/packages/vega/src/heatmap.ts @@ -1,22 +1,23 @@ import { EVisualizationType, IOnboardingMessage, generateMessages } from '@visahoi/core' import { Spec } from 'vega-typings' import { IOnboardingHeatmapSpec } from '@visahoi/core/src/heatmap' +// import { vega } from 'vega-embed' function extractOnboardingSpec (vegaSpec: Spec, elems: any[]): IOnboardingHeatmapSpec { return { chartTitle: { - // value: vegaSpec.title, - value: 'Cars origin and their horsepower based on number of cylinders', + value: vegaSpec?.title?.text, + // value: 'Cars origin and their horsepower based on number of cylinders', anchor: { - findDomNodeByValue: true, - offset: { left: -20, top: 5 } + findDomNodeByValue: true + // offset: { left: -20, top: 5 } } }, legendDescription: { value: 'Max of Horsepower', anchor: { - findDomNodeByValue: true - // offset: {} + findDomNodeByValue: true, + offset: { left: -20, top: 5 } } } @@ -24,6 +25,7 @@ function extractOnboardingSpec (vegaSpec: Spec, elems: any[]): IOnboardingHeatma } export function heatmapFactory (vegaSpec: Spec, elems: any[], visElement: Element): IOnboardingMessage[] { + console.log(vegaSpec, 'chart') const onbordingSpec = extractOnboardingSpec(vegaSpec, elems) return generateMessages(EVisualizationType.HEATMAP, onbordingSpec, visElement) } From d3511ab878a0740c8d4a0fb6d964ce33dddeebc7 Mon Sep 17 00:00:00 2001 From: dvsilviyageo Date: Mon, 26 Sep 2022 12:26:56 +0200 Subject: [PATCH 15/22] Changed the height of the chart and add onboarding(WIP) --- packages/core/src/components/stores.ts | 76 +++++++++++++------------- packages/core/src/utils.ts | 9 +++ packages/vega-demo/src/heatmap.js | 2 +- 3 files changed, 48 insertions(+), 39 deletions(-) diff --git a/packages/core/src/components/stores.ts b/packages/core/src/components/stores.ts index 9eaa49da..919965ee 100644 --- a/packages/core/src/components/stores.ts +++ b/packages/core/src/components/stores.ts @@ -1,60 +1,60 @@ -import { writable } from "svelte/store"; +import { writable } from 'svelte/store' import { IMarkerInformation, IOnboardingMessage, IOnboardingStage, - NavigationAlignment, -} from "../interfaces"; + NavigationAlignment +} from '../interfaces' export const initializeStoreValue = (defaultValue: any) => { - const { subscribe, set, update } = writable(defaultValue); + const { subscribe, set, update } = writable(defaultValue) return { subscribe, set, update, - reset: () => set(defaultValue), - }; -}; + reset: () => set(defaultValue) + } +} -export const showOnboarding = initializeStoreValue(false); -export const showOnboardingSteps = initializeStoreValue(false); -export const activeStep = initializeStoreValue(null); +export const showOnboarding = initializeStoreValue(false) +export const showOnboardingSteps = initializeStoreValue(false) +export const activeStep = initializeStoreValue(null) export const onboardingMessages = initializeStoreValue( [] -); +) export const navigationAlignment = - initializeStoreValue("column"); -export const onboardingStages = initializeStoreValue([]); + initializeStoreValue('column') +export const onboardingStages = initializeStoreValue([]) export const activeOnboardingStage = - initializeStoreValue(null); + initializeStoreValue(null) export const activeMarker = initializeStoreValue( null -); +) export const selectedMarker = initializeStoreValue( null -); -export const showBackdrop = initializeStoreValue(true); -export const backdropOpacity = initializeStoreValue(0.15); -export const showOnboardingNavigation = initializeStoreValue(false); -export const previousMarkerId = initializeStoreValue(""); -export const markerIndexId = initializeStoreValue(null); -export const showHideCloseText = initializeStoreValue(true); -export const isEditModeActive = initializeStoreValue(false); +) +export const showBackdrop = initializeStoreValue(true) +export const backdropOpacity = initializeStoreValue(0.15) +export const showOnboardingNavigation = initializeStoreValue(false) +export const previousMarkerId = initializeStoreValue('') +export const markerIndexId = initializeStoreValue(null) +export const showHideCloseText = initializeStoreValue(true) +export const isEditModeActive = initializeStoreValue(false) -export const visXPosition = writable(0); -export const visYPosition = writable(0); -export const visHeight = writable(0); -export const visWidth = writable(0); -export const markerInformation = writable([]); +export const visXPosition = writable(0) +export const visYPosition = writable(0) +export const visHeight = writable(0) +export const visWidth = writable(0) +export const markerInformation = writable([]) export const resetStore = () => { - showOnboarding.reset(); - activeStep.reset(); - onboardingMessages.reset(); - navigationAlignment.reset(); - onboardingStages.reset(); - activeOnboardingStage.reset(); - activeMarker.reset(); - selectedMarker.reset(); - markerIndexId.reset(); -}; + showOnboarding.reset() + activeStep.reset() + onboardingMessages.reset() + navigationAlignment.reset() + onboardingStages.reset() + activeOnboardingStage.reset() + activeMarker.reset() + selectedMarker.reset() + markerIndexId.reset() +} diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts index a1f6c204..6d51b5ba 100644 --- a/packages/core/src/utils.ts +++ b/packages/core/src/utils.ts @@ -9,6 +9,7 @@ import { * Returns the dom node which contains the passed text * @param textContent the text content of the dom node which should be found */ + const getDomNodeByTextContent = ( textContent: string, visElement: Element @@ -18,7 +19,11 @@ const getDomNodeByTextContent = ( visElement, // The root node of the chart NodeFilter.SHOW_TEXT, // Look for text nodes only { + acceptNode (node) { + console.log(node, 'node') + console.log(textContent, 'textContent') + console.log(node.textContent, 'Nodes text content') // The filter method of interface NodeFilter return new RegExp(textContent).test(node.textContent as string) // Check if text contains target string ? NodeFilter.FILTER_ACCEPT // Found: accept node @@ -43,10 +48,14 @@ export const getAnchor = ( } else if (prop.anchor?.findDomNodeByValue) { // the dom node should be found by it's content // TODO: can findDomNodeByValue be removed? + + // eslint-disable-next-line no-debugger + debugger const targetDomNode = getDomNodeByTextContent( prop.domNodeValue ? prop.domNodeValue : prop.value, visElement ) + console.log(targetDomNode, 'Target dom node') // if no node was found by the given text return undefined, otherwise return the dom node return targetDomNode ? Object.assign({ element: targetDomNode }, prop.anchor || {}) diff --git a/packages/vega-demo/src/heatmap.js b/packages/vega-demo/src/heatmap.js index c4b86b1e..ad339353 100644 --- a/packages/vega-demo/src/heatmap.js +++ b/packages/vega-demo/src/heatmap.js @@ -20,7 +20,7 @@ const opt = { // actions: false, description: 'An example vega-lite heatmap.', width: 'container', - height: 600, + height: 'container', padding: { left: 80, top: 30 From 6fd23ed3040bc35bff969cae496106d60aeab11a Mon Sep 17 00:00:00 2001 From: dvsilviyageo Date: Mon, 26 Sep 2022 14:44:38 +0200 Subject: [PATCH 16/22] Added title to onboarding message --- .../src/components/getMarkerInformation.ts | 1 - packages/core/src/utils.ts | 12 +++++------- packages/vega/src/heatmap.ts | 19 +++++++++---------- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/packages/core/src/components/getMarkerInformation.ts b/packages/core/src/components/getMarkerInformation.ts index 11d423a6..0772b5b1 100644 --- a/packages/core/src/components/getMarkerInformation.ts +++ b/packages/core/src/components/getMarkerInformation.ts @@ -7,7 +7,6 @@ const h = 30 const textOffset = 5 export function getMarkerInformation (onboardingMessages: IOnboardingMessage[]): IMarkerInformation[] { - console.log(onboardingMessages, 'Onboarding messages') const markerInformation: IMarkerInformation[] = [] onboardingMessages.forEach((message, index) => { if (!message.anchor) { diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts index 6d51b5ba..f1929232 100644 --- a/packages/core/src/utils.ts +++ b/packages/core/src/utils.ts @@ -21,9 +21,6 @@ const getDomNodeByTextContent = ( { acceptNode (node) { - console.log(node, 'node') - console.log(textContent, 'textContent') - console.log(node.textContent, 'Nodes text content') // The filter method of interface NodeFilter return new RegExp(textContent).test(node.textContent as string) // Check if text contains target string ? NodeFilter.FILTER_ACCEPT // Found: accept node @@ -49,13 +46,14 @@ export const getAnchor = ( // the dom node should be found by it's content // TODO: can findDomNodeByValue be removed? - // eslint-disable-next-line no-debugger - debugger - const targetDomNode = getDomNodeByTextContent( + let targetDomNode = getDomNodeByTextContent( prop.domNodeValue ? prop.domNodeValue : prop.value, visElement ) - console.log(targetDomNode, 'Target dom node') + + if (targetDomNode === undefined) { + targetDomNode = document.getElementById('vis') + } // if no node was found by the given text return undefined, otherwise return the dom node return targetDomNode ? Object.assign({ element: targetDomNode }, prop.anchor || {}) diff --git a/packages/vega/src/heatmap.ts b/packages/vega/src/heatmap.ts index 2f86becc..4f3c279d 100644 --- a/packages/vega/src/heatmap.ts +++ b/packages/vega/src/heatmap.ts @@ -1,31 +1,30 @@ import { EVisualizationType, IOnboardingMessage, generateMessages } from '@visahoi/core' import { Spec } from 'vega-typings' import { IOnboardingHeatmapSpec } from '@visahoi/core/src/heatmap' -// import { vega } from 'vega-embed' function extractOnboardingSpec (vegaSpec: Spec, elems: any[]): IOnboardingHeatmapSpec { return { chartTitle: { value: vegaSpec?.title?.text, // value: 'Cars origin and their horsepower based on number of cylinders', - anchor: { - findDomNodeByValue: true - // offset: { left: -20, top: 5 } - } - }, - legendDescription: { - value: 'Max of Horsepower', anchor: { findDomNodeByValue: true, - offset: { left: -20, top: 5 } + offset: { left: -20, top: -10 } } } + // legendDescription: { + // // value: 'Max of Horsepower', + // value: vegaSpec?.legends[0]?.title, + // anchor: { + // findDomNodeByValue: true, + // offset: { left: -20, top: 5 } + // } + // } } } export function heatmapFactory (vegaSpec: Spec, elems: any[], visElement: Element): IOnboardingMessage[] { - console.log(vegaSpec, 'chart') const onbordingSpec = extractOnboardingSpec(vegaSpec, elems) return generateMessages(EVisualizationType.HEATMAP, onbordingSpec, visElement) } From 24f845cdcfd28dc73f7ccf822c7ea37a6b4991db Mon Sep 17 00:00:00 2001 From: dvsilviyageo Date: Wed, 28 Sep 2022 13:44:28 +0200 Subject: [PATCH 17/22] Changed the heatmap vega renderer to svg and rendered the basic messages --- packages/core/src/utils.ts | 9 +-------- packages/vega-demo/src/heatmap.js | 6 +++++- packages/vega/src/heatmap.ts | 16 +++++++--------- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts index f1929232..a1f6c204 100644 --- a/packages/core/src/utils.ts +++ b/packages/core/src/utils.ts @@ -9,7 +9,6 @@ import { * Returns the dom node which contains the passed text * @param textContent the text content of the dom node which should be found */ - const getDomNodeByTextContent = ( textContent: string, visElement: Element @@ -19,7 +18,6 @@ const getDomNodeByTextContent = ( visElement, // The root node of the chart NodeFilter.SHOW_TEXT, // Look for text nodes only { - acceptNode (node) { // The filter method of interface NodeFilter return new RegExp(textContent).test(node.textContent as string) // Check if text contains target string @@ -45,15 +43,10 @@ export const getAnchor = ( } else if (prop.anchor?.findDomNodeByValue) { // the dom node should be found by it's content // TODO: can findDomNodeByValue be removed? - - let targetDomNode = getDomNodeByTextContent( + const targetDomNode = getDomNodeByTextContent( prop.domNodeValue ? prop.domNodeValue : prop.value, visElement ) - - if (targetDomNode === undefined) { - targetDomNode = document.getElementById('vis') - } // if no node was found by the given text return undefined, otherwise return the dom node return targetDomNode ? Object.assign({ element: targetDomNode }, prop.anchor || {}) diff --git a/packages/vega-demo/src/heatmap.js b/packages/vega-demo/src/heatmap.js index ad339353..0a37cb32 100644 --- a/packages/vega-demo/src/heatmap.js +++ b/packages/vega-demo/src/heatmap.js @@ -42,7 +42,11 @@ const opt = { config: { axis: { grid: true, labels: true } } +} +const config = { + responsive: true, + renderer: 'svg' } const getAhoiConfig = async () => { @@ -58,7 +62,7 @@ const getAhoiConfig = async () => { } async function render () { - chart = await embed('#vis', opt, { actions: false }) + chart = await embed('#vis', opt, config, { actions: false }) window.addEventListener('resize', debouncedResize) } diff --git a/packages/vega/src/heatmap.ts b/packages/vega/src/heatmap.ts index 4f3c279d..a7b0f6a7 100644 --- a/packages/vega/src/heatmap.ts +++ b/packages/vega/src/heatmap.ts @@ -6,20 +6,18 @@ function extractOnboardingSpec (vegaSpec: Spec, elems: any[]): IOnboardingHeatma return { chartTitle: { value: vegaSpec?.title?.text, - // value: 'Cars origin and their horsepower based on number of cylinders', anchor: { findDomNodeByValue: true, offset: { left: -20, top: -10 } } + }, + legendDescription: { + value: vegaSpec?.legends[0]?.title, + anchor: { + findDomNodeByValue: true, + offset: { left: -20, top: 5 } + } } - // legendDescription: { - // // value: 'Max of Horsepower', - // value: vegaSpec?.legends[0]?.title, - // anchor: { - // findDomNodeByValue: true, - // offset: { left: -20, top: 5 } - // } - // } } } From 1868e2aa3c43d6eeacea7b385088f9fe9b7e19b0 Mon Sep 17 00:00:00 2001 From: dvsilviyageo Date: Mon, 3 Oct 2022 10:44:03 +0200 Subject: [PATCH 18/22] Added axis and legend description --- packages/vega-demo/src/heatmap.js | 4 ++++ packages/vega/src/heatmap.ts | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/packages/vega-demo/src/heatmap.js b/packages/vega-demo/src/heatmap.js index 0a37cb32..f60c08cf 100644 --- a/packages/vega-demo/src/heatmap.js +++ b/packages/vega-demo/src/heatmap.js @@ -36,6 +36,10 @@ const opt = { field: 'Horsepower', aggregate: 'max', type: 'quantitative' + // scale: { + // range: ['#337ab7', '#f5f5f5', '#ec6836'] + // } + // legend: { title: 'legend' } } }, diff --git a/packages/vega/src/heatmap.ts b/packages/vega/src/heatmap.ts index a7b0f6a7..897b72bc 100644 --- a/packages/vega/src/heatmap.ts +++ b/packages/vega/src/heatmap.ts @@ -1,8 +1,10 @@ import { EVisualizationType, IOnboardingMessage, generateMessages } from '@visahoi/core' import { Spec } from 'vega-typings' import { IOnboardingHeatmapSpec } from '@visahoi/core/src/heatmap' +import { vega } from 'vega-embed' function extractOnboardingSpec (vegaSpec: Spec, elems: any[]): IOnboardingHeatmapSpec { + console.log(vegaSpec, 'Vega') return { chartTitle: { value: vegaSpec?.title?.text, @@ -17,6 +19,19 @@ function extractOnboardingSpec (vegaSpec: Spec, elems: any[]): IOnboardingHeatma findDomNodeByValue: true, offset: { left: -20, top: 5 } } + }, + axisDescription: { + value: vegaSpec?.axes[2]?.title, + anchor: { + findDomNodeByValue: true, + offset: { left: 80 } + } + }, + yAxis: { + value: vegaSpec?.axes[3]?.title + }, + xAxis: { + value: vegaSpec?.axes[2]?.title } } From a565591390e22beff0b7b5d8babd92ac6f5011c2 Mon Sep 17 00:00:00 2001 From: dvsilviyageo Date: Mon, 3 Oct 2022 10:44:16 +0200 Subject: [PATCH 19/22] Added axis and legend description --- packages/vega/src/heatmap.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/vega/src/heatmap.ts b/packages/vega/src/heatmap.ts index 897b72bc..16e6aa29 100644 --- a/packages/vega/src/heatmap.ts +++ b/packages/vega/src/heatmap.ts @@ -4,7 +4,6 @@ import { IOnboardingHeatmapSpec } from '@visahoi/core/src/heatmap' import { vega } from 'vega-embed' function extractOnboardingSpec (vegaSpec: Spec, elems: any[]): IOnboardingHeatmapSpec { - console.log(vegaSpec, 'Vega') return { chartTitle: { value: vegaSpec?.title?.text, From 371fee8f9764693ebc71cb8ea4405edf2675ff24 Mon Sep 17 00:00:00 2001 From: dvsilviyageo Date: Thu, 6 Oct 2022 09:51:55 +0200 Subject: [PATCH 20/22] setOnboarding message is used to change the message --- packages/vega-demo/src/heatmap.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/vega-demo/src/heatmap.js b/packages/vega-demo/src/heatmap.js index f60c08cf..eef3578a 100644 --- a/packages/vega-demo/src/heatmap.js +++ b/packages/vega-demo/src/heatmap.js @@ -1,5 +1,5 @@ import embed from 'vega-embed' -import { generateBasicAnnotations, ahoi, EVisualizationType } from '@visahoi/vega' +import { generateBasicAnnotations, ahoi, EVisualizationType, setOnboardingMessage } from '@visahoi/vega' import debounce from 'lodash.debounce' import '../public/data/jobsplan.json' @@ -83,6 +83,10 @@ const registerEventListener = () => { } }) } +setOnboardingMessage({ + id: 'unique-message-id-3', + text: 'A deep blue color indicates maximum horse power whereas a light blue indicates medium horse power. Minimum horse power is indicated with light bluish yellow' +}) registerEventListener() render() From bafdcbfb7bd156d5f458961b18cd2191a4632a23 Mon Sep 17 00:00:00 2001 From: dvsilviyageo Date: Thu, 6 Oct 2022 11:07:45 +0200 Subject: [PATCH 21/22] Changed the onboarding message of the colorscale --- packages/vega-demo/src/heatmap.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/vega-demo/src/heatmap.js b/packages/vega-demo/src/heatmap.js index eef3578a..1510f235 100644 --- a/packages/vega-demo/src/heatmap.js +++ b/packages/vega-demo/src/heatmap.js @@ -78,15 +78,15 @@ const registerEventListener = () => { if (showOnboarding) { const config = await getAhoiConfig() onboardingUI = await ahoi(EVisualizationType.HEATMAP, chart, config) + setOnboardingMessage({ + id: 'unique-message-id-3', + text: 'A deep blue color indicates maximum horse power whereas a light blue indicates medium horse power. Minimum horse power is indicated with light bluish yellow' + }) } else { onboardingUI?.removeOnboarding() } }) } -setOnboardingMessage({ - id: 'unique-message-id-3', - text: 'A deep blue color indicates maximum horse power whereas a light blue indicates medium horse power. Minimum horse power is indicated with light bluish yellow' -}) registerEventListener() render() From 4fc1fdc234576bbd306c84587953f374dcbacf25 Mon Sep 17 00:00:00 2001 From: dvsilviyageo Date: Thu, 6 Oct 2022 11:14:22 +0200 Subject: [PATCH 22/22] Added editTooltip to the store --- packages/core/src/components/stores.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/src/components/stores.ts b/packages/core/src/components/stores.ts index 919965ee..4febd34f 100644 --- a/packages/core/src/components/stores.ts +++ b/packages/core/src/components/stores.ts @@ -40,6 +40,7 @@ export const previousMarkerId = initializeStoreValue('') export const markerIndexId = initializeStoreValue(null) export const showHideCloseText = initializeStoreValue(true) export const isEditModeActive = initializeStoreValue(false) +export const editTooltip = initializeStoreValue(false) export const visXPosition = writable(0) export const visYPosition = writable(0)