miércoles, 13 de septiembre de 2017

Poner comas luego de los números para preparar una geocodificacion en Google

A veces necesitamos tener la información de una dirección en formato "Google" para que pueda ser geocodificada.
Google entiende la información de direcciones muy bien cuando tiene este formato:

calle numero, colonia, municipio, estado, país

Por ejemplo

Hidalgo 28, Centro, Cuauhtemoc, CDMX, México

Pero a veces puede estar de la siguiente forma, o muchas otras:

Hidalgo 28 Centro, Cuauhtemoc, CDMX, México
Hidalgo Num 28 Centro, Cuauhtemoc, CDMX, México

Etc.

Esto requiere un proceso de limpieza.

El siguiente código permite que estando la información en Excel, insertemos la necesaria coma, es decir:
CIRCUITO LAS MISIONES 219

Pase a

CIRCUITO LAS MISIONES 219, 


El código es este

Sub InsertarComasLuegoDeNumero()
'
    Palabra = ActiveCell.Value
    largo = Len(Palabra)
    
    PrimerNumero = "NO"
    NuevaPalabra = ""
    
    Numeros = 0
    For n = 1 To largo
     letra = Mid$(Palabra, n, 1)
           If letra = "0" Or letra = "1" Or letra = "2" Or letra = "3" Or letra = "4" Or letra = "5" Or letra = "6" Or letra = "7" Or letra = "8" Or letra = "9" Then
            Numeros = Numeros + 1
             If Numeros = 1 Then
              NuevaPalabra = NuevaPalabra + ", "
             End If
           End If
         NuevaPalabra = NuevaPalabra + letra
    Next
    
    ActiveCell.Value = NuevaPalabra
        
    ActiveCell.Offset(1, 0).Range("A1").Select
    
End Sub



Evidentemente si lo quisieramos hacer para un solo renglón no tendría ningun caso, pero supongamos que lo queremos hacer para muchos renglones, digamos 100, solo encerramos el codigo en un for-next, como sigue:



Sub InsertarComasLuegoDeNumero()
'
for m=1 to 100

    Palabra = ActiveCell.Value
    largo = Len(Palabra)
    
    PrimerNumero = "NO"
    NuevaPalabra = ""
    
    Numeros = 0
    For n = 1 To largo
     letra = Mid$(Palabra, n, 1)
           If letra = "0" Or letra = "1" Or letra = "2" Or letra = "3" Or letra = "4" Or letra = "5" Or letra = "6" Or letra = "7" Or letra = "8" Or letra = "9" Then
            Numeros = Numeros + 1
             If Numeros = 1 Then
              NuevaPalabra = NuevaPalabra + ", "
             End If
           End If
         NuevaPalabra = NuevaPalabra + letra
    Next
    
    ActiveCell.Value = NuevaPalabra
        
    ActiveCell.Offset(1, 0).Range("A1").Select

next
    
End Sub

viernes, 28 de febrero de 2014

Cuadrículas para estimación fractal

Puede ser importante obtener la dimensión fractal de un objeto geográfico. Por ejemplo, la dimensión fractal de un contorno urbano se relaciona con la dispersión urbana, y la dispersión a su vez se relaciona con el precio de suelo, la corrupción del gobierno local, el tiempo promedio de desplazamiento en la ciudad, etc.

No abundaremos en lo que es un fractal, pero recordemos que uno de los métodos para estimar la dimensión fractal es el de conteo de cajas. Esto es, para un objeto dado, trazamos distintas rejillas de distintas dimensiones. Con cajas grandes el objeto quedará incluido con pocas cajas y con cajas pequeñas con muchas. La ilustración resume el asunto:


En términos generales, la dimensión fractal será la pendiente de la recta que resulte de relacional el logaritmo del tamaño del lado de cada grid con el logaritmo del número de cuadros que ocupa el grid.

Aquí lo que es importante es como generar dichos grids. Para una tabla en MapInfo de poligonos que pueden ser ciduades o otra característica, se tiene el siguiente programa, donde CiudadesMasDe100MilHabs es una capa que contiene contornos de ciduades y MapaDeCuadrados un layer vacio donde se depositarán los grids. Nivel es el número de cuadrados de los grids. Este se puede ir cambiando o bien automatizar dicho cambio.


