[d3.js] 서울시 따릉이 대여소 위치 표현 (with QGIS)

Castle_Junny·2023년 4월 4일
0

d3.js랑 친해지기

목록 보기
2/4
post-thumbnail

0. 사전 지식

0.1 geojson

geojson은 지리 데이터를 json 형태로 encoding한 것이다. 여기엔 feature라는 json 객체들을 담고 있고, feature 객체는 지형의 경계를 coordinates 속성에 저장하고 지형에 대한 메타 데이터를 properties 속성에 저장한다.

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [102.0, 0.5]
      },
      "properties": {
        "prop0": "value0"
      }
    }
    
    ...

0.2 projection(투영법)

gis에서 투영법(projection)은 지구 상의 점을 평면에 렌더링 하는 과정을 의미한다.

이해하기 쉽게 설명하자면 지구는 곡면으로 이루어 져있기 때문에 지구상의 위도(Latitude)와 경도(longitude) 좌표를 그대로 사용할 경우 거리와 방향 등의 정보를 정확하게 표현하기 어렵다.

이래르 해결하기 위해 위 경도 좌표를 평면에 투영(projection)하여 좌표를 변환하고 이를 이용하여 지리 정보를 정확히 표현할 수 있다.

1. 데이터 준비

1.1 서울시 geojson

  1. 서울시 공강정보 다운
  2. qgis 다운

서울시 지리 데이터를 만들기 위헤 shp 파일QGIS를 이용해 geojson 파일로 convert 하였다.

  • QGIS 에서 shp 파일 열기

  • 한글 깨짐 방지

  • 한글 잘나오는지 확인

  • geojson으로 export

1.2 따릉이 대여소 위치 데이터

  1. 서울시 열린데이터 광장에 있는 공공 데이터를 다운로드
    22년 12월 기준 공공 자전거 대여소 정보 csv 파일 (링크)

  2. csv 파일을 엑셀에서 열어서 json형태로 바꿀 수 있게 컬럼 정리

  3. csv to json converter 사이트에서 변환 (링크)

2. d3를 이용해 그려보기

작업순서
1. 도화지를 준비한다.(svg)
2. 도화지 위에 서울시 지도를 올린다(서울시 svg)
3. 서울시 지도 위에 시군구를 표현한다.
4. 따릉이 대여소 위치도 표현한다.
5. 클릭(click) 이벤트도 추가해본다.

2.0 도화지 준비(svg)

<style>
        .OUTLINE {
            stroke-linejoin: round;
            stroke: #ffffff;
            stroke-width: 1;
        }

</style>
<body>
	<div id="main" style="width: 100%; height: 100vh"></div>
</body>
    const svg = d3.select('#main')
        .append('svg').attr('id', 'maps')
        .style("width", "100%")
        .style("height", "100%")
        .style("position", "absolute")
        .style("background-color", "rgb(164, 204, 239)");

    const width = document.getElementById('maps').clientWidth;
    const height = document.getElementById('maps').clientHeight;

    /* 랜덤 색상 얻기 */
    const getColor = () => '#' + Math.round(Math.random() * 0xffffff).toString(16)

2.1 서울시 표현

지리데이터를 활용하기 위해서는 투영법(projection)을 이용하여 곡면의 세계평면의 세계로 변환해주어야 한다.

여기선 웹 지도에서 가장 많이 사용되는 메르카토르(Mercator)도법을 사용했다. 구글 맵에서도 이 도법을 사용하므로 사실상 표준이다.

d3 에서 projection()을 사용하려면 library를 추가해주어야 한다.

geopath는 선택한 도법에 기초해 지리 데이터를 화면에 그린다.

  • projection 및 geopath 작성
    // 투영법 (projection) 설정
    const projection = d3.geoMercator()	
 	   // 서울시 중심 위경도
        .center([126.9717937, 37.5518911]) 
        .scale(100000)
        .translate([width / 2, height / 2]);

    const geoPath = d3.geoPath().projection(projection);
  • geojson 데이터 불러오기
// 서울시 지리 데이터 load
d3.json('./data/geoData/seoul.geojson').then((data) => {
        d3.select('#maps')
            .selectAll('path')
            .data(data.features)
            .enter()
            .append('path')
            .attr('fill', '#FAFAFA') 
            .attr('d', geoPath)
            .attr('class', 'OUTLINE') 
            .style("stroke", "#EAEAEA")
    })
  • 서울시 지리 표현

