Skip to content

Instantly share code, notes, and snippets.

@micahstubbs micahstubbs/.block
Last active Oct 29, 2018

Embed
What would you like to do?
Tie Fighter Marks
license: Apache-2.0
border: no

or, an ordinal boxplot with no q1 or q3 data. A boxplot without the box.


A visualization of monthly-attached-hmds

Road to VR ran the figures against the most recent Hardware & Software Survey (September 2018), and found the following counts for headsets (head-mounted displays, hmds) connected to users’ computers over the course of the month.

It’s worth noting that the Steam Hardware & Software Survey counts how many users have headsets attached to their computers; even if the user didn’t actually use the headset to play a game in the given month, it would still be counted. So it would be more accurate to call the figures above ‘Monthly Attached VR Headsets on Steam’ rather than ‘Monthly Active VR Users on Steam’, though this is the closest indicator we’ve got to the latter. Actual unit sales are likely significantly higher than the ‘headsets attached’ figures that we have here, but none of the above manufacturers have released official figures at this point.

https://www.roadtovr.com/new-valve-data-suggests-648000-active-vr-headsets-on-steam/amp/

https://twitter.com/micahstubbs/status/1056591387129405445

<DOCTYPE !html>
<html>
<head>
<title>Tie Fighter Marks</title>
<meta charset="utf-8" />
<style>
/* svg {
border: 1px solid gray;
}*/
line {
shape-rendering: crispEdges;
stroke: lightgray;
}
line.minor {
stroke: #777777;
stroke-dasharray: 2,2;
}
path.domain {
fill: none;
stroke: lightgray;
}
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js" type="text/JavaScript"></script>
<script src='./index.js'></script>
</body>
</html>
d3.csv('./monthly-attached-hmds.csv').then(data => boxplot(data))
function boxplot(data) {
// setup the plot area
const h = 500
const w = 500
const margin = {
top: 20,
bottom: 40,
left: 20,
right: 30
}
const innerHeight = h - margin.bottom
const innerWidth = w - margin.right
const outerHeight = 500
const outerWidth = 960
d3.select('body')
.append('svg')
.attr('height', outerHeight)
.attr('width', outerWidth)
//
// map variables in the data to types
//
// categorical variable
const catVariable = 'VR HMD'
const catValues = data.map(d => d[catVariable])
console.log('catValues', catValues)
// numeric variable statistics
const minVariable = 'min user count estimate'
const maxVariable = 'max user count estimate'
const medianVariable = 'median user count estimate'
const q1Variable = undefined
const q3Variable = undefined
// ensure numeric values read from csv data are numbers
data.forEach(d => {
if (minVariable) d[minVariable] = Number(d[minVariable])
if (maxVariable) d[maxVariable] = Number(d[maxVariable])
if (medianVariable) d[medianVariable] = Number(d[medianVariable])
if (q1Variable) d[q1Variable] = Number(d[q1Variable])
if (q3Variable) d[q3Variable] = Number(d[q3Variable])
})
// define the scales
xScale = d3
.scaleLinear()
.domain([
d3.min(data.map(d => d[minVariable])),
d3.max(data.map(d => d[maxVariable])) * 1.1
])
.rangeRound([margin.left, innerWidth])
yScale = d3
.scaleBand()
.domain(catValues)
.rangeRound([0, innerHeight])
console.log(data)
//
// setup the axes
//
// x-axis
const xTranslate = innerHeight
xAxis = d3
.axisBottom()
.scale(xScale)
.ticks(7)
.tickFormat(d3.format('~s'))
.tickSize(-xTranslate)
d3.select('svg')
.append('g')
.attr('transform', `translate(0,${xTranslate})`)
.attr('id', 'xAxisG')
.call(xAxis)
// text label for the x axis
d3.select('svg')
.append('text')
.attr('transform', `translate(${w / 2},${h - 5})`)
.style('text-anchor', 'middle')
.text('Steam Monthly Attached Head-Mounted Displays')
// y-axis
const yTranslate = innerWidth
yAxis = d3
.axisRight()
.scale(yScale)
.tickSize(-yTranslate)
.tickValues(catValues)
d3.select('svg')
.append('g')
.attr('transform', `translate(${yTranslate},0)`)
.attr('id', 'yAxisG')
.call(yAxis)
d3.select('svg')
.selectAll('g.box')
.data(data)
.enter()
.append('g')
.attr('class', 'box')
.attr('transform', d => {
const yValue = d[catVariable]
const yValueScaled = yScale(yValue)
const yOffset = margin.top * 2
// console.log('d', d)
console.log('yValue', yValue)
console.log('yValueScaled', yValueScaled)
return `translate(${xScale(d[medianVariable])},${yValueScaled + yOffset})`
})
.each(function(d, i) {
const minScreen = xScale(d[minVariable])
const medianScreen = xScale(d[medianVariable])
const maxScreen = xScale(d[maxVariable])
console.log('d', d)
console.log('minScreen', minScreen)
console.log('medianScreen', medianScreen)
console.log('maxScreen', maxScreen)
d3.select(this)
.append('line')
.attr('class', 'range')
.attr('x1', xScale(d[maxVariable]) - xScale(d[medianVariable]))
.attr('x2', xScale(d[minVariable]) - xScale(d[medianVariable]))
.attr('y1', 0)
.attr('y2', 0)
.style('stroke', 'black')
.style('stroke-width', '3px')
d3.select(this)
.append('line')
.attr('class', 'max')
.attr('x1', xScale(d[maxVariable]) - xScale(d[medianVariable]))
.attr('x2', xScale(d[maxVariable]) - xScale(d[medianVariable]))
.attr('y1', -10)
.attr('y2', 10)
.style('stroke', 'black')
.style('stroke-width', '3px')
d3.select(this)
.append('line')
.attr('class', 'min')
.attr('x1', xScale(d[minVariable]) - xScale(d[medianVariable]))
.attr('x2', xScale(d[minVariable]) - xScale(d[medianVariable]))
.attr('y1', -10)
.attr('y2', 10)
.style('stroke', 'black')
.style('stroke-width', '3px')
// only draw the box if q1 and q3 variables are defined
if (q1Variable && q3Variable) {
d3.select(this)
.append('rect')
.attr('class', 'range')
.attr('x', xScale(d[q1Variable]) - xScale(d[medianVariable]))
.attr('y', -10)
.attr('height', 20)
.attr('width', xScale(d[q3Variable]) - xScale(d[q1Variable]))
.style('fill', 'white')
.style('stroke', 'black')
.style('stroke-width', '3px')
}
// median
d3.select(this)
.append('line')
.attr('x1', 0)
.attr('x2', 0)
.attr('y1', -5)
.attr('y2', 5)
.style('stroke', 'darkgray')
.style('stroke-width', '3px')
})
}
Steam Monthly Active Users min % % that have max % VR HMD min user count estimate median user count estimate max user count estimate YYYYMM reporter source
90000000 0.335 0.34 0.3449 Oculus Rift 301500 306000 310410 201809 @micahstubbs https://store.steampowered.com/hwsurvey/Steam-Hardware-Software-Survey-Welcome-to-Steam?platform=combined
90000000 0.305 0.31 0.3149 HTC Vive 274500 279000 283410 201809 @micahstubbs https://store.steampowered.com/hwsurvey/Steam-Hardware-Software-Survey-Welcome-to-Steam?platform=combined
90000000 0.045 0.05 0.0549 Windows Mixed Reality 40500 45000 49410 201809 @micahstubbs https://store.steampowered.com/hwsurvey/Steam-Hardware-Software-Survey-Welcome-to-Steam?platform=combined
90000000 0.005 0.01 0.0149 HTC Vive Pro 4500 9000 13410 201809 @micahstubbs https://store.steampowered.com/hwsurvey/Steam-Hardware-Software-Survey-Welcome-to-Steam?platform=combined
90000000 0.005 0.01 0.0149 Oculus Rift DK2 4500 9000 13410 201809 @micahstubbs https://store.steampowered.com/hwsurvey/Steam-Hardware-Software-Survey-Welcome-to-Steam?platform=combined
90000000 0 0 0.0049 Oculus Rift DK1 0 0 4410 201809 @micahstubbs https://store.steampowered.com/hwsurvey/Steam-Hardware-Software-Survey-Welcome-to-Steam?platform=combined
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.