数据可视化【五】 Scatter Plot

Scatter Plot

vizhub上实现的代码:

https://vizhub.com/Edward-Elric233/53807a1b35d94329b3689081cd2ea945

https://vizhub.com/Edward-Elric233/b9647d50899a4a0e8e917f913cd0a53a

https://vizhub.com/Edward-Elric233/8c6b50cd81a04f048f490f48e4fe6264

由前面的柱状图,我们对图形进行一定的修改就可以得到散点图:

在这里插入图片描述只要将绑定数据以后enter进行添加矩形的操作换成圆形就可以了,不过需要注意的是不能够y坐标再使用scaleBand了,而应该使用scalePoint,如果继续使用scaleBand的话需要调整圆的坐标(y坐标是Categorical的)。注意圆形的属性是cx,cy,r分别表示圆心的坐标和半径。

index.html

<!DOCTYPE html>
<html>

<head>
    <title>Scatter Plot</title>
    <link rel="stylesheet" href="./styles.css">
    <script src="https://unpkg.com/d3@5.7.0/dist/d3.min.js"></script>
    <!-- find D3 file on UNPKG d3.min.js-->
</head>

<body>
    <svg width="960" height="500"></svg>
    <script src="./index.js">
        // console.log(d3); test whether you have imported d3.js or not
    </script>

</body>

</html>

index.js

const svg = d3.select('svg');
// svg.style('background-color', 'red'); test
const width = +svg.attr('width');
const height = +svg.attr('height');


const render = data => {
    const xValue = d => d.population;
    const yValue = d => d.country;
    const margin = { top: 60, right: 20, bottom: 80, left: 150 };
    const innerWidth = width - margin.left - margin.right;
    const innerHeight = height - margin.top - margin.bottom;

    const xScale = d3.scaleLinear()
        .domain([0, d3.max(data, xValue)])
        .range([0, innerWidth])
        .nice(); //作用是如果值域的最大值不够整齐可以变得整齐


    // const yScale = scaleBand()
    const yScale = d3.scalePoint()
        .domain(data.map(yValue))
        .range([0, innerHeight])
        .padding(0.5);

    const xAxisTickFormat = number => d3.format('.3s')(number).replace('G', 'B');

    const yAxis = d3.axisLeft(yScale)
        .tickSize(-innerWidth);;
    const xAxis = d3.axisBottom(xScale)
        .tickFormat(xAxisTickFormat)
        .tickSize(-innerHeight); //设置tick-line的长度



    const g = svg.append('g')
        .attr('transform', `translate(${margin.left},${margin.top})`);

    //yAxis(g.append('g'));
    const yAxisG = g.append('g').call(yAxis).selectAll('.domain').remove();
    const xAxisG = g.append('g').call(xAxis)
        .attr('transform', `translate(0,${innerHeight})`);
    xAxisG.selectAll('.domain').remove();

    xAxisG.append('text')
        .attr('class', 'axis-label')
        .attr('y', 60)
        .attr('x', innerWidth / 2)
        .attr('fill', 'black')
        .text('populiation');

    let colorSet = ['#eb2617', '#ffaa00', '#4dff00', '#00fbff', '#bb00ff', '#eeff00'];

    const createGetColor = (idx) => {
        var i = idx || -1;
        return {
            get: () => { i = (i + 1) % colorSet.length; return colorSet[i]; }
        };
    };

    const getColor = createGetColor();

    g.selectAll('circle').data(data)
        .enter().append('circle')
        .attr('cy', d => yScale(yValue(d)))
        .attr('cx', d => xScale(xValue(d)))
        .attr('r', 15)
        .attr('fill', getColor.get);

    g.append('text')
        .attr('class', 'title')
        .attr('y', -20)
        .text('Top 10 Most Population Countries');
};

d3.csv("https://gist.githubusercontent.com/Edward-Elric233/23f3024c472ffd7e34e6a5ac04bad26c/raw/6ced2249ea6f5d12f72c1eb00b8c1278d2c86e95/every%2520countries'%2520population").then(data => {
    data.forEach(d => {
        d.population = +d.population * 1000;
    });
    render(data);
    // console.log(data);
});

styles.css

body {
    margin: 0px;
    overflow: hidden;
    font-family: manosapce;
}

text {
    font-family: sans-serif;
}

.tick text {
    font-size: 2em;
    fill: #8E8883
}

.axis-label {
    fill: #8E8883;
    font-size: 2.5em
}

.title {
    font-size: 3em;
    fill: #8E8883
}

虽然大概实现了散点图,但是上面的数据不适合用散点图来进行表示。因此我们不妨更换数据,使用更适合的数据。

在这里插入图片描述这里因为y坐标也是Quantitative的,所以应该使用scaleLinear。画的时候注意坐标的方向,如果方向不对应的画可以调整scaleLineardomain或者range(反向即可)。这里因为圆形比较密集就设置了一下圆形的透明度opacity,看起来比较好看。

