Skip to content

Instantly share code, notes, and snippets.

@vbernardes
Last active August 5, 2019 23:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vbernardes/896d0879221501c9123dde33f30da12e to your computer and use it in GitHub Desktop.
Save vbernardes/896d0879221501c9123dde33f30da12e to your computer and use it in GitHub Desktop.
v1.0 – Risk on Prosper Loans
license: gpl-3.0
height: 1045
<html>
<meta charset="UTF-8">
<head>
<!-- <script src="https://d3js.org/d3.v5.min.js"></script> -->
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="http://dimplejs.org/dist/dimple.v2.3.0.min.js"></script>
<link rel="stylesheet" type="text/css" href="vizstyle.css">
</head>
<body>
<div class="viz-title-container">
<div class="viz-title">
High Risks and Low Returns
</div>
<div class="viz-description">
<p>Prosper is a P2P lending platform that allows investors to choose among personal loans to invest in. They do that by considering a number of factors, which include a custom calculated <span style="font-weight: normal">Prosper Score</span> that represents the risk for each loan. The higher the score, the lower the risk, and the lower the interest rates paid by the borrower to the investors.</p>
<p>However, on average, loans with a Prosper Score of 2-4 (<i>higher risk expected</i>) had similar proportions of bad loans (defaulted loans, charged off loans or loans past due) as loans with a score of 6-8 (<i>lower risk expected</i>). In other words, investors who invested in loans with a score of 6-8 expected <i>lower risk</i> loans — and received <i>lower rates</i> in return — but ended up with risky loans just the same.</p>
</div>
</div>
<div id="chart1Container">
</div>
<div id="chart2Container">
</div>
<script type="text/javascript">
// Draw reference lines
var drawLinesBetweenBars = function (chartNum, firstBar, secondBar) {
// Arguments should all be integers
// Hide gridlines but keep gridline container so we can draw reference lines
var chart = d3.select("#chart"+chartNum+"Container")
chart.select(".dimple-gridline").selectAll(".tick").html("");
// Get y pixels for bars
var firstBar_y = parseInt(chart.select(".dimple-"+firstBar).attr("y"));
var secondBar_y = parseInt(chart.select(".dimple-"+secondBar).attr("y"));
// Draw lines
chart.select(".dimple-gridline").append("line")
.style("stroke","lightgrey").attr("x1",0).attr("x2",510)
.attr("y1",firstBar_y).attr("y2",firstBar_y).attr("stroke-dasharray", "5,5");
chart.select(".dimple-gridline").append("line")
.style("stroke","lightgrey").attr("x1",0).attr("x2",510)
.attr("y1",secondBar_y).attr("y2",secondBar_y).attr("stroke-dasharray", "5,5");
}
var drawAnnotationBetweenBars = function (chartNum, firstBar, secondBar, heightOfBar, text) {
var tickHeight = 7;
var chart = d3.select("#chart"+chartNum+"Container");
var annotationGroup = chart.select(".annotation-group");
// Set pixel values
var x1 = parseInt(chart.select(".dimple-"+firstBar).attr("x"));
var x2 = parseInt(chart.select(".dimple-"+secondBar).attr("x")) +
parseInt(chart.select(".dimple-"+secondBar).attr("width"));
var y = chart.select(".dimple-"+heightOfBar).attr("y") - 20;
// Draw lines
annotationGroup.append("line")
.style("stroke","black").attr("x1",x1).attr("x2",x2)
.attr("y1",y).attr("y2",y);
annotationGroup.append("line")
.style("stroke","black").attr("x1",x1).attr("x2",x1)
.attr("y1",y).attr("y2",y+tickHeight);
annotationGroup.append("line")
.style("stroke","black").attr("x1",x2).attr("x2",x2)
.attr("y1",y).attr("y2",y+tickHeight);
var halfway = (x1+x2)/2;
annotationGroup.append("line")
.style("stroke","black").attr("x1",halfway).attr("x2",halfway)
.attr("y1",y).attr("y2",y-tickHeight);
// Draw text
var txt = annotationGroup.append("text")
.classed("annotation", true)
.classed("current-annotation", true)
.style("font-family", "sans-serif")
.style("font-size", "14px")
.style("font-weight", "lighter")
.text(text);
var txtElem = document.getElementsByClassName("current-annotation");
var bbox = txtElem[0].getBBox();
txt.attr("x",halfway - bbox.width/2).attr("y",y - 14);
txt.classed("current-annotation", false)
}
var drawAnnotations = function () {
var annotationGroup = d3.selectAll("svg")
.select(".dimple-chart")
.append("g")
.attr("class", "annotation-group");
drawAnnotationBetweenBars(1, 2, 4, 2, "Higher Return");
drawAnnotationBetweenBars(1, 6, 8, 6, "Lower Return");
drawAnnotationBetweenBars(2, 2, 8, 5, "Similar Risk Level");
}
function draw(data) {
// Event handler functions
var onMouseOver = function (e) {
d3.selectAll('.dimple-'+e.xValue)
.style('fill', '#80B1D3')
.style('stroke', '#80B1D3')
}
var onMouseOut = function (e) {
d3.selectAll('.dimple-'+e.xValue)
.style('fill', 'lightgrey')
.style('stroke', 'lightgrey')
}
// Set chart limits
var chartContainerWidth = 600;
var chartContainerHeight = 400;
var chartBoundsX = "10%";
var chartBoundsY = "10%";
var chartBoundsWidth = "85%";
var chartBoundsHeight = "75%";
// Set up first chart
var svg1 = dimple.newSvg("#chart1Container", chartContainerWidth, chartContainerHeight);
var ratePerScoreChart = new dimple.chart(svg1, data);
ratePerScoreChart.setBounds(chartBoundsX,
chartBoundsY,
chartBoundsWidth,
chartBoundsHeight);
ratePerScoreChart.defaultColors = [
new dimple.color("lightgrey")
];
// Set up axes
var x1 = ratePerScoreChart.addCategoryAxis("x", "ProsperScore");
x1.title = "Prosper Score";
var y1 = ratePerScoreChart.addMeasureAxis("y", "MeanRatePerScore");
y1.title = "Mean Interest Rate";
y1.overrideMax = 0.35;
// Add data series
ratePerScoreSeries = ratePerScoreChart.addSeries("ProsperScore", dimple.plot.bar);
// Set event handlers
ratePerScoreSeries.addEventHandler("mouseover", onMouseOver);
ratePerScoreSeries.addEventHandler("mouseout", onMouseOut);
ratePerScoreChart.draw();
/****************************************************************************************/
// Set up second chart
var svg2 = dimple.newSvg("#chart2Container", chartContainerWidth, chartContainerHeight);
var ProportionBadPerScoreChart = new dimple.chart(svg2, data);
ProportionBadPerScoreChart.setBounds(chartBoundsX,
chartBoundsY,
chartBoundsWidth,
chartBoundsHeight);
ProportionBadPerScoreChart.defaultColors = [
new dimple.color("lightgrey")
];
// Set up axes
var x2 = ProportionBadPerScoreChart.addCategoryAxis("x", "ProsperScore");
x2.title = "Prosper Score";
var y2 = ProportionBadPerScoreChart.addMeasureAxis("y", "PropBadPerScore");
y2.title = "Proportion of Bad Loans";
y2.overrideMax = 0.35;
ProportionBadPerScoreSeries = ProportionBadPerScoreChart.addSeries("ProsperScore", dimple.plot.bar);
// Set event handlers
ProportionBadPerScoreSeries.addEventHandler("mouseover", onMouseOver);
ProportionBadPerScoreSeries.addEventHandler("mouseout", onMouseOut);
ProportionBadPerScoreChart.draw();
// Draw annotations on both charts
drawAnnotations();
// Hide all gridlines
d3.selectAll(".dimple-gridline").selectAll(".tick").html("");
}
</script>
<script type="text/javascript">
// Read data using d3 and pass it to the draw function
d3.csv("prosper_loans_export.csv", draw);
</script>
</body>
</html>
ProsperScore MeanRatePerScore PropBadPerScore
1 4 0.225381286224692 0.100277888050814
2 5 0.229148282890044 0.137980230306736
3 2 0.27124604578564 0.121227887617066
4 6 0.206216924580551 0.116061247760222
5 7 0.185063461356988 0.0956874587147306
6 3 0.24785846637006 0.0969641455116462
7 1 0.302066633064516 0.314516129032258
8 9 0.125149573144263 0.0651135870351613
9 8 0.151730482037667 0.0861196382643325
10 10 0.0979689894736842 0.0229473684210526
11 11 0.0932809752747253 0.00206043956043956
.viz-title-container {
width: 550px;
height: 195px;
padding: 3%;
}
.viz-title {
font-size: 24px;
font-family: sans-serif;
margin-bottom: 2%;
font-weight: lighter;
}
.viz-description {
font-size: 15px;
font-family: sans-serif;
font-weight: lighter;
}
.annotation {
font-size: 12px;
font-family: sans-serif;
font-weight: lighter;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment