Built with blockbuilder.org
xxxxxxxxxx
<html>
<head>
<title>Market Cap vs. Twitter Followers</title>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.24.0/d3-legend.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/numeral.js/2.0.6/numeral.min.js"></script>
<style>
body {
margin: 0px;
}
.domain {
/* display: none; */
stroke: #C0C0BB;
}
.tick line {
stroke: #C0C0BB;
}
div.tooltip {
position: absolute;
max-width: 300px;
padding: 10px;
color: grey;
font-family:Arial, Helvetica, sans-serif;
font-size: .8em;
background: whitesmoke;
border: 1px solid grey;
border-radius: 3px;
pointer-events: none;
}
.tooltip h2 {
/* border: 1px solid red; */
margin: 5px 0 0 0;
padding: 0;
text-align: center;
}
.tooltip h4 {
/* border: 1px solid green; */
margin: 5px 0 0 0;
padding: 0;
font-style: italic;
font-weight: normal;
text-align: center;
}
.image-container {
margin: 3px 0 0 0;
text-align: center;
}
.tick text,
.legendCells text {
fill: #8E8883;
font-size: 10pt;
font-family: sans-serif;
}
.axis-label,
.legend-label {
fill: #635F5D;
font-size: 20pt;
font-family: sans-serif;
}
/* Make the chart container fill the page using CSS. */
#visualization {
position: fixed;
left: 0px;
right: 0px;
top: 0px;
bottom: 0px;
}
</style>
</head>
<body>
<div id="visualization"></div>
<script>
var tooltip;
tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
const defaults = {
margin: { left: 140, right: 105, top: 75, bottom: 100 },
colorLegendX: 0,
colorLegendY: 0,
colorLegendLabelX: 0,
colorLegendLabelY: 0,
xAxisLabelOffset: 75,
yAxisLabelOffset: -65,
circleOpacity: .8,
circleRadius: 5
};
const ScatterPlot = (() => {
const xScale = d3.scaleLinear();
const yScale = d3.scaleLinear();
const colorScale = d3.scaleOrdinal()
.range(d3.schemeCategory10);
const xAxis = d3.axisBottom()
.scale(xScale)
.tickPadding(15)
.tickFormat(function(d){
return numeral(d).format('0.0a').replace('b', 'B').replace('k', 'K').replace('.0', '');
});
const yAxis = d3.axisLeft()
.scale(yScale)
.ticks(5)
.tickPadding(5)
.tickFormat(function(d){
return '$' + numeral(d).format('0.0a').replace('b', 'B').replace('k', 'K').replace('.0', '');
});
return (svg, props) => {
const {
data,
width,
height,
xValue,
xLabel,
yValue,
yLabel,
colorValue,
colorLabel,
margin,
colorLegendX,
colorLegendY,
colorLegendLabelX,
colorLegendLabelY,
xAxisLabelOffset,
yAxisLabelOffset,
circleOpacity,
circleRadius,
} = Object.assign({}, defaults, props);
const innerWidth = width - margin.left - margin.right;
const innerHeight = height - margin.top - margin.bottom;
xAxis.tickSize(-innerHeight);
yAxis.tickSize(-innerWidth);
svg
.attr('width', width)
.attr('height', height);
let g = svg.selectAll('.container').data([null]);
const gEnter = g.enter().append('g').attr('class', 'container');
g = gEnter
.merge(g)
.attr('transform', `translate(${margin.left},${margin.top})`);
const xAxisGEnter = gEnter.append('g').attr('class', 'x-axis');
const xAxisG = xAxisGEnter
.merge(g.select('.x-axis'))
.attr('transform', `translate(0, ${innerHeight})`);
xAxisGEnter
.append('text')
.attr('class', 'axis-label')
.attr('y', xAxisLabelOffset)
.merge(xAxisG.select('.axis-label'))
.attr('x', innerWidth / 2)
.text(xLabel);
const yAxisGEnter = gEnter.append('g').attr('class', 'y-axis');
const yAxisG = yAxisGEnter.merge(g.select('.y-axis'));
yAxisGEnter
.append('text')
.attr('class', 'axis-label')
.attr('y', yAxisLabelOffset)
.style('text-anchor', 'middle')
.merge(yAxisG.select('.axis-label'))
.attr('x', -innerHeight / 2)
.attr('transform', `rotate(-90)`)
.text(yLabel);
const colorLegendGEnter = gEnter.append('g').attr('class', 'legend');
const colorLegendG = colorLegendGEnter
.merge(g.select('.legend'))
.attr('transform', `translate(${innerWidth + colorLegendX},${colorLegendY})`);
colorLegendGEnter
.append('text')
.attr('class', 'legend-label')
.attr('x', colorLegendLabelX)
.attr('y', colorLegendLabelY)
.merge(colorLegendG.select('legend-label'))
.text(colorLabel);
xScale
.domain(d3.extent(data, xValue))
.range([0, innerWidth])
.nice();
yScale
.domain(d3.extent(data, yValue))
.range([innerHeight, 0])
.nice();
var prev_stroke_color = 'rgb(0, 0, 0)';
const circles = g.selectAll('.mark').data(data);
circles
.enter().append('circle')
.attr('class', 'mark')
.attr('fill-opacity', circleOpacity)
.attr('r', circleRadius)
.merge(circles)
.attr('cx', d => xScale(xValue(d)))
.attr('cy', d => yScale(yValue(d)))
.attr('fill', d => colorScale(colorValue(d)))
.on('mouseover', function (d) {
prev_stroke_color = d3.select(this).style('stroke');
var tMsg = '<div class="image-container">';
tMsg += `<img src='${d.logo_url}' width='100' />`;
tMsg += '</div>';
tMsg += '<div>';
tMsg += `<h2>${d.coin_name} (${d.symbol})</h2>`;
tMsg += `<h4>${d.display_desc}</h4>`;
tMsg += `<br/>Market cap: $${numeral(d.market_cap_usd).format()}`;
tMsg += `<br/>Website: ${d.website_url1}`;
tMsg += `<br/>${d.twitter_url}`;
tMsg += `<br/>Follower count: ${numeral(d.twitter_followers_count).format()}`;
tooltip.transition().style("opacity", 1);
tooltip.html(tMsg).style("left", (d3.event.pageX + 15) + "px").style("top", (d3.event.pageY - 75) + "px");
d3.select(this).style("stroke", "green");
d3.select(this).style("stroke-width", "4");
})
.on('mouseout', function (d) {
d3.select(this).style("stroke", prev_stroke_color);
d3.select(this).style("stroke-width", "1.5");
tooltip.style("opacity", 0);
})
.on("click", function (d) {
window.open(d.twitter_url, '_blank');
});
xAxisG.call(xAxis);
yAxisG.call(yAxis);
}
})();
// The main entry point, which uses the Scatter Plot component.
function main() {
const visualization = d3.select('#visualization');
const visualizationDiv = visualization.node();
const svg = visualization.append('svg');
const row = d => {
d.market_cap_usd = +d.market_cap_usd;
d.reddit_subscriber_count = +d.reddit_subscriber_count;
d.twitter_followers_count = +d.twitter_followers_count;
return d;
};
d3.csv('crypto_scatter_v11.csv', row, data => {
// Render the scatter plot with updated width and height.
const render = () => {
ScatterPlot(svg, {
data,
width: visualizationDiv.clientWidth,
height: visualizationDiv.clientHeight,
xValue: d => d.twitter_followers_count,
xLabel: 'Twitter Followers Count',
yValue: d => d.market_cap_usd,
yLabel: 'Market Capitalization (USD)',
colorValue: d => d.symbol,
circleOpacity: defaults.circleOpacity,
circleRadius: defaults.circleRadius
});
}
// Draw for the first time to initialize.
render();
// Redraw based on the new size whenever the browser window is resized.
window.addEventListener('resize', render);
});
}
main();
</script>
</body>
</html>
https://d3js.org/d3.v4.min.js
https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.24.0/d3-legend.min.js
https://cdnjs.cloudflare.com/ajax/libs/numeral.js/2.0.6/numeral.min.js