Visualizzazione dei risultati da 1 a 3 su 3
  1. #1

    Problema grafici con libreria d3

    Ciao a tutti,
    devo creare dei diagrammi Alluvial , tipo quelli di Google Analytics per intenderci, che facciano vedere proprio come per Analytics il quantitativo di rotte che sono state intraprese dagli utenti.

    Il database da cui vengono presi i dati al momento è un SQLite 3, presto verrà cambiato in un MySQL.

    La libreria che sembra fare al caso mio, sembra essere la libreria d3 che mi sembra essere molto potente sotto questo punto di vista.

    Tra i vari esempi proposti ho trovato questo diagramma, che è proprio quello che fa al caso mio (esempio diagramma alluvial in PHP e JavaScript).

    Ora il problema è che questo diagramma crea ad ogni esecuzione dei dati casuali e mostra di conseguenza il grafico.

    Ho creato dunque un programma PHP che mi genera un file json valido (stando anche ai vari validatori online di json).
    Il json in questione ha una forma di questo tipo per capirci:
    codice:
    {
        "name": "00000000001",
        "children":  [
                  {
                                "name": "00000000002", "size": 458
                  },
                  {
                    "name": "00000000002",
                    "children": [
                              {
                                "name": "00000000003", "size": 224
                              }
                    ]
                  },
    
                                  [... molti altri oggetti, tutti partono da "00000000001" ...]
    
        ]
    }
    che è preso paro paro dagli esempi della libreria d3, solo modificati con i miei dati, dove size rappresenta la quantità di utenti che hanno preso quella strada.

    A questo punto ho cercato di inglobare questi oggetti nel nuovo script preso dall'esempio soprastante del grafico alluvial per farmi creare lo stesso con questi dati ma il problema principale con il quale mi sto scontrando è che non riesco a farglieli passare.

    Ho provato con jQuery:
    codice:
                $(document).ready(
                    function(){
                       $.getJSON(
                          './fileJson.json',
                          function(mioJson){
                             // ciclo l'array
                             for(i=0; i<mioJson.length; i++){
                                var nomeNodo  = mioJson[i].name;
                                var chidren = mioJson[i].children;
                                alert('nome ' + nomeNodo + ' children ' + children );
                             }
    
                          }
                       );
                    }
                 );
    (l'alert è messo solo a scopo di debug, perchè non riesco ad arrivare lì...)

    Ho provato a fare il parse del file json seguendo la guida di w3school e la guida qui di HTML.it , ma ancora non mi funziona....

    Sbaglio qualcosa che non riesco a vedere???

    Avete altre idee o suggerimenti???

  2. #2
    Ho risolto il passaggio di dati con $.ajax.
    codice:
        $.ajax({
            url: 'mioJson.json',
            async: false,
            dataType: 'json',
            success: function (response) {
                var nomeNodo = response.name;
                var ncount = response.children.length;
                alert('nome nodo ' + nomeNodo + ' contatore ' + ncount);
    
                [... tutto il codice dello script originario ...]
    
            }
        });
    Ora il problema è sostituire tutta la parte dello script che riguarda la creazione casuale dei dati con quelli che gli passo con il json.

    Questo il codice originario dello script:
    codice:
                /* Make Fake Data */
    
                var data = (function() {
                    var maxt = 5,
                        maxn = 12,
                        maxl = 4,
                        maxv = 10,
                        times = [],
                        allLinks = [],
                        counter = 0,
                        addNodes = function() {
                            var ncount = Math.random() * maxn + 1,
                                nodes = d3.range(0, ncount).map(function(nomeNodo) {
                                    return {
                                        id: counter++,
                                        nodeName: "Node " + nomeNodo,
                                        nodeValue: 0,
                                        incoming: []
                                    }
                                });
                            times.push(nodes);
                            return nodes;
                        },
                        addNext = function() {
                            var current = times[times.length-1],
                                nextt = addNodes();
                            // make links
                            current.forEach(function(n) {
                                var linkCount = Math.min(~~(Math.random() * maxl + 1), nextt.length),
                                    breaks = d3.range(linkCount-1)
                                        .map(function() { return Math.random() * n.nodeValue })
                                        .sort(d3.ascending),
                                    links = {},
                                    target, link, x;
                                for (x=0; x<linkCount; x++) {
                                    do { 
                                        target = nextt[~~(Math.random() * nextt.length)];
                                    } while (target.id in links);
                                    // add link
                                    link = {
                                        source: n.id,
                                        target: target.id,
                                        value: (breaks[x] || n.nodeValue) - (breaks[x-1] || 0)
                                    };
                                    links[target.id] = link;
                                    allLinks.push(link);
                                    target.nodeValue += link.value;
                                }
                            });
                            // prune next
                            times[times.length-1] = nextt.filter(function(n) { return n.nodeValue });
                        }
                    // initial set
                    addNodes().forEach(function(n) {
                        n.nodeValue = Math.random() * maxv + 1;
                    });
                    // now add rest
                    for (var t=0; t<maxt-1; t++) {
                        addNext();
                    }
    
                    return {
                        times: times,
                        links: allLinks
                    };
                })();
    
                /* Process Data */
    
                // make a node lookup map
                var nodeMap = (function() {
                    var nm = {};
                    data.times.forEach(function(nodes) {
                        nodes.forEach(function(n) {
                            nm[n.id] = n;
                            // add links and assure node value
                            n.links = [];
                            n.incoming = [];
                            n.nodeValue = n.nodeValue || 0;
                        })
                    });
                    return nm;
                })();
    
                // attach links to nodes
                data.links.forEach(function(link) {
                    nodeMap[link.source].links.push(link);
                    nodeMap[link.target].incoming.push(link);
                });
    
                // sort by value and calculate offsets
                data.times.forEach(function(nodes) {
                    var cumValue = 0;
                    nodes.sort(function(a,b) {
                        return d3.descending(a.nodeValue, b.nodeValue)
                    });
                    nodes.forEach(function(n, i) {
                        n.order = i;
                        n.offsetValue = cumValue;
                        cumValue += n.nodeValue;
                        // same for links
                        var lCumValue;
                        // outgoing
                        if (n.links) {
                            lCumValue = 0;
                            n.links.sort(function(a,b) {
                                return d3.descending(a.value, b.value)
                            });
                            n.links.forEach(function(l) {
                                l.outOffset = lCumValue;
                                lCumValue += l.value;
                            });
                        }
                        // incoming
                        if (n.incoming) {
                            lCumValue = 0;
                            n.incoming.sort(function(a,b) {
                                return d3.descending(a.value, b.value)
                            });
                            n.incoming.forEach(function(l) {
                                l.inOffset = lCumValue;
                                lCumValue += l.value;
                            });
                        }
                    })
                });
                data = data.times;
    
                // calculate maxes
                var maxn = d3.max(data, function(t) { return t.length }),
                    maxv = d3.max(data, function(t) { return d3.sum(t, function(n) { return n.nodeValue }) });
    
                /* Make Vis */
    
                // settings and scales
                var w = 1400,
                    h = 500,
                    gapratio = .7,
                    delay = 1500,
                    padding = 15,
                    x = d3.scale.ordinal()
                        .domain(d3.range(data.length))
                        .rangeBands([0, w + (w/(data.length-1))], gapratio),
                    y = d3.scale.linear()
                        .domain([0, maxv])
                        .range([0, h - padding * maxn]),
                    line = d3.svg.line()
                        .interpolate('basis');
    
                // root
                var vis = d3.select("body")
                  .append("svg:svg")
                    .attr("width", w)
                    .attr("height", h);
    
    
                var t = 0;
                function update(first) {
                    // update data
                    var currentData = data.slice(0, ++t);
    
                    // time slots
                    var times = vis.selectAll('g.time')
                        .data(currentData)
                      .enter().append('svg:g')
                        .attr('class', 'time')
                        .attr("transform", function(d, i) { return "translate(" + (x(i) - x(0)) + ",0)" });
    
                    // node bars
                    var nodes = times.selectAll('g.node')
                        .data(function(d) { return d })
                      .enter().append('svg:g')
                        .attr('class', 'node');
    
                    setTimeout(function() {
                        nodes.append('svg:rect')
                            .attr('fill', 'steelblue')
                            .attr('y', function(n, i) {
                                return y(n.offsetValue) + i * padding;
                            })
                            .attr('width', x.rangeBand())
                            .attr('height', function(n) { return y(n.nodeValue) })
                          .append('svg:title')
                            .text(function(n) { return n.nodeName });
                    }, (first ? 0 : delay));
    
                    var linkLine = function(start) {
                        return function(l) {
                            var source = nodeMap[l.source],
                                target = nodeMap[l.target],
                                gapWidth = x(0),
                                bandWidth = x.rangeBand() + gapWidth,
                                startx = x.rangeBand() - bandWidth,
                                sourcey = y(source.offsetValue) + 
                                    source.order * padding +
                                    y(l.outOffset) +
                                    y(l.value)/2,
                                targety = y(target.offsetValue) + 
                                    target.order * padding + 
                                    y(l.inOffset) +
                                    y(l.value)/2,
                                points = start ? 
                                    [
                                        [ startx, sourcey ], [ startx, sourcey ], [ startx, sourcey ], [ startx, sourcey ] 
                                    ] :
                                    [
                                        [ startx, sourcey ],
                                        [ startx + gapWidth/2, sourcey ],
                                        [ startx + gapWidth/2, targety ],
                                        [ 0, targety ]
                                    ];
                            return line(points);
                        }
                    }
    
                    // links
                    var links = nodes.selectAll('path.link')
                        .data(function(n) { return n.incoming || [] })
                        .enter().append('svg:path')
                        .attr('class', 'link')
                        .style('stroke-width', function(l) { return y(l.value) })
                        .attr('d', linkLine(true))
                        .on('mouseover', function() {
                            d3.select(this).attr('class', 'link on')
                        })
                        .on('mouseout', function() {
                            d3.select(this).attr('class', 'link')
                        })
                      .transition()
                        .duration(delay)
                        .attr('d', linkLine());
    
                }
    
                function updateNext() {
                    if (t < data.length) {
                        update();
                        window.setTimeout(updateNext, delay)
                    }
                }
                update(true);
                updateNext();
    Inizialmente sto cercando di fargli passare anche solo la rinominazione del nodo ma ancora non funziona...

  3. #3
    Ancora una volta mi rispondo da solo...
    Posto di modo che i posteri possano trovare facilmente la risposta.

    Il file json era da cambiare in quanto l'esempio del diagramma alluvial postato in precedenza accetta un'altro tipo di configurazione dell'oggetto, in particolare una cosa di questo tipo:
    codice:
    {
        "times":[
                    [
                        {
                            "id":0,
                            "nodeName":"Node 0",
                            "nodeValue":1.6540751387365162,
                            "incoming":[]
                        },
                        {
                            "id":1,
                            "nodeName":"Node 1",
                            "nodeValue":9.454112163744867,
                            "incoming":[]
                        },
                        {
                            "id":2,
                            "nodeName":"Node 2",
                            "nodeValue":1.1586284558288753,
                            "incoming":[]
                        },
    
                    [... altri array di oggetti che specificano l'id e il nome del nodo oltrechè la grandezza totale che dovrà avere graficamente ...]
    
                    ]
        ],
        "links":[
                    {
                        "source":0,
                        "target":12,
                        "value":0.43196107650089643
                    },
                    {
                        "source":0,
                        "target":11,
                        "value":1.2221140622356197
                    },
                    {
                        "source":1,
                        "target":8,
                        "value":4.204383976379911
                    },
    
                    [... altri oggetti che specificano l'id del nodo da cui parte il collegamento e l'id del nodo sul quale finisce oltrechè la grandezza della linea di collegamento ...]
    
        ]
    }
    L'array "times" quindi contiene la descrizione dei nodi, mentre l'array "link" contiene la descrizione dei collegamenti tra nodo e nodo.
    Il valore della grandezza del nodo nell'array "times" deve essere uguale alla somma dei valori di grandezza dei collegamenti che partono od arrivano al nodo stesso: questo vuol dire, ad esempio, che il valore "nodeValue" del nodo che ha "id" = 0 deve essere uguale alla somma dei valori dell'array "link" dei nodi che hanno "source" = 0.

    Nell'esempio specifico quindi:
    1.6540751387365162 = 0.43196107650089643 + 1.2221140622356197
    perchè ci sono solo due collegamenti che partono dal nodo con "id" = 0



    Per leggere tale json basterà fare quanto segue usando jQuery e quindi ricordandosi di importare l'apposita libreria:
    codice:
                $.ajax({
                    url: 'mioJson.json',
                    async: false,
                    dataType: 'json',
                    success: function (data) {
                        /* Process Data */
    
                    [... qui aggiungere tutta la parte che va da "Process Data" fino alla fine dello script postato nel precedente post, poi basta chiudere la funzione ajax di jQuery ...]
    
                    }
                });
    In pratica ho eliminato tutta la parte in cui lo script precedente si creava i valori casuali.

    A questo punto basta creare un programma, anche in PHP, che crea il json dai dati del database.

    Magari per creare il json ci sono metodi più furbi, ma al momento non me ne vengono in mente altri...

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.