डी 3 का एक सौम्य परिचय: एक पुन: प्रयोज्य बबल चार्ट कैसे बनाया जाए

डी 3 से शुरुआत हो रही है

जब मैंने डी 3 सीखना शुरू किया, तो मुझे कुछ भी समझ नहीं आया। चीजें तभी अधिक स्पष्ट हुईं जब मैंने पुन: प्रयोज्य चार्ट के बारे में सीखना शुरू किया।

इस लेख में, मैं आपको दिखाता हूं कि एक पुन: प्रयोज्य बबल चार्ट कैसे बनाया जाए और आपको रास्ते में डी 3 का एक सौम्य परिचय दिया जाए। हमारे द्वारा उपयोग किया जाने वाला डेटासेट जनवरी 2017 में फ्रीकोडकोड में प्रकाशित कहानियों से बना है।

यह वह चार्ट है जिसे आप बनाने जा रहे हैं

डी 3 के बारे में

डी 3 डेटा विज़ुअलाइज़ेशन के लिए एक जावास्क्रिप्ट लाइब्रेरी है। यह HTML, SVG और CSS का उपयोग करके जीवन में डेटा लाता है।

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

हम यहां 3 डी संस्करण 4.6.0 का उपयोग कर रहे हैं।

उपयोगी चार्ट

पुन: प्रयोज्य चार्ट पैटर्न के बाद के ग्राफ में दो विशेषताएं हैं:

  • Configurability। हम स्वयं कोड को संशोधित किए बिना ग्राफ़ की उपस्थिति और व्यवहार को संशोधित करना चाहते हैं।
  • एक स्वतंत्र तरीके से निर्मित होने की क्षमता। हम स्वतंत्र रूप से अपने डेटासेट से जुड़े हर ग्राफ तत्व को स्वतंत्र रूप से चाहते हैं। इस तरह से करना पड़ता है कि डी 3 डोम तत्वों के साथ डेटा इंस्टेंस को जोड़ता है। यह एक मिनट में और स्पष्ट हो जाएगा।
"योग करने के लिए: चार्ट को गेट्टर-सेटर विधियों के साथ बंद करने के रूप में लागू करें।" - माइक बोस्टॉक

बबल चार्ट

आपको पहले यह परिभाषित करने की आवश्यकता है कि चार्ट के किन तत्वों को अनुकूलित किया जा सकता है:

  • चार्ट का आकार
  • इनपुट डेटासेट

चार्ट के आकार को परिभाषित करना

आइए ग्राफ के सभी चर को अलग करने और डिफ़ॉल्ट मान सेट करने के लिए एक फ़ंक्शन बनाकर शुरू करें। इस संरचना को एक बंद कहा जाता है।

// बबल_ग्राफ.जेएस
var बबलचर = फ़ंक्शन () {
    var चौड़ाई = 600,
    ऊंचाई = 400;

    समारोह चार्ट (चयन) {
        // आप यहाँ प्राप्त करने वाले हैं
    }

    चार्ट वापसी;
}

आप कोड को बदले बिना विभिन्न आकारों के चार्ट बनाना चाहते हैं। इसके लिए आप निम्नानुसार चार्ट बनाएंगे:

// बुलबुला_ग्राफ। html
var चार्ट = bubbleChart ()। चौड़ाई (300) .height (200);

ऐसा करने के लिए, अब आप चौड़ाई और ऊंचाई चर के लिए एक्सेसर्स को परिभाषित करेंगे।

// बबल_ग्राफ.जेएस
var बबलचर = फ़ंक्शन () {
    var चौड़ाई = 600
    ऊंचाई = 400;
    समारोह चार्ट (चयन) {
        // हम यहां पहुंचने वाले हैं
    }

    chart. उपलब्धता = फ़ंक्शन (मान) {
        अगर (तर्कों) }
        चौड़ाई = मान;

        वापसी चार्ट;
    }
    chart.height = function (मान) {
        अगर (तर्क। गति) {वापसी ऊंचाई; }
        ऊँचाई = मान;

        चार्ट वापसी;
    }

    चार्ट वापसी;
}

