2013-01-22 4 views
12

Sto facendo una heatmap con l'API di Google v3. Darò un esempio. Consideriamo le grandezze dei terremoti. Assegno pesi ad ogni punto per specificare la loro grandezza. Tuttavia, Google considera la densità dei punti quando si riduce lo zoom. Più punti ci sono in un posto, più diventa rosso. Per esempio, se due earthqueaks sono avvenuti a chilometri l'uno dall'altro, uno con magnitudo 3 e un altro con magnitudo 8, il primo dovrebbe essere verde/blu e il secondo rosso. Ma una volta che si rimpicciolisce e si avvicinano i due punti nella mappa, google maps considera il numero di punti invece dei pesi e, di conseguenza, appare letto. Voglio che sia la media cioè (3 + 8) /2=5.5 ... qualunque sia il colore che rappresenta. È possibile?Heatmap basata su pesi medi e non sul numero di punti dati

risposta

2

Una mappa termica per definizione considera densità di punti, così come il peso assegnato a ciascun punto. Almeno la mappa termica di Google funziona in questo modo, per quanto ne so, lavorando con loro. Quindi quello di cui hai effettivamente bisogno non è una mappa termica ma una mappa di punti che saranno colorati in base a un valore.

Avevo anche bisogno di cambiare il rapporto densità/peso che le heatmap di Google prendono in considerazione per colorare la mappa ma non ho trovato alcun modo. Attualmente il fattore principale della heatmap è la densità e un cambiamento di peso ha un piccolo effetto sul colore.

2

Come soluzione parziale, ho modificato heatmap.js dal seguente progetto: https://github.com/pa7/heatmap.js

Per ottenere una media in un unico punto latitudine/longitudine Ho modificato la funzione _organiseData per memorizzare il PointCount e PointSum per ciascuna posizione x, y; e con questi valori ottengo la media in un punto con:

store [x] [y] = storePointSum [x] [y]/storePointCount [x] [y];

Sto ancora lavorando su come modificare il "blend" quando più x, y coords si impilano a varie risoluzioni di mappa ... Se lo capisco, lo posterò.

applausi

~ Aaron

+1

*** aggiornamento *** Appare come se il “alpha blending additivo” utilizzato è definito (e controllata) dalle specifiche html, e questo è ciò che determina fondamentalmente il colore disegnata in questo particolare calore mappa e probabilmente molti altri a causa della sua natura ad alte prestazioni. Sfortunatamente non sono stato in grado di trovare un modo per fare un "gradiente medio alfa-blend"; l'impostazione del contesto globalCompositeOperation sembrava promettente, ma sembra supportare solo le miscele tradizionali. Se qualcuno desidera esplorare ulteriormente, le due funzioni chiave per l'osservatore sono _drawAlpha e _getPointTemplate. –

3

C'è una soluzione un po 'decente se siete come me e non hanno il tempo di elaborazione o il potere di generare un overlay e non è possibile modificare le librerie esistenti i tuoi gusti

Ho usato la libreria heatmap di google maps e ho impostato maxIntensity e dissipato su false. Impostare il valore maxIntensity su un valore a tua scelta risolverà il problema dei punti heatmap che si colorano in relazione a vicenda anziché a 0 o un valore impostato. Impostando la dissolvenza su false si disabilitano le impostazioni automatiche del raggio che si verificano quando si modificano i livelli di zoom.

Successivamente ho creato un evento per ogni volta che il livello di zoom è cambiato e in tal caso ho impostato il raggio su un valore che sembrava rappresentare i miei dati nel modo più preciso per quel livello di zoom.

Ora per eliminare il problema relativo al punto in cui i punti della mappa si fondono e si sommano in un grande blob rosso, ho deciso di creare una griglia separata sulla mia mappa per ogni livello di zoom che desidero utilizzare.Ho mediato tutti i valori racchiusi all'interno dello stesso punto della griglia e mi assicuro che la griglia sia abbastanza grande da mantenere sovrapposti i punti della mappa di calore, ma abbastanza piccola da non sembrare un gruppo di cerchi. (Ho trovato che la griglia dovrebbe essere circa 0,4 volte la dimensione del raggio del punto di calore sulla mappa per un aspetto levigato).

