si619 lab4 notes - yuanlii/data-visualization-d3 GitHub Wiki

Running a Python Server

For security reasons, browsers don't allow loading external files such as our data.csv. There are a few different ways to fix this, one of which is to set up a local server.

  • On the mac, open terminal and navigate to the "inclass" folder. Then execute on of the above commands depending on your python version. InthePowerShellwindow,type:
python -m SimpleHTTPServer 8000

OR

python3 -m http.server
  • In Google Chrome, type: localhost:8000 in your browser address bar and hit enter.

Create a bar chart and small multiple bar charts

scale functions: D3 offers several useful functions that do the calculations for us. These are broadly called scale functions.

scale types: D3 offers the following types of scale types:

  • Scales with continuous input and continuous outputs (e.g., scaleLinear, scaleTime)
  • Scales with continuous input and discrete outputs (e.g., scaleQuantile )
  • Scales with discrete input and discrete outputs (e.g., scaleOrdnial, scaleBand)

forEach(): 方法对数组的每个元素执行一次提供的函数。

var array1 = ['a', 'b', 'c'];

array1.forEach(function(element) {
  console.log(element);
});

// expected output: "a"
// expected output: "b"
// expected output: "c"

The parseInt(): The parseInt() function parses a string argument and returns an integer of the specified e.g.,

console.log("take a look at data", d3.max(data, function (d) { return parseInt(d.n); }));

complete codes for draw.js:

var data = []; // the variable that holds the data from csv file
var category_colors = {
    "clothing, beauty, & fashion": "#5B7BE9",
    "computers & internet": "#E0D22E",
    "education": "#2CCEF6",
    "food & drink": "#FB7F23",
    "grab bag": "#D63CA3",
    "health & fitness": "#c38014",
    "home & garden": "#E24062",
    "human relations": "#5BB923",
    "law & government": "#555",
    "media & arts": "#B190D0",
    "pets & animals": "#bcc832",
    "religion & philosophy": "#ee7b9c",
    "science & nature": "#f299b3",
    "shopping": "#01d99f",
    "society & culture": "#177d62",
    "sports, hobbies, & recreation": "#a16c2f",
    "technology": "#a2262a",
    "travel & transportation": "#f29a76",
    "work & money": "#88a8b9",
    "writing & language": "#a46067"
}; // JSON object with colors assigned to each category.

$(document).ready(function () {
    
    loadData();

});


function loadData() {
    //code for Q1 goes here
    d3.csv("data/data.csv", function (d) {
        data = d; 
        visualizeBarChart(groupDataByYear());

        // plot the second chart
        visualizeSmallMultipleBarChart(groupDataByCategory())

        data.forEach(function (item) {
                item.n = parseInt(item.n);
            });
        }
    );
}

function groupDataByCategory() {
     //code for Q2 goes here
     var groupedData = d3.nest()
     .key(function (d) { return d.category })
     .entries(data); return groupedData;
}

function groupDataByYear() {
    //code for Q3 goes here
    var groupedData = d3.nest()
        .key(function (d) { return d.year })
        .rollup(function (v) { return d3.mean(v, function (d) {
            return d.n; }) })
        .entries(data);
     
    return groupedData;
}