यदि आप बबलचैट () (बिना चौड़ाई या ऊँचाई के गुण) कहते हैं, तो ग्राफ़ को डिफ़ॉल्ट चौड़ाई और ऊँचाई के मानों के साथ बनाया गया है जिसे आपने क्लोज़र के अंदर परिभाषित किया था। यदि तर्कों के बिना कहा जाता है, तो विधि चर मान लौटाती है।

// बुलबुला_ग्राफ। html
var चार्ट = bubbleChart ();
bubbleChart () चौड़ाई ()।; // रिटर्न 600

आप सोच रहे होंगे कि चार्ट फ़ंक्शन वापस करने के तरीके क्यों। यह एक जावास्क्रिप्ट पैटर्न है जिसका उपयोग कोड को सरल बनाने के लिए किया जाता है। इसे मेथड चैनिंग कहा जाता है। इस पैटर्न से आप इस तरह की नई वस्तुएँ बना सकते हैं:

// बुलबुला_ग्राफ। html
var चार्ट = bubbleChart ()। चौड़ाई (600) .height (400);

के बजाय:

// बुलबुला_ग्राफ। html
var चार्ट = bubbleChart ();
chart.setWidth (600);
chart.setHeight (400);

हमारे चार्ट के साथ डेटा को जोड़ना

अब चार्ट के तत्वों के साथ डेटा को जोड़ना सीखें। यहाँ चार्ट को कैसे संरचित किया गया है: ग्राफ के साथ div में एक SVG एलिमेंट है, और प्रत्येक डेटा पॉइंट चार्ट में एक सर्कल से मेल खाता है।

// bubble_graph.html, बुलबुलाचर्ट () फ़ंक्शन के बाद कहा जाता है

    <वृत्त>  // डेटा से एक कहानी
    <सर्कल>  // डेटा से एक और कहानी
    ...

Ata d3.data ()

D3.selection.data ([डेटा [, कुंजी]]) फ़ंक्शन एक नया चयन देता है जो डेटा के लिए सफलतापूर्वक एक तत्व का प्रतिनिधित्व करता है। ऐसा करने के लिए, आपको पहले .csv फ़ाइल से डेटा लोड करना होगा। आप d3.csv (url [[, row], कॉलबैक]) फ़ंक्शन का उपयोग करेंगे।

// बुलबुला_ग्राफ। html
d3.csv ('file.csv', फ़ंक्शन (त्रुटि, हमारा_डेटा) {
    var data = our_data; // यहां आप वह कर सकते हैं जो आप डेटा के साथ चाहते हैं
}
// medium_january.csv
| शीर्षक | श्रेणी | दिल |
| -------------------------------------- | ---------- ---- | -------- |
| कोई भी सॉफ्टवेयर का उपयोग नहीं करना चाहता है | विकास | 2700 |
| ट्रेल्स के साथ दोषरहित वेब नेविगेशन | डिजाइन | 688 |
| डेटा इंजीनियर का उदय | डाटा साइंस | 862 |

Selection डी 3-चयन

आप हमारे डेटा को चार्ट में पास करने के लिए d3-select () और डेटा () फ़ंक्शन का उपयोग करेंगे।

चयन दस्तावेज़ ऑब्जेक्ट मॉडल (DOM) के शक्तिशाली डेटा-चालित परिवर्तन की अनुमति देते हैं: सेट विशेषताएँ, शैलियाँ, गुण, HTML या पाठ सामग्री, और बहुत कुछ। - डी 3 प्रलेखन
// बुलबुला_ग्राफ। html
d3.csv ('medium_januge.csv', फ़ंक्शन (त्रुटि, हमारा_डेटा) {
    अगर (त्रुटि) {
        कंसोल। फेरर ('डेटा प्राप्त करने या पार्स करने में त्रुटि।');
        त्रुटि फेंक;
    }
    var चार्ट = bubbleChart ()। चौड़ाई (600) .height (400);
    । D3.select ( '# चार्ट') को डेटा (our_data) .call (चार्ट);
 });

एक अन्य महत्वपूर्ण चयनकर्ता d3.selectAll () है। मान लें कि आपके पास निम्नलिखित संरचना है:


    
    
    

d3.select ("बॉडी")। selectAll ("div") उन सभी डिव को हमारे लिए चुनता है।

Enter d3.enter ()

और अब आप एक महत्वपूर्ण डी 3 फ़ंक्शन के बारे में जानने जा रहे हैं: d3.enter ()। मान लीजिए कि आपके पास एक खाली बॉडी टैग और डेटा के साथ एक सरणी है। आप सरणी के प्रत्येक तत्व के माध्यम से जाना चाहते हैं और प्रत्येक तत्व के लिए एक नया div बनाना चाहते हैं। आप निम्न कोड के साथ ऐसा कर सकते हैं:



 // खाली
----
// js स्क्रिप्ट
var our_data = [1, 2, 3]

var div = d3.select ("बॉडी")
 .selectAll ( "div")
 .data (our_data)
 ।दर्ज()
 .append ( "div");

---


    
    
    

यदि आपको diva अभी भी मौजूद नहीं है, तो आपको selectAll ("div") की आवश्यकता क्यों है? क्योंकि डी 3 में कुछ करने के तरीके बताने के बजाय हम बताते हैं कि हमें क्या चाहिए।

इस स्थिति में, आप प्रत्येक div को सरणी के एक तत्व के साथ जोड़ना चाहते हैं। यही आप selectAll ("div") के साथ कह रहे हैं।

var div = d3.select ("बॉडी")
 .selectAll ("div") // यहाँ आप कह रहे हैं 'हे d3, अगले आने वाले एरे का प्रत्येक डेटा एलिमेंट एक div से बाउंड होगा'
 .data (our_data)
 । दर्ज () संलग्न ( "div");

प्रवेश () सरणी के तत्व के लिए बाध्य डेटा के साथ चयन लौटाता है। आप अंत में .append ("div") के साथ DOM में इस चयन को जोड़ते हैं

d3.forceSimulation ()

आपको मंडलियों के भौतिकी को अनुकरण करने के लिए कुछ चाहिए। इसके लिए आप d3.forceSimulation ([नोड्स]) का उपयोग करेंगे। आपको यह भी बताने की जरूरत है कि किस तरह का बल नोड्स की स्थिति या वेग को बदल देगा।

हमारे मामले में, हम d3.forceManyBody () का उपयोग करेंगे।

// बबल_चरट.जेएस
var सिमुलेशन = d3.forceSimulation (डेटा)
 .force ("चार्ज", d3.forceManyBody ()। शक्ति ([- 50]))
 .force ("x", d3.forceX ())
 .force ("y", d3.forceY ())
 .on ("टिक", टिकटिक);

एक सकारात्मक शक्ति मूल्य नोड्स को एक दूसरे को आकर्षित करने का कारण बनता है, जबकि एक नकारात्मक शक्ति मूल्य उन्हें एक दूसरे को पीछे हटाने का कारण बनता है।

ताकत () प्रभाव

हम पूरे SVG स्पेस के माध्यम से फैलने वाले नोड्स नहीं चाहते, हालाँकि, इसलिए हम d3.forceX (0) और d3.forceY (0) का उपयोग करते हैं। यह मंडलियों को 0 स्थिति में "ड्रग्स" करता है। आगे बढ़ो और इसे देखने के लिए कोड से निकालने का प्रयास करें।

जब आप पृष्ठ को ताज़ा करते हैं, तो आप देख सकते हैं कि मंडलियां तब तक समायोजित होती हैं जब तक कि वे अंत में स्थिर नहीं हो जाते। टिक () फ़ंक्शन हलकों की स्थिति को अपडेट करता है। D3.forceManyBody () प्रत्येक नोड की x और y स्थिति को अद्यतन करता रहता है, और टिक () फ़ंक्शन DOM को इन मानों (cx और साइबर विशेषताओं) से अपडेट करता है।

// बबल_ग्राफ.जेएस
समारोह टिक (ई) {
    node.attr ("cx", फ़ंक्शन (d) {रिटर्न d.x;})
        .attr ("साइबर", फंक्शन (d) {रिटर्न d.y;});
    // 'नोड' बबल चार्ट का प्रत्येक सर्कल है
 }

यहाँ सब कुछ एक साथ कोड है:

var सिमुलेशन = d3.forceSimulation (डेटा)
    .force ("चार्ज", d3.forceManyBody ()। शक्ति ([- 50]))
    .force ("x", d3.forceX ())
    .force ("y", d3.forceY ())
    .on ("टिक", टिकटिक);
समारोह टिक (ई) {
    node.attr ("cx", फ़ंक्शन (d) {रिटर्न d.x;})
        .attr ("साइबर", फंक्शन (d) {रिटर्न d.y;});
}

योग करने के लिए, यह सभी सिमुलेशन प्रत्येक सर्कल को एक एक्स और वाई स्थिति देता है।

d3.scales

यहां सबसे रोमांचक हिस्सा आता है: वास्तव में मंडलियों को जोड़ना। एंटर () फ़ंक्शन याद रखें? अब आप इसका इस्तेमाल करेंगे। हमारे चार्ट में प्रत्येक सर्कल की त्रिज्या प्रत्येक कहानी की सिफारिशों की संख्या के लिए आनुपातिक है। ऐसा करने के लिए आप एक रेखीय पैमाने का उपयोग करेंगे: d3.scaleLinear ()

तराजू का उपयोग करने के लिए आपको दो चीजों को परिभाषित करने की आवश्यकता है:

  • डोमेन: इनपुट डेटा के न्यूनतम और अधिकतम मूल्य (हमारे मामले में, न्यूनतम और अधिकतम संख्या में सिफारिशें)। न्यूनतम और अधिकतम मान प्राप्त करने के लिए, आप d3.min () और d3.max () फ़ंक्शन का उपयोग करेंगे।
  • रेंज: स्केल का न्यूनतम और अधिकतम आउटपुट मान। हमारे मामले में, हम आकार 5 का सबसे छोटा त्रिज्या और आकार 18 का सबसे बड़ा त्रिज्या चाहते हैं।
// बबल_ग्राफ.जेएस
var scaleRadius = d3.scaleLinear ()
            .domain ([d3.min (डेटा, फ़ंक्शन (d) {रिटर्न + d.views;});
                    d3.max (डेटा, फ़ंक्शन (डी) {रिटर्न + डी.व्यू;})]]
            .range ([5,18]);

और फिर आप अंत में मंडलियां बनाते हैं:

// बबल_ग्राफ.जेएस
var नोड = svg.selectAll ("सर्कल")
   .data (डेटा)
   ।दर्ज()
   .append ( "चक्र")
   .attr ('r', फंक्शन (d) {रिटर्न स्केलरेडियस (d.views)})
});

