block by micahstubbs ca2bbbc681dc9525d534e3197508139e

human text I/O in wpm

Full Screen

data on different text input and output methods inspired by @devonzuegelβ€˜s microblog post

read the macroblog post at http://devonzuegel.com/post/comparison-of-text-editing-methods

the data presented here combines the data presented in the post with additional research by @micahstubbs


πŸ’‘this table as a chart:

input-methods-table-960px


πŸ—ƒ in github repo form at https://github.com/micahstubbs/text-editing-methods


an iteration on Horizontal Bar Chart from @currankelleher

index.js

d3.csv('text-editing-methods-speed.csv')
  .then(data =>
    data.map(d => {
      d['Average Speed for adult [wpm]'] = Number(
        d['Average Speed for adult [wpm]']
      )
      d['Lower bound [wpm]'] = Number(d['Lower bound [wpm]'])
      d['Upper bound [wpm]'] = Number(d['Upper bound [wpm]'])
      return d
    })
  )
  .then(data =>
    data.sort(
      (a, b) =>
        a['Average Speed for adult [wpm]'] - b['Average Speed for adult [wpm]']
    )
  )
  .then(data => draw({ data }))

function draw({ data }) {
  console.log('data', data)

  const outerWidth = 960
  const outerHeight = 500
  const margin = { left: 100, top: 10, right: 50, bottom: 75 }

  // colors
  const themeDarkGray = '#444444'
  const themeBookEmojiGray = '#dfdfe8'
  const blogBlue = '#367da2'
  const blogGray = '#eaeaea'
  const blogDarkGray = '#333333'

  const selector = 'body'
  d3.select(selector)
    .append('div')
    .attr('id', 'vis')
    .append('svg')
    .attr('width', outerWidth)
    .attr('height', outerHeight)

  const parent = document.getElementById('vis')
  const svg = d3.select(parent).select('svg')

  // background
  svg
    .append('rect')
    .attr('x', 0)
    .attr('y', 0)
    .attr('width', outerWidth)
    .attr('height', outerHeight)
    .style('fill', blogGray)

  const g = svg
    .append('g')
    .attr('transform', `translate(${margin.left},${margin.top})`)

  const innerWidth = outerWidth - margin.left - margin.right
  const innerHeight = outerHeight - margin.top - margin.bottom

  const meanVariable = 'Average Speed for adult [wpm]'
  const minVariable = 'Lower bound [wpm]'
  const maxVariable = 'Upper bound [wpm]'
  const yVariable = 'emoji'

  const xAxisLabelText = 'input speed in words per minute (more is faster)'
  const xAxisLabelOffset = 50

  console.log('width', outerWidth)
  console.log('height', outerHeight)

  const xAxisG = g
    .append('g')
    .attr('class', 'x axis')
    .attr('transform', `translate(0,${innerHeight})`)

  const xAxisLabel = xAxisG
    .append('text')
    .style('text-anchor', 'middle')
    .style('fill', themeDarkGray)
    .style('font-size', 20)
    .attr('x', innerWidth / 2)
    .attr('y', xAxisLabelOffset)
    .attr('class', 'label')
    .text(xAxisLabelText)

  const yAxisG = g.append('g').attr('class', 'y axis')

  const xScale = d3
    .scaleLinear()
    .domain([0, d3.max(data, d => d[maxVariable])])
    .range([0, innerWidth])

  const yScale = d3
    .scaleBand()
    .domain(data.map(d => d[yVariable]).reverse())
    .range([innerHeight, 0])

  const xAxis = d3.axisBottom(xScale).ticks(5)
  const yAxis = d3.axisLeft(yScale)

  xAxisG.call(xAxis)
  yAxisG.call(yAxis)

  const yOffset = yScale.bandwidth() / 2

  const lines = g.selectAll('.line').data(data)
  lines
    .enter()
    .append('line')
    .attr('class', '.line')
    .attr('x1', d => xScale(d[minVariable]))
    .attr('x2', d => xScale(d[maxVariable]))
    .attr('y1', d => yScale(d[yVariable]) + yOffset)
    .attr('y2', d => yScale(d[yVariable]) + yOffset)
    .style('stroke', blogBlue)
    .style('stroke-width', '2px')

  const radius = 5
  const circles = g.selectAll('.circle').data(data)
  circles
    .enter()
    .append('circle')
    .attr('class', '.circle')
    .attr('cx', d => xScale(d[meanVariable]))
    .attr('cy', d => yScale(d[yVariable]) + yOffset)
    .attr('r', radius)
    .style('fill', blogBlue)
}

index.html

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
  <style>
    .axis text {
      fill: #333333;
    }
    .x.axis text {
      font-size: 12px;
    }
    .y.axis text {
      font-size: 28px;
    }
    .axis line {
      fill: #333333;
    }
    .axis path {
      fill: none;
      stroke: #333333;
    }
    .tick line {
      stroke: #333333;
    }

  </style>
</head>
<body>
  <script src='index.js'></script>
</body>

text-editing-methods-speed.csv

"Input Category","Input Type","Average Speed for adult [wpm]","Lower bound [wpm]","Upper bound [wpm]",emoji,citations
handwriting,printing,13,5,20,πŸ“,https://en.wikipedia.org/wiki/Words_per_minute#Handwriting
handwriting,cursive,16,16,25,✍️,http://sci-hub.tw/https://dl.acm.org/citation.cfm?id=1518788
"mobile typing",thumbs,13,11,15,πŸ“±πŸ‘,https://ux.stackexchange.com/questions/74623/touch-versus-trace-typing
"mobile typing",swype,13,11,50,πŸ“±πŸ‘†,https://ux.stackexchange.com/questions/74623/touch-versus-trace-typing
"keyboard typing",querty,40,38,95,⌨️,https://www.livechatinc.com/typing-speed-test/#/global-scores
"free-form speaking",audiobook,155,150,160,πŸŽ§πŸ“–,https://en.wikipedia.org/wiki/Words_per_minute#cite_note-14
"free-form speaking","slide presentation",112,100,125,πŸ“½πŸ“Š,https://en.wikipedia.org/wiki/Words_per_minute#cite_note-wong-15
reading,aloud,228,198,258,πŸ“–πŸ—£,https://en.wikipedia.org/wiki/Words_per_minute#Reading_and_comprehension
reading,silently,300,180,900,πŸ“–πŸ€«,https://en.wikipedia.org/wiki/Words_per_minute#Reading_and_comprehension|http://journals.sagepub.com/doi/pdf/10.1080/10862968909547667