Last active
August 15, 2017 23:08
-
-
Save alex-r-bigelow/bce2174cf2ed4a9efd93e65e5d1956cc to your computer and use it in GitHub Desktop.
tool-modality-attributes-and-pca
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
license: MIT | |
height: 1500 | |
scrolling: no | |
border: yes |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Modality | Usability Threshold | Expressiveness Ceiling | Number of Tasks Supported | Editing vs Starting From Scratch | Separation From the Graphics | Optimized for Algorithmic vs Immediate Tasks | PCA 1 | PCA 2 | |
---|---|---|---|---|---|---|---|---|---|
drawing tools | 1 | 4 | 1 | 2 | 2 | 2 | 2.5401611 | -1.95837756 | |
direct manipulation-based tools | 2 | 1 | 0 | 1 | 2 | 1 | 1.70458815 | 0.61036012 | |
GUI-based tools | 0 | 0 | 0 | 0 | 1 | 0 | 0.57795806 | 2.33751476 | |
grammars | 3 | 2 | 0 | 0 | 0 | 0 | -1.09200032 | 1.20664758 | |
libraries | 4 | 3 | 2 | 1 | 0 | 0 | -1.48451323 | -1.35504455 | |
programming languages | 5 | 5 | 1 | 0 | 0 | 0 | -2.24619376 | -0.84110035 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset=utf-8> | |
<title>Tool modalities</title> | |
<link href="https://fonts.googleapis.com/css?family=Roboto+Slab:700" rel="stylesheet"> | |
<link type="text/css" rel="stylesheet" href="style.css"/> | |
</head> | |
<body> | |
<div id="container"></div> | |
<script src="http://d3js.org/d3.v4.min.js"></script> | |
<script src="script.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import numpy as np | |
from sklearn.decomposition import PCA | |
import pandas as pd | |
import matplotlib.pyplot as plt | |
from sklearn.preprocessing import scale | |
%matplotlib inline | |
#Load data set | |
data = pd.read_csv('data.csv') | |
#convert it to numpy arrays | |
X=data.values[:,1:7] | |
print 'Raw data:\n', X, '\n' | |
#Scaling the values | |
X = scale(X) | |
pca = PCA(n_components=2) | |
pca.fit(X) | |
print 'Components:\n', pca.components_, '\n' | |
newCoords = pca.transform(X) | |
print 'Transformed Coordinates:\n', newCoords, '\n' | |
#The amount of variance that each PC explains | |
var = pca.explained_variance_ratio_ | |
#Cumulative Variance explains | |
var1 = np.cumsum(np.round(pca.explained_variance_ratio_, decimals=4)*100) | |
plt.plot(var1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* globals d3 */ | |
const radius = 5; | |
const bigRadius = 4 * radius; | |
const bigPadding = 3 * bigRadius; | |
const jitter = 2 * radius; | |
const padding = 3 * radius; | |
const scales = { | |
'Usability Threshold': d3.scaleLinear() | |
.domain([0, 5]) | |
.range([588 - padding, 490 + padding]), | |
'Expressiveness Ceiling': d3.scaleLinear() | |
.domain([0, 5]) | |
.range([490 - padding, 392 + padding]), | |
'Number of Tasks Supported': d3.scaleLinear() | |
.domain([0, 2]) | |
.range([392 - padding, 294 + padding]), | |
'Editing vs Starting From Scratch': d3.scaleLinear() | |
.domain([0, 2]) | |
.range([294 - padding, 196 + padding]), | |
'Separation From the Graphics': d3.scaleLinear() | |
.domain([0, 2]) | |
.range([196 - padding, 98 + padding]), | |
'Optimized for Algorithmic vs Immediate Tasks': d3.scaleLinear() | |
.domain([0, 2]) | |
.range([98 - padding, 0 + padding]) | |
}; | |
const pcaScales = { | |
'x': d3.scaleLinear() | |
.range([bigPadding, 832 - bigPadding]), | |
'y': d3.scaleLinear() | |
.range([bigPadding, 832 - bigPadding]) | |
}; | |
const reverseLabels = { | |
'drawing tools': true, | |
'direct manipulation-based tools': true, | |
'GUI-based tools': false, | |
'grammars': false, | |
'libraries': false, | |
'programming languages': false | |
}; | |
d3.text('template.svg', template => { | |
d3.select('#container').html(template); | |
const background = d3.select('#Background'); | |
const scatterFrame = d3.select('#ScatterFrame'); | |
const scatterGroup = d3.select('svg').append('g'); | |
d3.csv('data.csv', data => { | |
// Clean the data | |
data = data.map(row => { | |
Object.keys(row).forEach(key => { | |
let floatValue = parseFloat(row[key]); | |
if (!isNaN(floatValue)) { | |
row[key] = floatValue; | |
} | |
}); | |
return row; | |
}); | |
// Figure out the PCA domains | |
pcaScales.x.domain(d3.extent(data, d => d['PCA 1'])); | |
pcaScales.y.domain(d3.extent(data, d => d['PCA 2'])); | |
// Generate a plot for each possible pairing | |
let pairwisePlots = []; | |
Object.keys(scales).forEach(xKey => { | |
Object.keys(scales).forEach(yKey => { | |
pairwisePlots.push({xKey, yKey}); | |
}); | |
}); | |
let smallMultiples = scatterGroup.selectAll('.smallMultiple').data(pairwisePlots); | |
smallMultiples.exit().remove(); | |
let smallMultiplesEnter = smallMultiples.enter().append('g') | |
.classed('smallMultiple', true); | |
smallMultiples = smallMultiplesEnter.merge(smallMultiples); | |
// Generate the points in those plots | |
let modalities = smallMultiples.selectAll('.modality').data((plot, index) => { | |
// Derive the location of each point in its plot | |
let locationHashTable = {}; | |
data.forEach(d => { | |
let derivedPoint = { | |
Modality: d.Modality, | |
includeLabel: index === 0, | |
x: scales[plot.xKey](d[plot.xKey]), | |
y: scales[plot.yKey](d[plot.yKey]), | |
pcaX: pcaScales.x(d['PCA 1']), | |
pcaY: pcaScales.y(d['PCA 2']) | |
}; | |
if (isNaN(derivedPoint.pcaX) || isNaN(derivedPoint.pcaY)) { | |
throw new Error(); | |
} | |
let hash = derivedPoint.x + ',' + derivedPoint.y; | |
derivedPoint.hash = hash; | |
if (!locationHashTable[hash]) { | |
locationHashTable[hash] = []; | |
} | |
locationHashTable[hash].push(derivedPoint); | |
}); | |
// Where there are hash collisions, jitter the points | |
Object.keys(locationHashTable).forEach(hash => { | |
let pointsAtLocation = locationHashTable[hash]; | |
if (pointsAtLocation.length > 1) { | |
let center = hash.split(',').map(d => parseFloat(d)); | |
pointsAtLocation.forEach((point, index) => { | |
let offset = ((index + 0.5) / pointsAtLocation.length) - 0.5; | |
point.x = center[0] + offset * jitter; | |
point.y = center[1] - offset * jitter; | |
}); | |
} | |
}); | |
// Finally convert the locationHashTable to an array of points | |
return Object.keys(locationHashTable).reduce((acc, hash) => { | |
return acc.concat(locationHashTable[hash]); | |
}, []); | |
}, d => d.Modality); | |
modalities.exit().remove(); | |
let modalitiesEnter = modalities.enter().append('g') | |
.attr('class', d => 'modality ' + d.Modality.replace(/[ -]/g, '')); | |
modalities = modalitiesEnter.merge(modalities); | |
modalitiesEnter.append('circle'); | |
modalitiesEnter.append('text') | |
.attr('x', d => reverseLabels[d.Modality] ? -1.5 * bigRadius : 1.5 * bigRadius) | |
.attr('text-anchor', d => reverseLabels[d.Modality] ? 'end' : 'start') | |
.attr('y', '0.35em') | |
.text(d => d.includeLabel ? d.Modality : ''); | |
modalities.attr('transform', function (d) { | |
return 'translate(' + d.x + ',' + d.y + ')'; | |
}); | |
// Okay, now let's deal with animation. First, get the background to match | |
// the badge | |
let t = d3.transition() | |
.delay(10000) | |
.duration(2500); | |
background | |
// .attr('fill', '#000000') | |
// .transition(t) | |
.attr('fill', '#333333'); | |
// Show the ScatterFrame | |
scatterFrame | |
.attr('opacity', 0) | |
.transition(t) | |
.attr('opacity', 1); | |
// Rotate the scatterGroup | |
scatterGroup | |
.attr('transform', 'translate(109,472) rotate(0)') | |
.transition(t) | |
.attr('transform', 'translate(525,472) rotate(45)'); | |
// Move all the points into their scatterplot positions | |
modalities | |
.attr('transform', d => 'translate(' + d.pcaX + ',' + d.pcaY + ')') | |
.transition(t) | |
.attr('transform', d => 'translate(' + d.x + ',' + d.y + ')'); | |
// Make the points smaller | |
modalities.select('circle') | |
.attr('r', bigRadius) | |
.transition(t) | |
.attr('r', radius); | |
// Hide the labels | |
modalities.select('text') | |
.attr('opacity', 1) | |
.transition(t) | |
.attr('opacity', 0); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
html, | |
body { | |
padding: 0px; | |
margin: 0px; | |
} | |
.modality circle { | |
stroke: rgba(255,255,255,0.8); | |
stroke-width: 1px; | |
} | |
.modality text { | |
fill: rgba(255,255,255,0.8); | |
font-family: 'Roboto Slab', 'Helvetica', sans-serif; | |
font-size: 2em; | |
font-weight: 700; | |
} | |
.drawingtools circle { | |
fill: #1b9e77; | |
} | |
.directmanipulationbasedtools circle { | |
fill: #d95f02; | |
} | |
.GUIbasedtools circle { | |
fill: #7570b3; | |
} | |
.grammars circle { | |
fill: #e7298a; | |
} | |
.libraries circle { | |
fill: #e6ab02; | |
} | |
.programminglanguages circle { | |
fill: #666666; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment