Skip to content

Instantly share code, notes, and snippets.

@yonicd
Forked from timelyportfolio/.block
Last active January 6, 2018 03:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yonicd/77a46bd2f44c314fa81fe9b96f18bfaf to your computer and use it in GitHub Desktop.
Save yonicd/77a46bd2f44c314fa81fe9b96f18bfaf to your computer and use it in GitHub Desktop.
alternate version of market quilt
license: mit
height: 600

Built with blockbuilder.org


This all started here ...

Omg this chart is a mess. https://t.co/pnWa2RMVcm pic.twitter.com/kFm1n1MqDl

— yoni sidi (@yoniceedee) January 4, 2018
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

These market quilts or carpets are extremely common and popular, but for almost my entire career I have thought there must be a better way to communicate this information.

This is a very ugly sketch of an alternate version with imaginary data. It is sort of like a bump chart. I don't think it is any better.

Code in R and JavaScript

library(htmltools)
library(dplyr)

# make some fake data to use with rawgraph bump chart
#  but rawgraphs doesn't work as I would like
dat <- data.frame(
  idx = rep(LETTERS[1:10], each=10),
  date = rep(
    seq.Date(from=as.Date("2000-12-31"), to=as.Date("2009-12-31"), by="years"),
    10
  ),
  perf = rnorm(10 * 10,100,1),
  stringsAsFactors = FALSE
)%>%
  group_by(idx)%>%mutate(perf=perf/head(perf,1))



# so go custom
browsable(
  tagList(
    d3r::d3_dep_v4(),
    tags$script(HTML(
sprintf(
'
var data = %s
var height = 500, width = 900
var color = d3.scaleOrdinal(d3.schemeCategory10)

var svg = d3.select("body").append("svg")
  .attr("width", width)
  .attr("height", height)
  .append("g")
  .attr("transform", "translate(20,20)")

var sc_x = d3.scalePoint()
  .domain(data.map(d => (d.date)))
  .range([0,width - 40])

var sc_y = d3.scaleLinear()
  .domain(d3.extent(data.map(d => d.perf)))
  .range([height - 40, 0])

var line = d3.line()
  .x(d => sc_x(d.date))
  .y(d => sc_y(d.perf))
  .curve(d3.curveBasis)

var nested = d3.nest().key(d => d.idx).entries(data)

var lines = svg.selectAll(".line").data(nested)

lines.exit().remove()

lines = lines.merge(lines.enter().append("path"))

lines
  .classed("line", true)
  .attr("d", d => line(d.values))
  .style("fill", "none")
  .style("opacity", 0.5)
  .style("stroke", d => color(d.key))
  .style("stroke-width", 20)
',
  jsonlite::toJSON(dat, dataframe="rows", pretty=TRUE)
)
    ))
  )
)


