Last active
August 5, 2019 23:08
-
-
Save vbernardes/896d0879221501c9123dde33f30da12e to your computer and use it in GitHub Desktop.
v1.0 – Risk on Prosper Loans
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: gpl-3.0 | |
height: 1045 |
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> | |
<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> |
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
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 |
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
.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