ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Django] 장고에서 차트그리기
    django study 2020. 12. 19. 18:22

     

     

    장고 웹에 차트를 그려보았다. Highchart를 사용하였으며 (개인사용은 무료, 상업적사용은 유료) 적용방식은 여러 다른 차트들도 유사하리라 본다. 장고 View에서 템플릿으로 데이터를 보내는 다양한 방법이 있다. 여기서는 템플릿(Front-End)에서 특정 API주소에 접근(GET)하여 데이터를 가져오는 방식으로 rest-framwork와 ajax를 사용하였다. ajax에 대해서는 추후 정리해보겠다.

     

    <작업순서>

    1. DB Model 작성 및 데이터 수집 (생략)

    2. View 함수 작성

    3. URL CONF 작성

    4. Templete 작성


    <예시1>

    기본적인 line차트를 그리는 방법이다. 

     

    (1) View 함수 작성

    view.py에 import와 view함수를 추가한다.

    - ResultAPIView는 request의 session에 저장해둔 데이터 가져와 보내는 역할이다. 데이터는 리스트 형태이다.

    view간 데이터를 공유하기 위해 전역변수대신 세션, 쿠키, 캐쉬를 이용할수있다. 이들에 대해서는 별도로 정리할예정이다.  또는 ORM으로 DB의 테이블내용을 가져와서 사용할수있다. (예시2에 설명)

    - result_detail함수는 chart 페이지를 보여주는 역할이다.

     

    from rest_framework.response import Response
    from rest_framework.views import APIView
    from django.views.generic import View
    from django.shortcuts import render
    
    class ResultAPIView(APIView):
        
        authentication_classes = []
        permission_classes = []
    
        def get(self, request): 
            data = request.session.get('result')
            return Response(data)
    
    def result_detail(request):
    
        context = {}
        return render(request, 'chartapp/chart.html', context )

     

    (2) URF CONF 추가

    chartapp내의 url.py 를 작성한다.

     

       path('api/result/', views.ResultAPIView.as_view(), name="result_api"),
       path('result/', views.result_detail, name='result_detail'),

     

    (3) 템플릿 작성

    chart.html 를 작성한다. 

    ajax를 사용하여 url에 get으로 접근하여 data를 받은다음 chart를 렌더링하는 function을 실행한다.

     

       <div id="container">
        
        <script src="https://code.highcharts.com/highcharts.src.js"></script>
        <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
        <script>
    
        $.ajax({
            url: "{% url 'chartapp:result_api' %}",
            dataType: 'json',
            success: function (data) {
    
                Highcharts.chart('container', {
    
                    title: {
                        text: 'Chart drawing'
                        },
                    series: [{
                        name: "line name",
                        data: data
                        }],
    
                    responsive: {
                        rules: [{
                            condition: {
                                maxWidth: 500
                            },
                            chartOptions: {
                                legend: {
                                    layout: 'horizontal',
                                    align: 'center',
                                    verticalAlign: 'bottom'
                                }
                            }
                        }]
                    }
    
                });
            }
        });
    
        </script>
        </div>

     

    (5) 데이터 및 차트 확인

    여기서는 x값을 제외한 y값만을 데이터로 보냈다. [y1,y2,y3....yn], x축은 자동으로 index값이 된다.

    x축을 함께 표현하려면 [[x1,y1],[x2,y2],....[xt,yt]] 와 같이 보내면 된다.

    - 주소 chartapp/api/result/에 접근하면 첫번째와 같이 웹페이지가 표시된다.

    - 주소 chartapp/result/ 에는 두번째와 같이 차트가 표시된다. 

     

    rest-framework를 사용하여 데이터를 깔끔하게 볼수있다.

     

    짜잔

     


     

    <예시2>

    주가(시계열데이터) 차트 그리기

     

    (1) DB 모델과 데이터 수집

    model.py의 모델과 DB에 수집된 데이터는 다음과 같다.

     

    class KospiPredict(models.Model):
        date = models.DateField("날짜", max_length=10, null=False, unique=True)
        close = models.FloatField("종가", null=True)
        open = models.FloatField("시가", null=True)

    데이터베이스내 테이블내용이다.

     

    (2) View 함수 작성

    view.py에 import와 class형 view를 추가한다.

     

    첫번째로 KospiPredictAPIView는 DB에서 데이터를 가져와 json형태로 보내주는 역할을 한다. rest-framework의 APIView클래스를 이용하였기 때문에 웹페이지에서 해당 데이터를 확인할 수 있다. 자세하게는 DB에서 해당테이블의 레코드를 date순으로 가져온 다음 (원하는 형태로 가공) 딕셔너리형의 data변수로 저장하고 Response() 로 return 한다.  여기서 주의할점은 날짜(date)인데 2010-12-11이라는 datetime형태가 아닌 utc형(1540000231)으로 변환해주어야 나중에 highstock에서 제대로 된 시간축(x축)을 만들수있다. 또한 보내주는 데이터형식은 [[x1,y1],[x2,y2],....[xt,yt]]와 같아야 하고 2개이상의 line chart를 그리기 위해서 최종적으로 { close: [[x1,y1]...[xt,yt]] , open: [[x1,y1]...[xt,yt]] } 와 같은 형식이 된다.

     

    두번째로 ChartView는 해당url에 접속했을때 단순히 chart.html을 렌더링하는 기능으로 아래 함수와 동일하다.

    def chartview (request): 

        return render(request, 'nameapp/chart.html')

     

    from nameapp.models import KospiPredict
    from rest_framework.response import Response
    from rest_framework.views import APIView
    from django.views.generic import View
    from django.shortcuts import render
    
    from time import mktime, strptime
    
    class KospiPredictAPIView(APIView):
    
        authentication_classes = []
        permission_classes = []
    
        def get(self, request):
            stocks = KospiPredict.objects.all().order_by('date')
    
            close_list = []
            open_list = []
            for stock in stocks:
                time_tuple = strptime(str(stock.date), '%Y-%m-%d')  
                utc_now = mktime(time_tuple) * 1000           
                close_list.append([utc_now, stock.close])
                open_list.append([utc_now, stock.open])
    
            data = {
                'close': close_list,
                'open': open_list
            }
    
            return Response(data)
    
    class ChartView(View):
        def get(self, request, *args, **kwargs):
            return render(request, 'nameapp/chart.html')

     

    (3) URF CONF 작성

    url.py에 다음과 같이 추가한다.

     

    path('api/predict/', views.KospiPredictAPIView.as_view(), name="predict_kospi_api"),
    path('chart', views.ChartView.as_view(), name="chart"),

     

    (4) Templete 작성

    chart.html 을 작성한다. <body></body> 사이의 원하는 위치에 추가한다.

    여기서는 highchart 에서 주가차트에 특화된 highstock을 이용하였다.

    다른 차트를 이용하고 싶다면 https://www.highcharts.com/demo 의 예제를 살펴보자.

     

    <div id="container">
     
      <script src="https://code.highcharts.com/stock/highstock.js"></script>
      <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
      <script>
    
        function setChart() {
          Highcharts.setOption({
            global: {
              useUTC: false
            }
          });
        };
    
        $.ajax({
          url: "{% url 'nameapp:predict_kospi_api' %}",
          dataType: 'json',
          success: function (data) {
    
            Highcharts.setOptions({
              global: {
                useUTC: false
              }
            });
    
            Highcharts.stockChart("container", {
    
              chart: {
                height: 500
              },
    
              title: { 
                text: '코스피 지수' 
              }, 
    
              rangeSelector: {
                selected: 5,
                inputEnabled: false
              },
    
              xAxis: {
                type: 'datetime',
                labels:{
                  formatter: function(){
                    return Highcharts.dateFormat('%y.%m.%d', this.value);
                  },
                  step: 3
                }
              },
    
              yAxis: {
                labels: {
                  format: '{value}p',
                  style: {
                    color: 'rgba(0,0,0,.6)',
                  },
                  x: 30,
                },
                opposite: false,
                tickInterval: 50,   
              },
    
              tooltip: {
                xDateFormat: '%Y-%m-%d',
                split: true
              },
    
              series: [{
                  name: '시가',          
                  data: data.open,
                  color: 'rgba(0,200,0,.6)',
                  lineWidth: 2
              }, 
              {
                  name: '종가',          
                  data: data.close,
                  lineWidth: 3
              }],
    
              legend: {
                enabled: true, 
                align: 'left',
                verticalAlign: 'top',
                floating: true,
                x: 30,
                y: 70
              },
              
              responsive: {
                rules: [{
                  condition: {
                    maxWidth: 600
                  },
                  chartOptions: {
                    chart: {
                      height: 300
                    },
                    navigator: {
                      enabled: false
                    }
                  }
                }]
              }
            });
          }
        });
    
      </script>
    </div>

     

    (5) 작동확인

    먼저 데이터를 보내주는 api가 잘 작동하는지 api/predict/ 를 확인해본다.

    그리고 chart/ 차트 페이지를 확인한다.

     

    두둥

    아래는 차트를 구현하기위해 검색한 노가다의 흔적이다.

    그 외 구글검색 또는 직접 웹페이지의 소스보기로 코드를 참조할수있다. 

     

    https://www.highcharts.com/demo highcharts 사용예제 
    https://simpleisbetterthancomplex.com/tutorial/2018/04/03/how-to-integrate-highcharts-js-with-django.html  highcharts 기본예제
    https://github.com/sibtc/django-highcharts-example  타이타닉생존자 예측결과를 그래프로
    https://www.slideshare.net/hwangyoungjae/djangohighchart highchart를 사용하는 대략적인 순서 확인
    https://m.blog.naver.com/PostView.nhn?blogId=jhc9639&logNo=221103902611&proxyReferer=https%3A%2F%2Fwww.google.com%2F echart 적용예제
       
       

     

    유사한 라이브러리로 ChartJs, echart 가 있다. 

    또한 Django NVD3, Django Graphos, Django ChartJS, Django Uncharted, Django ChartBuilder 이 있다.

    아래 차트에 대해서는 이런게 있다정도만 확인해봤고 더 알아볼 예정이다.

    Chartit : http://chartit.shutupandship.com/demo/chart/basic-line/

    ChartJs : https://github.com/novafloss/django-chartjs

    장고 차트 : http://www.fusioncharts.com/django-charts/

    Django nvd3 : https://github.com/areski/django-nvd3

    Django graphos : http://agiliq.com/demo/graphos/

    Django Gcharts : https://github.com/rhblind/django-gcharts

     

    마침.

    댓글

Designed by Tistory.