# so go custom 2
browsable(
  tagList(
    d3r::d3_dep_v4(),
    tags$script(HTML(
      sprintf(
'
var data = %s

var height = 600, width = 900
var margin = {
  top: 20,
  bottom: 50,
  left: 50,
  right: 20
}

var color = d3.scaleOrdinal(d3.schemeCategory10)

var svg = d3.select("body").append("svg")
  .attr("width", width)
  .attr("height", height)

var g_plot = svg.append("g")
  .attr("transform", "translate(" + margin.left + "," + margin.top + ")")

var sc_x = d3.scaleBand()
  .domain(data.map(d => (d.date)))
  .range([0,width - margin.left - margin.right])

var sc_y = d3.scaleLinear()
  .domain(d3.extent(data.map(d => d.perf)))
  .range([height - margin.top - margin.bottom, 0])

var line = d3.line()
  .curve(d3.curveMonotoneX)

var horiz_smooth = 50

var nested = d3.nest().key(d => d.idx).entries(data)

var highlight = function() {
  svg.selectAll(".line").style("opacity", 0.25)
  d3.select(this).style("opacity", 1)
}

var unhighlight = function() {
  svg.selectAll(".line").style("opacity", 0.5)
}

nested.map(function(d) {
points = []

d.values.forEach(function(dd, i) {
  if(i > d.values.length - 2) {
    points.push([sc_x(dd.date) + horiz_smooth, sc_y(dd.perf)])
    return
  }

  if(i === 0) {
    points.push([sc_x(dd.date), sc_y(dd.perf)]),
    points.push([sc_x(dd.date) + horiz_smooth, sc_y(dd.perf)])
    points.push([sc_x(dd.date) + sc_x.bandwidth(), sc_y(d.values[i+1].perf)])
    return
  }

  points.push([sc_x(dd.date) + horiz_smooth, sc_y(dd.perf)])

  points.push([sc_x(dd.date) + sc_x.bandwidth(), sc_y(d.values[i+1].perf)])
})

g_plot.append("path")
  .classed("line", true)
  .attr("d", line(points))
  .style("fill", "none")
  .style("stroke", color(d.key))
  .style("stroke-width", 10)
  .style("opacity", 0.5)
  .on("mouseover", highlight)
  .on("mouseout", unhighlight)
})

g_plot.append("g")
  .call(d3.axisBottom().scale(sc_x))
  .attr("transform", "translate(" + (-sc_x.bandwidth()/2 + horiz_smooth/2) + "," + (+height - margin.top - margin.bottom) + ")")

g_plot.append("g")
  .call(d3.axisLeft().scale(sc_y))
',
  jsonlite::toJSON(dat, dataframe="rows", pretty=TRUE)
)
    ))
  )
)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<script src="https://unpkg.com/d3"></script>
</head>
<body style="background-color:white;">
<script>
var data = [
{
"idx": "A",
"date": "2000-12-31",
"perf": 1
},
{
"idx": "A",
"date": "2001-12-31",
"perf": 1.0003
},
{
"idx": "A",
"date": "2002-12-31",
"perf": 0.9726
},
{
"idx": "A",
"date": "2003-12-31",
"perf": 1.0016
},
{
"idx": "A",
"date": "2004-12-31",
"perf": 1.0073
},
{
"idx": "A",
"date": "2005-12-31",
"perf": 0.9905
},
{
"idx": "A",
"date": "2006-12-31",
"perf": 0.9923
},
{
"idx": "A",
"date": "2007-12-31",
"perf": 0.9934
},
{
"idx": "A",
"date": "2008-12-31",
"perf": 1.0122
},
{
"idx": "A",
"date": "2009-12-31",
"perf": 0.9895
},
{
"idx": "B",
"date": "2000-12-31",
"perf": 1
},
{
"idx": "B",
"date": "2001-12-31",
"perf": 1.0002
},
{
"idx": "B",
"date": "2002-12-31",
"perf": 0.9904
},
{
"idx": "B",
"date": "2003-12-31",
"perf": 1.0004
},
{
"idx": "B",
"date": "2004-12-31",
"perf": 0.9864
},
{
"idx": "B",
"date": "2005-12-31",
"perf": 0.9993
},
{
"idx": "B",
"date": "2006-12-31",
"perf": 1.0017
},
{
"idx": "B",
"date": "2007-12-31",
"perf": 1.0147
},
{
"idx": "B",
"date": "2008-12-31",
"perf": 1.0227
},
{
"idx": "B",
"date": "2009-12-31",
"perf": 1.0063
},
{
"idx": "C",
"date": "2000-12-31",
"perf": 1
},
{
"idx": "C",
"date": "2001-12-31",
"perf": 1.0054
},
{
"idx": "C",
"date": "2002-12-31",
"perf": 1.0102
},
{
"idx": "C",
"date": "2003-12-31",
"perf": 1.0146
},
{
"idx": "C",
"date": "2004-12-31",
"perf": 1.0161
},
{
"idx": "C",
"date": "2005-12-31",
"perf": 1.0058
},
{
"idx": "C",
"date": "2006-12-31",
"perf": 1.0073
},
{
"idx": "C",
"date": "2007-12-31",
"perf": 1.0039
},
{
"idx": "C",
"date": "2008-12-31",
"perf": 1.0161
},
{
"idx": "C",
"date": "2009-12-31",
"perf": 1.0331
},
{
"idx": "D",
"date": "2000-12-31",
"perf": 1
},
{
"idx": "D",
"date": "2001-12-31",
"perf": 1.0091
},
{
"idx": "D",
"date": "2002-12-31",
"perf": 0.9869
},
{
"idx": "D",
"date": "2003-12-31",
"perf": 1.0103
},
{
"idx": "D",
"date": "2004-12-31",
"perf": 0.9976
},
{
"idx": "D",
"date": "2005-12-31",
"perf": 0.9931
},
{
"idx": "D",
"date": "2006-12-31",
"perf": 0.9959
},
{
"idx": "D",
"date": "2007-12-31",
"perf": 0.9854
},
{
"idx": "D",
"date": "2008-12-31",
"perf": 1.003
},
{
"idx": "D",
"date": "2009-12-31",
"perf": 1.0006
},
{
"idx": "E",
"date": "2000-12-31",
"perf": 1
},
{
"idx": "E",
"date": "2001-12-31",
"perf": 0.9943
},
{
"idx": "E",
"date": "2002-12-31",
"perf": 1.0111
},
{
"idx": "E",
"date": "2003-12-31",
"perf": 0.9981
},
{
"idx": "E",
"date": "2004-12-31",
"perf": 1.0018
},
{
"idx": "E",
"date": "2005-12-31",
"perf": 1.0046
},
{
"idx": "E",
"date": "2006-12-31",
"perf": 1.0094
},
{
"idx": "E",
"date": "2007-12-31",
"perf": 0.9915
},
{
"idx": "E",
"date": "2008-12-31",
"perf": 0.9856
},
{
"idx": "E",
"date": "2009-12-31",
"perf": 1.0061
},
{
"idx": "F",
"date": "2000-12-31",
"perf": 1
},
{
"idx": "F",
"date": "2001-12-31",
"perf": 0.9804
},
{
"idx": "F",
"date": "2002-12-31",
"perf": 0.9901
},
{
"idx": "F",
"date": "2003-12-31",
"perf": 0.9761
},
{
"idx": "F",
"date": "2004-12-31",
"perf": 0.9626
},
{
"idx": "F",
"date": "2005-12-31",
"perf": 0.9846
},
{
"idx": "F",
"date": "2006-12-31",
"perf": 0.9979
},
{
"idx": "F",
"date": "2007-12-31",
"perf": 0.9663
},
{
"idx": "F",
"date": "2008-12-31",
"perf": 0.9832
},
{
"idx": "F",
"date": "2009-12-31",
"perf": 0.9861
},
{
"idx": "G",
"date": "2000-12-31",
"perf": 1
},
{
"idx": "G",
"date": "2001-12-31",
"perf": 0.9767
},
{
"idx": "G",
"date": "2002-12-31",
"perf": 0.9952
},
{
"idx": "G",
"date": "2003-12-31",
"perf": 0.9839
},
{
"idx": "G",
"date": "2004-12-31",
"perf": 0.9864
},
{
"idx": "G",
"date": "2005-12-31",
"perf": 1.0067
},
{
"idx": "G",
"date": "2006-12-31",
"perf": 0.9998
},
{
"idx": "G",
"date": "2007-12-31",
"perf": 0.9727
},
{
"idx": "G",
"date": "2008-12-31",
"perf": 0.9822
},
{
"idx": "G",
"date": "2009-12-31",
"perf": 0.9946
},
{
"idx": "H",
"date": "2000-12-31",
"perf": 1
},
{
"idx": "H",
"date": "2001-12-31",
"perf": 0.9972
},
{
"idx": "H",
"date": "2002-12-31",
"perf": 1.0127
},
{
"idx": "H",
"date": "2003-12-31",
"perf": 1.0047
},
{
"idx": "H",
"date": "2004-12-31",
"perf": 1.0137
},
{
"idx": "H",
"date": "2005-12-31",
"perf": 1.0045
},
{
"idx": "H",
"date": "2006-12-31",
"perf": 0.9928
},
{
"idx": "H",
"date": "2007-12-31",
"perf": 1.0005
},
{
"idx": "H",
"date": "2008-12-31",
"perf": 0.9931
},
{
"idx": "H",
"date": "2009-12-31",
"perf": 1.0011
},
{
"idx": "I",
"date": "2000-12-31",
"perf": 1
},
{
"idx": "I",
"date": "2001-12-31",
"perf": 0.9939
},
{
"idx": "I",
"date": "2002-12-31",
"perf": 1.0033
},
{
"idx": "I",
"date": "2003-12-31",
"perf": 0.9989
},
{
"idx": "I",
"date": "2004-12-31",
"perf": 0.9875
},
{
"idx": "I",
"date": "2005-12-31",
"perf": 1.0078
},
{
"idx": "I",
"date": "2006-12-31",
"perf": 0.9894
},
{
"idx": "I",
"date": "2007-12-31",
"perf": 0.9994
},
{
"idx": "I",
"date": "2008-12-31",
"perf": 1.0047
},
{
"idx": "I",
"date": "2009-12-31",
"perf": 0.9983
},
{
"idx": "J",
"date": "2000-12-31",
"perf": 1
},
{
"idx": "J",
"date": "2001-12-31",
"perf": 1.0007
},
{
"idx": "J",
"date": "2002-12-31",
"perf": 1.0058
},
{
"idx": "J",
"date": "2003-12-31",
"perf": 0.9991
},
{
"idx": "J",
"date": "2004-12-31",
"perf": 1.002
},
{
"idx": "J",
"date": "2005-12-31",
"perf": 0.9954
},
{
"idx": "J",
"date": "2006-12-31",
"perf": 0.997
},
{
"idx": "J",
"date": "2007-12-31",
"perf": 1.0011
},
{
"idx": "J",
"date": "2008-12-31",
"perf": 1.0303
},
{
"idx": "J",
"date": "2009-12-31",
"perf": 1.0021
}
]
var height = 600, width = 900
var margin = {
top: 20,
bottom: 50,
left: 50,
right: 20
}
var color = d3.scaleOrdinal(d3.schemeCategory10)
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
var g_plot = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
var sc_x = d3.scaleBand()
.domain(data.map(d => (d.date)))
.range([0,width - margin.left - margin.right])
var sc_y = d3.scaleLinear()
.domain(d3.extent(data.map(d => d.perf)))
.range([height - margin.top - margin.bottom, 0])
var line = d3.line()
.curve(d3.curveMonotoneX)
var horiz_smooth = 50
var nested = d3.nest().key(d => d.idx).entries(data)
var highlight = function() {
svg.selectAll(".line").style("opacity", 0.25)
d3.select(this).style("opacity", 1)
}
var unhighlight = function() {
svg.selectAll(".line").style("opacity", 0.5)
}
nested.map(function(d) {
points = []
d.values.forEach(function(dd, i) {
if(i > d.values.length - 2) {
points.push([sc_x(dd.date) + horiz_smooth, sc_y(dd.perf)])
return
}
if(i === 0) {
points.push([sc_x(dd.date), sc_y(dd.perf)]),
points.push([sc_x(dd.date) + horiz_smooth, sc_y(dd.perf)])
points.push([sc_x(dd.date) + sc_x.bandwidth(), sc_y(d.values[i+1].perf)])
return
}
points.push([sc_x(dd.date) + horiz_smooth, sc_y(dd.perf)])
points.push([sc_x(dd.date) + sc_x.bandwidth(), sc_y(d.values[i+1].perf)])
})
g_plot.append("path")
.classed("line", true)
.attr("d", line(points))
.style("fill", "none")
.style("stroke", color(d.key))
.style("stroke-width", 10)
.style("opacity", 0.5)
.on("mouseover", highlight)
.on("mouseout", unhighlight)
})
g_plot.append("g")
.call(d3.axisBottom().scale(sc_x))
.attr("transform", "translate(" + (-sc_x.bandwidth()/2 + horiz_smooth/2) + "," + (+height - margin.top - margin.bottom) + ")")
g_plot.append("g")
.call(d3.axisLeft().scale(sc_y))
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment