Séries de mapas com formatos múltiplos em QGIS 2.6 – Parte 1

EN | PT

Para não variar, a nova versão do QGIS (o QGIS 2.6 Brigthon) traz um conjunto alargado de novas funcionalidades que permitem ao utilizador fazer mais, melhor e mais rápido do que com a versão anterior. Uma das novidades desta versão é a possibilidade de controlar algumas propriedades dos itens do compositor através de dados (por exemplo, o tamanho e a posição). Algo que abre a porta a aplicações bastante interessantes. Nos próximos artigos, proponho-me a mostrar como criar séries de mapas com multiplos formatos.

Neste primeiro artigo, o objectivo é que, mantendo o tamanho da folha, o mapa seja criado com a orientação (paisagem ou retrato) que melhor se adapte à forma do elemento do atlas. Para exemplificar, usei a amostra de dados do Alaska para criar  um mapa de cada uma das regiões do Alaska.

Em primeiro lugar comecei por criar o meu layout numa dos formatos, colocando vários itens nas posições que desejava.

mapa_base_atlas

Para  controlar a orientação da folha através do atlas, fui ao separador “Composição” e na opção orientação, usei no botão propriedades definidos por dados a seguinte expressão:

CASE WHEN bounds_width( $atlasgeometry ) >=  bounds_height( $atlasgeometry ) THEN 'landscape' ELSE 'portrait' END

Usando a opção de pré-visualização do atlas, podemos verificar que a orientação da folha já muda de acordo com a forma do elemento do atlas. No entanto, os itens não acompanham essa mudança e alguns ficam até fora da área de impressão.

Screenshot from 2014-11-08 23:29:49

Para controlar o tamanho e posição dos itens do mapa tive em consideração o tamanho de uma folha A4 (297 x 210 mm), as dimensões das margens do mapa ( 20 mm, 5 mm, 10 mm, 5 mm) e os pontos de referência dos itens.

No caso do item “mapa”, usando como ponto de referência o canto superior esquerdo, foi necessário alterar a sua altura e largura. Sabia que a altura do item era é subtracção do tamanho das margens superiores e inferiores (30 mm) da altura folha por isso a expressão a usar foi:

(CASE WHEN  bounds_width(  $atlasgeometry ) >=  bounds_height( $atlasgeometry) THEN 297 ELSE 210 END) - 30

De forma análoga, a expressão a usar para a largura foi:

(CASE WHEN  bounds_width(  $atlasgeometry ) >=  bounds_height( $atlasgeometry) THEN 210 ELSE 297 END) - 10

Screenshot from 2014-11-09 00:02:15

Os restantes itens ocupavam sempre uma posição relativa na folha sem que fosse necessário alterar o seu tamanho e por isso tinha apenas de controlar a sua posição. Por exemplo, o título encontrava-se centrado no topo da folha, e portanto, usando como ponto de referência o topo-centro, bastou definir a seguinte expressão para a posição X:

Screenshot from 2014-11-09 00:13:17

(CASE WHEN  bounds_width(  $atlasgeometry ) >=  bounds_height( $atlasgeometry)  THEN 297 ELSE 210 END)  / 2.0

Screenshot from 2014-11-09 00:30:57

Já a legenda exige alterar a posição em X e em Y. Usando como ponto de referência o canto inferior direito, a expressão para a posição em X foi:

(CASE WHEN  bounds_width(  $atlasgeometry ) >=  bounds_height( $atlasgeometry) THEN 297 ELSE 210 END) - 7

E para a posição em Y:

(CASE WHEN  bounds_width(  $atlasgeometry ) >=  bounds_height( $atlasgeometry) THEN 210 ELSE 297 END) - 12

Screenshot from 2014-11-09 00:47:28

Para os restantes itens (rosa dos ventos, escala gráfica e texto no canto inferior esquerdo), as expressões a usar eram em tudo similares às já apresentadas, e, após definidas em cada um dos itens, fiquei com o layout preparado para se adaptar às duas orientações da folha.

output_9

