Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Here is the modified code with annotations to highlight the outliers:
- ```html
- <!doctype html>
- <meta charset="utf-8" />
- <html>
- <head>
- <script src="https://d3js.org/d3.v6.min.js" charset="utf-8"></script>
- <script src="https://rawgit.com/susielu/d3-annotation/master/d3-annotation.min.js"></script>
- </head>
- <style>
- * {
- font-family: sans-serif;
- }
- #tooltip {
- visibility: hidden;
- position: absolute;
- opacity: 0.8;
- padding: 10px;
- vertical-align: middle;
- border-radius: 5px;
- background-color: #ecf0f1;
- font-size: 14px;
- }
- .textbox {
- font-size: 14px;
- }
- #legend {
- opacity: 0.2;
- fill: #2c3e50;
- }
- #title {
- text-anchor: middle;
- font-size: 22px;
- }
- .label {
- text-anchor: middle;
- }
- #svg {
- background-color: white;
- }
- .annotation {
- fill: #c86984;
- stroke: #c86984;
- }
- </style>
- <body>
- <div id="container" align="center"></div>
- <script type="text/javascript">
- var url =
- "https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/cyclist-data.json";
- var colors = ["#27ae60", "#8e44ad"];
- var legendKeys = ["No Doping Allegations", "Doping Allegations"];
- const tooltip = d3
- .select("body")
- .append("div")
- .attr("id", "tooltip")
- .style("visibility", "hidden");
- d3.json(url).then(function (data) {
- var width = 700;
- var height = 500;
- var margin = { left: 90, top: 80, bottom: 50, right: 20 };
- var axisOffset = 10;
- const svg = d3
- .select("#container")
- .append("svg")
- .attr("id", "svg")
- .attr("width", width)
- .attr("height", height);
- var xMin = d3.min(data, (d) => d["Year"]);
- var xMax = d3.max(data, (d) => d["Year"]);
- var parseTime = d3.timeParse("%M:%S");
- var yMin = d3.min(data, (d) => parseTime(d["Time"]));
- var yMax = d3.max(data, (d) => parseTime(d["Time"]));
- var xScale = d3
- .scaleLinear()
- .domain([xMin, xMax])
- .range([margin.left + axisOffset, width - margin.right]);
- var yScale = d3
- .scaleTime()
- .domain([yMax, yMin])
- .range([height - margin.bottom - axisOffset, margin.top]);
- var xAxis = d3.axisBottom().scale(xScale).tickFormat(d3.format("d"));
- var yAxis = d3
- .axisLeft()
- .scale(yScale)
- .tickFormat(d3.timeFormat("%M:%S"));
- svg
- .append("g")
- .attr("transform", "translate(0, " + (height - margin.bottom) + ")")
- .attr("id", "x-axis")
- .call(xAxis);
- svg
- .append("g")
- .attr("transform", "translate(" + margin.left + ", 0)")
- .attr("id", "y-axis")
- .call(yAxis);
- svg
- .selectAll("scatterPoints")
- .data(data)
- .enter()
- .append("circle")
- .attr("cx", (d) => xScale(d["Year"]))
- .attr("cy", (d) => yScale(parseTime(d["Time"])))
- .attr("r", 5)
- .attr("fill", (d) => (d["Doping"] == "" ? colors[0] : colors[1]))
- .attr("class", "dot")
- .attr("data-xvalue", (d) => d["Year"])
- .attr("data-yvalue", (d) => parseTime(d["Time"]))
- .on("mouseover", function (d) {
- info = d["originalTarget"]["__data__"];
- tooltip
- .style("visibility", "visible")
- .style("left", event.pageX + 10 + "px")
- .style("top", event.pageY - 80 + "px")
- .attr("data-year", info["Year"])
- .html(
- info["Name"] +
- " (" +
- info["Year"] +
- ") <br> Time: " +
- info["Time"] +
- "<br><br>" +
- info["Doping"]
- );
- })
- .on("mousemove", function () {
- tooltip.style("left", event.pageX + 10 + "px");
- })
- .on("mouseout", function () {
- tooltip.style("visibility", "hidden");
- });
- svg
- .append("text")
- .attr("x", margin.left + (width - margin.left - margin.right) / 2)
- .attr("y", height - margin.bottom / 5)
- .attr("class", "label")
- .text("Year");
- svg
- .append("text")
- .attr("y", margin.left / 4)
- .attr("x", -height / 2)
- .attr("transform", "rotate(-90)")
- .attr("class", "label")
- .text("Time to finish");
- svg
- .append("text")
- .attr("x", margin.left + (width - margin.left - margin.right) / 2)
- .attr("y", margin.top / 2.6)
- .attr("id", "title")
- .text("Doping in professional bike racing");
- svg
- .append("text")
- .attr("x", margin.left + (width - margin.left - margin.right) / 2)
- .attr("y", margin.top / 1.4)
- .text("35 fastest times to finish Alpe d'Huez")
- .style("font-size", "16px")
- .style("text-anchor", "middle");
- svg
- .selectAll("legendSymbols")
- .data(legendKeys)
- .enter()
- .append("circle")
- .attr("cx", width - margin.right - 200)
- .attr("cy", (d, i) => 150 + i * 25)
- .attr("r", 5)
- .attr("fill", (d, i) => colors[i]);
- svg
- .selectAll("legendTexts")
- .data(legendKeys)
- .enter()
- .append("text")
- .text((d) => d)
- .attr("x", width - margin.right - 200 + 15)
- .attr("y", (d, i) => 150 + i * 25 + 5)
- .attr("class", "textbox");
- const legend = svg
- .append("rect")
- .attr("x", width - margin.right - 200 - 15)
- .attr("y", 150 - 5 - 10)
- .attr("rx", 5)
- .attr("ry", 5)
- .attr("width", 195)
- .attr("height", 55)
- .attr("id", "legend");
- // Annotations
- const outliers = data.filter(d => parseTime(d["Time"]) < parseTime("38:00"));
- const annotations = outliers.map(d => ({
- note: { label: d["Name"] + " (" + d["Year"] + ")" },
- x: xScale(d["Year"]),
- y: yScale(parseTime(d["Time"])),
- dx: 50,
- dy: -30
- }));
- const makeAnnotations = d3.annotation()
- .annotations(annotations)
- .type(d3.annotationLabel);
- svg.append("g")
- .attr("class", "annotation-group")
- .call(makeAnnotations);
- });
- </script>
- </body>
- </html>
- ```
- This code adds annotations to the scatter plot to highlight the outliers. The outliers are defined as the cyclists who finished the race in less than 38 minutes. The annotations are created using the d3-annotation library. Each annotation consists of a label with the cyclist's name and year, and an arrow pointing to the corresponding data point on the scatter plot. The annotations are styled with a fill and stroke color of #c86984.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement