Published
Edited
Aug 26, 2020
1 fork
2 stars
Insert cell
md`# Interactive Bar Chart of Taylor Swift Lyrics made on Twitch `
Insert cell
md`### Below is data of Taylor Swift lyrics`
Insert cell
Insert cell
FileAttachment("tswiftlyrics.csv")
Insert cell
md`#### Require d3`
Insert cell
d3 = {
const d3 = require("d3-dsv@1", "d3@5","d3-scale@3","d3-scale-chromatic@1", "d3-shape@1", "d3-array@2")
return d3
}
Insert cell
data = {
const text = await FileAttachment("tswiftlyrics.csv").text();
return d3.csvParse(text, ({lyric}) => ({
lyric: lyric
}));
}
Insert cell
md`#### Make a lyrics array of just the lyrics from the csv file`
Insert cell
lyrics = []
Insert cell
data.forEach(lyric => lyrics.push(lyric.lyric));
Insert cell
lyrics
Insert cell
md`#### regex, convert to lower-case, clean up text`
Insert cell
newLyrics = lyrics.join(' ').replace(/[.,\/#!""'$%\?^&\*;:{}=\-_`~()0-9]/g,"").toLowerCase()
Insert cell
md`#### stop words`
Insert cell
stopwords = ['i','me','my','myself','we','our','ours','ourselves','you','your','yours','yourself','yourselves','he','him','his','himself','she','her','hers','herself','it','its','itself','they','them','their','theirs','themselves','what','which','who','whom','this','that','these','those','am','is','are','was','were','be','been','being','have','has','had','having','do','does','did','doing','a','an','the','and','but','if','or','because','as','until','while','of','at','by','for','with','about','against','between','into','through','during','before','after','above','below','to','from','up','down','in','out','on','off','over','under','again','further','then','once','here','there','when','where','why','how','all','any','both','each','few','more','most','other','some','such','no','nor','not','only','own','same','so','than','too','very','s','t','can','will','just','don','should','now', 'im', 'ill', 'let', 'said', 'thats', 'oh', 'say', 'see', 'yeah', 'youre', 'ey', 'cant', 'dont', 'cause']
Insert cell
remove_stopwords = function(str) {
var res = []
var words = str.split(' ')
for(let i=0;i<words.length;i++) {
var word_clean = words[i].split(".").join("")
if(!stopwords.includes(word_clean)) {
res.push(word_clean)
}
}
return(res.join(' '))
}
Insert cell
lyrics_no_stopwords = remove_stopwords(newLyrics)
Insert cell
md`#### Get string frequency for each lyric`
Insert cell
strFrequency = function (stringArr) { //es6 way of getting frequencies of words
return stringArr.reduce((count, word) => {
count[word] = (count[word] || 0) + 1;
return count;
}, {})
}
Insert cell
obj = strFrequency(lyrics_no_stopwords.split(' '))
Insert cell
md`#### function to return the first n items in the object`
Insert cell
md`#### sort the frequencies to be max to min`
Insert cell
sortedObj = Object.fromEntries(
// switch a[1] and b[1] in the arrow function
Object.entries(obj).sort( (a,b) => b[1] - a[1] )
)
Insert cell
Insert cell
md`#### set attributes of the chart/graph`
Insert cell
margin = ({top: 20, right: 0, bottom: 30, left: 40})
Insert cell
height = 500
Insert cell
x = d3.scaleBand()
.domain(final.map(d => d.lyric))
.rangeRound([margin.left, width - margin.right])
.padding(0.1)
Insert cell
y = d3.scaleLinear()
.domain([0, d3.max(final, d => d.freq)])
.range([height - margin.bottom, margin.top])
Insert cell
yTitle = g => g.append("text")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.attr("y", 10)
.text("Frequency")
Insert cell
xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x).tickSizeOuter(0))
Insert cell
yAxis = g => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y).ticks(15))
.call(g => g.select(".domain").remove())
Insert cell
tooltip = d3.select("body")
.append("div")
.style("position", "absolute")
.style("font-family", "'Open Sans', sans-serif")
.style("font-size", "15px")
.style("z-index", "10")
.style("background-color", "#A7CDFA")
.style("color", "#B380BA")
.style("border", "solid")
.style("border-color", "#A89ED6")
.style("padding", "5px")
.style("border-radius", "2px")
.style("visibility", "hidden");
Insert cell
{
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height]);

// Call tooltip
tooltip;

svg.append("g")
.selectAll("rect")
.data(final)
.enter().append("rect")
.attr('x', d => x(d.lyric))
.attr('y', d => y(d.freq))
.attr('width', x.bandwidth())
.attr('height', d => y(0) - y(d.freq))
.style("padding", "3px")
.style("margin", "1px")
.style("width", d => `${d * 10}px`)
.text(d => d)
.attr("fill", "#CEBEDE")
.attr("stroke", "#FFB9EC")
.attr("stroke-width", 1)
.on("mouseover", function(d) {
tooltip.style("visibility", "visible").text(d.lyric + ": " + d.freq);
d3.select(this).attr("fill", "#FDE5BD");
})
.on("mousemove", d => tooltip.style("top", (d3.event.pageY-10)+"px").style("left",(d3.event.pageX+10)+"px").text(d.lyric + ": " + d.freq))
.on("mouseout", function(d) {
tooltip.style("visibility", "hidden");
d3.select(this)
.attr("fill", "#CEBEDE")
});

svg.append("g")
.call(xAxis);
svg.append("g")
.call(yAxis);
svg.call(yTitle);

return svg.node();
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more