2

이것은 dc.js/d3.js/crossfilter.js 주제에 대한 두 번째 질문입니다. 기본적인 개인 대시 보드를 구현하려고하는데 시간이 지남에 따라 측정 항목을 출력하는 매우 간단한 lineChart (rangeChart가 연결된)를 만드는 것으로 시작했습니다.8k + 항목의 dc.js lineChart 성능 문제

데이터 내가 JSON로 저장하고 다음과 같습니다 (나는 또한 날짜 형식을 유지 JSON를 사용하는 지금 그래서, 이후 단계에서 MongoDB를 인스턴스에 저장됩니다) :

[ 
{"date":1374451200000,"prodPow":0.0,"consPow":0.52,"toGridPow":0.0,"fromGridPow":0.52,"prodEn":0.0,"consEn":0.0,"toGridEn":0.0,"fromGridEn":0.0}, 
{"date":1374451500000,"prodPow":0.0,"consPow":0.34,"toGridPow":0.0,"fromGridPow":0.34,"prodEn":0.0,"consEn":0.0,"toGridEn":0.0,"fromGridEn":0.0}, 
{"date":1374451800000,"prodPow":0.0,"consPow":0.42,"toGridPow":0.0,"fromGridPow":0.42,"prodEn":0.0,"consEn":0.0,"toGridEn":0.0,"fromGridEn":0.0}, 
... 
] 

나는 약 22000 개의 항목이 있으며, 대시 보드를 열 때 많은 성능 문제가 발생합니다.이 있습니다. 8000 개의 레코드 집합으로 데이터를 조각하려고해도 성능은 여전히 ​​좋지 않지만 적어도 렌더링은 일정 시간이 지나면 끝나며 데이터와의 상호 작용은 끔찍합니다. dc.js와 crossfilter.js가 100k + 항목과 하나 이상의 차원에서 어려움을 겪을 것으로 예상하기 때문에 코드에 약간의 함정이 있다는 것을 짐작할 수 있습니다!

그럼에도 불구하고 크롬으로 프로파일 링하고 온라인으로 읽는 것이별로 도움이되지 못했습니다 (나중에 변경하려고 시도한 것에 대한 자세한 내용). 여기

graph.js 코드 : 나는 몇 가지 CPU 프로파일 링을 수행하는 크롬 개발 도구를 사용
queue() 
    .defer(d3.json, "/data") 
    .await(makeGraphs); 

function makeGraphs(error, recordsJson) { 

    // Clean data 
    var records = recordsJson; 

    // Slice data to avoid browser deadlock 
    records = records.slice(0, 8000); 

    // Crossfilter instance 
    ndx = crossfilter(records); 

    // Define Dimensions 
    var dateDim = ndx.dimension(function(d) { return d.date; }); 

    // Define Groups 
    var consPowByDate = dateDim.group().reduceSum(function (d) { return d.consPow; }); 
    var prodPowByDate = dateDim.group().reduceSum(function (d) { return d.prodPow; }); 

    // Min and max dates to be used in the charts 
    var minDate = dateDim.bottom(1)[0]["date"]; 
    var maxDate = dateDim.top(1)[0]["date"]; 

    // Charts instance 
    var chart = dc.lineChart("#chart"); 
    var volumeChart = dc.barChart('#volume-chart'); 

    chart 
     .renderArea(true) 
     /* Make the chart as big as the bootstrap grid by not setting ".width(x)" */ 
     .height(350) 
     .transitionDuration(1000) 
     .margins({top: 30, right: 50, bottom: 25, left: 40}) 
     .dimension(dateDim) 
     /* Grouped data to represent and label to use in the legend */ 
     .group(consPowByDate, "Consumed") 
     /* Function to access grouped-data values in the chart */ 
     .valueAccessor(function (d) { 
      return d.value; 
     }) 
     /* x-axis range */ 
     .x(d3.time.scale().domain([minDate, maxDate])) 
     /* Auto-adjust y-axis */ 
     .elasticY(true) 
     .renderHorizontalGridLines(true) 
     .legend(dc.legend().x(80).y(10).itemHeight(13).gap(5)) 
     /* When on, you can't visualize values, when off you can filter data */ 
     .brushOn(false) 
     /* Add another line to the chart; pass (i) group, (ii) legend label and (iii) value accessor */ 
     .stack(prodPowByDate, "Produced", function(d) { return d.value; }) 
     /* Range chart to link the brush extent of the range with the zoom focus of the current chart. */ 
     .rangeChart(volumeChart) 
     ; 

    volumeChart 
     .height(60) 
     .margins({top: 0, right: 50, bottom: 20, left: 40}) 
     .dimension(dateDim) 
     .group(consPowByDate) 
     .centerBar(true) 
     .gap(1) 
     .x(d3.time.scale().domain([minDate, maxDate])) 
     .alwaysUseRounding(true) 
     ; 

    // Render all graphs 
    dc.renderAll(); 
}; 

