block by timelyportfolio f5ce5602160c1654e519e5035aef705d

alternate version of market quilt

Full Screen

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

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)

# 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 = runif(10 * 10,-20,20),
  stringsAsFactors = FALSE
)



# 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)
)
    ))
  )
)

index.html

<!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": -4.5761
  },
  {
    "idx": "A",
    "date": "2001-12-31",
    "perf": -15.0073
  },
  {
    "idx": "A",
    "date": "2002-12-31",
    "perf": -17.911
  },
  {
    "idx": "A",
    "date": "2003-12-31",
    "perf": 18.5215
  },
  {
    "idx": "A",
    "date": "2004-12-31",
    "perf": -15.0506
  },
  {
    "idx": "A",
    "date": "2005-12-31",
    "perf": -18.6963
  },
  {
    "idx": "A",
    "date": "2006-12-31",
    "perf": -8.8435
  },
  {
    "idx": "A",
    "date": "2007-12-31",
    "perf": -8.6675
  },
  {
    "idx": "A",
    "date": "2008-12-31",
    "perf": -6.3162
  },
  {
    "idx": "A",
    "date": "2009-12-31",
    "perf": -4.4992
  },
  {
    "idx": "B",
    "date": "2000-12-31",
    "perf": -15.469
  },
  {
    "idx": "B",
    "date": "2001-12-31",
    "perf": 15.4334
  },
  {
    "idx": "B",
    "date": "2002-12-31",
    "perf": 9.1245
  },
  {
    "idx": "B",
    "date": "2003-12-31",
    "perf": 17.9742
  },
  {
    "idx": "B",
    "date": "2004-12-31",
    "perf": -8.7123
  },
  {
    "idx": "B",
    "date": "2005-12-31",
    "perf": 4.4175
  },
  {
    "idx": "B",
    "date": "2006-12-31",
    "perf": -9.2237
  },
  {
    "idx": "B",
    "date": "2007-12-31",
    "perf": -8.1461
  },
  {
    "idx": "B",
    "date": "2008-12-31",
    "perf": 14.835
  },
  {
    "idx": "B",
    "date": "2009-12-31",
    "perf": -14.0465
  },
  {
    "idx": "C",
    "date": "2000-12-31",
    "perf": -4.4291
  },
  {
    "idx": "C",
    "date": "2001-12-31",
    "perf": -3.4441
  },
  {
    "idx": "C",
    "date": "2002-12-31",
    "perf": 1.7558
  },
  {
    "idx": "C",
    "date": "2003-12-31",
    "perf": -5.0047
  },
  {
    "idx": "C",
    "date": "2004-12-31",
    "perf": -14.5759
  },
  {
    "idx": "C",
    "date": "2005-12-31",
    "perf": 6.6994
  },
  {
    "idx": "C",
    "date": "2006-12-31",
    "perf": -1.5583
  },
  {
    "idx": "C",
    "date": "2007-12-31",
    "perf": -13.2864
  },
  {
    "idx": "C",
    "date": "2008-12-31",
    "perf": -7.2503
  },
  {
    "idx": "C",
    "date": "2009-12-31",
    "perf": 15.2747
  },
  {
    "idx": "D",
    "date": "2000-12-31",
    "perf": 13.9626
  },
  {
    "idx": "D",
    "date": "2001-12-31",
    "perf": 3.243
  },
  {
    "idx": "D",
    "date": "2002-12-31",
    "perf": -13.3865
  },
  {
    "idx": "D",
    "date": "2003-12-31",
    "perf": 15.8711
  },
  {
    "idx": "D",
    "date": "2004-12-31",
    "perf": -6.6842
  },
  {
    "idx": "D",
    "date": "2005-12-31",
    "perf": 6.5636
  },
  {
    "idx": "D",
    "date": "2006-12-31",
    "perf": 11.7851
  },
  {
    "idx": "D",
    "date": "2007-12-31",
    "perf": -19.8014
  },
  {
    "idx": "D",
    "date": "2008-12-31",
    "perf": 15.0866
  },
  {
    "idx": "D",
    "date": "2009-12-31",
    "perf": 19.3894
  },
  {
    "idx": "E",
    "date": "2000-12-31",
    "perf": -18.8695
  },
  {
    "idx": "E",
    "date": "2001-12-31",
    "perf": -14.0828
  },
  {
    "idx": "E",
    "date": "2002-12-31",
    "perf": 18.333
  },
  {
    "idx": "E",
    "date": "2003-12-31",
    "perf": -14.6408
  },
  {
    "idx": "E",
    "date": "2004-12-31",
    "perf": 19.4939
  },
  {
    "idx": "E",
    "date": "2005-12-31",
    "perf": -16.546
  },
  {
    "idx": "E",
    "date": "2006-12-31",
    "perf": -14.883
  },
  {
    "idx": "E",
    "date": "2007-12-31",
    "perf": -5.0652
  },
  {
    "idx": "E",
    "date": "2008-12-31",
    "perf": -8.3776
  },
  {
    "idx": "E",
    "date": "2009-12-31",
    "perf": -15.234
  },
  {
    "idx": "F",
    "date": "2000-12-31",
    "perf": -3.273
  },
  {
    "idx": "F",
    "date": "2001-12-31",
    "perf": -19.6255
  },
  {
    "idx": "F",
    "date": "2002-12-31",
    "perf": 7.7506
  },
  {
    "idx": "F",
    "date": "2003-12-31",
    "perf": -16.6891
  },
  {
    "idx": "F",
    "date": "2004-12-31",
    "perf": 2.3649
  },
  {
    "idx": "F",
    "date": "2005-12-31",
    "perf": -9.3366
  },
  {
    "idx": "F",
    "date": "2006-12-31",
    "perf": -2.0149
  },
  {
    "idx": "F",
    "date": "2007-12-31",
    "perf": -7.6408
  },
  {
    "idx": "F",
    "date": "2008-12-31",
    "perf": 1.4748
  },
  {
    "idx": "F",
    "date": "2009-12-31",
    "perf": -7.5252
  },
  {
    "idx": "G",
    "date": "2000-12-31",
    "perf": -9.9526
  },
  {
    "idx": "G",
    "date": "2001-12-31",
    "perf": 18.2518
  },
  {
    "idx": "G",
    "date": "2002-12-31",
    "perf": -17.8075
  },
  {
    "idx": "G",
    "date": "2003-12-31",
    "perf": 2.4835
  },
  {
    "idx": "G",
    "date": "2004-12-31",
    "perf": -10.259
  },
  {
    "idx": "G",
    "date": "2005-12-31",
    "perf": 14.1983
  },
  {
    "idx": "G",
    "date": "2006-12-31",
    "perf": 19.1988
  },
  {
    "idx": "G",
    "date": "2007-12-31",
    "perf": 3.6613
  },
  {
    "idx": "G",
    "date": "2008-12-31",
    "perf": 11.9808
  },
  {
    "idx": "G",
    "date": "2009-12-31",
    "perf": -19.6471
  },
  {
    "idx": "H",
    "date": "2000-12-31",
    "perf": 15.8034
  },
  {
    "idx": "H",
    "date": "2001-12-31",
    "perf": -13.0795
  },
  {
    "idx": "H",
    "date": "2002-12-31",
    "perf": 16.4691
  },
  {
    "idx": "H",
    "date": "2003-12-31",
    "perf": -17.0362
  },
  {
    "idx": "H",
    "date": "2004-12-31",
    "perf": -12.3088
  },
  {
    "idx": "H",
    "date": "2005-12-31",
    "perf": 4.455
  },
  {
    "idx": "H",
    "date": "2006-12-31",
    "perf": 18.8401
  },
  {
    "idx": "H",
    "date": "2007-12-31",
    "perf": -15.571
  },
  {
    "idx": "H",
    "date": "2008-12-31",
    "perf": 11.0688
  },
  {
    "idx": "H",
    "date": "2009-12-31",
    "perf": -0.7543
  },
  {
    "idx": "I",
    "date": "2000-12-31",
    "perf": 19.4466
  },
  {
    "idx": "I",
    "date": "2001-12-31",
    "perf": -10.4479
  },
  {
    "idx": "I",
    "date": "2002-12-31",
    "perf": -18.4353
  },
  {
    "idx": "I",
    "date": "2003-12-31",
    "perf": 9.3312
  },
  {
    "idx": "I",
    "date": "2004-12-31",
    "perf": 13.7115
  },
  {
    "idx": "I",
    "date": "2005-12-31",
    "perf": -18.4976
  },
  {
    "idx": "I",
    "date": "2006-12-31",
    "perf": -3.3736
  },
  {
    "idx": "I",
    "date": "2007-12-31",
    "perf": 4.9811
  },
  {
    "idx": "I",
    "date": "2008-12-31",
    "perf": -19.9589
  },
  {
    "idx": "I",
    "date": "2009-12-31",
    "perf": 19.8707
  },
  {
    "idx": "J",
    "date": "2000-12-31",
    "perf": 14.8278
  },
  {
    "idx": "J",
    "date": "2001-12-31",
    "perf": -10.8594
  },
  {
    "idx": "J",
    "date": "2002-12-31",
    "perf": -4.0786
  },
  {
    "idx": "J",
    "date": "2003-12-31",
    "perf": 18.2823
  },
  {
    "idx": "J",
    "date": "2004-12-31",
    "perf": 8.9381
  },
  {
    "idx": "J",
    "date": "2005-12-31",
    "perf": -11.6092
  },
  {
    "idx": "J",
    "date": "2006-12-31",
    "perf": 17.0184
  },
  {
    "idx": "J",
    "date": "2007-12-31",
    "perf": 0.5828
  },
  {
    "idx": "J",
    "date": "2008-12-31",
    "perf": -7.9249
  },
  {
    "idx": "J",
    "date": "2009-12-31",
    "perf": -1.397
  }
]

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>