Depois disso, a impressão/exportação de todos os (25) mapas ficou à distância de um só clique.

mosaico_regioes

No próximo artigo da série, procurarei explicar como criar séries de mapas em que seja o tamanho da folha a adaptar-se de forma a manter uma escala constante.

Anúncios

Instalar duas versões de QGIS em Linux

Instalar duas versões de QGIS em Linux

QGIS24_QGISmaster

Em altura de testes à versão em desenvolvimento do QGIS (versão master), dá jeito  ter também instalada a última versão estável do QGIS. Em windows isso não representa um problema, uma vez que se podem instalar várias versões do QGIS em paralelo (tanto via Osgeo4w como standalone). Em linux, o processo não é tão directo pelo facto da instalação se realizar por obtenção de diversos pacotes disponíveis nos repositórios, não sendo por isso possível instalar mais do que uma versão sem que se originem quebras de dependências. Assim, instalando a versão estável através dos repositórios, as alternativas para instalação da versão em desenvolvimento são:

  • Compilar o QGIS master do código fonte;
  • Instalar o QGIS master num docker;
  • Instalar o QGIS master numa máquina virtual;

Neste artigo vou mostrar como compilar o código fonte em Ubuntu 14.04. Afinal não é tão difícil quanto parece. Meia dúzia de comandos e um pouco de paciência e vai-se lá. Usei como base as indicações do ficheiro INSTALL.TXT disponível no código fonte com umas pequenas alterações.

Instalar todas as dependências necessárias

Num terminal correr o seguinte comando para instalar todas as dependências e ferramentas necessárias à compilação do QGIS. (adicionei o ccmake e o git ao comando original)

sudo apt-get install bison cmake doxygen flex git graphviz grass-dev libexpat1-dev libfcgi-dev libgdal-dev libgeos-dev libgsl0-dev libopenscenegraph-dev libosgearth-dev libpq-dev libproj-dev libqscintilla2-dev libqt4-dev libqt4-opengl-dev libqtwebkit-dev libqwt5-qt4-dev libspatialindex-dev libspatialite-dev libsqlite3-dev lighttpd pkg-config poppler-utils pyqt4-dev-tools python-all python-all-dev python-qt4 python-qt4-dev python-sip python-sip-dev spawn-fcgi txt2tags xauth xfonts-100dpi xfonts-75dpi xfonts-base xfonts-scalable xvfb cmake-curses-gui

Configurar o ccache

Este passo permite optimizar a compilação e tornar a compilação mais rápida nas próximas vezes que se fizer:

cd /usr/local/bin
sudo ln -s /usr/bin/ccache gcc
sudo ln -s /usr/bin/ccache g++

 Obter o código fonte do Github

O código fonte pode ser colocado numa pasta à escolha de cada um. Seguindo a sugestão do ficheiro de instruções acabei por colocar tudo na minha pasta home/alexandre/dev/cpp.

mkdir -p ${HOME}/dev/cpp
cd ${HOME}/dev/cpp

Já dentro da pasta home/alexandre/dev/cpp, podemos obter o código do qgis executando o seguinte comando git:

git clone git://github.com/qgis/QGIS.git

Nota: Se pretendesse fazer alterações ao código e experimentar se funcionava, então deveria fazer o clone do fork do qgis do meu próprio repositório, ou seja:

git clone https://github.com/SrNetoChan/Quantum-GIS

Preparar directorias de compilação e instalação

O código fonte tem de ser compilado e instalado em locais próprios para evitar conflitos com outras versões do QGIS. Por isso, há que criar uma pasta para efectuar a instalação:

mkdir -p ${HOME}/apps

E outra onde será feita a compilação:

cd QGIS
mkdir build-master
cd build-master

Configuração

Já na pasta build-master damos início ao processo de compilação. O primeiro passo é a configuração, onde vamos dizer onde queremos instalar o QGIS master. Para isso executamos o seguinte comando (não esquecer os dois pontos):

ccmake ..