및 요약 이러한 결과입니다

  • d3_json가 구문 분석 상단은 약 70ms (#records와 무관)
  • 2000 레코드 :
    • make_graphs은 1s 미만으로 약간 걸립니다.
    • 치수 집계 11ms;
    • 그룹 집합체 약 8ms;
    • dc.lineChart 약 16ms 소요;
    • dc.barChart 약 8ms 소요;
    • 렌더링은 약 700ms (lineChart의 경우 450ms) 소요됩니다.
    • 데이터 상호 작용이 매우 부드럽지는 않지만 여전히 충분합니다. 8000 개 레코드
  • :
    • make_graphs는 기가 주위에 소요;
    • 치수 집합체 약 80ms;
    • 그룹 집합체 약 55ms;
    • dc.lineChart 약 25ms 소요;
    • dc.barChart 약 15ms 소요;
    • 렌더링은 5.3 초 (lineChart의 경우 3 초)입니다.
    • 데이터 상호 작용은 끔찍하며 필터링에는 많은 시간이 걸립니다.
  • 모든 기록은 브라우저가 멈추고 스크립트를 중지해야합니다.

thread을 읽은 후 날짜가 문제가 될 수 있다고 생각하여 코드 대신 날짜 대신 숫자를 사용하도록 수정했습니다. 여기에 (I 변경 사항 만 적어 것) 내가 수정 한 것입니다 : 눈에 띄는

// Added before creating the crossfilter to coerce a number date 
records.forEach(function(d) { 
    d.date = +d.date; 
}); 

// In both the lineChart and barChart I used a numeric range 
.x(d3.scale.linear().domain([minDate, maxDate])) 

불행하게도 아무것도 성능이 많다는 변경되지 않습니다. 여기 당신이 원하는 경우 github link입니다 :


편집 ... 나는이 문제를 해결하는 방법에 대한 단서가 없다 실제로 나는 대시 보드에 더 많은 그룹, 치수 및 차트를 추가하고 싶습니다 내 코드를 직접 테스트 해보십시오.

: 귀하의 브라우저로 이동 한 후

python3 dashboard.py

과 :

pip3 install flask

대시 보드를 실행 : 당신은 그냥 플라스크에 설치해야하므로

나는, 서버 측에 대한 python3 및 플라스크를 사용

localhost:5000

+0

물론이 게시물에 링크를 추가했습니다. 시간 내 주셔서 감사드립니다. – Bertone

답변

4

시도하지 않고 말하기는 어렵지만 아마도 일어나는 일은 너무 많은 고유 한 날짜가 있다는 것입니다. 그래서 많은 수의 DOM 객체로 끝납니다. 자바 스크립트는 빠르지 만 DOM은 느리다는 것을 기억하십시오. 따라서 최대 0.5GB의 데이터를 처리하는 것이 좋지만 브라우저가 울리기 전에 수천 개의 DOM 객체 만 가질 수 있습니다.

이것은 크로스 필터가 처리 할 수 ​​있도록 설계된 것입니다. 당신이해야 할 일은 집계뿐입니다. 당신은 1000 점의 점수를 볼 수 없을 것입니다. 귀하의 차트는 (아마) 단지 수백 픽셀 너비이므로 그들은 길을 잃을 것입니다.

그래서 시간 척도에 따라, 당신은 시간 단위로 집계 수 : 분, 일, 년

var consPowByHour = dateDim.group(function(d) { 
    return d3.time.hour(d); 
}).reduceSum(function (d) { return d.consPow; }); 

chart.group(consPowByHour) 
    .xUnits(d3.time.hours) 

또는 유사를, 무엇을. 필요 이상으로 복잡 할 수도 있지만 this example은 시간 간격을 전환하는 방법을 보여줍니다.

(전체 스택을 설치하지 않으려 고합니다. 대부분의 예제는 JS이므로 jsfiddle 등에서 쉽게 테스트 할 수 있습니다. 설명이 없으면 스크린 샷을 추가 할 수도 있습니다. 도움이 될 것입니다.)

EDIT : 귀하의 데이터는 정수이지만 귀하의 척도는 시간에 기반한 것으로 나타났습니다. 어쩌면 항상 객체를 생성 할 수 있습니다.시도해보십시오.

+0

귀하의 조언에 감사드립니다. 나는 당신의 해결책을 시도했지만 아주 약간의 향상만을 볼 수 있습니다. 나는 심지어 며칠 씩 집계하려했지만 아무런 변화가 없었다. 나는 당신이 올바른 방향으로 나를 가리키고 있다고 생각한다. (js는 빠르며 DOM은 그렇지 않다.)하지만 나는 다른 종류의 수정을 찾아야한다. – Bertone

+0

흠.이 크기의 데이터는 절대로 문제가되지 않습니다. 위의 또 다른 힌트를 추가했습니다. – Gordon

+0

와우 덕분에 성능이 크게 향상되었습니다! 이제 24k 항목을 시간 단위로 그룹화하면 브라우저가로드 속도가 빠르며 대화 형 (매우 부드럽지는 않지만 충분히 좋습니다)입니다. 썰기는 매우 빠릅니다. 아직도 나는이 문제를 잘 이해하지 못한다. 또한 * 이전 해결책 *에서이 에러를 발견했다 :'TypeError : date.getFullYear is not function' ... JSON이 datetime 형식을 유지하고 있다고 생각했다. 'd3.json (...)'내 날짜는 javascript _Dates_가 아닌 ... 또한, 왜 그런 식으로 "모든 시간에"객체를 만들겠습니까? – Bertone