Saltar a contenido

Index

Python Scripting for Students of Remote Sensing

Python Scripting for Students of Remote Sensing es un manual de python orientado a la teledetección. Si no sabes nada de python es mejor empezar por otro manual y luego saltar directamente al capítulo 5, «Plottin». La parte de python en sí es muy básica y no está muy bien explicada. Del capítulo 5 al 10 se muestran algunas librerías interesantes de python para mostrar gráficos (matplotlib), para estadística y calculos científicos (numpy), para procesado de raster (gdal), o ejemplos sencillos de trabajo con datos lidar en ficheros ascii. La información que dan es bastante escueta, pero si ya conoces python en un par de horas puedes leerlo para hacerte una idea de que posibilidades hay en estos campos.

En la misma página se pueden encontrar otros manuales interesantes sobre teledetección.

Descubrí el curso gracias al comentario de José Guerrero.

Como carga gvSIG las extensiones

En la línea abierta por Andrés de «Como gvSIG hace xxx» os presento un artículo que explica como se gestiona la carga de las extensiones en gvSIG. Antes de nada debo agradecer a Cartolab cederme tiempo para poder escribirlo.

Lo que sucede cuando lanzamos gvSIG es que la máquina virtual de java ejecuta el método main() de la clase Launcher de andami, el framework que sostiene el sistema de ventanas y plugins de gvSIG.

A efectos de este artículo sobre la carga de extensiones podemos decir que ese método main() es el responsable de lo siguiente:

  1. Procesar los parámetros que se le pasan por línea de comandos
  2. Cargar los plugins
  3. Cargar las clases de los plugins
  4. Recuperar la configuración persistida de los plugins
  5. Inicializar las extensiones
  6. Cargar menus y toolbars
  7. Hacer la postinicialización de las extensiones

1.- Procesar los parámetros que se le pasan por línea de comandos

Lo más habitual es que la orden que ejecute el sistema operativo (quitando los parametros que se pasan a la jvm) sea algo parecido a:

$ java com.iver.andami.Launcher gvSIG gvSIG/extensiones «$@»

donde la parte en negrita serían los parámetros que pasamos al main(). En concreto ese segundo parámetro gvSIG/extensiones es el que está definiendo donde está la carpeta de plugins de gvSIG, como ruta relativa desde donde se encuentra el fichero andami.jar.

Es decir, que si bien el directorio de extensiones suele estar en un punto predefinido nosotros podriamos escoger otra ubicación.

2.- Carga de los plugins

Procesados los parámetros de entrada la aplicación recorre todos los directorios contenidos en la carpeta de plugins. Si dentro del directorio existe un fichero de nombre «config.xml» lo parsea y en caso de ser correcto añade el par [«nombre del directorio», objeto PluginConfig] al campo de la clase Launcher

<br></br>private static HashMap pluginsConfig = new HashMap();<br></br>
Donde PluginConfig es una clase que se encarga de mantener toda la información que aportan los ficheros config.xml.

Lo más interesante de esta fase es entender que el orden en que se recorren los directorios, y por tanto el orden en que luego se inicializarán las extensiones, es aleatorio, o en realidad es el orden que devuelve el método lisFiles() de la clase File de Java, que especifica en su documentación que el orden en se devuelven los ficheros no está asegurado y supongo, dependerá de la implementación concreta de la máquina virtual y del sistema operativo que se emplee.

Hay que aclarar que en este contexto, un plugin, es igual a un directorio contenido dentro del directorio de extensiones/plugins definido como parámetro.

3.- Carga de las clases de los plugins

Lo siguiente que intenta hacer es indexar todas las clases de todos los plugins. Para ello recorre pluginsConfig, solicitando el valor de la etiqueta del config <libraries library-dir=»VALOR» />. Lo más habitual es que ese VALOR sea «./», es decir el propio directorio del plugin. Para cada plugin mantiene un objeto PluginClassLoader que basicamente contiene un índice de todos ficheros .class que están dentro de los ficheros .zip o .jar que están en ese library-dir.