Na configuração é necessário alterar o valor do CMAKE_INSTALL_PREFIX que define onde vai ser feita a instalação, no meu caso usei a pasta já criada ‘home/alexandre/apps’ . Para editar o valor há que mover o cursor até à linha em causa e carregar em [enter], depois de editar, volta-se a carregar em [enter]. Depois há que carregar em [c] para refazer a configuração e depois em ‘g’ para gerar a configuração.

Screenshot from 2014-10-08 23:33:39

 Compilação e instalação

Já com tudo configurado resta compilar o código e depois instalá-lo:

make
sudo make install

Nota: Estes dois passos podem demorar um bocadinho, principalmente na primeira vez que o código for compilado.

Depois de instalado podemos correr o QGIS master a partir da pasta de instalação:

cd ${HOME}/apps/bin/
export LD_LIBRARY_PATH=/home/alexandre/apps/lib
export QGIS_PREFIX_PATH=/home/alexandre/apps
${HOME}/apps/bin/qgis

Para se tornar mais cómodo, podemos colocar os últimos 3 comandos num ficheiro .sh e gravá-lo num local acessível (desktop ou home) para executarmos o qgis sempre que necessário.

Screenshot from 2014-10-09 00:36:52

UPDATE: Actualizar a versão master

Como já foi referido num comentário, a versão em desenvolvimento está constantemente a ser alterada, por isso para testar se determinados bugs foram entretanto corrigidos há que a actualizar. Trata-se de um processo bastante simples. O primeiro passo é actualizar o código fonte:

cd ${HOME}/dev/cpp/qgis
git pull origin master

E depois é voltar a correr a compilação (que desta feita será mais rápida):

cd build-master
ccmake ..
make
sudo make install

Coordenadas dos cantos do mapa em QGIS

Coordenadas dos cantos do mapa em QGIS

EN | PT

O desafio

Em tempos na lista de discussão do qgis-pt alguém perguntou como dispor as coordenadas dos cantos do mapa no QGIS. Não estando (ainda) disponível tal funcionalidade, tentei chegar sem sucesso a uma solução que fosse de certa forma automática. Depois de remoer a ideia, e de ler um artigo do Nathan Woodrow, achei que a solução poderia passar por criar uma função para o construtor de expressões que pudesse ser usada em etiquetas no mapa.

 A solução

Seguindo as indicações do referido artigo, comecei por criar um ficheiro userfunctions.py, que gravei na pasta .qgis2/python e, com uma ajuda do Nyall Dawson, escrevi o seguinte código.

from qgis.utils import qgsfunction, iface
from qgis.core import QGis

@qgsfunction(2,"python")
def map_x_min(values, feature, parent):
 """
 Returns the minimum x coordinate of a map from
 a specific composer.
 """
 composer_title = values[0]
 map_id = values[1]
 composers = iface.activeComposers()
 for composer_view in composers():
  composer_window = composer_view.composerWindow()
  window_title = composer_window.windowTitle()
  if window_title == composer_title:
   composition = composer_view.composition()
   map = composition.getComposerMapById(map_id)
   if map:
    extent = map.currentMapExtent()
    break
 result = extent.xMinimum()
 return result

Depois de correr o comando import userfunctions na consola python (Módulos > Consola python), já conseguia usar a função map_x_min() (disponível na categoria python) numa expressão para obter o valor mínimo em X.

Screenshot from 2014-09-09 16^%29^%29
Bastava então criar as restantes funções map_x_max(), map_y_min() e map_y_max(). Como parte do código seria repetida, decidi encapsulá-lo na função map_bound() que recebesse como argumentos o título do compositor de impressão e o id do mapa e me devolvesse a extensão do mesmo (sob a forma de um QgsRectangle).

from qgis.utils import qgsfunction, iface
from qgis.core import QGis

def map_bounds(composer_title, map_id):
 """
 Returns a rectangle with the bounds of a map
 from a specific composer
 """
 composers = iface.activeComposers()
 for composer_view in composers:
  composer_window = composer_view.composerWindow()
  window_title = composer_window.windowTitle()
  if window_title == composer_title:
   composition = composer_view.composition()
   map = composition.getComposerMapById(map_id)
   if map:
    extent = map.currentMapExtent()
    break
 else:
  extent = None

 return extent

