2013-02-05 12 views
22

में लापता डेटा बिंदुओं के साथ परतों को कैसे संभालें I stacked क्षेत्र चार्ट बनाने के लिए d3.stack का उपयोग कर रहा हूं लेकिन मुझे एक त्रुटि मिलती है यदि मेरे पास समान संख्या में आइटम नहीं हैं प्रत्येक परत। मैं इस तरह के डेटा की एक सरणी के साथ शुरू कर रहा हूँ:)d3.layout.stack()

[ 
    {key:'Group1',value,date}, 
    {key:'Group1',value,date}, 
    {key:'Group1',value,date}, 
    {key:'Group2',value,date}, 
    {key:'Group2',value,date} 
] 

और बाद मैं (घोंसला के माध्यम से चलाने के लिए और ढेर() मैं इस प्रारूप के साथ खत्म हो, के रूप में उम्मीद:

[ 
    {key: 'Group1', 
    values: [ {key,value,date}, {key,value,date}, {key,value,date} ] }, 
    {key: 'Group2', 
    values: [ {key,value,date}, {key,value,date} ] } 
] 

मैं थोड़ा इस jsFiddle में इस मुद्दे को प्रदर्शित करने के लिए एक स्टैक्ड क्षेत्र नमूना संशोधित किया है: आप sourceData सरणी में डेटा बिंदुओं में से किसी एक को निकाल देते हैं आप त्रुटि संदेश दिखाई देगा http://jsfiddle.net/brentkeller/rTC3c/2/

"संपत्ति पढ़ा नहीं जा सकता '1' अपरिभाषित की" कंसोल में।

क्या d3.stack को खोने वाले डेटा बिंदुओं के लिए शून्य मान मानने का कोई तरीका है? यदि नहीं, तो क्या गुम मूल्यों को भरने के लिए एक शानदार समाधान है?

उत्तर

17

यह डी 3 विशिष्ट नहीं बल्कि कुंजीपटल डेटा की एक सरणी में अंतराल को भरने के लिए एक सामान्य समाधान है। मैं निम्नलिखित समारोह के साथ अपने jsfiddle here संशोधित:

function assignDefaultValues(dataset) 
{ 
    var defaultValue = 0; 
    var keys = [ 'Group1' , 'Group2', 'Group3' ]; 
    var hadData = [ true, true, true]; 
    var newData = []; 
    var previousdate = new Date(); 
    var sortByDate = function(a,b){ return a.date > b.date ? 1 : -1; }; 

    dataset.sort(sortByDate); 
    dataset.forEach(function(row){ 
     if(row.date.valueOf() !== previousdate.valueOf()){ 
      for(var i = 0 ; i < keys.length ; ++i){ 
       if(hadData[i] === false){ 
        newData.push({ key: keys[i], 
            value: defaultValue, 
            date: previousdate }); 
       } 
       hadData[i] = false; 
      } 
      previousdate = row.date; 
     } 
     hadData[keys.indexOf(row.key)] = true; 
    }); 
    for(i = 0 ; i < keys.length ; ++i){ 
     if(hadData[i] === false){ 
      newData.push({ key: keys[i], value: defaultValue, 
          date: previousdate }); 
     } 
    } 
    return dataset.concat(newData).sort(sortByDate); 
} 

यह दिया डाटासेट के माध्यम से जब भी यह एक नया date मूल्य भर आता चलता है और, किसी भी keys कि अभी तक नहीं देखा गया है के लिए एक डिफ़ॉल्ट मान प्रदान करती है। डी 3 टुकड़ों के लिए गैर मानक उपयोग खोजने के लिए

+0

एक डिफ़ॉल्ट मान शायद मदद नहीं करेगा। यह स्टैक्ड ग्राफ को मनमाने ढंग से डुबकी बना देगा (डिफ़ॉल्ट मान पर, संभवतः 0)। –

+0

इसके अलावा मूल अनुरोध था: "क्या d3.stack को खोने का कोई तरीका है, बस गायब डेटा बिंदुओं के लिए शून्य मान मानें?" –

+0

धन्यवाद @ChrisG। मैंने इस दृष्टिकोण के साथ जाने का फैसला किया। मैंने चाबियाँ बनाने के लिए थोड़ा सा जवाब दिया था और थाटा सरणी अधिक लचीला था। मदद के लिये शुक्रिया! –

5

स्टैक वास्तव में जो करता है वह करता है, ग्राफ को ढेर करता है, ताकि आप सही प्रारूप में डेटा प्रदान करने के लिए उपयोगकर्ता जिम्मेदार हों। यदि आप इसके बारे में सोचते हैं तो यह समझ में आता है, क्योंकि स्टैक मूल रूप से डेटा प्रारूप अज्ञेयवादी है। यह लचीलापन का एक बड़ा सौदा प्रदान करता है, केवल एक ही प्रतिबंध के साथ कि प्रत्येक परत के लिए यह अंक की एक ही संख्या तक पहुंच सकता है। यह निर्धारित कैसे करेगा कि कौन से अंक गुम हैं? यह देखते हुए कि पहली परत में पांच अंक थे और दूसरी परत में दस अंक हैं, क्या पहली परत पांच अंक लापता है? या दोनों परत लापता बिंदु हैं क्योंकि एक तीसरी परत में और भी अंक हैं। और फिर यदि अंक गुम हैं, तो कौन से? शुरुआत में, अंत में, बीच में कहीं? फिर इसे समझने के लिए एक स्टैक कार्यान्वयन के लिए कोई समझदार तरीका नहीं है (जब तक कि यह बहुत कठोर डेटा संरचनाओं को मजबूर नहीं करेगा)।

तो, लेकिन क्या आप ऐसा कुछ भी नहीं कर सकते हैं? मै सोचता हूँ तुम कर सकते हो। मैं आपको पूर्ण कार्यान्वयन नहीं दे सकता लेकिन आपको सही दिशा में कुछ पॉइंटर्स दे सकता हूं। हम यहां शुरू करते हैं:

var stack = d3.layout.stack() 
    .offset("zero") 
    .values(function(d) { return d.values; }) 

यहां आप केवल मान वापस कर सकते हैं, जो आपके उदाहरण में घोंसला ऑपरेटर का परिणाम होगा। तो इस बिंदु पर आपके पास मूल्यों को "ठीक करने" की क्षमता है।

पहली चीज़ जो आपको करने की ज़रूरत है वह अधिकतम अवलोकनों का निर्धारण कर रही है।

var nested = nest.entries(data); 
var max = nested.reduce(function(prev, cur) { 
    return Math.max(prev, cur.values.length); 
}, 0); 

अब मुश्किल हिस्सा है। एक बार जब आप तत्वों की अधिकतम संख्या जानते हैं, तो आपको मानों को पारित किए गए फ़ंक्शन को समायोजित करने की आवश्यकता होगी। यहां आपको डेटा पर धारणाएं करनी होंगी। आपके प्रश्न से मैं समझता हूं कि कुछ समूहों के मानों के लिए मूल्य गुम हैं। तो दो संभावनाएं हैं। या तो आप मानते हैं कि तत्वों की अधिकतम संख्या वाले समूह में श्रेणी में सभी आइटम शामिल हैं या आप एक निश्चित सीमा मानते हैं और यदि वे आपकी सीमा में प्रत्येक "टिक" के मान रखते हैं तो सभी समूहों की जांच करें। तो यदि आपकी सीमा एक तिथि सीमा है (जैसा कि आपके उदाहरण में है) और आप प्रत्येक दिन (या उस मामले के लिए कभी भी अंतराल) की अपेक्षा करते हैं, तो आपको समूह में आइटम चलना होगा और अंतराल को भरना होगा। मैं एक संख्यात्मक श्रृंखला के लिए एक (untested) उदाहरण दे करने की कोशिश करेंगे:

// define some calculated values that can be reused in correctedValues 
var range = [0, 1]; 
var step = 0.1; 

function correctedValues(d) { 
    var values = d.values; 
    var result = []; 
    var expected = 0; 
    for (var i = 0; i < values.length; ++i) { 
    var value = values[i]; 
    // Add null-entries 
    while (value.x > expected) { 
     result.push({x: expected, otherproperties_you_need... }); 
     expected += step; 
    } 
    result.push(value); // Now add the real data point. 
    expected = value.x; 
    } 

    // Fill up the end of of the array if needed 
    while(expected < range[1]) { 
    result.push({x: expected, otherproperties_you_need... }); 
    expected += step; 
    } 
    return result; 
} 

// Now use our costom function for the stack 
var stack = d3.layout.stack() 
.offset("zero") 
.values(correctedValues) 
... 

के रूप में कहा, इस हिस्से अपरीक्षित है और सीधे अपनी समस्या का समाधान नहीं (के रूप में मैं एक संख्यात्मक रेंज का उपयोग कर रहा है), लेकिन मैं इसे लगता है आपको अपनी समस्या को हल करने के बारे में एक विचार देना चाहिए (और आपकी समस्या का वास्तविक स्रोत क्या है)।

1

जैसा कि अन्य ने समझाया है, स्टैक्ड चार्ट के लिए प्रत्येक डेटा बिंदु के लिए गुम मूल्यों पर अनुमान लगाने के लिए अनुचित होगा, क्योंकि मूल्यों को अलग करने के कई तरीके हैं और कोई स्पष्ट विकल्प नहीं है।

हालांकि, d3.svg.line() आप प्रक्षेप की अपनी खुद की विधि लेने और लापता मूल्यों में भरने के लिए एक उचित तरीका प्रदान करते हैं लगता है। हालांकि यह एसवीजी पथ उत्पन्न करने के लिए डिज़ाइन किया गया है, लेकिन आप इसे सामान्य रूप से लाइनों को परिभाषित करने के लिए अनुकूलित कर सकते हैं। प्रक्षेप तरीकों यहाँ का सुझाव दिया जाता है:

https://github.com/mbostock/d3/wiki/SVG-Shapes#wiki-line_interpolate

ऐसा नहीं है कि वर्ग, अब के लिए, इन सभी अद्भुत प्रक्षेप विधियों (कि d3 में और कहीं भी दिखाई नहीं देते) है, लेकिन इसके बजाय एसवीजी पथ डेटा पैदा करने के लिए प्रतिबंधित है दुर्भाग्यपूर्ण है मनमाने ढंग से मध्यवर्ती मूल्यों का। शायद अगर @mbostock इसे देखता है, तो वह कार्यक्षमता को सामान्यीकृत करने पर विचार करेगा।

हालांकि, अब के लिए तुम सिर्फ डी 3 का एक कांटा बनाने के लिए और इससे पहले कि यह source कि नीचे प्रक्षेप करता है, के हिस्से में, एक एसवीजी path स्ट्रिंग के लिए लिखा है line(data) के मध्यवर्ती परिणाम लेने के लिए चाहते हो सकता है:

function line(data) { 
    var segments = [], 
     points = [], 
     i = -1, 
     n = data.length, 
     d, 
     fx = d3_functor(x), 
     fy = d3_functor(y); 

    function segment() { 
     segments.push("M", interpolate(projection(points), tension)); 
    } 

    while (++i < n) { 
     if (defined.call(this, d = data[i], i)) { 
     points.push([+fx.call(this, d, i), +fy.call(this, d, i)]); 
     } else if (points.length) { 
     segment(); 
     points = []; 
     } 
    } 

    if (points.length) segment(); 

    return segments.length ? segments.join("") : null; 
    } 
+0

+1। मैं पूरे स्थान पर पैमाने का उपयोग कर रहा हूं .. –