Dim MaximaCaja As Object
Dim X1,X2,Y1,Y2,LadoMaximo As Float
Dim CuadradoDibujado As OBject
Dim LadoMayor As Float
Dim Columna, Renglon As Integer
Dim Q As Integer
Dim Lag As Float
Dim Nivel As Integer

Select Obj From CiudadesMasDe100MilHabs Where RowId=1

For Q=1 to 79
Select Obj From CiudadesMasDe100MilHabs Where RowId=Q
Nivel=4

MaximaCaja=MBR(Selection.Obj)
X1=ObjectGeography(MaximaCaja,1)
Y1=ObjectGeography(MaximaCaja,2)
X2=ObjectGeography(MaximaCaja,3)
Y2=ObjectGeography(MaximaCaja,4)

LadoMayor=Maximum(Abs(X2-X1),Abs(Y2-Y1))
Lag=LadoMayor/Nivel
X2=X1+Lag
Y2=Y1+lag

For Columna=0 To Nivel
For Renglon=0 To Nivel

Create Region Into Variable CuadradoDibujado 0
Alter Object CuadradoDibujado Node Add ((X1+Renglon*Lag),(Y1+Columna*Lag))
Alter Object CuadradoDibujado Node Add ((X1+Renglon*Lag),(Y2+Columna*Lag))
Alter Object CuadradoDibujado Node Add ((X2+Renglon*Lag),(Y2+Columna*Lag))
Alter Object CuadradoDibujado Node Add ((X2+Renglon*Lag),(Y1+Columna*Lag))

Insert Into MapaDeCuadros (Obj) Values (CuadradoDibujado)

Next
Next
Next

miércoles, 6 de noviembre de 2013

Macro para rellenar espacios vacíos

En muchos programas no es lo mismo un espacio vacío que un cero. Por ejemplo en JMP pueden ocurrir algunos problemas de cálculo si en vez de cero hay vacíos. Abajo se muestra un ejemplo de una encuesta que ha sido capturada con espacios en vez de ceros.


La sencilla macro que desarrollaremos aquí es para limpiar esos espacios y colocarles un cero.
Supongamos como haríamos nosotros el trabajo y luego encarguémoslo al robot.
Lo que haríamos sería ir desde la primer columna que carece de ceros una por una de las casillas hacia abajo llenando las vacias con cero. O sea, esto

Do While AComparar <> "FIN"


    ActiveCell.Offset(1, 0).Range("A1").Select
    AComparar = ActiveCell.Value
   
    If AComparar = "" Then
       
        ActiveCell.Value = 0
   
    End If
   

Loop

Al final de la columna podemos acotarla con un "FIN", así:
De esta forma cuando el cursor llegue a esa celda le podremos decir que detenga o cambie el proceso.
Si corremos el código anterior veremos que el cursor se detiene al llegar a "FIN". Pero falta decirle que suba. Esto es así:

  Selection.End(xlUp).Select
   ActiveCell.Offset(0, 1).Range("A1").Select

El cursor sube todo hacia arriba por celdas no vacias, pero como ya las rellenamos todas llegará al tope, y luego se hace una celda a la derecha. 

Ahora, solo falta que al llegar de nuevo arriba, repita la operación, lo cual se logra insertando un FOR NEXT con el número de columnas que queremos procesar, por ejemplo 5. Pero hay que decirle al robot que hemos cambiado el valor de la celda activa. El programa queda así:


Sub SustituyeNadaPorCero()
'
' SustituyeNadaPorCero Macro
'
For N = 1 To 5

'
Do While AComparar <> "FIN"


    ActiveCell.Offset(1, 0).Range("A1").Select
    AComparar = ActiveCell.Value
    
    If AComparar = "" Then
        
        ActiveCell.Value = 0
    
    End If
    

Loop

  AComparar = "Algo"
  Selection.End(xlUp).Select
  ActiveCell.Offset(0, 1).Range("A1").Select
    
Next

End Sub


Y el resultado, el siguiente:


Ya no contiene vacíos.


jueves, 17 de octubre de 2013

Programa MapBasic para estimacion de distancias promedio