2.2 따릉이 대여소 위치 표현

csv 파일을 json 파일로 변경하였는데, 사용자의 입맛에 맞게 데이터를 가공을 하여 사용하였다. (사실 별로 가공안함)
(json안에 대여소 위경도 데이터 포함도어 있음)

2.2.1 모든 따릉이 대여소를 원(circle)으로 표현

  • (코드) 모든 따릉이 대여소를 원(circle)으로 표현하기
    새로 생성한 svg(#cycle_loca) 내부에 <g> 요소를 생성 후 <circle>요소를 그려준다.
    이때, 대여소 위경도 또한 projection으로 변형해야한다.

    function showAllLocation(data) {
     
           const cycle_svg = d3.select('#main')
               .insert('svg', '#cycle_loca_summary')
               .attr('id', 'cycle_loca')
               .attr('width', '100%')
               .attr('height', '100%')
               .style("position", "absolute")
    
           const cycle_loca = cycle_svg.selectAll('g')
               .data(data)
               .enter()
               .append('g')
    
           cycle_loca.append('circle')
               .attr('fill', d => getColor())
               .attr('r', 1)
               .attr('cx', d => projection([d.lng, d.lat])[0])
               .attr('cy', d => projection([d.lng, d.lat])[1])
       }```
    
  • (결과) 모든 따릉이 대여소을 원(circle)으로 표현하기

2.2.2 서울시 구별 따릉이 수량 표현

  • (코드) 서울시 구별 따릉이 수량 표현
    json파일을 이용해서 구별로 대여소 수를 합산하고 진행하였다.
    <g> 안에 <circle>, <text> 요소 추가해주고 텍스트 위치를 하드코딩으로 조절 하였다.
   function showLocaSummary(data) {
        const cycle_svg = d3.select('#main')
            .append('svg')
            .attr('id', 'cycle_loca_summary')
            .attr('width', '100%')
            .attr('height', '100%')
            .style("position", "absolute")

        const cycle_loca = cycle_svg.selectAll('g')
            .data(data)
            .enter()
            .append('g')

        cycle_loca.append('circle')
            .attr('fill', d => getColor())
            .attr('r', 6)
            .attr('cx', d => projection([d.lng, d.lat])[0])
            .attr('cy', d => projection([d.lng, d.lat])[1])
     // 바로여기에 click 이벤트 추가 될거임 

        cycle_loca.append('text')
            .text(d => `${d.sgg} : ${d.qty}`)
            .attr('x', d => projection([d.lng, d.lat])[0] - 12)
            .attr('y', d => projection([d.lng, d.lat])[1] - 10)
            .style('font-size', '10px')
    }

  • (결과) 서울시 구별 따릉이 수량 표현

3. click event

기능을 추가해서 특정 구를 click해당 구의 대여소 수를 알려주는 alert을 띄우고 해당 구모든 대여소를 띄워보자

  • click event 추가
    위에 주석에 적어 둔 곳에 click이벤트 추가
	.on("click", d => {
	  alert(`${d.sgg}에는 따릉이 대여소가 ${d.qty}개 있습니다.`)
      // 선택한 대여소 표현 function
	  showSelectedLoca(d.sgg)
});
  • 선택한 구의 대여소에 대한 데이터 가공
    선택한 구의 데이터만 filtering 후 전달
    function showSelectedLoca(sgg) {
        const selectedData = cycleData.filter(e => e.sgg === sgg);
        showAllLocation(selectedData);
    }
  • svg 추가 시 insert() 사용이유
    showSelectedLoca() 함수를 보면 insert()를 하는게 있다. 여기서 insert()를 하지 않고 append()를 할 경우

  • 2.2.2 서울시 구별 따릉이 수량 표현위에 2.2.1 모든 따릉이 대여소를 원(circle)으로 표현가 올라가기 때문에 클릭이 안된다.

  • append로 element를 뒤에 잇는게 아니라 A와 B사이insert() 해줘야 한다.

  • insert('이거 추가해줘', '여기 뒤에') 이렇게 사용..ㅋㅋ

        const cycle_svg = d3.select('#main')
            .insert('svg', '#cycle_loca_summary')

4. 결론 (전체코드)

공공데이터를 활용하면 좀 더 재밌는 데이터로 재밌는 시각화 화면을 만들 수 있을 거 같다. d3, gis 하나씩 배워갈 수록 재밌는거 같다..!

0개의 댓글