# Rendering point symbols on top of diagrams?

I've got some data where I have categorized symbology for point data with different colors showing different categories. I would also like to display some data using the pie charts function. I would like to have the different colored point on top of the pie charts to get a symbol that looks something like the mock-up below. I can't find a way to get the points on top of the charts. Any suggestion?

• Is the pie chart solution strictly necessary? Or you may also recur to other symbology types? You could create a custom symbology through the geometry generator, for example. – mgri Mar 25 '17 at 20:22

Another approach would be recurring to symbology only: the main advantage is that the result will be customizable with practically infinite combinations of parameters.

The following procedure will use a custom function and it will work independently from the number of categories you will use.

Assuming you are working on a projected CRS (instead, if you are using a Geographic Coordinate System, see the note at the end of the answer), I want to underline that I will focus the attention on the explanation of the minimal things to do for reproducing the desired result: this means that some other minor parameters (like sizes, widths and so on) should be easily adjusted by you for better fitting your needs.

You will discover that reading the following solution will require more time than applying it directly (since the custom function will automatically do the most of the job).

# Context

Let assume to start from this point vector layer: which stores several categories that we want to display: # Solution

Assuming we want to categorize the `"cat_1"`, `"cat_2"` and `"cat_3"` fields, we will render the point at the center (the yellow point in your original question) with one `Geometry generator` symbol layer. Then, we will render the several categories using a number of `Geometry generator` symbol layers which is equal to the number of categories themselves. So, for this case, we will use three `Geometry generator` symbol layers: In the further explanation, the colors of the squares in the above image will help you to understand which geometry we are creating.

### 1) Geometry Generator No. 1

Add a new symbol layer and select the `Geometry generator` and the `Polygon / MultiPolygon` types: Insert this expression in the Expression field:

``````buffer(\$geometry,10)
``````

We have just defined a circle which has a radius of 10 meters.

### 2) Geometry Generator No. 2

From the `Style` dialog, add a new `Geometry generator` symbol layer having `Polygon / MultiPolygon` as geometry type. Then click on the `Function Editor` tab: Then, click on `New file` and type `piechart` as the name of the new function: You will see that a new function has been created and it is listed on the left side of the dialog. Now, click on the name of the function and replace the default `@qgsfunction` with the following code (don't delete the libraries imported by default and remember to add the `import math` line):

``````from qgis.core import *
from qgis.gui import *
import math

@qgsfunction(args=-1, group='Custom')
def piechart(in_list, feature, parent):
to_show =in_list[-1] - 1
fields =in_list[:-2]
len_fields = len(in_list)
sum_val = sum([feature[k] for k in fields])
geom = feature.geometry()
first = True
slices = []
for field in fields:
point_1 = geom.asPoint()
points = [point_1]
perim = buffered.length()
percent = float(feature[field])/(sum_val)
l = percent * perim
if first:
start = 0
end = azimuth
first = False
else:
start = end
end += azimuth
if abs(math.degrees(start - end)) <= 180:
point_2 = QgsPoint(point_1 + dist_x, point_1 + dist_y)
point_3 = QgsPoint(point_1 + dist_x, point_1 + dist_y)
point_4 = QgsPoint(point_1 + dist_x, point_1 + dist_y)
else:
point_2 = QgsPoint(point_1 + dist_x, point_1 + dist_y)
point_3 = QgsPoint(point_1 - dist_x, point_1 - dist_y)
point_4 = QgsPoint(point_1 + dist_x, point_1 + dist_y)
points.append(point_2)
points.append(point_3)
points.append(point_4)
trGeom = QgsGeometry().fromPolygon([points])
if  math.degrees(azimuth) <= 180:
if start >= end:
slice = buffered.difference(trGeom)
else:
slice = buffered.intersection(trGeom)
else:
if start >= end:
slice = buffered.intersection(trGeom)
else:
slice = buffered.difference(trGeom)
slices.append(slice)
return slices[to_show]
``````

Once you have done this, click on the `Load` button and you will be able to see the function from the `Custom` Menu of the `Expression` dialog.

Now, type this expression (see the image below as reference):

``````piechart('cat_1', 'cat_2', 'cat_3', 20, 1)
`````` We have just defined the first sector of the pie chart by entering the names of the fields to categorize (`'cat_1', 'cat_2', 'cat_3'`), the radius of the pie chart (`20`) and a number which indicates the category (starting from 1) to display: for this case, we will render the first category from the list, so we need to set `1` as value. As you will see in the following steps, this number will be the unique value to change.

### 3) Geometry Generator No. 3

From the `Style` dialog, add a new `Geometry generator` symbol layer having `Polygon / MultiPolygon` as geometry type. Then click on the `Function Editor` tab: Then, type this expression in the `Expression` field:

``````piechart('cat_1', 'cat_2', 'cat_3', 20, 2)
``````

We have just defined the second sector of the pie chart. The unique difference with the previous step is that we set 2 as the last parameter: this because we want to render the second category field (i.e. `"cat_2"`).

### 4) Geometry Generator No. 4

From the `Style` dialog, add a new `Geometry generator` symbol layer having `Polygon / MultiPolygon` as geometry type. Then click on the `Function Editor` tab: Then, type this expression in the `Expression` field:

``````piechart('cat_1', 'cat_2', 'cat_3', 20, 3)
``````

We have just defined the third sector of the pie chart. The unique difference with the previous step is that we set 3 as the last parameter: this because we want to render the third category field (i.e. `"cat_3"`).

# Final result

Click on the `Apply` button for applying the renderer: we have finished. If you correctly performed the previous tasks, you should be able to get something like this: # Final notes

If you are using a Geographic Coordinate System, i.e. if you are dealing with degrees and not with distances, it should be enough using the proper value for the fourth parameter of the `piechart` function: this means that you need to replace it with other arbitrary values expressed in degrees (for example, 0.0002, 0.002 and so on).

Please note that my example will work fon any number of fields to categorize, assuming that you will create the proper number of geometry generators and set the correct values for the fourth parameter in the `piechart` function.

• Many thanks! This is so great. I can only say wow. :) – Kazuhito Apr 1 '17 at 2:05
• Very creative solution, although there should be an easier solution than creating custom functions. +1 from me. – ahmadhanb Apr 1 '17 at 4:52
• @Kazuhito, thanks, I really appreciate! I hope it will be useful for you or other users! =) – mgri Apr 1 '17 at 9:31
• @ahmadhanb thanks. I'm sure there will be some faster way in the next releases for doing this: in the meanwhile, I'm just exploring the power of custom function! :) – mgri Apr 1 '17 at 9:35
• Thanks @mgri. Got this to work on 2.18.20 but on 3.0.3 only the first symbol appeared. I would guess this has to do with the changes to Python 3. Any thoughts what needs to be modified to get this to work with QGIS 3? – Techie_Gus Jun 27 '18 at 14:00

I think this is a bug. I have the same issue, and I tested on both QGIS 2.14.10 and QGIS 2.18.2, and there is no way show the point simple style above the graphs, although the point shapefile is located above the graph, as you can see below: Here is the point shapefile without the graphs:

The only I can show the point is by setting the layer transparency for the pie chart appearance: You can report this bug here.

• Thanks @ahmadhanb , so helpful as always. I am getting more anxious about the timing of the fix (if possible at all), so I think the other approach proposed by mgri would be beneficial for us all. – Kazuhito Apr 1 '17 at 2:04