मंडलियों को रंगने के लिए, आप एक श्रेणीगत पैमाने का उपयोग करेंगे: d3.scaleOrdinal ()। यह पैमाना असतत मूल्यों को लौटाता है।

हमारे डेटासेट में 3 श्रेणियां हैं: डिज़ाइन, विकास और डेटा विज्ञान। आप इनमें से प्रत्येक श्रेणी को एक रंग में मैप करेंगे। d3.schemeCategory10 हमें 10 रंगों की एक सूची देता है, जो हमारे लिए पर्याप्त है।

// बबल_ग्राफ.जेएस
var colorCircles = d3.scaleOrdinal (d3.schemeCategory10);

var नोड = svg.selectAll ("सर्कल")
    .data (डेटा)
    ।दर्ज()
    .append ( "चक्र")
    .attr ('r', फंक्शन (d) {रिटर्न स्केलरेडियस (d.views)})
    .स्टाइल ("भरें", फ़ंक्शन (डी) {वापसी colorCircles (d.category)});

आप एसवीजी के बीच में खींचे गए वृत्त चाहते हैं, इसलिए आप प्रत्येक वृत्त को मध्य (आधी चौड़ाई और आधी ऊँचाई) पर ले जाएँगे। आगे बढ़ो और यह देखने के लिए कोड से हटा दें कि क्या होता है।