index.html

<!DOCTYPE html>
<html>

<head>
    <title>Cars Scatter Plot</title>
    <link rel="stylesheet" href="./styles.css">
    <script src="https://unpkg.com/d3@5.7.0/dist/d3.min.js"></script>
    <!-- find D3 file on UNPKG d3.min.js-->
</head>

<body>
    <svg width="960" height="500"></svg>
    <script src="./index.js">
        // console.log(d3); test whether you have imported d3.js or not
    </script>
</body>

</html>

index.js

const svg = d3.select('svg');
// svg.style('background-color', 'red'); test
const width = +svg.attr('width');
const height = +svg.attr('height');

//mpg	cylinders	displacement	horsepower	weight	acceleration	year	origin	name


const render = data => {
    const title = 'Cars: Mpg vs. Horsepower';
    const xValue = d => d.mpg;
    const xAxisLabel = 'Mpg';
    const yValue = d => d.horsepower;
    const yAxisLabel = 'Horsepower';
    const margin = { top: 60, right: 20, bottom: 80, left: 100 };
    const innerWidth = width - margin.left - margin.right;
    const innerHeight = height - margin.top - margin.bottom;
    const circleRadius = 10;

    const xScale = d3.scaleLinear()
        //.domain([min(data, xValue), max(data, xValue)])	//和下面的写法等价
        .domain(d3.extent(data, xValue))
        .range([0, innerWidth])
        .nice(); //作用是如果值域的最大值不够整齐可以变得整齐


    // const yScale = scaleBand()
    const yScale = d3.scaleLinear()
        .domain([d3.max(data, yValue), d3.min(data, yValue)])
        .range([0, innerHeight])
        .nice();

    //const xAxisTickFormat = number => format('.3s')(number).replace('G','B');

    const yAxis = d3.axisLeft(yScale)
        .tickSize(-innerWidth)
        .tickPadding(15);
    const xAxis = d3.axisBottom(xScale)
        //.tickFormat(xAxisTickFormat)
        .tickSize(-innerHeight) //设置tick-line的长度
        .tickPadding(15); //通过设置Padding让x轴的数字离远一点



    const g = svg.append('g')
        .attr('transform', `translate(${margin.left},${margin.top})`);

    //yAxis(g.append('g'));
    const yAxisG = g.append('g').call(yAxis);
    yAxisG.selectAll('.domain').remove();

    yAxisG.append('text')
        .attr('class', 'axis-label')
        .attr('y', -70)
        .attr('x', -innerHeight / 2)
        .attr('fill', 'black')
        .attr('transform', `rotate(-90)`)
        .attr('text-anchor', 'middle') //设置锚点在中心
        .text(yAxisLabel);

    const xAxisG = g.append('g').call(xAxis)
        .attr('transform', `translate(0,${innerHeight})`);
    xAxisG.selectAll('.domain').remove();

    xAxisG.append('text')
        .attr('class', 'axis-label')
        .attr('y', 60)
        .attr('x', innerWidth / 2)
        .attr('fill', 'black')
        .text(xAxisLabel);

    let colorSet = ['#eb2617', '#ffaa00', '#4dff00', '#00fbff', '#bb00ff', '#eeff00'];

    const createGetColor = (idx) => {
        var i = idx || -1;
        return {
            get: () => { i = (i + 1) % colorSet.length; return colorSet[i]; }
        };
    };

    const getColor = createGetColor();

    g.selectAll('circle').data(data)
        .enter().append('circle')
        .attr('cy', d => yScale(yValue(d)))
        .attr('cx', d => xScale(xValue(d)))
        .attr('r', circleRadius)
        .attr('fill', getColor.get);

    g.append('text')
        .attr('class', 'title')
        .attr('y', -20)
        .attr('x', innerWidth / 2)
        .attr('text-anchor', 'middle')
        .text(title);
};

d3.csv('https://vizhub.com/curran/datasets/auto-mpg.csv').then(data => {
    data.forEach(d => {
        //得到的数据默认每个属性的值都是字符串,因此需要进行转换
        d.mpg = +d.mpg;
        d.cylinders = +d.cylinders;
        d.displacement = +d.displacement;
        d.horsepower = +d.horsepower;
        d.weight = +d.weight;
        d.acceleration = +d.acceleration;
        d.year = +d.year;
    });
    render(data);
    // console.log(data);
});

styles.css

body {
    margin: 0px;
    overflow:hidden;
    font-family: manosapce;
  }
  
  circle {
    opacity : 0.5;
  }
  
  
  text {
    
    font-family : sans-serif;
  }
  
  .tick text {
    font-size : 2em;
      fill : #8E8883
  }
  
  .tick line {
      stroke : #E5E2E0
  }
  
  .axis-label {
      fill : #8E8883;
    font-size: 2.5em
  }
  
  .title {
      font-size : 3em;
    fill : #8E8883
  }

