9

Utilizzando l'API di visualizzazione di Google, utilizzo google.visualization.data.group per creare tabelle secondarie in base ai miei dati non elaborati. I miei dati grezzi utilizzano il trucco di {v: "US", f: "Stati Uniti"} per visualizzare qualcosa di diverso dal valore, ma quando utilizzo la funzione di aggregazione, la formattazione viene eliminata lasciando solo la parte "Stati Uniti".Conserva la formattazione utilizzando il gruppo per aggregazione nell'API di visualizzazione di Google

C'è un modo per mantenere la formattazione originale o un modo semplice per aggiungerlo nuovamente ai DataTable creati utilizzando l'aggregazione di gruppo?

dati del campione:

[2010, {v:"MA", f:"Morocco"}, {v:"002", f:"Africa"}, {v:"002", f:"Northern Africa"}, 21.12724], 
[2010, {v:"AW", f:"Aruba"}, {v:"019", f:"Americas "}, {v:"019", f:"Caribbean"}, 0.98], 
[2010, {v:"AF", f:"Afghanistan"}, {v:"142", f:"Asia"}, {v:"142", f:"Southern Asia"}, 0.9861], 
[2010, {v:"AO", f:"Angola"}, {v:"002", f:"Africa"}, {v:"002", f:"Middle Africa"}, 5.11774], 

aggregazione Funzione:

var countryData = google.visualization.data.group(
    rawData, 
    [0, 1], 
    [{'column': 4, 'aggregation': google.visualization.data.sum, 'type': 'number'}] 
); 

Edit:

Su ulteriore riflessione, è probabilmente impossibile gruppo con il formato poiché non v'è alcuna garanzia che il formato per ogni valore sarà coerente. Con questo in mente, probabilmente è meglio (o solo possibile) scrivere una funzione che aggiungerà i formati a ciascuna colonna dei miei dati. Quindi la domanda diventa: "Come diavolo faccio?"

Preferisco davvero non creare i miei dati non elaborati come valori non formattati da solo, e quindi tabelle aggiuntive per cercare i formati per ogni valore. Ciò richiederebbe due tabelle aggiuntive (una per le regioni che è di 28 righe, una per i paesi che supera le 240 righe) e quindi la creazione di due funzioni per esaminare ciascun valore nella tabella raggruppata (che avrà più di 30 anni di dati, significa migliaia di righe) aggiungendo i valori.

Sembra una soluzione davvero complessa.

C'è un modo per farlo con le funzioni di modifica? Posso scrivere una funzione per restituire ogni valore nella tabella come un oggetto formattato {v: "US", f: "Stati Uniti"}? O c'è un modo semplice per scrivere un formattatore di colonne che cercherà il valore appropriato nella mia tabella originale e adotterà quel formato? Quale causerebbe il minimo mal di testa sia per me (chi deve scriverlo), sia per gli utenti (che devono caricarlo)?

EDIT 2:

Sembra che dovrei essere in grado di creare un formattatore per la nuova tabella utilizzando qualcosa di simile:

function (dt, row) { 
    return { 
     v: (dt.getValue(row, 1)/1000000), 
     f: (dt.getValue(row, 1)/1000000) + 'M' 
    } 
} 

Ma il problema diventa quello dal momento che non sto trattando con il numero formati, dovrei creare una sorta di tabella di ricerca che prenderà il valore, cercarlo in una tabella di ricerca e quindi restituire il formato appropriato. Sembra anche che possa dover scorrere l'intera tabella, riga per riga, che è migliaia di righe.

Non riesco a immaginare che non ci sia un modo semplice per farlo senza un ciclo di forza bruta e l'assegnazione di valori.

EDIT 3:

Così ho provato qualcosa di complicato. Anziché impostare ogni riga come valore/formato, ho creato la parte valore/formato come una stringa, quindi, dopo il raggruppamento, ho utilizzato eval() per valutare gli oggetti. Questo ha funzionato alla grande.Ecco i dati:

[2010, "{v: 'MA', f: 'Morocco'}", 21.13], 
[2010, "{v: 'AW', f: 'Aruba'}", 0.98], 
[2010, "{v: 'AF', f: 'Afghanistan'}", 0.99], 
[2010, "{v: 'AO', f: 'Angola'}", 5.12], 

Ecco il nuovo codice:

var countryCount = countryData.getColumnRange(0).count; 

    for (var i = 0; i <= countryCount; i++) { 
    countryData.setValue(i, 1, eval('(' + countryData.getValue(i,1) + ')')); 
    }; 

Il problema è che quando l'uscita ad un Google DataTable, mostra {v: 'AE', f: ' Emirati Arabi Uniti} nonostante il fatto che il controllo del risultato con eval correttamente mi dà:

>>> eval('(' + countryData.getValue(i,1) + ')') 
Object v="AE" f="United Arab Emirates" 

Così che cosa sto facendo male qui?

risposta

1

Mi sono imbattuto in questo problema. Ho deciso di utilizzare un modificatore per modificare il valore sul valore formattato utilizzando il dataTable originale per trovare i valori formattati. Questo non è terribilmente efficiente, ma funziona e i computer sono veloci.

Innanzitutto creare una funzione di ricerca:

function getFormatForValue(dataTable, column, value) { 

    // we need to spin through column in the dataTable looking 
    // for the matching value and then return the formatted value 
    var rowcount = dataTable.getNumberOfRows(); 
    for (var i=0; i<rowcount; i++) { 
     if (dataTable.getValue(i, column) === value) { 

      // we found it, this will look much better 
      return dataTable.getFormattedValue(i, column);  
     } 
    } 

    // better than nothing 
    return value; 
} 

quindi chiamare che in un modificatore, cambiare la chiamata di gruppo originale:

var countryData = google.visualization.data.group(
    rawData, 
    [ 
    { 
     'column': 0, 
     'modifier': function(value) { return getFormatForValue(rawData, 0, value); }, 
     'type': 'string' 
    }, 
    { 
     'column': 1, 
     'modifier': function(value) { return getFormatForValue(rawData, 1, value); }, 
     'type': 'string' 
    } 
    ], 
    [{'column': 4, 'aggregation': google.visualization.data.sum, 'type': 'number'}] 
); 

Aggiornamento: Sembra che è necessario il valore e il valore formattato conservato. Nel mio caso di visualizzazione di grafici a torta, non mi interessa conservare il valore originale. Immagino che questo non funzioni per te, ma lascerò qui questa risposta per altri che potrebbero avere un caso più semplice come il mio.

Ho dedicato qualche minuto in più e qui è un'alternativa che copierà il valore formattato mantenendo il valore della cella originale.

Creare una funzione di copia che utilizza la funzione di ricerca:

function copyFormattedValues(oldDataTable, oldColumn, newDataTable, newColumn) { 

    var rowcount = newDataTable.getNumberOfRows(); 
    for (var i=0; i<rowcount; i++) { 
     var value = newDataTable.getValue(i, newColumn); 
     var formatted = getFormatForValue(oldDataTable, oldColumn, value); 
     newDataTable.setFormattedValue(i, newColumn, formatted); 
    } 

} 

Quindi nel tuo caso, lo chiamano una volta per ogni colonna che si desidera copiare.

copyFormattedValues(rawData, 0, countryData, 0); 
copyFormattedValues(rawData, 1, countryData, 1); 

Le colonne di origine e di destinazione sono le stesse ma in alcuni casi possono essere diverse.

Naturalmente, idealmente tutto ciò sarebbe successo automaticamente.

4

Ok, ho capito questo fuori (quanto era odiosamente complesso).

Ho provato un nuovo approccio. Ho riformattato i miei dati e poi ho creato una funzione per restituire un valore/formato basato su un divisore all'interno di quella stringa. Così i miei dati sembra ora così:

[2010, "'MA'|'Morocco'", 21.13], 
[2010, "'AW'|'Aruba'", 0.98], 
[2010, "'AF'|'Afghanistan'", 0.99], 
[2010, "'AO'|'Angola'", 5.12], 

allora io uso questo per ottenere la posizione di divisione per la colonna 1:

var countryCount = countryData.getNumberOfRows(); 

for (var i = 0; i <= countryCount; i++) { 
    var stringToSplit = countryData.getValue(i,1); 
    var dividerLocation = stringToSplit.indexOf("|"); 
    alert("Divider: " + dividerLocation + ", String: " + stringToSplit); 
    countryData.setValue(i, 1, splitFormat(dividerLocation, stringToSplit)); 
}; 

E poi ho utilizzare questa funzione per dividere la stringa:

function splitFormat(dividerLocation, stringToSplit) { 
    // alert("entered splitFormat Function"); 
    var stringValue = ""; 
    var formatValue = ""; 
    stringValue = stringToSplit.substring(0, dividerLocation); 
    formatValue = stringToSplit.substring(dividerLocation + 1) 
    alert("v: " + stringValue + ", f: " + formatValue); 
    return { 
     v: stringValue, 
     f: formatValue 
    } 
     } 

Il problema è che sto definendo la colonna 1 dei miei dati come "stringa", ma firebug mi sta dicendo che l'oggetto restituito dalla funzione splitFormat() è un oggetto (poiché suppongo sia un array). Anche se ho impostato il datatable originale con av: ef: componente, non vuole accettare un valore di oggetto matrice restituita, come Firebug mi dà il seguente oh-così-consigli utili:

"Error: Type mismatch. Value [object Object] does not match type string in column index 1 (table.I.js,137)" 

La questione è che mentre è possibile definire un DataTable utilizzando la sintassi {v:, f:}, non è possibile restituire la sintassi alla tabella perché il valore per quella colonna è impostato come stringa. Invece ho usato la proprietà "setFormattedValue" della DataTable per risolvere il problema:

function drawVisualization() { 
    var countryTable = new google.visualization.Table(document.getElementById('table')); 

    var countryCount = countryData.getNumberOfRows() - 1; 

    for (var i = 0; i <= countryCount; i++) { 
     var stringToSplit = countryData.getValue(i,1); 
     var dividerLocation = stringToSplit.indexOf("|"); 
     var stringValue = stringToSplit.substring(0, dividerLocation); 
     var stringFormat = stringToSplit.substring(dividerLocation + 1); 
     countryData.setValue(i, 1, stringValue); 
     countryData.setFormattedValue(i, 1, stringFormat); 
    }; 

Questa correttamente mi ha dato i valori appropriati per entrambi, anche se è un po 'intensivo per grandi insiemi di dati. Se qualcuno sa di un modo più semplice per farlo, sarei più che felice di sentirlo.