Para cada plugin se crea un objeto PluginServices que a su vez mantiene la instancia del PluginClassLoader que le corresponde. Esos PluginServices se almacenan en el campo
<br></br>private static HashMap pluginsServices= new HashMap();<br></br>
de la clase Launcher.

Hay que tener en cuenta que a la hora de cargar las clases de un plugin, si en el config se ha definido que depende de otro mediante una etiquetacarga la clases de la dependencia (de forma recursiva) antes que el nuestro. Por tanto, en pluginsServices los plugins se reordenan respecto a pluginsConfig poniendo los plugins de los que se depende antes. Se mantiene también una variable pluginsOrdered con el nombre de los plugins en el mismo orden que pluginsServices

4.- Persistencia de los plugins

Se actualiza el andamiConfig que contiene una lista (el fichero andami-config.xml habitualmente) que persiste con todos los plugins presentes el directorio de plugins.

Luego se recupera de disco la configuración persistida de los plugins en el fichero plugins-persistance.xml, y se setea esa configuración en el PluginServices asociado a cada plugin.

5.- Inicialización de las Extensiones

Es en esta fase cuando salen por consola los mensajes de:

Initializing extensions from «Nombre_del_plugin» (para cada plugin)

y

Initializing «Nombre_de_la_Extension» … (para cada extensión)

Se recorre pluginsOrdered, y para cada plugin se crea una instancia de cada extensión (en el orden que se define en el config del plugin) y se llama a su método initialize(). Además se almacena esas instancia en el campo de Launcher:
<br></br>private static ArrayList extensions=new ArrayList();<br></br>
Por el medio crea también un objeto ExtensionDecorator que nos da un control adicional sobre las extensiones pero esto no nos interesa a los efectos de este artículo.

6.- Menus y Toolbars

Se cargarn los menus y los toolbars definidos por los plugins a través de los métodos installPluginsMenus() y installPluginsControls().

7.- Post-inicialización de las extensiones

Se va llamando al método postInitialize de cada extensión en el orden en que aparecen en el array extensions. Con este paso finalizaría el proceso de carga.

Una cosa que no he investigado a fondo pero que intuyo que es así, es que en algún momento de este proceso se asocian las instancias del array extensions a los menús y botones del toolbar. De este modo las extensiones (clases que heredan de extension y aparecen en los config) se comportan como una especie de singleton, porque gvSIG siempre la recupera de ese array de extensiones, y cuando el desarrollador externo llama a PluginServices.getExtension(Class) la está recuperando de ahí también (del ExtensionDecorator del que hablamos antes en realidad, pero la idea es la misma)

Esto explica también porque cuando recompilamos nuestro código, si cambiamos algo en la clase de la extensión debemos cerrar y abrir gvSIG. La instancia de la extensión se crea durante la carga de gvSIG y se mantiene hasta que cerramos gvSIG, y por tanto no es «recargada» de los nuevos .class

Me quedan un par de dudas que quedan para estudiar para próximos posts o para quien se anime a escribir más artículos de la serie de «Como hace gvSIG XXX»:

  • Al parecer existe una extension del tipo ExclusiveUIExtension a la que se hace referencia en Launcher.initializeExclusiveUIExtension() que no tengo muy claro como funciona
  • Estaría bien explicar en detalle el comportamiento de los ExtensionDecorator
  • Estaría bien explicar detalladamente el proceso de creación y ubicación de los menús y toolbars
  • Algunas partes del código son un poco liosas. Tengo algunas ideas de como refactorizarlo así que si alguien se anima que pregunte

Quien tiene la culpa de la crisis

Aviso antes de que sigas leyendo: Este artículo contine cierta dosis de demagogia, pero a veces hace falta llegar al extremo para saber donde está el centro.

Andrés publico hace poco un artículo, titulado los culpables de la deuda que dió pie a algo de debate en los comentarios de su blog y que hace que revisite algunas lecturas y descubra otras.

