Método de localización de instalaciones utilizando mapas de calor (Google Maps + Javascript)
Google Maps (Javascript)
Mucho se ha desarrollado en la literatura académica acerca de los métodos o algoritmos de localización de instalaciones. En el estudio de localización se pueden abordar dos grandes aspectos: macrolocalización y microlocalización. En ambos casos el procedimiento de análisis de localización abordará las fases de:
- Análisis preliminar
- Búsqueda de alternativas de localización
- Evaluación de alternativas
- Selección de localización
Microlocalización: Es decir, la selección específica del sitio o terreno que se encuentra en la región que ha sido evaluada como la más conveniente.
Algunos de los algoritmos que apoyan las fases del procedimiento de localización, presentan dificultades propias del contexto operacional real que se pretende abordar. Por ejemplo, el Método de Centro de Gravedad, requiere de la consideración de un conjunto de instalaciones existentes, y su objetivo es el de establecer la ubicación de un punto de servicio / atención / suministro para los puntos dados. Requiere para ello de la existencia de un sistema de coordenadas con un punto de origen.
Recuerdo que cuando utilicé este algoritmo en la Universidad utilizamos la copia de un mapa de la región, sobre ella trazamos un plano cartesiano, definimos las ubicaciones del caso, registramos las coordenadas y como resultado obtuvimos las coordenadas de la localización ideal. La dificultad subyace en la falta de practicidad.
Otro método, como el Heurístico de Ardalan, utiliza un conjunto de instalaciones existentes, y un conjunto de localizaciones tentativas. Toma como base una matriz de distancias y el objetivo consiste en optimizar la cobertura. Sin embargo, obtener la información requiere del levantamiento de mínimo una matriz n * m. En la medida en la que el número de ubicaciones aumenta el algoritmo se convierte en complejo.
Desde hace algunos años, la disponibilidad de servidores de aplicaciones de mapas, los sistemas de posicionamiento satelital, los sistemas de información geográfica, entre otros; han facilitado la adopción de soluciones basadas en entornos reales, como herramientas que apoyen algunas de las fases del procedimiento de localización de ubicaciones.
En este artículo utilizaremos mapas de calor y servidores de aplicaciones de mapas, como herramienta visual de soporte en los procesos de selección de localizaciones.
¿Qué es un mapa de calor?
En este contexto, un mapa de calor es una capa de visualización que se utiliza para representar la intensidad de los datos en puntos geográficos (ubicaciones). Cuando la capa de mapa de calor se encuentra habilitada, aparecerá una superposición de color en la parte superior del mapa. De forma predeterminada (es un estándar), las áreas de mayor intensidad se colorearán en rojo y las áreas de menor intensidad aparecerán en verde.
La intensidad de los datos de una región en particular puede aumentar dada la concentración de ubicaciones en una zona específica. Del mismo modo, pueden utilizarse puntos de datos ponderados, es decir, que un punto geográfico en particular puede tener un peso que hará que el punto se represente con mayor intensidad.
Un ejemplo de aplicación práctica de los puntos de datos ponderados, puede ser la cantidad de individuos que vivan en un punto específico. En este caso, los puntos ponderados ayudarán a representar densidad poblacional.
Mapas de calor + Google Maps
El servidor de aplicaciones de mapas más popular del mundo: Google Maps, cuenta con una librería de visualización que nos permite el uso de mapas de calor con puntos normales o ponderados. Evaluaremos su uso por medio de un caso práctico.
El Departamento de Desarrollo Sostenible de la ciudad de Cali se encuentra implementando una estrategia piloto de recolección de aceite de cocina usado. Ha articulado este proyecto con una Universidad, la cual desarrolló 4 contenedores inteligentes (BIN’s) para la disposición del bioresiduo. En investigaciones asociadas, la Universidad ha determinado que el reciclaje del aceite es un problema de densidad; esto quiere decir que es vital la ubicación de los contenedores (cobertura), para así mismo optimizar el proceso de disposición y recolección. El proyecto piloto piensa articular a las instituciones de educación como puntos potenciales de recolección. Por medio de las instituciones piensan socializar el programa con la comunidad. El primer reto del proyecto consiste en determinar la ubicación de los contenedores inteligentes (4 unidades). La información relacionada con las instituciones de educación que hacen parte del programa (ubicación geográfica / población estudiantil), se detalla a continuación:
Establecimiento | Latitud / Longitud | Número de estudiantes |
Comfandi San Nicolás | 3.4535911182, -76.522548858 | 1494 |
Mayor de Santiago de Cali | 3.4515777580, -76.510232156 | 908 |
Municipal Comfandi | 3.4481079145, -76.510747140 | 697 |
Internado San Carlos | 3.4469941349, -76.515253250 | 1714 |
León de Greiff | 3.4479794015, -76.499932474 | 1731 |
Nuestra Señora de la Anunciación | 3.4451521118, -76.496413416 | 2297 |
Fernando de Aragón | 3.4373556029, -76.513837044 | 1265 |
Casa Evangélica | 3.4379553366, -76.522999470 | 1658 |
San Alberto Magno | 3.4330289411, -76.527076427 | 604 |
Santa María Goretty | 3.4334144860, -76.507206624 | 416 |
San Alberto Magno | 3.4331574561, -76.526733104 | 1584 |
San Ignacio de Loyola | 3.4317866287, -76.517334644 | 2350 |
Nuestro Futuro | 3.4306299916, -76.503601735 | 964 |
Sabio Caldas | 3.4290878065, -76.516605083 | 329 |
CREAD | 3.4250609784, -76.514888470 | 774 |
Licomtec | 3.4166645586, -76.516733829 | 1818 |
Nuestra Señora De La Providencia | 3.4195347715, -76.495919889 | 1530 |
Real Suizo | 3.4152080294, -76.493237680 | 2106 |
Nuevo Edén | 3.4157220988, -76.533835594 | 330 |
Católico | 3.4130660706, -76.539843742 | 976 |
Santa María Stella | 3.4270315559, -76.551345054 | 1975 |
Santa Isabel | 3.4080535495, -76.508172225 | 936 |
Compartir | 3.4319576632, -76.474955752 | 1563 |
Lancaster | 3.4007708157, -76.551774213 | 1219 |
Parroquial Divino Salvador | 3.3970865884, -76.542590328 | 1954 |
Reyes Católicos | 3.3933166668, -76.537354656 | 399 |
Liceo Anglo del Valle | 3.3873187189, -76.519759374 | 1741 |
Laurence | 3.3834202377, -76.520789343 | 1111 |
Los Almendros | 3.3812782083, -76.520231443 | 1826 |
Bautista | 3.3772083395, -76.523278432 | 1772 |
Lacordaire | 3.3781508370, -76.544607357 | 1965 |
General José María Córdoba | 3.3935733137, -76.549328047 | 841 |
El Hogar | 3.3907458636, -76.550315100 | 770 |
Americano | 3.3790932549, -76.546881873 | 650 |
Santa Filomena | 3.4019699352, -76.513450821 | 1401 |
Tomás Vasconi | 3.4030409276, -76.517313202 | 1474 |
República del Salvador | 3.4044546356, -76.521433075 | 1926 |
Los Andes | 3.4296010767, -76.537612160 | 1566 |
Villacolombia | 3.4454939428, -76.501692020 | 2354 |
Las Américas | 3.4492208216, -76.505940638 | 2043 |
Santa Fe | 3.4422382667, -76.509888850 | 2333 |
Evaristo García | 3.4407817764, -76.517527780 | 696 |
Alfredo Vásquez Cobo | 3.4355983661, -76.516454898 | 1073 |
Ciudad de Cali | 3.4311431813, -76.512721263 | 1275 |
INEM | 3.4827619907, -76.4997608303 | 1485 |
Olaya Herrera | 3.4781785185, -76.512807093 | 1470 |
Guillermo Valencia | 3.4744945902, -76.513665400 | 1248 |
José Ignacio Rengifo | 3.4716245430, -76.513665400 | 2160 |
Santo Tomás | 3.4583022697, -76.516454898 | 1776 |
La Merced | 3.4627144903, -76.502464496 | 706 |
Pedro Antonio Molina | 3.4828048267, -76.487615789 | 2369 |
Santa Librada | 3.4622861203, -76.523020945 | 2498 |
República de Israel | 3.4636569037, -76.510532580 | 1510 |
San Vicente Paul | 3.4662271172, -76.509502612 | 2330 |
Manuel María Mallarino | 3.4567601292, -76.488517010 | 1464 |
Sebastián de Belalcázar | 3.4602299411, -76.485212529 | 628 |
Liceo Departamental | 3.4238604624, -76.538556302 | 364 |
Libardo Madrid | 3.4220611537, -76.543834890 | 2439 |
Metropolitano Santa Anita | 3.4016910381, -76.542182651 | 1815 |
San José | 3.3969358164, -76.550315108 | 2230 |
De acuerdo a la información disponible, es posible utilizar un mapa de calor como herramienta de análisis preliminar y búsqueda de alternativas de localización. Veamos.
Agregar una capa de mapa de calor
La API de Google Maps puede utilizarse de la misma manera en la que un sitio web incorpora un mapa tradicional a su plataforma (Javascript). También pueden utilizarse plataformas externas para su visualización como JSFiddle.
Lo primero que haremos es configurar el mapa sobre el cual se ubicarán los puntos:
let map, heatmap;
function initMap() {
map = new google.maps.Map(document.getElementById("map"), {
zoom: 13,
center: { lat: 3.43, lng: -76.51 },
mapTypeId: "satellite",
});
heatmap = new google.maps.visualization.HeatmapLayer({
data: getPoints(),
map: map,
});
document
.getElementById("toggle-heatmap")
.addEventListener("click", toggleHeatmap);
document
.getElementById("change-gradient")
.addEventListener("click", changeGradient);
document
.getElementById("change-opacity")
.addEventListener("click", changeOpacity);
document
.getElementById("change-radius")
.addEventListener("click", changeRadius);
}
zoom: Indicará el nivel de cercanía inicial del mapa de acuerdo a su centro. De igual forma, como usuarios podemos utilizar los controles para acercar o alejar una vez tengamos la visualización.
center: Indicará las coordenadas centrales del mapa (latitud y longitud). En nuestro ejemplo hemos adicionado las coordenadas de la ciudad de Cali (lat: 3.43, lng: -76.51).
mapTypeId: Tipo de mapa a utilizar. Podemos elegir un mapa tipo relieve o un mapa satelital (satellite).
En este mapa utilizaremos algunas funciones que nos permitirán cambiar algunos atributos de visualización: degradado, opacidad, radio de calor.
gradient: Corresponde al degradado de color del mapa de calor, de manera predeterminada degradará desde el rojo (máxima intensidad) hacia el verde. Sin embargo, usted puede configurar la matriz de colores del degradado. En nuestro ejemplo, permitiremos que el usuario haga un cambio en la configuración del degradado con un clic.
opacity: La opacidad corresponde a la transparencia de la capa del mapa de calor, expresada como un número entre 0 y 1. En nuestro ejemplo, permitiremos que el usuario haga un cambio en la configuración de la opacidad con un clic.
radius: Corresponde al radio de influencia de cada punto de datos, en píxeles. Este es uno de los atributos más importantes del mapa de calor, ya que a partir de su valor podremos visualizar mejor o no, la data correspondiente. En nuestro ejemplo, permitiremos que el usuario haga un cambio en la configuración del radio con un clic.
Cambio de atributos
Las siguientes líneas permitirán cambiar los atributos ya mencionados con un solo clic. A continuación se establecen los valores opcionales de cada atributo.
function toggleHeatmap() {
heatmap.setMap(heatmap.getMap() ? null : map);
}
function changeGradient() {
const gradient = [
"rgba(0, 255, 255, 0)",
"rgba(0, 255, 255, 1)",
"rgba(0, 191, 255, 1)",
"rgba(0, 127, 255, 1)",
"rgba(0, 63, 255, 1)",
"rgba(0, 0, 255, 1)",
"rgba(0, 0, 223, 1)",
"rgba(0, 0, 191, 1)",
"rgba(0, 0, 159, 1)",
"rgba(0, 0, 127, 1)",
"rgba(63, 0, 91, 1)",
"rgba(127, 0, 63, 1)",
"rgba(191, 0, 31, 1)",
"rgba(255, 0, 0, 1)",
];
heatmap.set("gradient", heatmap.get("gradient") ? null : gradient);
}
function changeRadius() {
heatmap.set("radius", heatmap.get("radius") ? null : 20);
}
function changeOpacity() {
heatmap.set("opacity", heatmap.get("opacity") ? null : 5);
}
Data de entrada: Ubicaciones
A continuación se ingresarán las 50 ubicaciones de nuestro caso de ejemplo. Utilizaremos puntos ponderados, con coordenadas de latitud y longitud, y un peso determinado por la población estudiantil de cada punto.
function getPoints() {
return [
{location: new google.maps.LatLng(3.453591118286918, -76.52254885881977), weight: 1494},
{location: new google.maps.LatLng(3.451577758085148, -76.51023215602375), weight: 908},
{location: new google.maps.LatLng(3.4481079145332427, -76.51074714011278), weight: 697},
{location: new google.maps.LatLng(3.4469941349057063, -76.51525325089182), weight: 1714},
{location: new google.maps.LatLng(3.4479794015658674, -76.49993247424311), weight: 1731},
{location: new google.maps.LatLng(3.4451521118907227, -76.49641341630138), weight: 2297},
{location: new google.maps.LatLng(3.4373556029276764, -76.51383704461735), weight: 1265},
{location: new google.maps.LatLng(3.4379553366684252, -76.52299947000571), weight: 1658},
{location: new google.maps.LatLng(3.4330289411959662, -76.52707642704613), weight: 604},
{location: new google.maps.LatLng(3.4334144860421287, -76.50720662416609), weight: 416},
{location: new google.maps.LatLng(3.433157456127054, -76.52673310420856), weight: 1584},
{location: new google.maps.LatLng(3.431786628745183, -76.51733464458373), weight: 2350},
{location: new google.maps.LatLng(3.4306299916118603, -76.50360173554287), weight: 964},
{location: new google.maps.LatLng(3.4290878065901618, -76.51660508379094), weight: 329},
{location: new google.maps.LatLng(3.4250609784210844, -76.51488847016083), weight: 774},
{location: new google.maps.LatLng(3.4166645586142086, -76.51673382932174), weight: 1818},
{location: new google.maps.LatLng(3.419534771537968, -76.49591988905668), weight: 1530},
{location: new google.maps.LatLng(3.41520802942298, -76.493237680305), weight: 2106},
{location: new google.maps.LatLng(3.4157220988351096, -76.53383559476927), weight: 330},
{location: new google.maps.LatLng(3.4130660706512925, -76.53984374247463), weight: 976},
{location: new google.maps.LatLng(3.427031555952873, -76.55134505496746), weight: 1975},
{location: new google.maps.LatLng(3.408053549563415, -76.50817222583817), weight: 936},
{location: new google.maps.LatLng(3.431957663249241, -76.47495575209557), weight: 1563},
{location: new google.maps.LatLng(3.400770815705138, -76.55177421321405), weight: 1219},
{location: new google.maps.LatLng(3.3970865884759056, -76.54259032842468), weight: 1954},
{location: new google.maps.LatLng(3.393316666803048, -76.53735465673438), weight: 399},
{location: new google.maps.LatLng(3.387318718983735, -76.5197593748766), weight: 1741},
{location: new google.maps.LatLng(3.3834202377137204, -76.52078934305466), weight: 1111},
{location: new google.maps.LatLng(3.381278208361199, -76.52023144362487), weight: 1826},
{location: new google.maps.LatLng(3.377208339558826, -76.52327843281832), weight: 1772},
{location: new google.maps.LatLng(3.378150837005705, -76.54460735730136), weight: 1965},
{location: new google.maps.LatLng(3.3935733137749238, -76.54932804783431), weight: 841},
{location: new google.maps.LatLng(3.390745863684127, -76.55031510067163), weight: 770},
{location: new google.maps.LatLng(3.3790932549330677, -76.54688187341141), weight: 650},
{location: new google.maps.LatLng(3.4019699352880104, -76.51345082175563), weight: 1401},
{location: new google.maps.LatLng(3.4030409276299833, -76.51731320242338), weight: 1474},
{location: new google.maps.LatLng(3.4044546356985284, -76.52143307513562), weight: 1926},
{location: new google.maps.LatLng(3.429601076750566, -76.53761216054455), weight: 1566},
{location: new google.maps.LatLng(3.4454939428890783, -76.5016920200071), weight: 2354},
{location: new google.maps.LatLng(3.4492208216317457, -76.50594063874162), weight: 2043},
{location: new google.maps.LatLng(3.4422382667554077, -76.50988885009086), weight: 2333},
{location: new google.maps.LatLng(3.4407817764607853, -76.51752778074483), weight: 696},
{location: new google.maps.LatLng(3.435598366122187, -76.51645489840418), weight: 1073},
{location: new google.maps.LatLng(3.431143181324255, -76.51272126375868), weight: 1275},
{location: new google.maps.LatLng(3.48276199070547, -76.49976083030087), weight: 1485},
{location: new google.maps.LatLng(3.4781785185724408, -76.51280709388969), weight: 1470},
{location: new google.maps.LatLng(3.474494590235007, -76.51366540070475), weight: 1248},
{location: new google.maps.LatLng(3.47162454307462, -76.51366540070475), weight: 2160},
{location: new google.maps.LatLng(3.458302269741842, -76.51645489800703), weight: 1776},
{location: new google.maps.LatLng(3.4627144903470133, -76.50246449692165), weight: 706},
{location: new google.maps.LatLng(3.4828048267502214, -76.48761578902122), weight: 2369},
{location: new google.maps.LatLng(3.4622861203152, -76.52302094514219), weight: 2498},
{location: new google.maps.LatLng(3.4636569037348472, -76.51053258098315), weight: 1510},
{location: new google.maps.LatLng(3.4662271172959103, -76.5095026128051), weight: 2330},
{location: new google.maps.LatLng(3.4567601292443983, -76.4885170108912), weight: 1464},
{location: new google.maps.LatLng(3.460229941169211, -76.48521252965324), weight: 628},
{location: new google.maps.LatLng(3.423860462402868, -76.53855630259389), weight: 364},
{location: new google.maps.LatLng(3.422061153775949, -76.54383489070575), weight: 2439},
{location: new google.maps.LatLng(3.4016910381681438, -76.54218265181241), weight: 1815},
{location: new google.maps.LatLng(3.396935816423716, -76.55031510890593), weight: 2230},
];
}
A partir de estas configuraciones y data de entrada, podemos obtener un mapa de calor soportado en Google Maps. Podemos ver este ejemplo en: Mapa de calor Google Maps Ejemplo.
El resultado será:
Podemos ocultar o visualizar la capa del mapa de calor; cambiar los colores del degradado; cambar el radio de intensidad de cada punto ponderado; y por último, cambiar la transparencia de la capa.
Así mismo, podemos considerar, por ejemplo, que la representación visual se encuentra muy dispersa y no nos permite tener una idea concluyente. Podemos intentar ampliando el radio (radius) de cada punto (en el código directamente), es decir, su influencia. De manera que nos permita una visualización con mayor densidad. Ampliando a 70 píxeles el radio del código anterior, tendríamos:
A partir de esta imagen los tomadores de decisiones pueden tener una idea aproximada respecto a las zonas geográficas de mayor densidad poblacional. Al contrario de los algoritmos tradicionales, no obtendremos una coordenada específica (que probablemente conduzca a un lugar inhabitable o no disponible); tendremos zonas de densidad basadas en la ponderación deseada.
Podemos ampliar el zoom sobre una zona deseada y conocer los puntos específicos (con su intensidad respectiva):
Aquí podemos ver con claridad la diferencia del peso ponderado de los puntos; aquellos puntos más intensos serán aquellas instituciones educativas con mayor población estudiantil (de acuerdo a nuestro caso). Podemos incluso, haciendo uso del registro de imágenes en campo de Google, revisar un sector en específico; revisar el estado de las vías, revisar si existen unidades habitables, entre otros:
Tal como lo hemos mencionado, los mapas de calor son no nos proporcionan como resultado una localización específica; nos proporcionan una visión de densidad basada en un factor de ponderación establecido. Además, es una herramienta dinámica, la cual puede integrarse con fuentes de datos diversas, que puede manipularse en un entorno geográfico real.
Es una herramienta que recomendamos para el análisis preliminar y la búsqueda de zonas de localización.
Sin embargo, al utilizar mapas de calor en entornos como por ejemplo Python, podemos integrar a esta herramienta, un método heurístico que nos proporcione una localización específica. Si quieres conocer un modelo que integra ambas herramientas, te invitamos a leer: Mapas de calor y Algoritmo de Centro de Gravedad utilizando Python.