Com essa função disponível podia usá-la internamente nas funções para devolver cada um dos mínimos e máximos em X e Y, tornando o código mais compacto e fácil de manter. Adicionei ainda ao código original alguns mecanismos para evitar erros.

@qgsfunction(2,"python")
def map_x_min(values, feature, parent):
 """
 Returns the minimum x coordinate of a map from a specific composer.
 Calculations are in the Spatial Reference System of the project.
 
 <h2>Syntax</h2>
 
 map_x_min(composer_title, map_id)
 
 <h2>Arguments</h2>
 
 composer_title - is string. The title of the composer where the map is.
 map_id - integer. The id of the map.
 
 <h2>Example</h2>
 
 map_x_min('my pretty map', 0) -> -12345.679
 
 """
 composer_title = values[0]
 map_id = values[1]
 map_extent = map_bounds(composer_title, map_id)
 if map_extent:
  result = map_extent.xMinimum()
 else:
  result = None
 
 return result
 
@qgsfunction(2,"python")
def map_x_max(values, feature, parent):
 """
 Returns the maximum x coordinate of a map from a specific composer.
 Calculations are in the Spatial Reference System of the project.
 
 <h2>Syntax</h2>
 
 map_x_max(composer_title, map_id)
 
 <h2>Arguments</h2>
 
 composer_title - is string. The title of the composer where the map is.
 map_id - integer. The id of the map.
 
 <h2>Example</h2>
 
 map_x_max('my pretty map', 0) -> 12345.679
 
 """
 composer_title = values[0]
 map_id = values[1]
 map_extent = map_bounds(composer_title, map_id)
 if map_extent:
  result = map_extent.xMaximum()
 else:
  result = None
 
 return result
 
@qgsfunction(2,"python")
def map_y_min(values, feature, parent):
 """
 Returns the minimum y coordinate of a map from a specific composer.
 Calculations are in the Spatial Reference System of the project.
 
 <h2>Syntax</h2>
 
 map_y_min(composer_title, map_id)
 
 <h2>Arguments</h2>
 
 composer_title - is string. The title of the composer where the map is.
 map_id - integer. The id of the map.
 
 <h2>Example</h2>
 
 map_y_min('my pretty map', 0) -> -12345.679
 
 """
 composer_title = values[0]
 map_id = values[1]
 map_extent = map_bounds(composer_title, map_id)
 if map_extent:
  result = map_extent.yMinimum()
 else:
  result = None
 
 return result
 
@qgsfunction(2,"python")
def map_y_max(values, feature, parent):
 """
 Returns the maximum y coordinate of a map from a specific composer.
 Calculations are in the Spatial Reference System of the project.
 
 <h2>Syntax</h2>
 
 map_y_max(composer_title, map_id)
 
 <h2>Arguments</h2>
 
 composer_title - is string. The title of the composer where the map is.
 map_id - integer. The id of the map.
 
 <h2>Example</h2>
 
 map_y_max('my pretty map', 0) -> 12345.679
 
 """
 composer_title = values[0]
 map_id = values[1]
 map_extent = map_bounds(composer_title, map_id)
 if map_extent:
  result = map_extent.yMaximum()
 else:
  result = None
 
 return result

As funções ficaram disponíveis no construtor de expressões na categoria “Python” (podia ter-lhe dado outro nome qualquer) e as descrições das funções são transformadas em textos de ajuda para fornecer ao utilizador informação de como utilizar as funções.

Screenshot from 2014-09-09 15^%39^%19

Usando as funções recentemente criadas, foi fácil posicionar etiquetas  junto dos cantos do mapa com as coordenadas dos mesmos. Qualquer alteração à extensão do mapa, reflecte-se nas etiquetas, podendo por isso ser usadas convenientemente com a funcionalidade de atlas.

