Page 1 of 1 (3 posts)

  • talks about »
  • cartografia

Tags

Last update:
Sat Aug 19 11:45:19 2017

A Django site.

QGIS Planet

Dica para ajustar posição de símbolos em QGIS | Hack to adjust map symbols location in QGIS

De quando em vez aparecem-me zonas com demasiado símbolos no mesmo local, e pensei como seria fantástico se os pudesse arrastar para um local mais conveniente sem ter de alterar as suas geometrias, tal como é possível fazer com as etiquetas. Esse pensamento deu-me a ideia base para a dica que vou demonstrar.

Now and then I get too many map symbols (points) in the same place, and I thought how nice it would be if we could drag n’ drop them around without messing with their geometries position, just like we do with labels. That thought gave me an idea for a cool hack.

Escolha a sua camada de pontos e comece por criar dois novos campos chamados symbX e symbY (Tipo: Decimal; Tamanho: 20; precisão: 5). No separador “Estilo” das propriedades da camada, defina para cada nível do seu símbolo o seguinte: Escolher “unidade do mapa” como a unidade para as opções de afastamento; Usar a seguinte expressão na opção afastamento das propriedades definidas por dados.

Choose your point layer and start by creating two new fields called symbX and symbY (Type: Decimal number; Size: 20; Precision: 5). Now go the layer properties and in the Style tab edit your symbol. For each level of your symbol select “map units” as the offset units, and set the following expression in the offset data define properties option:


CASE WHEN symbX IS NOT NULL AND symbY IS NOT NULL THEN
    tostring($x - symbX) + ',' + tostring($y - symbY)
ELSE
    '0,0'
END

Screenshot from 2015-02-22 18:18:43

Tenha atenção que, se as coordenadas do seu mapa tiver valores negativos, será necessário uma pequena alteração ao código. E. g., se tiver valores negativos em X deverá usar-se  antes a expressão “tostring(symbX -$x)”.

Beware that if your coordinates have negative values you need to adapt the code. E.g., If you have negative values in X you should use “tostring(symbX -$x)” instead.

De forma temporária coloque etiquetas na sua camada usando um texto pequeno (eu usei o ‘+’ (sinal de mais) centrado e com um buffer branco) e defina as coordenadas X e Y dos propriedades definidadas por dados usando os campos symbX e symbY,

Now, temporarly  label your layer with a small convenient text (I used a centered ‘+’ (plus sign) with a white buffer) and set its coordinates to data defined using the symbX and symbY Fields.

Screenshot from 2015-02-22 22:42:07

A partir desse momento, quando usar a ferramenta de mover etiquetas, não só alterará a posição da etiqueta, mas também a do próprio símbolo! Fantástico, não?

From this point on, when you use the move label tool, not only the label position change but also the actual symbol! Pretty cool, isn’t it?

anim

Note que as geometria dos elementos não são alteradas durante o processo. Para além disso, lembre-se que neste caso também poderá adicionar linhas de guia para ligar os símbolos à posição original do ponto.

Notice that the features geometries are not changed during the process. Also, remember that in this case you can also add leading lines to connect the symbols to the original position of the points.


Hack to adjust map symbols location in QGIS

EN | PT

Now and then I get too many map symbols (points) in the same place, and I thought how nice it would be if we could drag n’ drop them around without messing with their geometries position, just like we do with labels. That thought gave me an idea for a cool hack.

Choose your point layer and start by creating two new fields called symbX and symbY (Type: Decimal number; Size: 20; Precision: 5). Now go the layer properties and in the Style tab edit your symbol. For each level of your symbol select “map units” as the offset units, and set the following expression in the offset data define properties option:


CASE WHEN symbX IS NOT NULL AND symbY IS NOT NULL THEN
    tostring($x - symbX) + ',' + tostring($y - symbY)
ELSE
    '0,0'
END

Screenshot from 2015-02-22 18:18:43

Be aware that, if your coordinates have negative values, you need to adapt the code. E.g., If you have negative values in X you should use “tostring(symbX -$x)” instead.

Now, temporarly  label your layer with a small convenient text (I used a centered ‘+’ (plus sign) with a white buffer) and set its coordinates to data defined using the symbX and symbY Fields.

Screenshot from 2015-02-22 22:42:07

From this point on, when you use the move label tool, not only the label position change but also the actual symbol! Pretty cool, isn’t it?

anim

Notice that the features geometries are not changed during the process. Also, remember that in this case you can also add leading lines to connect the symbols to the original position of the points.


Map corner coordinates in QGIS

EN | PT

Some time ago in the qgis-pt mailing list, someone asked how to show the coordinates of a map corners using QGIS. Since this features wasn’t available (yet), I have tried to reach a automatic solution, but without success,  After some thought about it and after reading a blog post by Nathan Woodrow, it came to me that the solution could be creating a user defined function for the expression builder to be used in labels in the map.

Closely following the blog post instructions, I have created a file called userfunctions.py in the  .qgis2/python folder and, with a help from Nyall Dawson I wrote the following code.

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

After running the command import userfunctions in the python console  (Plugins > Python Console), it was already possible to use the  map_x_min() function (from the python category) in an expression to get the minimum X value of the map.

Screenshot from 2014-09-09 16^%29^%29

All I needed now was to create the other three functions,  map_x_max(), map_y_min() and map_y_max().  Since part of the code would be repeated, I have decided to put it in a function called map_bound(), that would use the print composer title and map id as arguments, and return the map extent (in the form of a 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

With this function available, I could now use it in the other functions to obtain the map X and Y minimum and maximum values, making the code more clear and easy to maintain. I also add some mechanisms to the original code to prevent errors.

@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

The functions became available to the expression builder in the “Python” category (could have been any other name) and the functions descriptions are formatted as help texts to provide the user all the information needed to use them.

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

Using the created functions, it was now easy to put the corner coordinates in labels near the map corners. Any change to the map extents is reflected in the label, therefore quite useful to use with the atlas mode.

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

The functions result can be used with other functions. In the following image, there is an expression to show the coordinates in a more compact way.

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

There was a setback… For the functions to become available, it was necessary to manually import them in each QGIS session. Not very practical. Again with Nathan’s help, I found out that it’s possible to import python modules at QGIS startup by putting a startup.py file with the import statements in the .qgis2/python folder. In my case, this was enough.

import userfunctions

I was pretty satisfied with the end result. The ability to create your own functions in expressions demonstrates once more how easy it is to customize QGIS and create your own tools. I’m already thinking in more applications for this amazing functionality.

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

You can download the Python files with the functions HERE. Just unzip both files to the .qgis2/python folder, and restart QGIS, and the functions should become available.

Disclaimer: I’m not an English native speaker, therefore I apologize for any errors, and I will thank any advice on how to improve the text.


  • Page 1 of 1 ( 3 posts )
  • cartografia

Back to Top

Sponsors