Il raggio del punto della mappa di calore è impostato da google in pixel. Non sapevo come convertire i pixel in Lat/Long, quindi l'ho appena misurato disegnando le linee oltre un cerchio con un certo raggio e misurando la distanza tra queste linee. Quel metodo di conversione funzionerà piuttosto bene se non stai pianificando di mappare molto più di un piccolo paese.

Per quanto riguarda le prestazioni, non è così male come pensavo. Sto caricando circa 2300 punti e la mappa si carica velocemente come prima di creare una griglia per ogni livello di zoom, e in realtà non si vedono i punti di dati da aggiornare mentre si cambiano i livelli di zoom.

Ecco alcuni pezzi di codice per tutto quanto sopra:

Impostazioni della mappa:

map.heatmap.set('maxIntensity', 12000); 
map.heatmap.set('dissipating', false); 

Modifica griglia e raggio per ogni livello di zoom:

map._on({ 
    obj: map.gMap, 
    event: "zoom_changed", 
    callback: function(){ 
     var zoomLevel = map.zoom(); 
     switch(zoomLevel){ 
      case 7: 
       map.heatmap.setData(gridData[zoomLevel]); 
       map.heatmap.set('radius', 0.04); 
       break; 
      case 8: 
       map.heatmap.setData(gridData[zoomLevel]); 
       map.heatmap.set('radius', 0.03); 
       break; 
      case 9: 
       map.heatmap.setData(gridData[zoomLevel]); 
       map.heatmap.set('radius', 0.02); 
       break; 
      case 10: 
       map.heatmap.setData(gridData[zoomLevel]); 
       map.heatmap.set('radius', 0.01); 
       break; 
      case 11: 
       map.heatmap.setData(gridData[zoomLevel]); 
       map.heatmap.set('radius', 0.005); 
       break; 
      case 12: 
       map.heatmap.setData(gridData[zoomLevel]); 
       map.heatmap.set('radius', 0.0025); 
       break; 
      case 13: 
       map.heatmap.setData(gridData[zoomLevel]); 
       map.heatmap.set('radius', 0.00225); 
       break; 
      default: 
       map.heatmap.setData(gridData[zoomLevel]); 
       map.heatmap.set('radius', 0.000625); 
     } 
    } 
}); 

mie griglie sono generati in PHP che probabilmente avrà un aspetto diverso per tutti, ma solo a titolo di esempio, ecco la funzione che utilizzo:

function getHeatGrid($gridSize){ 
$mapGrid = false; 
$mapData = false; 
$radius = $gridSize * 2.8 * 0.3; //grid size is multiplied by 2.8 to convert from the heat map radius to lat/long values(works for my lat/long, maybe not yours). * 0.3 is arbitrary to avoid seeing the grid on the map. 
$string = file_get_contents("mapData.json"); 
$json_a = json_decode($string, true); 

forEach($json_a as $key => $value){ 
    $row = intval(round(($value['center_longitude']/$radius))); 
    $column = intval(round(($value['center_latitude']/$radius)/68*111)); //around 52.0;5.0 latitude needs to be scaled to make a square grid with the used longitude grid size 
    if(isset($mapGrid[$row][$column])){ 
     $mapGrid[$row][$column] = round(($value['solarValue'] + $mapGrid[$row][$column])/2); 
    } else { 
     $mapGrid[$row][$column] = $value['solarValue']; 
    } 
} 

forEach($mapGrid as $long => $array){ 
    forEach($array as $lat => $weight){ 
     $mapData[] = array(
      "center_longitude" => $long * $radius, 
      "center_latitude" => ($lat * $radius)/111*68, 
      "solarValue" => $weight 
     ); 
    } 
} 
return $mapData; 
} 

Purtroppo non sono in grado di visualizzare la mappa in questo momento come è attualmente privato per i clienti della società che io lavoro a, ma se diventa disponibile pubblicamente vorrei aggiungere un link in modo da poter vedere come questo metodo funziona .

Spero che questo aiuti qualcuno.

Lukas

Problemi correlati