Screenshot from 2014-09-09 15^%40^%27

O resultado destas funções pode ser usado com outras. Na imagem seguinte apresenta-se uma expressão para apresentar as coordenadas de forma mais compacta.

Screenshot from 2014-09-09 15^%43^%55

Havia um senão… Para as funções ficarem disponíveis, seria necessário importá-las manualmente em cada utilização do QGIS. Algo que não era prático. Novamente com a ajuda do Nathan, fiquei a saber que podemos importar módulos Python no arranque do QGIS colocando na pasta .qgis2/python um ficheiro com o nome startup.py com os comandos de importação. Para o meu caso bastou o seguinte.

import userfunctions

Conclusões

Fiquei bastante satisfeito com o resultado. A possibilidade do utilizador criar as usas próprias funções para usar em expressões vem mais uma vez demonstrar como é fácil personalizar e criar as minhas próprias ferramentas para QGIS. Já estou a matutar em mais aplicações para estar fantástica funcionalidade.

UT 9 - Qta da Peninha - Vegetação potencial

Os ficheiros Python com as funções criadas podem ser descarregados AQUI. Basta descompactar os dois ficheiros para a pasta .qgis2/python e reiniciar o QGIS, e as funções devem ficar disponíveis.

Por favor, use o operador “IN”

Por favor, use o operador “IN”

EN | PT

Já não é a primeira vez que vejo pessoas que para seleccionarem elementos pelos valores dos seus atributos, usam expressões como

"field" = 'value1' OR "field" = 'value2' OR "field" = 'value3' [OR ...]

Uma forma mais prática e bonita de o fazer é usar o operador IN.

"field" IN ('value1','value2','value3'[,...])

Este operador existe em quase todos os softwares SIG que conheço. No QGIS, pode ser usado mesmo quando não existe um botãozinho para clicar.

Captura de tela 2014-04-23 16.50.40

Na verdade, trata-se de uma abreviatura do que é usado em SQL, onde o operador é usado na expressão WHERE.

SELECT *
FROM parks
WHERE "tipo" IN ('PI','CM','PJ');

Old map in QGIS

Old map in QGIS

EN | PT

Inspirado num artigo da Anita Graser, tentei usar o QGIS para criar um mapa de Cascais que tivesse um aspecto antigo, como que se tivesse sido metodicamente desenhado à mão, embora tivesse ligeiramente maltratado.

Definir os Estilos

Comecei por definir a simbologia para cada um dos elementos a representar.

Edifícios

Para preenchimento dos edifícios tentei usar uma cor que lembrasse os telhados portugueses, e muito usada em mapas antigos de cidades, com um contorno ligeiramente mais escuro do mesma cor.

Para dar dimensão aos edifícios criei uma sombra por baixo, adicionando um “simple fill” em tons escuros e usando a opção Offset X,Y. Os valores escolhidos tiveram em conta a direcção predominante das fachadas dos edíficios de forma a que o efeito fosse visível por toda a área do mapa.

Capturar_4

Capturar_6

Espaços verdes

Para espaços verdes, usei 3 camadas de simbologia. Uma base com o preenchimento a verde. Uma segunda camada com um contorno grosso ligeiramente mais escuro, e com uma funcionalidade que surgiu na versão 2.2 e que permite mostrar as linhas de contorno apenas no interior do polígono. Para tal é necessário escolher o tipo “outline: simple line” e seleccionar a opção “draw line only inside polygon”.

Capturar_5

.A última camada de simbologia é uma linha fina num verde mais escuro que as restantes.

Capturar_7

O Mar

Para o mar usei a mesma técnica que para os espaços verdes, mas em tons de azul e com o contorno do meio mais exagerado.

Capturar_8

 Estradas

Para símbolo das estradas usei uma linha grossa com um tom pastel alaranjado. Criei também etiquetas dos nomes das ruas ao longo das linhas usando uma fonte script (no meu caso o Pristina Bold). Para melhorar a legibilidade adicionei um pequeno buffer branco com 50% de transparência.