Antes que hablar de distancia media, cabe mencionar que la media es un promedio, lo mismo que la mediana y la moda. Un promedio es un estadígrafo que me da una aproximación de una sola variable al conjunto. Así, promedio no es sinónimo de media. La distancia promedio es un indicador de concentración.

La distancia media se define como el promedio de todos los promedios de distancias de cada punto contra los otros. En términos numéricos:


Si P es un conjunto de puntos p1,p2…pn, tales que existen en un plano de tal modo que hay una xi y una yi tales que son coordenadas de pi, entonces la distancia promedio de pi a P será para un j



Y la distancia promedio total será





La distancia promedio nos dará una idea, en un espacio isomorfo de que puntos tienen la cercanía óptima en el conjunto. Tiene diversas aplicaciones. Por ejemplo, si los puntos son escuelas, y se desea que una de las escuelas sea un centro de zona, la que tenga menor distancia promedio será aquella en la que la suma de los viajes es menor.



En el cálculo de la distancia promedio hay dos opciones, contar o no la distancia de cada punto contra si mismo. Normalmente no se cuenta.
El algoritmo para programación geográfica en MapBasic es el que sigue. Algoritmos muy similares pueden escribirse en Avenue, Autolisp u otros lenguajes de objetos geográficos. Para correrlo debe haber una tabla de puntos en MapInfo que contengan una columna llamada DistanciaPromAlRest donde se almacenarán los datos de distancia promedio.
Dim Fin, NumeroDePuntos, M As Integer
Dim X,Y,SUMA,Distancia,DistanciaPromedio As Float
Dim PuntoAEvaluar As Object                        ‘es posible definir variables
                                               ‘objeto, las comillas son remakes
                                               ‘que permiten ignorar el comentario
                                               ‘siguiente como en este caso

Fin=TableInfo(Puntos,8)’ la variable fin es el número de renglones en la tabla
Select * From Puntos Where RowId=1                 ‘selecciona el primer registro de
                                               ‘ la tabla


For NumeroDePuntos =1 To FIN                       ‘se inicia un ciclo para recorrer
                                                    ‘todos los objetos de la tabla, son
                                                    ‘puntos sobre los cuales se medirá
                                                    ‘ la distancia al resto

Select Obj From Puntos Where RowId=NumeroDePuntos ‘selecciona el renglón que va en el ciclo

PuntoAEvaluar= Selection.Obj ‘se define un objeto a examinar

   X=ObjectGeography(PuntoAEvaluar,1)          ‘se extraen las coordenadas del
                                                    ‘punto
   y=ObjectGeography(PuntoAEvaluar,2)

   Suma=0                                      ‘Se inicia acumulador donde se
                                               ‘añade distancia total

   For M=1 To FIN
       Select * From Puntos Where RowId=M          ‘Se inicia ciclo para medir la
                                               ‘distancia al segundo punto

       Distancia=Distance(X,Y,CentroidX(Selection.Obj),CentroidY(Selection.Obj),"cm")
                                               ‘se estima la distancia

       Suma=Suma+Distancia                     ‘se suma la distancia
   Next

DistanciaPromedio=Suma/FIN                     ‘se promedia

Update Puntos
   Set DistanciaPromAlResto = DistanciaPromedio    ‘se almacena
   Where Rowid = NumeroDePuntos


Next


Si interpolamos el resultado sale algo como lo siguiente:


Programa en MapBasic para convertir distancia euclidiana a distancia Manhattan

En muchas ocasiones en problemas de cartografía numérica, tenemos un archivo con líneas. Pueden referirse por ejemplo a líneas de deseo de una encuesta origen destino. La apariencia es esta:


Es muy probable que estemos interesados no en conocer la distancia euclidiana o la loxodrómica sino la distancia Manhattan. A veces por la contabilidad cartográfica no es posible conocer el trayecto exacto de un objeto, pero si puntos origen destino. Entonces la distancia entre estos puntos es una aproximación al recorrido real. En la figura de abajo se muestra como representamos normalmente el recorrido entre dos puntos. 


Sin embargo el recorrido real puede ser como el que se muestra abajo. Cabe mencionar que entre más cercanos sean los puntos se tenderá a mayor tensión de línea, es decir, a tener una línea más  cercana a la recta euclidiana.


