Skip to content

Instantly share code, notes, and snippets.

@easadler
Last active January 3, 2016 22:43
Show Gist options
  • Save easadler/853206b91056002a162b to your computer and use it in GitHub Desktop.
Save easadler/853206b91056002a162b to your computer and use it in GitHub Desktop.
Letter Frequency

Uses react and d3 to plot the letter fequency of a sentance as it is typed. React and D3 integration based on this blog post by Nicolas Hery and letter frequency chart based on this example by Mike Bostock.

function barChart() {
var margin = {top: 20, right: 30, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 470 - margin.top - margin.bottom,
xValue = function(d) { return d[0]; },
yValue = function(d) { return d[1]; },
xScale = d3.scale.ordinal(),
yScale = d3.scale.linear();
function chart(selection) {
selection.each(function(data) {
// Convert data to standard representation greedily;
// this is needed for nondeterministic accessors.
data = data.map(function(d, i) {
return [xValue.call(data, d, i), yValue.call(data, d, i)];
});
// Update the x-scale.
xScale
.domain(data.map(function(d) { return d[0]; }))
.rangeRoundBands([0, width], .1, .2);
// Update the y-scale.
yScale
.domain([0, d3.max(data, function(d) { return d[1]; })])
.range([height, 0]);
// Select the svg element, if it exists.
var svg = d3.select(this).selectAll("svg").data([data]);
// Otherwise, create the skeletal chart.
var gEnter = svg.enter().append("svg").append("g").append('g').attr('class','x axis');
// Update the outer dimensions.
svg.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
// Update the inner dimensions.
var g = svg.select("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Update the bars.
var bars = g.selectAll("rect").data(data);
bars.enter().append("rect")
.attr("width", xScale.rangeBand())
.attr('class','bar')
bars
.attr("x", function(d) { return xScale(d[0]); })
.attr("y", function(d) { return yScale(d[1]); })
.attr("height", function(d) { return 420 - yScale(d[1]); })
// Update the x-axis.
g.select(".x.axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.svg.axis().scale(xScale).orient("bottom"));
});
}
// The x-accessor for the path generator; xScale ∘ xValue.
function X(d) {
return xScale(d[0]);
}
// The x-accessor for the path generator; yScale ∘ yValue.
function Y(d) {
return yScale(d[1]);
}
chart.margin = function(_) {
if (!arguments.length) return margin;
margin = _;
return chart;
};
chart.width = function(_) {
if (!arguments.length) return width;
width = _;
return chart;
};
chart.height = function(_) {
if (!arguments.length) return height;
height = _;
return chart;
};
chart.x = function(_) {
if (!arguments.length) return xValue;
xValue = _;
return chart;
};
chart.y = function(_) {
if (!arguments.length) return yValue;
yValue = _;
return chart;
};
return chart;
}
<!DOCTYPE html>
<meta charset="utf-8">
<head>
<link rel="stylesheet" type="text/css" href="style.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.12.2/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.12.2/JSXTransformer.js"></script>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script type="text/javascript" src="chart.js"></script>
</head>
<body>
<script type="text/javascript">
window.chart = barChart()
.x(function(d) { return d.key; })
.y(function(d) { return +d.value; });
</script>
<script type="text/jsx">
var Chart = React.createClass({
componentDidMount: function() {
var el = this.getDOMNode();
d3.select(el)
.datum(this.props.data)
.call(chart);
},
componentDidUpdate: function() {
var el = this.getDOMNode();
d3.select(el)
.datum(this.props.data)
.call(chart);
},
render: function() {
return (
<div className="Chart"></div>
);
}
});
var App = React.createClass({
getInitialState:function(){
return {
data: d3.entries(this.makeArray())
}
},
update: function(e){
var text = e.target.value.toLowerCase().replace(/[^A-Za-z]/g, "");
var splitText = text.split('');
var data = this.makeArray()
for (var i = 0; i < splitText.length; i++) {
data[splitText[i]]++;
};
this.setState({data: d3.entries(data)})
},
reset: function(){
this.setState({data: d3.entries(this.makeArray())});
this.refs.myInput.getDOMNode().value = '';
},
makeArray: function(){
var a = 97;
var charArray = {};
for (var i = 0; i<26; i++)
charArray[String.fromCharCode(a + i)] = 0;
return charArray;
},
propTypes:{
txt: React.PropTypes.string
},
render: function(){
return (
<div className = "container">
<input ref="myInput" type ="text" onChange={this.update} autoFocus={focus}/>
<button onClick={this.reset}>Reset</button>
<Chart data={this.state.data}/>
</div>
);
}
})
React.render(<App />, document.body);
</script>
.container {
text-align: center;
padding-top: 20px;
}
input {
width: 500px;
display: inline-block;
}
button {
display: inline-block;
margin-left: 5px;
}
.bar {
fill: steelblue;
}
.bar:hover {
fill: brown;
}
.axis {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment