Prepping for Open Vis Conf talk.
The simple line chart part of this sketch originally forked from Bostock’s simple line chart: http://bl.ocks.org/mbostock/3883245
Might be worth having two versions of this: one which compares STL decomposition w/ all 3 components. Another which uses the ‘seasonal’ package to show w/ and w/out seasonal.
Goal is to show the decompositions in an interesting and meaningful way
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="stl.css">
<link href='//fonts.googleapis.com/css?family=Raleway:400,700' rel='stylesheet' type='text/css'>
</head>
<body>
<div>Seasonal Decomposition</div>
<div class="vis"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script src="stl.js"></script>
</body>
Decompose a weekly time series
========================================================
Read in a weekly time series and set up so that it's
```{r}
gunData <- read.csv("learninghtml/webProjects/visualizeSTL/gunSalesMonthlyOrig.csv", header = TRUE, as.is = TRUE)
gunDataLimited <- gunData[c("guns_total")]
```
convert data to "time series" format, using the values, a frequency, and a starting value. The frequency determines how the function will read the start value. Here it is expecting the 14th week of 1993.
```{r}
dfTS <- ts(gunDataLimited$guns_total, frequency = 12, start = c(2000, 1))
```
Run the STL decomposition.
Note: change s.window to be 6, 10, etc
Can also change t.window
```{r}
output <- stl(dfTS, s.window=6, robust=TRUE)
```
and plot it
```{r fig.width=7, fig.height=6}
plot(output)
```
save the output
```{r}
write.csv(as.data.frame(output$time.series), "learninghtml/webProjects/visualizeSTL/stloutput.csv", quote = FALSE, row.names = FALSE)
```
// look at seasonality from NYT project
```{r}
gunData <- read.csv("learninghtml/webProjects/visualizeSTL/gunSalesMonthlyOrig.csv", header = TRUE, as.is = TRUE)
gunData$seasonal <- gunData$guns_total - gunData$guns_total_seas
ggplot(gunData, aes(x = month, color = factor(year), y = seasonal, group = factor(year))) + geom_line() + theme_bw()
ggplot(gunData, aes(x = year, color = factor(month), y = seasonal, group = factor(month))) + geom_line() + theme_bw()
```
.hidden {
display: none;
}
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.line {
fill: none;
stroke-width: 2px;
}
.annualPaths {
stroke-width: 1px;
fill: none;
}
/*
.residual {
stroke: #000;
opacity: 0.3;
stroke-width: 2px;
}
.seasonal {
stroke: #f00;
opacity: 0.5;
stroke-width: 2px;
}
*/
"use strict";
// date helpers
var startDate = new Date(2000, 0, 1)
var interval = 1
// since data comes in without date information -> need start date and intervals
var getDateByWeeksSinceStart = function(months) {
var dat = new Date(startDate)
dat.setMonth(dat.getMonth() + interval * months)
return dat
}
// general parameters
var margin = {
top: 100,
right: 50,
bottom: 400,
left: 100
},
mainChartWidth = 1000,
width = 1400 - margin.left - margin.right,
height = 1200 - margin.top - margin.bottom;
var chartHeight = 150;
var chartSep = 30;
// dataset information
var dataSetHelpers = {
'guns': {
'title': 'Monthly Gun Sales, United States',
'startDate': new Date(2000, 0, 1),
}
}
// chart specific paramenters
var params = {
'original': {
yChartOffset: 0,
name: 'Original Timeseries',
color: 'black'
},
'trend': {
yChartOffset: 200,
name: 'Trend',
color: '#103392'
},
'seasonal': {
yChartOffset: 400,
name: 'Seasonality',
color: '#0f3431'
},
'remainder': {
yChartOffset: 600,
name: 'Remainder (variation from seasonal/trend patterns)',
color: '#793131'
}
}
// formatting helpers
var formatDate = d3.time.format("%d-%b-%y");
var monthFormat = function(month) {
var monthLookup = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
return monthLookup[month]
}
var x = d3.time.scale()
.range([0, mainChartWidth]);
var getXAxis = function(scale) {
return d3.svg.axis()
.scale(scale)
.orient("bottom");
}
var getYAxis = function(scale) {
return d3.svg.axis()
.scale(scale)
.orient("left")
.tickFormat(d3.format(".2s"));
}
var getLine = function(className, yScale) {
return d3.svg.line().x(function(d) {
return x(d.date)
}).y(function(d) {
return yScale(d[className])
})
}
var getAnnualLine = function(className, xScale, yScale) {
return d3.svg.line().x(function(d) {
return xScale(d.date.getMonth())
}).y(function(d) {
return yScale(d[className])
})
}
// svg setup
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.csv("stloutput.csv", function(error, data) {
if (error) throw error;
// manage data
data.forEach(function(data, i) {
data.remainder = +data.remainder;
data.seasonal = +data.seasonal;
data.trend = +data.trend
data.original = data.remainder + data.seasonal + data.trend;
data.date = getDateByWeeksSinceStart(i)
})
// nest data by year for annual charts
var annualNested = d3.nest()
.key(function(d) {
return d.date.getFullYear()
})
.entries(data)
// date min to date max
x.domain(d3.extent(data, function(d) {
return d.date;
}));
// 0 to max for y: note - assume min value of 0 for time series
var domainExtent = [0, d3.max(data, function(d) {
return d.original;
})];
// shift it so that 0 is in the middle, for seasonal & remainder
var midDomainExtent = [-domainExtent[1] / 2, domainExtent[1] / 2]
var drawChart = function(svg, className) {
var chartParams = params[className];
// everything
var chart = svg.append("g").attr("class", className)
var minValue = d3.min(data, function(d) {
return d[className]
})
var yDomain = minValue > 0 ? domainExtent : midDomainExtent
var yFunction = d3.scale.linear()
.range([chartHeight + chartParams.yChartOffset, chartParams.yChartOffset])
.domain(yDomain);
chart.append("g").attr("class", "x axis")
.attr("transform", "translate(0," + yFunction(0) + ")")
.call(getXAxis(x));
chart.append("g").attr("class", "y axis")
.call(getYAxis(yFunction))
.append("text")
.attr("transform", "translate(" + 4 + "," + yFunction.range()[1] + ")")
.attr("dy", ".71em")
.style("text-anchor", "start")
.text(params[className].name);
chart.append("g").attr("class", "fullPaths")
.append("path")
.datum(data)
.attr("class", "line")
.attr("stroke", params[className].color)
.attr("d", getLine(className, yFunction))
}
var drawRemainder = function(svg, className) {
var chartParams = params[className];
// everything
var chart = svg.append("g").attr("class", className)
var minValue = d3.min(data, function(d) {
return d[className]
})
var yDomain = minValue > 0 ? domainExtent : midDomainExtent
var yFunction = d3.scale.linear()
.range([chartHeight + chartParams.yChartOffset, chartParams.yChartOffset])
.domain(yDomain);
chart.append("g").attr("class", "fullPaths")
.selectAll(".remainderBars")
.data(data)
.enter()
.append("line")
.attr("stroke", params[className].color)
.attr({
"x1": function(d) {
return x(d.date);
},
"x2": function(d) {
return x(d.date);
},
"y1": function(d) {
return yFunction(0);
},
"y2": function(d) {
return yFunction(d[className]);
},
"stroke-width": 3,
"opacity": .5
})
}
var drawOverlayChart = function(svg, className) {
var chartParams = params[className];
// everything
var chart = svg.append("g").attr("class", className)
var minValue = d3.min(data, function(d) {
return d[className]
})
var oneYearWidth = (x(startDate.getTime() + 24 * 60 * 60 * 1000 * 365) - x(startDate)) * 2;
console.log(oneYearWidth)
var xOneYear = d3.scale.linear().domain([0, 11]).range([mainChartWidth + chartSep, mainChartWidth + chartSep + oneYearWidth])
var colorByYear = d3.scale.linear()
.domain([x.domain()[0].getFullYear(), x.domain()[1].getFullYear()])
.range([-5, 0])
var yDomain = minValue > 0 ? domainExtent : midDomainExtent
var yFunction = d3.scale.linear()
.range([chartHeight + chartParams.yChartOffset, chartParams.yChartOffset])
.domain(yDomain);
console.log(yDomain)
chart.append("g").attr("class", "x axis")
.attr("transform", "translate(0," + yFunction(0) + ")")
.call(getXAxis(xOneYear).tickFormat(monthFormat).tickValues([0, 3, 6, 9]));
chart.append("g").attr("class", "y axis")
.attr("transform", "translate(" + (mainChartWidth + chartSep) + ",0)")
.call(getYAxis(yFunction).tickFormat(""))
chart.append("g").attr("class", "data")
.selectAll(".annualPaths")
.data(annualNested)
.enter()
.append("path")
.datum(function(d) {
return d.values
})
.attr("stroke", function(d) {
return d3.hcl(params[className].color).darker(colorByYear(d[0].date.getFullYear()))
})
.attr("class", "annualPaths")
.attr("d", getAnnualLine(className, xOneYear, yFunction))
}
// draw them!
drawChart(svg, 'original')
drawChart(svg, 'trend')
drawChart(svg, 'seasonal')
drawChart(svg, 'remainder')
drawRemainder(svg, 'remainder')
drawOverlayChart(svg, 'original')
drawOverlayChart(svg, 'trend')
drawOverlayChart(svg, 'seasonal')
drawOverlayChart(svg, 'remainder')
});
.hidden
display: none
body
font: 10px sans-serif;
.axis path,
.axis line
fill: none
stroke: #000
shape-rendering: crispEdges
.line
fill: none
stroke: darkblue
stroke-width: 1.5px
.minusSeasonal
fill: steelblue
stroke: none
opacity: .5
.minusSeasonalLine
fill: none
stroke: darkblue
stroke-width: 1px
opacity: 1
/*
.residual
stroke: black
opacity: .3
stroke-width: 2px
.seasonal
stroke: red
opacity: .5
stroke-width: 2px
*/
seasonal,trend,remainder
-74882.458333205,666032.601884754,-16199.1435515491
-22174.4273991801,663912.440165694,7372.98723348603
6714.50639912742,661792.278446634,-3884.78484576149
-101041.16036918,659672.116727574,-5665.956358394
-165200.399487483,657551.955008514,-24639.5555210308
-174366.319005639,655431.793289454,-1817.47428381455
-168992.759506004,653279.321116635,-4267.56161063118
-20800.9935360497,651126.848943817,-11758.8554077673
38337.5291528881,648974.376770999,48070.0940761131
138250.519817988,646821.90459818,7442.57558383211
197933.937020897,644669.432425362,18278.6305537405
343368.335655948,642519.883408482,-1265.21906442998
-73257.1452847653,640370.334391602,904.810893163201
-21180.6257233577,638220.785374722,-8028.15965136432
7313.32865558355,636071.236357842,3875.43498657446
-99803.9253700175,633921.687340962,-10592.7619709445
-164334.01027173,631810.962254775,4466.04801695514
-174761.659967718,629700.237168588,18661.42279913
-168743.947288092,627589.512082401,5433.4352056908
-22419.7011367882,625478.786996215,41030.9141405736
36236.9594862329,623368.061910028,164875.97860374
137854.118543705,621273.795980078,201762.085476217
195257.610059102,619179.530050128,41881.8598907698
344103.028743422,617085.264120178,11307.7071363997
-70337.2040585898,614990.998190229,-17754.7941316388
-20154.0124024666,612896.732260279,-32563.7198578123
8100.40252220008,611091.753069624,-23595.1555918239
-97919.8207492303,609286.773878969,-8408.95312973834
-162629.060166682,607481.794688313,-3974.73452163173
-175402.32532324,605676.815497658,-20532.490174418
-168322.655745785,603871.836307003,-11384.1805612182
-24651.7782998009,602624.024330697,2537.75396910391
31771.5714551568,601376.212354391,-14699.7838095479
136727.592553116,600128.400378085,-9046.99293120089
190923.928447136,598880.588401779,-11861.516848915
345944.64231999,597632.776425474,-42700.4187454636
-63931.8965255916,597368.109377098,-13167.2128515067
-17187.0829305415,597103.442328723,-4116.35939818143
9126.36722503269,596838.775280348,2371.85749461967
-92344.5534776002,596574.108231972,-11509.5547543721
-159684.998309982,596309.441183597,6912.55712638504
-179276.474108612,596999.82045031,-6353.34634169808
-168402.04776594,597690.199717023,-13861.151951083
-33757.7395408012,598380.578983736,-3682.83944293472
24173.2974061831,599070.958250449,-6150.2556566319
133813.36965479,599761.337517162,-5210.70717195177
176771.861193075,601119.891775695,-28041.7529687703
347908.317434559,602478.446034229,-18072.7634687879
-53546.116845435,603837.000292762,13522.116552673
-4030.28875280569,605195.554551295,1023.73420151032
17214.0812312349,606554.108809829,-10539.1900410636
-85413.1045784384,608705.112727824,-711.008149385336
-164633.44562531,610856.116645819,-9788.67102050851
-182097.196405755,613007.120563813,-174.924158058595
-173453.390924905,615158.124481808,13888.2664430963
-52016.3632039823,617309.128399803,-10675.7651958211
24543.8690642222,619969.054565408,-9128.92362962989
122163.513967095,622628.980731012,14625.5053018932
168381.768695892,625288.906896616,-5952.67559250817
364164.649023599,627948.833062221,-2815.48208581982
-40843.0102923822,630608.759227825,-31028.7489354428
5956.9062302073,633499.127844017,-12578.0340742241
28985.6110279577,636389.496460209,-19269.1074881662
-81933.5323662679,639279.8650764,2972.66728986742
-165874.525062719,642170.233692592,-16447.7086298731
-180097.471630095,645060.602308784,-12499.1306786888
-176408.849423211,648164.15893006,-9833.30950684857
-62670.1997753478,651267.715551335,-14379.5157759873
18498.4563951694,654371.272172611,10103.2714322199
101451.935476321,657474.828793886,2347.23572979274
161628.625000349,660578.385415162,17467.9895844894
376076.035726802,663763.926477925,64068.0377952724
-37284.5124849224,666949.467540689,28885.0449442334
10969.0520711466,670135.008603453,19296.9393254007
39899.0271579081,673320.549666216,17232.4231758757
-79176.3832681751,676506.09072898,-7390.70746080473
-154579.446814312,679322.99698304,-18442.5501687275
-174862.537746684,682139.9032371,-7054.36549041618
-175283.323013258,684956.80949116,-23900.4864779022
-63692.3008574802,687773.71574522,-6441.41488774028
3521.00270822266,690590.621999281,20884.3752924969
83265.3272558275,692907.816009726,-15272.1432655531
153519.614857701,695225.010020171,6438.37512212875
374104.369076352,697542.204030616,22237.4268930319
-35668.5088739168,699859.398041061,4934.11083285592
16780.0803375389,702176.592051506,-9875.67238904489
48488.4716089446,704218.124459496,15313.4039315594
-77871.7844558627,706259.656867486,9351.12758837675
-135465.790164206,708301.189275476,31609.6008887296
-166330.194924343,710342.721683466,60921.4732408767
-170424.23815506,712384.254091456,28156.984063604
-60827.8944076365,714784.259001222,20535.6354064145
-14623.1751802597,717184.263910988,-12886.0887307281
76966.8266862489,719584.268820754,-32468.0955070026
139871.204466264,721984.273730519,-21942.4781967831
355150.291451375,724384.278640285,-35398.5700916601
-39529.594229381,727102.182621546,-11418.5883921654
24925.9992062923,729820.086602807,1011.91419090063
58822.4572332874,732537.990584068,-19692.4478173555
-70704.0010969047,735255.894565329,-7004.89346842421
-118443.995124332,737973.79854659,-5263.80342225789
-158327.137192353,740385.847141824,-23814.7099494707
-162210.046348939,742797.895737057,-8518.84938811837
-59726.6962264507,745209.944332291,-4802.24810584041
-29659.5643274803,747621.992927525,-17319.4286000446
74706.8157739626,750034.041522759,54696.1427032788
122847.273943527,752695.901688698,419722.824367775
327235.612502587,755357.761854637,192915.625642776
-49644.6450640477,758019.622020576,187407.023043472
48383.675344973,760681.482186515,148307.842468512
82199.1453621612,763343.342352454,170296.512285385
-53817.8451478613,766947.376289682,164158.46885818
-125885.731634713,770551.410226909,60088.3214078035
-168519.705548417,774155.444164137,30273.26138428
-167708.149047378,777759.478101364,10430.6709460143
-68004.2389530205,781363.512038592,-402.273085571127
-38361.4763100247,785440.804227537,-56.3279175125062
66701.9460033763,789518.096416483,4641.95758014079
126291.959681605,793595.388605429,-27899.3482870334
317933.941504795,797672.680794374,-29423.6222991698
-52126.784556958,801749.97298332,-14746.1884263621
72207.4830665136,806542.996122863,-19237.4791893762
111029.539698031,811336.019262405,-20579.5589604361
-35792.6660109853,816129.042401948,-19432.3763909626
-143805.34775077,820922.065541491,-30640.7177907206
-177870.75371311,825715.088681033,-30367.3349679227
-179002.540033386,832261.743576229,-14404.203542843
-78887.1226813158,838808.398471424,-19866.2757901083
-37919.2605743266,845355.05336662,-20223.7927922929
53784.9653847215,851901.708261815,-32583.6736465365
138178.124749487,858448.363157011,-20152.4879064973
317606.977828145,866589.229399616,12495.7927722386
-49044.3515912419,874730.095642222,-15316.7440509801
80468.3292085592,882870.961884828,14113.7089066129
124227.681570917,891011.828127434,21007.4903016498
-29710.9283568668,899152.694370039,9433.23398682754
-157339.2069031,908502.641327388,-28228.4344242875
-183576.719463367,917852.588284736,-37182.8688213694
-189689.373949646,927202.535242085,-42031.1612924387
-85456.0281031045,936552.482199433,-11380.4540963285
-33914.9708176912,945902.429156782,-15237.4583390903
43592.9260099375,953999.110954039,-25876.0369639769
158383.102553578,962095.792751297,21574.104695125
320801.817934904,970192.474548555,201642.707516541
-55392.1857713343,978289.156345813,26190.0294255211
100956.134893286,986385.838143071,196652.026963643
135660.388671691,992730.967925604,108316.643402705
-38486.3086387889,999076.097708138,8483.21093065105
-173096.208083561,1005421.22749067,31722.9805928896
-188916.72297625,1011766.3572732,40690.3657030452
-202646.413824188,1018111.48705574,61192.9267684498
-87493.3891745545,1024015.47005046,129274.919124092
-35710.1770177814,1029919.45304519,41656.723972594
44964.1255470885,1035823.43603991,64595.4384129995
203439.980105937,1041727.41903464,341197.600859426
318590.993167742,1047631.40202936,1021905.6048029
-65796.1066477353,1053019.08506104,911138.021586691
134218.951519346,1058406.76809273,491205.280387927
129913.005403483,1063794.45112441,376601.543472108
-63981.6744559595,1069182.13415609,228492.540299868
-188173.146285601,1074569.81718777,116133.329097826
-199366.280830842,1078250.07460428,16120.2062265638
-200230.018309079,1081930.33202078,-8374.31371170259
-91387.9750033567,1085610.58943729,57626.3855660709
-43463.6176667972,1089290.84685379,16547.7708130078
56865.4273464285,1092971.10427029,-12852.5316167215
222010.178576903,1094903.14198488,32233.6794382131
318608.957524752,1096835.17969947,177798.862775774
-67546.050778329,1098767.21741407,-42135.1666357364
143003.133917778,1100699.25512866,23593.6109535664
125649.22239959,1102631.29284325,35298.4847571629
-73430.9426959215,1104548.62434961,-17473.6816536915
-192240.590300227,1106465.95585598,-25930.3655557521
-203880.55340311,1108383.28736235,-89785.7339592348
-198589.81456128,1110300.61886871,-90077.8043074319
-91310.3774603377,1112217.95037508,-20781.5729147398
-45527.9384926722,1114110.39307647,-25820.4545837953
60546.3444136566,1116002.83577786,16400.8198084859
228917.143659947,1117895.27847925,26826.5778608052
318909.468416883,1119787.72118064,261399.810402479
-69200.7965091811,1121680.16388203,15921.6326271533
147470.408689101,1123569.81720767,18827.774103232
124735.881917455,1125459.47053331,-26044.3524507619
-78489.4409094109,1127349.12385895,-39406.6829495353
-194699.442959576,1129238.77718459,-318.334225009196
-205944.156622966,1131128.43051023,-27654.273887259
-198053.065050657,1133033.78470641,20724.2803442487
-91416.5634493619,1134939.13890259,8263.42454677098
-46778.2146102381,1136844.49309877,-2577.27848853543
62432.0722560506,1138749.84729496,23744.080448993
233590.20320827,1140655.20149114,110840.595300591