Captura de tela 2014-04-11 17.55.04

Capturar_9

Praia

Nas praias, para além da base, usei um point pattern fill, com um círculo bastante pequeno.

Capturar_11Capturar_10

Composição do mapa

Embora o aspecto do mapa não esteja muito longe do resultado final, é no Print Composer que se dão os toques finais. Em primeiro lugar, comecei por preencher toda a folha com a imagem de uma textura de papel antigo (aliás, o mesmo usado pela Anita no seu artigo). Para o efeito não ficar demasiado pesado, apliquei uma transparência de 20% à imagem.

Captura de tela 2014-04-14 11.24.53

Depois adiciona-se o mapa propriamente dito e nas suas propriedades alteramos o modo de rendering de “normal” (usado por defeito) para “multiply“. Desta forma parece que o mapa foi desenhado directamente sobre o papel antigo.

Captura de tela 2014-04-14 11.30.07

Depois é uma questão de adicionar mais umas etiquetas (nomes de praias e locais), uma rosa dos ventos e uma escala gráfica (usando sempre o modo de rendering “multiply” para parecer que foi desenhado por cima da folha), e… Voilá, temos mapa!

mapa_antigo

Novo plugin QGIS “Walking time”

EN | PT

Finalmente “terminei” o meu novo plugin. Coloquei o termo entre aspas porque creio que ainda há espaço para alguma melhorias. Este plugin surgiu da necessidade de estimar o tempo de percurso das pequenas e grandes rotas de cascais, e começou como um pequeno script em python. Depois decidi criar um interface gráfico e publicá-lo como plugin porque talvez seja útil a mais pessoas.

icon_large

O Walking time é um plugin python para QGIS que usa a Tobbler’s hiking function para estimar o tempo de percurso ao longo de uma linha consoante o declive.

Os dados de input necessários são uma camada vectorial de linhas e uma camada raster com valores de elevação (1). É possível ajustar a velocidade base (em terreno plano) de acordo com o tipo de caminhada ou caminhante. Por defeito, o valor usado é de 5 km\h (2). O plugin actualiza ou cria campos com o tempo estimado em minutos, no sentido directo e no sentido inverso (3). É possível correr o plugin para todos os elementos da camada vectorial, ou apenas nos percursos seleccionados (4).

O plugin pode também ser usado para preparar uma rede (grafo) para realizar análise de redes onde se queira usar como custo o tempo de percurso.

Captura de tela 2014-03-24 12.12.17-01

Repositório QGIS: http://plugins.qgis.org/plugins/walkingtime/

Código: https://github.com/SrNetoChan/WalkingTime

Reportar bugs | Bug report: https://github.com/SrNetoChan/WalkingTime/issues

Mapas de fluxos em QGIS

Mapas de fluxos em QGIS

Hoje surgiu a questão “Como consigo fazer um mapa em que a sobreposição de símbolos aumente a opacidade?“. Fiz o meu melhor para descrever como fazê-lo em QGIS, que transcrevo agora para português.

Este tipo de mapas pode ser feito em QGISs usando a uma combinação da transparência e cor dos símbolos e o blending mode dos elementos.

Note-se a diferença entre a transparência e blending mode da camada (que é aplicado a toda a camada) e a transparência do símbolo e blending dos elementos (que acumulam com outros elementos da mesma camada).

Esta opções estão disponíveis em Propriedades da camada > Estilo.

testes_opacidade_opcoes

Com um valor de transparência do símbolo de 95%, a cor do elemento tornar-se à totalmente opaca quando pelo menos 20 elementos de sobrepuserem. Este número é limitado à sobreposição de 100 elementos(tranparencia 99%).

Usando diferentes modos de blending (como a multiplicação ou a adição) consegues-se obter outros efeitos.

Testes_com_opacidade_2

Duplicando a camada, usando diferentes cores (no exemplo abaixo o verde para uma camada e o vermelho para a imediatamente baixo) e usando blending mode dogde,consegue-se obter efeitos ainda mais interessantes.

opacity dodge