对于时间轴的处理可以使用scaleTime
在这里插入图片描述
index.html

<!DOCTYPE html>
<html>

<head>
    <title>Temperature in San Francisc Scatter Plot</title>
    <link rel="stylesheet" href="./styles.css">
    <script src="https://unpkg.com/d3@5.7.0/dist/d3.min.js"></script>
    <!-- find D3 file on UNPKG d3.min.js-->
</head>

<body>
    <svg width="960" height="500"></svg>
    <script src="./index.js">
        // console.log(d3); test whether you have imported d3.js or not
    </script>

</body>

</html>

html.js

const svg = d3.select('svg');
// svg.style('background-color', 'red'); test
const width = +svg.attr('width');
const height = +svg.attr('height');

const render = data => {
    const title = 'A week in San Francisco';
    const xValue = d => d.timestamp;
    const xAxisLabel = 'Time';
    const yValue = d => d.temperature;
    const yAxisLabel = 'Temperature';
    const margin = { top: 60, right: 20, bottom: 80, left: 100 };
    const innerWidth = width - margin.left - margin.right;
    const innerHeight = height - margin.top - margin.bottom;
    const circleRadius = 6;

    const xScale = d3.scaleTime()
        //.domain([min(data, xValue), max(data, xValue)])	//和下面的写法等价
        .domain(d3.extent(data, xValue))
        .range([0, innerWidth])
        .nice(); //作用是如果值域的最大值不够整齐可以变得整齐


    // const yScale = scaleBand()
    const yScale = d3.scaleLinear()
        .domain([d3.max(data, yValue), d3.min(data, yValue)])
        .range([0, innerHeight])
        .nice();

    //const xAxisTickFormat = number => format('.3s')(number).replace('G','B');

    const yAxis = d3.axisLeft(yScale)
        .tickSize(-innerWidth)
        .tickPadding(15);
    const xAxis = d3.axisBottom(xScale)
        //.tickFormat(xAxisTickFormat)
        .tickSize(-innerHeight) //设置tick-line的长度
        .tickPadding(15); //通过设置Padding让x轴的数字离远一点



    const g = svg.append('g')
        .attr('transform', `translate(${margin.left},${margin.top})`);

    //yAxis(g.append('g'));
    const yAxisG = g.append('g').call(yAxis);
    yAxisG.selectAll('.domain').remove();

    yAxisG.append('text')
        .attr('class', 'axis-label')
        .attr('y', -70)
        .attr('x', -innerHeight / 2)
        .attr('fill', 'black')
        .attr('transform', `rotate(-90)`)
        .attr('text-anchor', 'middle') //设置锚点在中心
        .text(yAxisLabel);

    const xAxisG = g.append('g').call(xAxis)
        .attr('transform', `translate(0,${innerHeight})`);
    xAxisG.selectAll('.domain').remove();

    xAxisG.append('text')
        .attr('class', 'axis-label')
        .attr('y', 60)
        .attr('x', innerWidth / 2)
        .attr('fill', 'black')
        .text(xAxisLabel);

    let colorSet = ['#eb2617', '#ffaa00', '#4dff00', '#00fbff', '#bb00ff', '#eeff00'];

    const createGetColor = (idx) => {
        var i = idx || -1;
        return {
            get: () => { i = (i + 1) % colorSet.length; return colorSet[i]; }
        };
    };

    const getColor = createGetColor();

    g.selectAll('circle').data(data)
        .enter().append('circle')
        .attr('cy', d => yScale(yValue(d)))
        .attr('cx', d => xScale(xValue(d)))
        .attr('r', circleRadius)
        .attr('fill', 'red');

    g.append('text')
        .attr('class', 'title')
        .attr('y', -20)
        .attr('x', innerWidth / 2)
        .attr('text-anchor', 'middle')
        .text(title);
};

d3.csv('https://vizhub.com/curran/datasets/temperature-in-san-francisco.csv').then(data => {
    // console.log(data);
    data.forEach(d => {
        //得到的数据默认每个属性的值都是字符串,因此需要进行转换
        d.temperature = +d.temperature;
        d.timestamp = new Date(d.timestamp);
    });
    render(data);
});

styles.css

body {
    margin: 0px;
    overflow: hidden;
    font-family: manosapce;
}

circle {
    opacity: 0.5;
}

text {
    font-family: sans-serif;
}

.tick text {
    font-size: 2em;
    fill: #8E8883
}

.tick line {
    stroke: #E5E2E0
}

.axis-label {
    fill: #8E8883;
    font-size: 2.5em
}

.title {
    font-size: 3em;
    fill: #8E8883
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值