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