Una aproximación que no refleja el recorrido exacto pero tampoco es tan generalizado como el euclidiano, es la distancia Manhattan, que por definición es la distancia resultante entre dos puntos de sumar los lados que resultan del tríángulo que tiene esa distancia por hipotenusa en un ángulo recto con lados paralelos a los ejes cartesianos.



Además esta distancia tiene la propiedad de que será igual en cualquier trayecto a base de ángulos rectos que se haga. Tal como se muestra en la figura de abajo. Será lo mismo caminar del punto superior al inferior con cualquier combinación, siempre y cuando el trayecto forme ángulos rectos.


Bien, ahora, como se cálcula la distancia?. Simplemente hay que extraer el objeto, estimar las coordenadas del punto origen (X1,Y1) y las del punto destino (X2,Y2) , y estimar las ditancias de los lados.

Si tenemos un archivo en MapInfo de rectas, llamado "Lineas" con una columna llamada Manhhatan, solamente vamos extrayendo cada recta. Y obtenemos la distancia del punto X1,Y1 al punto X2,Y1 que es el lado paralelo a las X, y luego, de X1,Y1 a X1,Y2. Y se suman.

He aquí el programa para correr en MapBasic:

Dim Fin,N As Integer
Dim X1,X2,Y1,Y2,DistH,DistV,Hipo,Manhatan As Float
Dim Tp As String
Dim MyLine As Object
Dim Tabla As String
Tabla="Lineas"
Fin=TableInfo(Tabla,8)

For N=1 To Fin
Select Obj From Tabla Where RowId=N Into Provi
MyLine=Provi.Obj

X1=ObjectGeography(MyLine,1)
X2=ObjectGeography(MyLine,3)
Y1=ObjectGeography(MyLine,2)
Y2=ObjectGeography(MyLine,4)

DistH=Distance(X1,Y1,X2,Y1,"km")
DistV=Distance(X1,Y1,X1,Y2,"km")
Hipo=Sqr(DistH*DistH+DistV*DistV)
Manhatan=DistH+DistV
Print N
Print Manhatan

UpDate Tabla
Set DistanciaManhattan=Manhatan
Where RowId=N


Next


martes, 15 de octubre de 2013

Programa para transformar nodos de rutas en líneas de rutas

Programa en MapBasic para realizar rutas a partir de puntos. Esto puede ser útil en muchas circunstancias, por ejemplo en una encuesta origen destino donde se tienen los nodos pero se quiere representar la ruta.

Este programa para un archivo de 400 puntos, genera una linea secuencial entre ellos. Es decir, une el primer punto con el segundo, el segundo con el tercero, etc.

Es decir, desde algo como esto:


Genera esto:

El resultado lo almacena en un archivo llamado Rutas.

Para correrlo se necesita tener un archivo en Mapinfo que se llame Puntos donde se almacenan los 400 puntos (pueden ser más siempre y cuando se modifique la línea del for N=1 to 400. Otro archivo vacío se debe llamar rutas.

'Programa para dibujo de rutas Tona Mini

Dim PuntoACrecer               As Object                           'define variable objeto donde estará siguiente pto.
Dim N                                  As Integer                           'se almacena contador
Dim CurrentX,CurrentY        As Float                              'se almacena coordenadas 1
Dim CurrentX2,CurrentY2    As Float                              'coordenadas siguientes


Select Obj From Puntos Where RowId=1                        'se selecciona el primer punto
PuntoACrecer=Selection.Obj                                           'se almacena en una variable objeto
CurrentX=CentroidX(PuntoACrecer)                               'se extraen sus coordenadas
CurrentY=CentroidY(PuntoACrecer)



For N=2 To 400                                                               'se inicia el conteo para el total de puntos

Select Obj From Puntos Where RowId=N Into Sel   'almacena punto en archivo dedicado a puntos

PuntoACrecer=Sel.Obj                                            'se almacena en punto variable objeto
CurrentX2=CentroidX(PuntoACrecer)                     'se extraen coordenadas
CurrentY2=CentroidY(PuntoACrecer)


Insert Into Rutas (Obj)                                              'se realiza el dibujo
Values (CreateLine (CurrentX,CurrentY,CurrentX2,CurrentY2))   'se almacena en geobase

CurrentX=CurrentX2    'almacenan segundas coords. en las primeras para repetir operacion
CurrentY=CurrentY2

Next