Gracias a esta pequeña investigación he descubierto que la culpa la tienen los gobiernos, ya sean los del psoe, o los del pp; los bancos, los endeudados, el capitalismo, … O en resumen, la culpa la tenemos todos. Queda a juício del lector que porcentaje de responsabilidad corresponde a cada cual, aunque yo creo que lo tengo más o menos claro.

Aunque lo que en realidad me preocupa no es quien tiene la culpa, si no quien la va a pagar.

Si debo escoger entre que la pague una familia que se queda en la calle o los responsables de la política económica de la entidad que hizo el prestamo, escogeré a quien tenga que vender el chalet de la playa para pagar su irresponsabilidad.

Si hay que decidir entre recortar la ayuda al desarrollo o suprimir el >presentar máquinas destinadas a matar como espectáculo para niños la decisión también la tengo clara…

Dan Pink en la sorprendente ciencia de la motivación

Sergio me pasa un vídeo que da los puntos básicos sobre como debería ser una gestión empresarial moderna. Promoción horizontal, incentivos, gestión, productividad, … son temas de moda sobre los que espero seguir escribiendo pero las premisas básicas son fáciles de condensar:

Cuando las tareas a realizar involucran sólo habilidades mecánicas los incentivos económicos funcionan muy bien. A mayor recompensa mayor rendimiento.

Pero en general una vez alcanzado un incentivo económico razonable, un aumento de este en forma de recopensa no se traduce en un mayor rendimiento, si no que de hecho, en muchas ocasiones reduce la productividad.

La motivación extrínseca (como el dinero) sólo funciona para alcanzar cierto nivel de rendimiento, a partir de ese nivel la motivación intrínseca es más importante. Por tanto, los incentivos otorgados para incrementar el rendimiento deberían basarse en estas tres premisas

  • Autonomía: El impulso de dirigir nuestra propia vida. Mientras que la gestión tradicional funciona cuando lo que necesitas es conformismo, otorgar autonomía tiende a funcionar cuando lo que necesitas es autonomía.
  • Maestría: El deseo de ser mejor y mejor en algo que importa
  • Propósito: El deseo de hacer lo que hacemos al servicio de algo más grande que nosotros mismos

Comentario sobre el diseño de bases de datos PostGIS

Un par de comentarios muy rápidso sobre una práctica que considero acertada a la hora del diseño con bases de datos PostGIS.

No uses el esquema public

PostGIS emplea de forma intensiva el esquema public para crear funciones, tipos de datos etc… Si tu también empleas ese esquema cuando vuelques tu base de datos ese esquema tendrá que ser incluído y no sólo irán tus datos si no también toda la parte de PostGIS lo que incrementará el tamaño del dump y el tiempo de restauración.

Además si el usuario quiere restaurar la bd sobre una ya existente con PostGIS saldrán un montón de errores de que las funciones ya existen, con lo que se hace difícil depurar otros posibles errores. También se pueden producir errores si tu dump corresponde a una versión de PostGIS distinta a la que tiene el usuario.

Cuando vuelques tu base de datos excluye el esquema public del volcado

Por lo ya explicado en el punto 1. Hacer esto es tan sencillo como:

<br></br>pg_dump --no-owner -N public -h servidor -U usuario -f /tmp/base_de_datos.sql base_de_datos<br></br>

Vuelca también la tabla geometry_columns

Los únicos datos que estarán en el esquema público que te hacen falta serán los de la tabla geometry_columns. Vuelca por tanto esos datos (no hace falta la estructura) a otro fichero sql.

<br></br>pg_dump --no-owner -a -t geometry_columns -h servidor -U usuario -f /tmp/geometry_columns.sql base_de_datos<br></br>

Teniendo en cuenta estos consejos apenas tendrás trabajo extra y harás la vida mucho más fácil a quien tenga que restaurar la base de datos (que puede que seas tu mismo)

Actualización 17/Febrero/2013. Acabo de encontarme por primera vez desde que escribí esto con alguien que también declara en un post lo importante de no usar el schema public cuando se trabaja con postgis.