block by zanarmstrong d9d04a0ab0af77fdbb14

d9d04a0ab0af77fdbb14

Full Screen

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

index.html

<!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>

seasonality.rmd

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()
```

stl.css

.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;
}
*/

stl.js

"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')

});

stl.styl

.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
	*/

stloutput.csv

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