■きっかけ
自分の日々の作業の量を比較するため、グラフを使って比較したとき、
「なんとなく忙しいようにみえる」 と 「なんとなく」 でしかわからなかったため、
ひと目で分かる方法がないか、と考えたのがきっかけでした。
また、Salesforce のグラフ上で実現できないか、を考えました。
■ケース
毎日行う作業とそれを累計したグラフです。(Google SpreadSheet)
日々の件数が棒グラフ、累計が線グラフ、横軸が日、縦軸が件数です。
ある月 | べつの月 |
---|---|
![]() |
![]() |
「ある月」と「別の月」を比較すると
- 「ある月」は、初旬はそこまで日々の件数は少なかったものの、中旬ごろから件数が増え、忙しくなったように見えます。
- 「べつの月」は、初旬から忙しく、中旬ごろからは、日々の件数は少なくなり、ゆったりしたように見えます。
あくまでも感覚なので、わかりやすくならないか、考えました。
グラフには、「トレンドライン」という機能があります。
種類でいくつか選ぶことができ、今回は「線形」を選びました。
ある月 | べつの月 |
---|---|
![]() |
![]() |
- 「ある月」のほうが角度が急です。
- やっぱり、突然いそがしくなった、と言えそうです。
- 4日ごろから線が発生しているので、そのあたりから忙しくなった、と言えそうです。
- 「べつの月」のほうは角度が緩やかです。
この線、わかりやすいですね。
では、この「トレンドライン」の「線形」のこの線はどうやって求めるのでしょうか。
■検証しましょう
この線は「近似直線」というらしいです。
(数学は詳しくないので、細かいことまでわかりませんが汗)
式を求めるため調べました。
こちらのページで理解しました。
y = ax + b
a = (ΣXiYi - nX'Y') / (ΣXi^2 - nX'^2)
b = Y'-aX' (i=1,2,3・・・)
らしいです。わかりやすくします。
a = (X×Yの合計 - 標本数 × Xの平均 × Yの平均) ÷ (Xを二乗した合計 - 標本数 × Xの平均の二乗)
b = b = (Yの平均 - a × Xの平均)
上記のページで示されている例題で試してみましょう。
x | y |
---|---|
10 | 6 |
12 | 9 |
14 | 10 |
16 | 10 |
- 標本数 は、x と y の組み合わせの個数、今回は 4 です。
- x の平均
- (10 + 12 + 14 + 16) ÷ 4 = 13
- y の平均
- (6 + 9 + 10 + 10) ÷ 4 = 8.75
- x の2乗 と x×y の合計
x | y | x の 2乗 | x×y | |
---|---|---|---|---|
10 | 6 | 100 | 60 | |
12 | 9 | 144 | 108 | |
14 | 10 | 196 | 140 | |
16 | 10 | 256 | 160 | |
合計 | - | - | 696 | 468 |
- x の 2乗の合計(ΣXi^2) = 696
- x × y の合計(ΣXiYi) = 468
a = (X×Yの合計 - 標本数 × Xの平均 × Yの平均) ÷ (Xを二乗した合計 - 標本数 × Xの平均の二乗)
a = (468 - 4 × 13 × 8.75) ÷ (696 - 4 × 13 × 13)
a = 0.65
b = (Yの平均 - a × Xの平均)
b = (8.75 - 0.65 × 13)
b = 0.3
つまり、
y = ax + b
y = 0.65 × x + 0.3
となります。
では、上記の式にサンプルに当てはめてみたいと思います。
x | y | y = 0.65 × x + 0.3 |
---|---|---|
10 | 6 | 6.8 |
12 | 9 | 8.1 |
14 | 10 | 9.4 |
16 | 10 | 10.7 |
トレンドラインで表示したときのグラフと、この計算で取得した値で作ったグラフを比較してしましょう。
トレンドライン | 計算して取得した値で作ったグラフ |
---|---|
![]() |
![]() |
同じ形になりました。
これで、トレンドラインの線形は、この計算方法で算出できることがわかりました。
■実装してみましょう
では、これを Salesforce Visualforce の Chart で実装してみましょう。
基本的な Salesforce Visualforce の Chart の使い方は以下を参考にしてください。
■Visualforce Charting を使用した複雑なグラフの作成
https://developer.salesforce.com/docs/atlas.ja-jp.pages.meta/pages/pages_charting_example.htm
■近似直線計算クラス
public class ApproximationStraightLine {
public Double x {get; set;}
public Double y {get; set;}
public Double ay {get; set;}
public ApproximationStraightLine(Double x, Double y) {
this.x = x;
this.y = y;
this.ay = 0;
}
public static List<ApproximationStraightLine> calcurate(List<ApproximationStraightLine> listData) {
Double numberOfSamples = numberOfSamples(listData);
Double averageX = getAverageX(listData);
Double averageY = getAverageY(listData);
Double sigmaXiYi = getSigmaXiYi(listData);
Double sigmaXiPow2 = getSigmaXiPow2(listData);
// a = (ΣXiYi-標本数×Xの平均×Yの平均)÷(ΣXi^2-標本数×Xの平均の二乗)
Double a = (sigmaXiYi - numberOfSamples * averageX * averageY) / (sigmaXiPow2 - numberOfSamples * Math.pow(averageX, 2));
// b = (Yの平均-a×Xの平均)
Double b = averageY - a * averageX;
for (ApproximationStraightLine data : listData) {
// y = xa + b
data.ay = data.x * a + b;
}
return listData;
}
private static Double numberOfSamples(List<ApproximationStraightLine> listData) {
Double size = (Double) listData.size();
return size;
}
private static Double getAverageX(List<ApproximationStraightLine> listData) {
Double total = 0;
Integer count = 0;
for (ApproximationStraightLine data : listData) {
total += data.x;
count++;
}
return total / count;
}
private static Double getAverageY(List<ApproximationStraightLine> listData) {
Double total = 0;
Integer count = 0;
for (ApproximationStraightLine data : listData) {
total += data.y;
count++;
}
return total / count;
}
private static Double getSigmaXiYi(List<ApproximationStraightLine> listData) {
Double value = 0;
for (ApproximationStraightLine data : listData) {
value += (data.x * data.y);
}
return value;
}
private static Double getSigmaXiPow2(List<ApproximationStraightLine> listData) {
Double value = 0;
for (ApproximationStraightLine data : listData) {
value += Math.pow(data.x, 2);
}
return value;
}
}
■Visualforceページのコントロールクラス
public class ChartTestController {
public List<ApproximationStraightLine> getData() {
List<ApproximationStraightLine> listData = new List<ApproximationStraightLine>();
listData.add(new ApproximationStraightLine(10, 6));
listData.add(new ApproximationStraightLine(12, 9));
listData.add(new ApproximationStraightLine(14, 10));
listData.add(new ApproximationStraightLine(16, 10));
return ApproximationStraightLine.calcurate(listData);
}
}
■Visualforceページ
<apex:page controller="ChartTestController">
<apex:chart height="400" width="700" data="{!data}">
<apex:axis type="Numeric" position="left" fields="y" title="Y" grid="true" minimum="0" maximum="12"/>
<apex:axis type="Category" position="bottom" fields="x" title="X"/>
<apex:barSeries orientation="vertical" axis="left" xField="x" yField="y">
<apex:chartTips height="20" width="120"/>
</apex:barSeries>
<apex:lineSeries axis="left" xField="x" yField="ay" markerType="circle" markerSize="4" markerFill="#00FF00"/>
</apex:chart>
</apex:page>
同じ近似直線を実現することができました。