Otros Mapas Georeferenciados de M????xico para Visualizaci????n

Continuando con el tema del post anterior sobre la creación de visualizaciones de mapas georeferenciados de México he hecho un par de mapas más que pueden dar buenos resultados.

Todos están basados en este Mapa que tiene bien marcados los límites visibles en coordenadas geográficas y que es una proyección equirectangular. Yo eliminé la información hidrográfica e hice varias versiones incluyendo o no los estados y con diferentes colores. Los límites son los siguientes:

float lng_max=-86.3;
float lng_min=-118.5;
float lat_max=33.3;
float lat_min=14.2;

 

Ejemplo:

Licencia: Creative Commons Attribution 3.0 Unported

These files are licensed under the Creative Commons Attribution 3.0 Unported license. You are free: to share – to copy, distribute and transmit the work to remix – to adapt the work Under the following conditions: attribution – You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work).

Cómo Hacer Mapas Georeferenciados de México para Visualización

La visualización de información es uno de los aspectos fundamentales del análisis de datos en la actualidad, como en el caso de la reciente visualización de amistad en Facebook que tuvo gran éxito

En OCCMundial estamos trabajando en geolocalización de ofertas de trabajo. Obtuvimos datos muy interesantes pero al tratar de visualizarlos con un mapa de fondo para hacer más interesante la presentación de los datos me encontré con el problema de conseguir un mapa georeferenciado sobre el cual mostrar la información. De otras regiones tales como el mundo completo, Estados Unidos o Europa es sencillo conseguirlos pero fue más complicado en el caso de México. Tampoco encontré un procedimiento sencillo para generarlo, por lo que en este post pongo mi experiencia y los resultados esperando que le sirvan a alguien más. La idea vino de Minigis que lo usa en un mapa mundial.

El problema consiste en conseguir una imagen de un mapa en el cual se tenga una correspondencia entre coordenadas geográficas y los pixeles. Los buenos mapas que escalan con el nivel de zoom son imágenes vectoriales.Wikimedia es un excelente recurso para comenzar. Los mapas estan en formato SVG. Aquí se encuentran los mapas de México. Es importante fijarse en el tipo de proyección ya que afecta el aspecto del mapa. Para este caso necesitamos un mapa equirectangular en el cual las coordenadas geográficas se pueden mapear de forma lineal con los pixeles de la imagen. Aunque el mejor mapa de México que conseguí tiene división política por municipios, lo que lo hace pesado y no muy bonito para algunos casos, pero es suficientemente bueno para nuestro uso.

Desafortunadamente el mapa no especifica las coordenadas que comprende por lo que es necesario averiguarlas. Usando Inkscape abrí el mapa y encontré que tiene marcados paralelos y meridianos cada 5 grados. Dado que el primer meridiano que se muestra es el 15 y está en la posición Y=48.4, el siguiente es el 20 y está en la posición Y=173.739 podemos comprobar que cada 5 grados corresponden a 125 pixeles, 1 grado a 2.06 pixeles y 0.03999 grados a 1 pixel. De la misma forma podemos comprobar para los paralelos ya que el último paralelo mostrado es el 115W (-115.0) en posición X=56.79 y se mantiene la misma proporción de grados a pixeles (lo que es correcto dado que es una proyección equirectangular). Con esto podemos calcular que el origen de la imagen se encuentra en 13.064° de latitud y -117.271° de longitud (dicho sea de paso, usaremos grados decimales por simplicidad).

Con esto se puede generar una imagen bitmap para ser usado en algún programa o con lenguaje de programación. En este caso estoy usando Processing para generar las visualizaciones. Importante, en general en las imágenes raster el origen no se encuentra en la esquina inferior izquierda como en el SVG sino en la superior izquierda, por lo que el origen se encuentra en 34.6586° lat y -117.271° long, que son las coordenadas se deben usar para calcular las posiciones de los pixeles. La longitud mínima se encuentra en -86.54. Para calcular los pixeles se usan las funciones lineales descritas abajo. La derivación es sencilla por lo que dejo solo una imagen de mis notas por si le sirve a alguien.

En el sketch de processing se puede ver una prueba con algunos puntos interesantes para comprobar que funciona. IMPORTANTE: los datos son muy aproximados, por lo que no recomendaría usar estos métodos para algo mas que visualizaciones sencillas, no mediciones o para ubicar exactamente alguna posición.

Cómo usar:

Se puede usar esta imagen con las dimensiones descritas arriba y las siguientes funciones para calcular pixeles a partir de coordenadas.

 

 
  int x = int( (117.271-lng)*770/(117.271-86.54) );
  int y = int( (34.6586-lat)*540/(34.6586-13.064) );
  

 

Otra imagen, con fondo negro que suele ser mejor para visualizaciones.

En caso de requerir una imagen de otro tamaño no es dificil escalar estas imágenes y encontrar las correspondientes funciones.

Sketch de Processing bajar

//Mantiene las mismas dimensiones del SVG original
int imgx=770;
int imgy=540;