// बबल_ग्राफ.जेएस
var नोड = svg.selectAll ("सर्कल")
 .data (डेटा)
 ।दर्ज()
 .append ( "चक्र")
 .attr ('r', फंक्शन (d) {रिटर्न स्केलरेडियस (d.views)})
 .स्टाइल ("भरें", फ़ंक्शन (डी) {वापसी colorCircles (d.category)})
 .attr ('रूपांतर', 'अनुवाद' ('+ [चौड़ाई / 2, ऊँचाई / 2] +') ');

अब आप चार्ट में टूलटिप्स जोड़ेंगे। जब भी हम माउस को मंडलियों के ऊपर रखते हैं, तो उन्हें दिखाई देना चाहिए।

var टूलटिप = चयन
 .append ( "div")
 .स्टाइल ("स्थिति", "पूर्ण")
 .स्टाइल ("दृश्यता", "छिपा हुआ")
 .स्टाइल ("रंग", "सफेद")
 .स्टाइल ("पैडिंग", "8 पीएक्स")
 .स्टाइल ("पृष्ठभूमि-रंग", "# 626D71")
 .स्टाइल ("बॉर्डर-रेडियस", "6px")
 .स्टाइल ("पाठ-संरेखित", "केंद्र")
 .स्टाइल ("फ़ॉन्ट-परिवार", "मोनोस्पेस")
 .स्टाइल ("चौड़ाई", "400px")
 .text ( "");
var नोड = svg.selectAll ("सर्कल")
 .data (डेटा)
 ।दर्ज()
 .append ( "चक्र")
 .attr ('r', फंक्शन (d) {रिटर्न स्केलरेडियस (d.views)})
 .स्टाइल ("भरें", फ़ंक्शन (डी) {वापसी colorCircles (d.category)})
 .attr ('रूपांतर', 'अनुवाद' ('+ [चौड़ाई / 2, ऊँचाई / 2] +') ')
 .on ("माउसओवर", फ़ंक्शन (d) {
     tooltip.html (d.category + "
" + d.title + "
" + d.views);      टूलटिप.स्टाइल ("दृश्यता", "दृश्यमान";};)  .on ("मूसमव", फंक्शन () {    वापसी टूलटिप.स्टाइल ("शीर्ष", (d3.event.pageY- 10) + "px")। शैली ("बाएं", (d3.event.pageX + 10) + "px");}};  .on ("माउसआउट", फ़ंक्शन () {रिटर्न टूलटिप.स्टाइल ("दृश्यता", "छिपा हुआ");});

माउस हिलने पर मूसमव कर्सर का अनुसरण करता है। d3.event.pageX और d3.event.pageY माउस निर्देशांक लौटाते हैं।

और बस! आप यहां अंतिम कोड देख सकते हैं।

आप यहां बबल चार्ट के साथ खेल सकते हैं।

क्या आपको यह लेख मददगार लगा? मैं हर महीने एक गहरा गोता लेख लिखने के लिए अपनी पूरी कोशिश करता हूं, जब आप एक नया प्रकाशित करते हैं तो आप एक ईमेल प्राप्त कर सकते हैं।

कोई सवाल या सुझाव? उन्हें टिप्पणियों में छोड़ दें। पढ़ने के लिए धन्यवाद!

जॉन कारमाइकल और अलेक्जेंड्रे सिस्नेयरोस के लिए विशेष धन्यवाद।