I need to create dot grids for multiple projects and looking for a way to generate/symbolize them systematically to save time. These grids have a couple rules to them though, and the way QGIS generates grids starts top right whereas I want it to start from bottom left.

The grid needs to generate all points, but then only symbolize certain ones to show which points in the grid are "valid" for use. The grid is generated from a baseline and goes up in strip lines from there, moving left to right. ie. starts bottom left at strip line 1, and when it reaches the top of the grid extent, it returns to the baseline and starts up a second strip line that is one grid space distance offset from the last.

Strip line #1 of grid plots needs to start at 1x the grid space distance, then for the remainder of strip line #1 the points need to jump 2x the grid space distance. Then for the second strip line it needs to start at 2x the grid space distance and then continue to place/symbolize them at 2x grid space distance. This creates a staggered grid.

Here is an image showing how it needs to be, though here every second point has been dropped/hidden to achieve the offset staggering between strip lines, and ideally point 24 should be point 2 when numbering from bottom left to top right instead of top left to bottom right, since the origin of the grid is at the bottom left of the first stripline.

grid arrangement

My issue is I cannot save out a layer style with this symbology filtering, as the grid size changes depending on the area it is being applied to, and so the first strip line may not have 25 plots in it anymore, it may only get 24, or might have 26, and that messes up the numbering for stripline 2, so the points that get shown are not offset properly. Below is an example of this with some of the errant points circled in red:

plots offset as stripline 1 grid space distance is larger than previous

I am currently achieving this with a klunky implementation that uses rule-based symbology filtering, giving the layer a list of feature ID's that are valid to display, so if stripline 1 has a different number of points it causes a renumbering of all the valid feature ID #'s after it, not ideal, but it was what I could come up with to try first.

I am not a python programmer, so looking for some way in QGIS to achieve this somewhat dynamic grid building/displaying and open to any suggestions on re-approaching the problem, or a fancy SQL way of making the existing symbology filtering work.

  • Might be worth adding the grid lines to your point diagrams above - I'm not entirely clear on the rules you've described. Also, how are you determining the grid in the first place - because that will help with the filtering. Jul 29, 2023 at 22:29
  • The grid's origin is the intersection of the southern most and western most vertices of a polygon, in the diagram above it is the blow fill polygon. The grid space distance is determined by a formula, and there is also an offset for the grid's origin that is meant to make things random. There have been attempts to automate the generation of this grid but without some serious programming skills (which I don't have) there were too many manual bits to make automation work. I'll try to find some time to make a new pic with the grid lines added.
    – forestGIS
    Aug 1, 2023 at 15:15
  • I'd suggest you add things like the grid space formula and the origin offset to the question too (or an example of each, if the full detail is too involved). Also, the grid presumably needs to extend beyond the polygon? While it may seem like unnecessary detail, it's easier for someone to have the full requirement in order to replicate what you're asking. For example, if you know the height of the polygon, the grid space formula and the offset, it should be possible to derive a formula for the filtering. Aug 2, 2023 at 0:03
  • Grid space distance is figured out by someone else, I just get the number and go from that. The grid offset distance is derived by taking that grid space distance and multiplying it by a percentage that is set by a government office and changes randomly every month. This changes each time I have to make one of these grids unfortunately.
    – forestGIS
    Aug 3, 2023 at 14:59

1 Answer 1


There's a few details in the question that are not entirely clear, but I'd approach it in four steps as follows:

Step 1: Create bounding box layer for grid

This is the most complicated part, as you need to calculate the co-ordinates of the corners of the grid, based on the extent of the original polygon layer. In my example below, I have used a layer called 'Country' but you can replace this as appropriate.

Use the Geometry by Expression tool from the Processing Toolbox, with the following expression.

I have used dummy values for grid space as 0.1, and the offset (%) as 15% (0.15). I have assumed that the bottom left origin point needs to be adjusted by 15% of the grid spacing in both the X and Y directions.

There is also a float adjustment - needed to avoid possible floating point rounding issues with the bounding box. Essentially it makes the box a tiny bit bigger to ensure that you don't lose the last row/column of the grid in the next step.

with_variable('offset', 0.15,
with_variable('grid_space', 0.1,
with_variable('float_adj', 0.0000001,
with_variable('layer_max_y', y_max(layer_property('Country','extent')),
with_variable('layer_min_y', y_min(layer_property('Country','extent')),
with_variable('layer_max_x', x_max(layer_property('Country','extent')),
with_variable('layer_min_x', x_min(layer_property('Country','extent')), 
with_variable('grid_min_y', @layer_min_y - @offset * @grid_space,
with_variable('grid_max_y', @grid_min_y + ceil((@layer_max_y - @grid_min_y) 
    / @grid_space) * @grid_space,
with_variable('grid_min_x', @layer_min_x - @offset * @grid_space,
with_variable('grid_max_x', @grid_min_x + ceil((@layer_max_x - @grid_min_x) 
    / @grid_space) * @grid_space,
    make_point(@grid_max_x + @float_adj, @grid_max_y),
    make_point(@grid_min_x, @grid_max_y),
    make_point(@grid_min_x, @grid_min_y - @float_adj)

Step 2: Create grid

Run the Create Grid tool from the Processing Toolbox, with the Horizontal and Vertical spacing as the grid space (0.1), and using the layer created above as the extent.

Step 3: Add new id field to grid

This step creates a new id field with numbering from the bottom left to top right (instead of top left to bottom right).

Use the Field Calculator to create a field (new_id, type = Integer) using the following expression:

with_variable('grid_space', 0.1,
with_variable('layer_max_y', y_max(layer_property(@layer,'extent')),
with_variable('layer_min_y', y_min(layer_property(@layer,'extent')),
with_variable('y', floor((@layer_max_y - @layer_min_y) / @grid_space + 1),
floor(($id - 1) / @y) * @y + @y - ($id - 1) % @y

enter image description here

Step 4: Select the features for display

Use the following rule in either Select by Expression, or using the Rule-based Symbology in the Symbology tab. Someone smarter than me might be able to combine it into one logical case rather than two:

with_variable('id2', "new_id",
with_variable('grid_space', 0.1,
with_variable('layer_max_y', y_max(layer_property(@layer,'extent')),
with_variable('layer_min_y', y_min(layer_property(@layer,'extent')),
with_variable('dy', (@id2 - 1) % (4 * @y),
((floor(@dy / @y) = 0 and @dy % 2 = 1) or (floor(@dy / @y) = 2 and @dy % 2 = 0))

enter image description here

All of this could be built into a series of PyQGIS commands, but I've left it as QGIS expressions based on your question. You could probably also build it into a model.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.