void setup()
{
  //También se puede bajar con la URL directa a Wikimedia 
  //http://commons.wikimedia.org/wiki/File:Municipalities_of_Mexico_(equirectangular_projection).svg
  PShape mx = loadShape( "Municipalities_of_Mexico_(equirectangular_projection).svg" );
 
  size(imgx,imgy);
  shape(mx,0,0,imgx,imgy);
  smooth();
  noLoop();
  
  //Puntos de prueba
  plotAt(19.43333,-99.1333333,5); //DF
  plotAt(25.6666,-100.5, 5);   //MTY
  plotAt(20.6666,-103.3333, 5);  //GDL
 
  plotAt(32.534, -117.123,5); //Tijuana 
  plotAt(21.227, -86.7199,5); //Isla Mujeres
  
  plotAt(14.5176, -92.2199, 5); //Sur
  plotAt(17.8212, -89.1551, 5); //Belice
  plotAt(20.7959, -90.4006, 5); //Campeche
  plotAt(25.9393, -97.1231, 5); //Tamps
  plotAt(29.8605, -102.2996, 5); //Coah Nte
  plotAt(31.7820, -106.5058, 5); //Chih
  plotAt(32.7125, -114.7015, 5); //Nte
  plotAt(22.8865, -109.9164, 5); //Cabos
  plotAt(20.6,-100.38333, 5); //Qro
  plotAt(16.85,-99.93333, 5); //Acapulco
  
  save("mexico.jpg");
}

void plotAt(float lat, float lng, float rad)
{
  lng=-lng; //Si viene en long oeste
  int x = int( (117.271-lng)*770/(117.271-86.54) );
  int y = int( (34.6586-lat)*540/(34.6586-13.064) );
  

  println(x);
  println(y);
  
  fill(10,10,60,80);
  ellipse(x,y,rad,rad);
 }

Espejo del mapa SVG

Imagen con los puntos de prueba

Visualización – Algunas ofertas de empleo actuales (naranja), y principales ciudades (azul)

Arduino RGB LED HSV “Color Wheel”

Recently I’ve been playing with Arduino, Scratch and the 3pi robot for a personal project that I hope will be interesting enough to show soon. (I’ve got a lot of motivation from these guys specially the little one with big eyes).

To start I made this little example of a RGB Led. Usually you begin making a loop through the RGB scale of colors. But it doesn’t look very natural since you expect to loop through a color hue. What you need is to convert a HSV (Hue Saturation Value) scale to RGB (Red Green Blue) scale that the LED support, and then loop through the Hue domain mantaining the Saturation and Value constants.

Circuit is here, look for the RGB LED example

Video:

Code (I’ve coded it as close as I could to the Arduino sample guidelines).

UPDATE (2019-08-21): Check repository at Github

/*
 * Color Wheel LED
 *
 * Loops a RGB LED attached to pins 9,10,11 through
 * all the "exterior" colors of a Color Wheel
 * 
 * The RGB LED uses a 3 component (red green blue) model which adds light colors to produce 
 * a composite color. But the RGB does not make easy to loop through a more
 * "natural" sequence of colors. The HSV (hue saturation value) model uses a color cylinder
 * in which each color is a point inside the cylinder. 
 * The hue is represented by the angle at which the point is, the saturation represents
 * the length (how close to the center the point is) and the value represent the height at
 * which the point is. 
 *
 * By cycling the hue value from 0 to 360 degrees, and keeping the saturation and value at 1
 * we can represent all the brightest colors of the wheel, in a nice natural sequence.
 *
 * The algorithm to convert a HSV value to a RGB value is taken from Chris Hulbert's blog (splinter)
 *
 * Created 1 January 2011
 * By Eduardo A. Flores Verduzco
 * http://eduardofv.com
 *
 * References:
 * http://en.wikipedia.org/wiki/HSL_and_HSV
 * http://en.wikipedia.org/wiki/Color_wheel
 * http://splinter.com.au/blog/?p=29
 *
 *
 */

void setup() {
  //Set the pins to analog output
  pinMode(9,OUTPUT);
  pinMode(10,OUTPUT);
  pinMode(11,OUTPUT);
}

void loop() {
  //The Hue value will vary from 0 to 360, which represents degrees in the color wheel
  for(int hue=0;hue<360;hue++)
  {
    setLedColorHSV(hue,1,1); //We are using Saturation and Value constant at 1
    delay(10); //each color will be shown for 10 milliseconds
  }
}

//Convert a given HSV (Hue Saturation Value) to RGB(Red Green Blue) and set the led to the color
//  h is hue value, integer between 0 and 360
//  s is saturation value, double between 0 and 1
//  v is value, double between 0 and 1
//http://splinter.com.au/blog/?p=29
void setLedColorHSV(int h, double s, double v) {
  //this is the algorithm to convert from RGB to HSV
  double r=0; 
  double g=0; 
  double b=0;

  double hf=h/60.0;

  int i=(int)floor(h/60.0);
  double f = h/60.0 - i;
  double pv = v * (1 - s);
  double qv = v * (1 - s*f);
  double tv = v * (1 - s * (1 - f));

  switch (i)
  {
  case 0: //rojo dominante
    r = v;
    g = tv;
    b = pv;
    break;
  case 1: //verde
    r = qv;
    g = v;
    b = pv;
    break;
  case 2: 
    r = pv;
    g = v;
    b = tv;
    break;
  case 3: //azul
    r = pv;
    g = qv;
    b = v;
    break;
  case 4:
    r = tv;
    g = pv;
    b = v;
    break;
  case 5: //rojo
    r = v;
    g = pv;
    b = qv;
    break;
  }

  //set each component to a integer value between 0 and 255
  int red=constrain((int)255*r,0,255);
  int green=constrain((int)255*g,0,255);
  int blue=constrain((int)255*b,0,255);

  setLedColor(red,green,blue);
}

//Sets the current color for the RGB LED
void setLedColor(int red, int green, int blue) {
  //Note that we are reducing 1/4 the intensity for the green and blue components because 
  //  the red one is too dim on my LED. You may want to adjust that.
  analogWrite(9,red); //Red pin attached to 9
  analogWrite(10,green/3); //Red pin attached to 9
  analogWrite(11,blue/3); //Red pin attached to 9
}