如何在 Vizframe 图表中实现线性回归线?
How can I implement a linear regression line in a Vizframe Chart?
我有一个散点图 Vizframe 图表,我需要在其中包含一条线性 regression/trend 线。知道如何做到这一点吗?这似乎不是 vizframe 'out of box' 提供的东西?我找不到解决方案!
问题:
关于在散点图 Vizframe 图表上实现回归线的可行方法有什么建议吗?
这是我的设置代码。按下按钮时,散点图会在 dialog/modal 中打开。
sap.ui.define([
'jquery.sap.global',
'vizConcept/controller/BaseController',
'sap/ui/model/json/JSONModel',
'vizConcept/model/viewControls',
'sap/m/Button',
'sap/m/Dialog',
],
function (jQuery, BaseController, JSONModel, viewControls, Button, Dialog) {
"use strict";
var controls;
var mainController = BaseController.extend("vizConcept.controller.Main", {
onInit: function(oEvent) {
// Access/expose the defined model(s) configured in the Component.js or Manifest.json within the controller.
this.getView().setModel(this.getOwnerComponent().getModel("products"), "products");
var oModel = this.getView().getModel("products");
this.getView().setModel(oModel);
var sUrl = "#" + this.getOwnerComponent().getRouter().getURL("page2");
$(function() {
var dataset = new sap.viz.ui5.data.FlattenedDataset({
dimensions : [
{
axis : 1,
name : 'Award Date',
value : "{AwdDate}"
}
],
measures : [
{
group: 1,
name : 'Award Date',
value : '{Hist}'
},
{
group: 2,
name : 'Current PPI',
value : '{Current}'
}
],
data : {
path : "/ProductCollection"
}
});
var scatterViz = new sap.viz.ui5.Scatter({
id : "idscatter",
width : "1000px",
height : "400px",
title : {
text : 'Pricing Tool Scatter Plot Example'
},
xAxis : {
title : {
visible : true
}
},
yAxis : {
title : {
visible : true
}
},
dataset : dataset
});
scatterViz.setModel(sap.ui.getCore().getModel());
scatterViz.setModel(oModel);
var dlg = new sap.m.Dialog({
id: 'vizModal',
title: 'Scatter Plot Example Viz',
width : "1800px",
height : "600px",
content : [scatterViz],
beginButton: new Button({
text: 'Close',
press: function () {
dlg.close();
}
})
});
(new sap.m.Button({
text: 'open',
type: 'Accept',
press: function() {
dlg.open();
scatterViz.invalidate();
}
})).placeAt('content');
});
},
onToPage2 : function () {
this.getOwnerComponent().getRouter().navTo("page2");
},
});
return mainController;
});
编辑
这是在 vizframe 图表上输出的 'products' 模型。我在 manifest.json 中定义了产品模型,但那里的连接很好:
产品型号
{
"ProductCollection": [
{
"Item": "1",
"AwdDate": "20160715",
"Hist": 171.9,
"Current": 183
},
{
"Item": "2",
"AwdDate": "20160701",
"Hist" : 144.3,
"Current": 158.6
},
{
"Item": "3",
"AwdDate": "20150701",
"Hist": 160,
"Current": 165
},
{
"Item": "1",
"AwdDate": "20160715",
"Hist": 201,
"Current": 167
},
{
"Item": "2",
"AwdDate": "20160801",
"Hist" : 175.3,
"Current": 178.2
},
{
"Item": "3",
"AwdDate": "20150721",
"Hist": 160,
"Current": 147
},
{
"Item": "1",
"AwdDate": "20160715",
"Hist": 175.9,
"Current": 185.2
},
{
"Item": "2",
"AwdDate": "20161101",
"Hist" : 165.3,
"Current": 158.2
},
{
"Item": "3",
"AwdDate": "201700101",
"Hist": 160,
"Current": 165
},
{
"Item": "4",
"AwdDate": "201600401",
"Hist": 173,
"Current": 177
}
]
};
编辑 2
这是我尝试提供的解决方案 here。但是在controller的onInit()函数中包含这个之后什么也没有出现
var regressionData = [];
for (var i = 0; i < 10; i++) {
regressionData[i] = [oData.ProductCollection[i].Current, oData.ProductCollection[i].Hist];
};
regression('linear', regressionData);
不幸的是,可视化图表存在一些固有的局限性。即:
- 您不能向图表添加 "oblique" 参考线(= 趋势线)。您只能通过 Reference Line feature. Check out the (non-intuitive) documentation on this: Viz Charts Documentation 添加垂直/水平线(查看 plotArea.referenceLine.line;它只是一个数字 = 将是水平线/垂直线,具体取决于您的图表类型或方向)。
- 不能将散点图与折线图结合使用。如果您查看相同的 Viz Charts Documentation,您会看到在左侧的组合 "chapter" 中,没有 "Line - Scatter" 组合。
此外,您的 X 值 (AwDate) 是 ABAP 样式的日期,如 string。更适合使用日期/时间图表来正确显示它们。无论如何,当您使用日期时,回归更有意义。否则你的数据是 "categorical" 并且你可以进行回归的唯一方法是对它们进行排序并认为它们在 X 轴上等距 - 如果你有非等距数据(如你的示例中的数据),这不是你通常想要的).
我的建议是:
- 使用折线图代替散点图(这样也可以显示趋势线)。
- 将 ABAP 样式的字符串转换为日期,以便您可以使用时间序列图表。您的示例数据中有一些 "wrong" 日期顺便说一下:“201600401”。
- 根据需要进行回归并将其添加为单独的 "trend" 系列。您需要为其他系列中的每个点计算 "trend" 系列中的一个点(基本上,您必须向 ProductCollection 中的每一行添加一个 "trend" 属性)。如果您使用的是 OData 模型,那么您将需要切换到 JSON 客户端模型或使用格式化程序做一些丑陋的变通方法。
应要求,我在这里做了一个示例实现:https://jsfiddle.net/93mx0yvt/23/. The regression algorithm I borrowed from here: https://dracoblue.net/dev/linear-least-squares-in-javascript/。代码要点是:
// format for parsing the ABAP-style dates
var oFormat = DateFormat.getDateInstance({
pattern: "yyyyMMdd"
});
// maps an ProductCollection entry to a new object
// which has the parsed date (and only the needed attributes)
var fnMapData = function(oEntry) {
return {
date: oFormat.parse(oEntry.AwdDate),
current: oEntry.Current,
historical: oEntry.Hist
};
};
var fnProcessData = function(oD) {
var aEntries = oD.ProductCollection.map(fnMapData),
aXs = aEntries.map(function(oE) { // get the Xs
// we take the millis to be able to do arithmetics
return oE.date.getTime();
}),
aYs = aEntries.map(function(oE) { // get the Ys (hist)
return oE.historical;
}),
//changed the function to only return only result Ys
aRs = findLineByLeastSquares(aXs, aYs);
//save the Ys into the result
for (var i = 0; i < aEntries.length; ++i) {
aEntries[i].trend = aRs[i];
}
return {
data: aEntries
};
};
您可以在 JSON 模型中使用 fnProcessData
函数返回的数据,然后基于它构建一个简单的多系列 date/time 折线图。
我有一个散点图 Vizframe 图表,我需要在其中包含一条线性 regression/trend 线。知道如何做到这一点吗?这似乎不是 vizframe 'out of box' 提供的东西?我找不到解决方案!
问题:
关于在散点图 Vizframe 图表上实现回归线的可行方法有什么建议吗?
这是我的设置代码。按下按钮时,散点图会在 dialog/modal 中打开。
sap.ui.define([
'jquery.sap.global',
'vizConcept/controller/BaseController',
'sap/ui/model/json/JSONModel',
'vizConcept/model/viewControls',
'sap/m/Button',
'sap/m/Dialog',
],
function (jQuery, BaseController, JSONModel, viewControls, Button, Dialog) {
"use strict";
var controls;
var mainController = BaseController.extend("vizConcept.controller.Main", {
onInit: function(oEvent) {
// Access/expose the defined model(s) configured in the Component.js or Manifest.json within the controller.
this.getView().setModel(this.getOwnerComponent().getModel("products"), "products");
var oModel = this.getView().getModel("products");
this.getView().setModel(oModel);
var sUrl = "#" + this.getOwnerComponent().getRouter().getURL("page2");
$(function() {
var dataset = new sap.viz.ui5.data.FlattenedDataset({
dimensions : [
{
axis : 1,
name : 'Award Date',
value : "{AwdDate}"
}
],
measures : [
{
group: 1,
name : 'Award Date',
value : '{Hist}'
},
{
group: 2,
name : 'Current PPI',
value : '{Current}'
}
],
data : {
path : "/ProductCollection"
}
});
var scatterViz = new sap.viz.ui5.Scatter({
id : "idscatter",
width : "1000px",
height : "400px",
title : {
text : 'Pricing Tool Scatter Plot Example'
},
xAxis : {
title : {
visible : true
}
},
yAxis : {
title : {
visible : true
}
},
dataset : dataset
});
scatterViz.setModel(sap.ui.getCore().getModel());
scatterViz.setModel(oModel);
var dlg = new sap.m.Dialog({
id: 'vizModal',
title: 'Scatter Plot Example Viz',
width : "1800px",
height : "600px",
content : [scatterViz],
beginButton: new Button({
text: 'Close',
press: function () {
dlg.close();
}
})
});
(new sap.m.Button({
text: 'open',
type: 'Accept',
press: function() {
dlg.open();
scatterViz.invalidate();
}
})).placeAt('content');
});
},
onToPage2 : function () {
this.getOwnerComponent().getRouter().navTo("page2");
},
});
return mainController;
});
编辑
这是在 vizframe 图表上输出的 'products' 模型。我在 manifest.json 中定义了产品模型,但那里的连接很好:
产品型号
{
"ProductCollection": [
{
"Item": "1",
"AwdDate": "20160715",
"Hist": 171.9,
"Current": 183
},
{
"Item": "2",
"AwdDate": "20160701",
"Hist" : 144.3,
"Current": 158.6
},
{
"Item": "3",
"AwdDate": "20150701",
"Hist": 160,
"Current": 165
},
{
"Item": "1",
"AwdDate": "20160715",
"Hist": 201,
"Current": 167
},
{
"Item": "2",
"AwdDate": "20160801",
"Hist" : 175.3,
"Current": 178.2
},
{
"Item": "3",
"AwdDate": "20150721",
"Hist": 160,
"Current": 147
},
{
"Item": "1",
"AwdDate": "20160715",
"Hist": 175.9,
"Current": 185.2
},
{
"Item": "2",
"AwdDate": "20161101",
"Hist" : 165.3,
"Current": 158.2
},
{
"Item": "3",
"AwdDate": "201700101",
"Hist": 160,
"Current": 165
},
{
"Item": "4",
"AwdDate": "201600401",
"Hist": 173,
"Current": 177
}
]
};
编辑 2 这是我尝试提供的解决方案 here。但是在controller的onInit()函数中包含这个之后什么也没有出现
var regressionData = [];
for (var i = 0; i < 10; i++) {
regressionData[i] = [oData.ProductCollection[i].Current, oData.ProductCollection[i].Hist];
};
regression('linear', regressionData);
不幸的是,可视化图表存在一些固有的局限性。即:
- 您不能向图表添加 "oblique" 参考线(= 趋势线)。您只能通过 Reference Line feature. Check out the (non-intuitive) documentation on this: Viz Charts Documentation 添加垂直/水平线(查看 plotArea.referenceLine.line;它只是一个数字 = 将是水平线/垂直线,具体取决于您的图表类型或方向)。
- 不能将散点图与折线图结合使用。如果您查看相同的 Viz Charts Documentation,您会看到在左侧的组合 "chapter" 中,没有 "Line - Scatter" 组合。
此外,您的 X 值 (AwDate) 是 ABAP 样式的日期,如 string。更适合使用日期/时间图表来正确显示它们。无论如何,当您使用日期时,回归更有意义。否则你的数据是 "categorical" 并且你可以进行回归的唯一方法是对它们进行排序并认为它们在 X 轴上等距 - 如果你有非等距数据(如你的示例中的数据),这不是你通常想要的).
我的建议是:
- 使用折线图代替散点图(这样也可以显示趋势线)。
- 将 ABAP 样式的字符串转换为日期,以便您可以使用时间序列图表。您的示例数据中有一些 "wrong" 日期顺便说一下:“201600401”。
- 根据需要进行回归并将其添加为单独的 "trend" 系列。您需要为其他系列中的每个点计算 "trend" 系列中的一个点(基本上,您必须向 ProductCollection 中的每一行添加一个 "trend" 属性)。如果您使用的是 OData 模型,那么您将需要切换到 JSON 客户端模型或使用格式化程序做一些丑陋的变通方法。
应要求,我在这里做了一个示例实现:https://jsfiddle.net/93mx0yvt/23/. The regression algorithm I borrowed from here: https://dracoblue.net/dev/linear-least-squares-in-javascript/。代码要点是:
// format for parsing the ABAP-style dates
var oFormat = DateFormat.getDateInstance({
pattern: "yyyyMMdd"
});
// maps an ProductCollection entry to a new object
// which has the parsed date (and only the needed attributes)
var fnMapData = function(oEntry) {
return {
date: oFormat.parse(oEntry.AwdDate),
current: oEntry.Current,
historical: oEntry.Hist
};
};
var fnProcessData = function(oD) {
var aEntries = oD.ProductCollection.map(fnMapData),
aXs = aEntries.map(function(oE) { // get the Xs
// we take the millis to be able to do arithmetics
return oE.date.getTime();
}),
aYs = aEntries.map(function(oE) { // get the Ys (hist)
return oE.historical;
}),
//changed the function to only return only result Ys
aRs = findLineByLeastSquares(aXs, aYs);
//save the Ys into the result
for (var i = 0; i < aEntries.length; ++i) {
aEntries[i].trend = aRs[i];
}
return {
data: aEntries
};
};
您可以在 JSON 模型中使用 fnProcessData
函数返回的数据,然后基于它构建一个简单的多系列 date/time 折线图。