Тепловая карта, основанная на средних весах, а не на количестве точек данных

Я делаю плакат с Google API v3. Я приведу пример. Давайте рассмотрим величины землетрясений. Я назначаю веса каждой точке, чтобы указать их величину. Однако Google учитывает плотность точек при уменьшении масштаба. Чем больше очков в месте, тем более красным оно становится. Например, если два earthqueaks произошли в милях друг от друга, один с магнитудой 3, а другие с магнитудой 8, первый один должен быть зеленым/синим цветом, а второй один будет красным. Но как только вы уменьшаете масштаб, и две точки становятся ближе к карте, карты google учитывают количество точек вместо весов, и в результате они выглядят считанными. Я хочу, чтобы он был средним, т.е. (3 + 8)/2=5.5... любым цветом, который представляет. Это возможно?

Ответы

Ответ 1

Вы можете сделать это, наложив изображение тепловой карты на карту. Там очень хороший пример с открытым исходным кодом в https://github.com/jeffkaufman/apartment_prices

Ответ 2

Если вы похожи на меня и у вас нет времени на обработку или мощности для создания оверлея, существует несколько достойное решение, и вы не можете изменять существующие библиотеки по своему вкусу.

Я использовал библиотеку Heatmap карт google и установил maxIntensity и рассеивался на false. Установка maxIntensity на выбранное вами значение решит проблему того, что ваши точки нагрева будут окрашены по отношению друг к другу, а не к 0 или заданному значению. При настройке параметра disipating to false вы можете отключить параметры автоматического радиуса, которые происходят при изменении уровней масштабирования.

Далее я сделал событие для каждого изменения уровня масштабирования, и в этом случае я установил радиус в значение, которое, казалось, представляло мои данные самым точным способом для этого уровня масштабирования.

Теперь, чтобы избавиться от проблемы, когда точки данных на карте смешиваются и объединяются в большой красный блок, я решил сделать отдельную сетку на моей карте для каждого уровня масштабирования, который я хочу использовать. Я усредняю ​​все значения, которые помещаются внутри одной и той же точки сетки, и убедитесь, что сетка достаточно велика, чтобы точки точек нагрева не перекрывались, но достаточно мала, чтобы не выглядеть как куча кругов. (Я обнаружил, что сетка должна быть примерно в 0,4 раза больше радиуса теплоты на карте для гладкого внешнего вида).

Радиус точки Heatmap задается Google в пикселях. Я не знал, как преобразовать пиксели в Lat/Long, поэтому я просто измерил его, вычерчивая линии за круг с определенным радиусом и измеряя расстояние между этими линиями. Этот метод конвертации будет работать очень хорошо, если вы не планируете отображать гораздо больше, чем небольшая страна.

Производительность - это не так плохо, как я думал. Я загружаю около 2300 точек, а карта загружается так же быстро, как и до того, как я сделал сетку для каждого уровня масштабирования, и вы фактически не видите, что обновленные точки данных обновляются при изменении уровней масштабирования.

Вот некоторые фрагменты кода для всего вышеперечисленного:

Настройки карты:

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

Измените сетку и радиус для каждого уровня масштабирования:

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);
        }
    }
});

Мои сетки генерируются в PHP, которые, вероятно, будут выглядеть разными для всех, но, как пример, здесь используется функция:

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;
}

К сожалению, я не могу отобразить карту прямо сейчас, поскольку она в настоящее время остается конфиденциальной для клиентов компании, в которой я работаю, но если она станет доступна публично, я добавлю ссылку, чтобы вы могли видеть, насколько хорошо этот метод работает.

Надеюсь, это поможет кому-то.

Лукаса

Ответ 3

Тепловая карта по определению рассматривает плотность точек, а также вес, присвоенный каждой точке. Насколько я знаю из-за работы с ними, по крайней мере, Google Heat Map работает так. Так что вам действительно нужна не карта тепла, а карта точек, в которой они будут окрашены в зависимости от значения.

Мне также нужно было изменить плотность/вес отношения, которые учитывают диаграммы Google, чтобы окрасить карту, но я не нашел никакого способа. В настоящее время основным фактором тепловой карты является плотность, а изменение веса мало влияет на цвет.

Ответ 4

Как частичное решение, я изменил heatmap.js из следующего проекта: https://github.com/pa7/heatmap.js

Чтобы получить среднее значение в одной длинной/лат-точке, я изменил функцию _organiseData для хранения PointCount и PointSum для каждой позиции x, y; и с этими значениями я получаю среднее значение в точке с:

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

Я все еще работаю над тем, как модифицировать "blend", когда несколько x, y coords стека при различных разрешениях карты... Если я выясню это, я опубликую его.

веселит

~ Аарон