function visualizeBarChart(dataitems) {
    // code for Q4 goes here
    var margin = { top: 20, right: 20, bottom: 30, left: 60 }, 
        width = 940 - margin.left - margin.right,
        height = 500 - margin.top - margin.bottom;
    
    var x = d3.scaleBand()
        .domain(dataitems.map(function (d) { return d.key; })) 
        .range([0, width])
        .padding(0.1);

    var y = d3.scaleLinear()
        .domain([0, d3.max(dataitems, function (d) { return d.value; })]) 
        .range([height, 0]);
    
    var svg = d3.select("#chart1").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g")
        .attr("transform",
        "translate(" + margin.left + "," + margin.top + ")");
    
    svg.selectAll(".bar")
        .data(dataitems)
        .enter().append("rect")
        .attr("class", "bar")
        .attr("fill", "#E0D22E")
        .attr("x", function (d) { return x(d.key); }) .attr("width", x.bandwidth())
        .attr("y", function (d) { return y(d.value); }) .attr("height", function (d) { return height - y(d.value); });
    
    // add the x Axis
    svg.append("g")
        .attr("transform", "translate(0," + height + ")") .call(d3.axisBottom(x));
    
    // add the y Axis
    svg.append("g")
        .call(d3.axisLeft(y));

}

 
function visualizeSmallMultipleBarChart(dataitems) {

       // code for Q12 goes here
        var margin = { top: 0, right: 10, bottom: 40, left: 40 }, 
            width = 280 - margin.left - margin.right,
            height = 150 - margin.top - margin.bottom;

        var x = d3.scaleBand()
            .domain(dataitems[0].values.map(function (d) { return d.year; })) 
            .range([0, width])
            .padding(0.1);
        
        console.log(data)
        let maximam = 0;
        data.forEach((d) => {
            let number = parseInt(d.n);
            console.log("now:", d.n);
            if (number > maximam) {
                maximam = number;
            }
        })
        console.log(`Our own maxima ${maximam}`);
        console.log("take a look at data", d3.max(data, function (d) { return parseInt(d.n); }));
        
        
        var y = d3.scaleLinear()
            .domain([0, d3.max(data, function (d) { return parseInt(d.n); })])  
            .range([height, 0]);
        
        dataitems.forEach(function (v, i) {
            var div = d3.select("#chart2").append("div")
                .attr("id", "holder" + v.key)
                .attr("class", "chartholder");
            
            div.append("h6").html(v.key);

            var svg = div.append("svg")
                .attr("class", "categoryBar")
                .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g")
                .attr("transform", "translate(" + margin.left + "," +
                margin.top + ")");
            
            svg.selectAll(".bar")
                .data(v.values)
                .enter().append("rect")
                .attr("class", "bar")
                .attr("fill", function (d) { return category_colors[v.key] })
                .attr("x", function (d) { return x(d.year); }) 
                .attr("width", x.bandwidth())
                .attr("y", function (d) { return y(d.n); }) 
                .attr("height", function (d) { return height - y(d.n); });
            
            // add the y Axis
            svg.append("g")
                .call(d3.axisLeft(y).ticks(5));
            

            svg.append("g")
                .attr("transform", "translate(0," + height + ")") 
                .call(d3.axisBottom(x))
                .selectAll("text")
                .style("text-anchor", "end")
                .attr("dx", "-.8em")
                .attr("dy", ".15em")
                .attr("transform", "rotate(-65)");
            
            });
	   	   
}

complete codes for index.html:

<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>SI 649 Lab 4</title>
    <link rel="stylesheet" href="css/skeleton.css" />
    <link rel="stylesheet" href="css/normalize.css" />
    <link rel="stylesheet" href="css/style.css" />
</head>
<body>
    <script src="https://code.jquery.com/jquery-3.1.1.min.js"
            integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
            crossorigin="anonymous"></script>
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <script type="text/javascript" src="js/draw.js"></script>
    <div class="container">
        <div class="row">
            <div class="twelve columns alpha" style="border-bottom:2px solid #494949;margin-bottom:30px;">
                <h1>SI-649 Lab 4</h1>
            </div>
        </div>
        <div class="row">
            <div class="twelve columns alpha">
                <h5>Draw a bar chart showing number of questions by year:</h5>
            </div>
        </div>
        <div class="row">
            <div class="twelve columns question alpha" id="chart1">
            </div>
        </div>
        <div class="row">
            <div class="twelve columns alpha">
                <h5>Draw a small-multiple bar chart by category:</h5>
            </div>
        </div>
        <div class="row">
            <div class="twelve columns question alpha" id="chart2">
            </div>
        </div>
</body>
</html>

snippet of data.csv:

year,category,n
2004,"clothing, beauty, & fashion",141
2004,computers & internet,2489
2004,education,151
2004,food & drink,275
2004,grab bag,285
2004,health & fitness,379
...

final result: img

Debugging Processes: Need to adjust the scale of the y-axis accordingly; remember to user parseInt().

var y = d3.scaleLinear()
            .domain([0, d3.max(data, function (d) { return parseInt(d.n); })])  
            .range([height, 0]);

If not sure where is the problem, constantly use console.log() to print out the results and debug.

⚠️ **GitHub.com Fallback** ⚠️