Recently I was working with some data layers in QuantumGIS, playing to decide the proper color combination for my visualization. The result had to be presented in a web environment using OpenLayers.
The point is. I define and check the visualization in Qgis, and then I want to export the results to be served as a OpenLayers Vectorlayer, or as a Mapserver layer. Of course, with the color defined in Qgis.
Openlayers and Mapserver give the option to read the color from an attribute value (here and here). Maybe there is an easier way, but in this case I developed a small plugin to export the current visualized color into a specific layer attribute.
Screenshots
- Color to Attribute – Icon in Qgis main screen
- Main window of the plugin. Select layer and attribute
- Creating a new attribute to fill with the color value
- Feature list after adding the new attribute
..
NOTE from the future:
The plugin has been modified to work for 2.0+ Check out the 2.0 branch on github
..
Plugin Description
The plugin currently supports three basic renderer styles on Qgis. Obtaining only the base color (not the possible patterns).
- Single symbol
- Categorized
- Graduated
Other renderers like rule based, and point displacement will simply throw an error/information message.
Iep, I’m not done with everything. But now works for what I wanted it 🙂 .
V1 renderers will also complain (read the small letters too!).
Code highlights
It all started with a Qgis python-console “script”, but I imagined a plugin and started to drool with the idea. In this section, I will describe some highlights, if you want to read the full code check my github.
In Qgis, each layer is assigned a renderer, and there are various types of renderers that define which symbol to use for each of the features. Given that situation, I created a specific function for every renderer that I was interested in.
def fill_color_attribute_rendererV2(self): """ Fill the color attribute using a renderer V2""" r = self.renderer rtype = type(renderer) if rtype == QgsSingleSymbolRendererV2: self.fill_color_attribute_singlesymbol_renderer(r) elif rtype == QgsCategorizedSymbolRendererV2: self.fill_color_attribute_categorizedsymbol_renderer(r) elif rtype == QgsGraduatedSymbolRendererV2: self.fill_color_attribute_graduatedsymbol_renderer(r) else: self.fill_color_attribute_custom_renderer(r)
Each one of those functions fills the selected attribute with a color string in hexadecimal. (like “#ff0000”).
Note also that the code in this post is not complete. I omit the process dialog code and similars to leave only the minimum lines needed.
>> Single Symbol
This is the boring one. Get the symbol color and set it everywhere.
- Get symbol
- For each feature
- Assign symbol
def fill_color_attribute_singlesymbol_renderer(self,renderer): """ Set the single color into each of the features """ layer = self.layer attribute = self.attribute colorstr = str(renderer.symbol().color().name()) provider = layer.dataProvider() feat = QgsFeature() newattrs = { attribute : QVariant(colorstr)} provider.select(provider.attributeIndexes()) while provider.nextFeature(feat): fid = feat.id() provider.changeAttributeValues({ fid : newattrs })
>> Categorized
With categorized renderer, a list of categories with symbols is stored, and from this list the features rendered.
- Get the categorization attribute index
- for each feature
- Get the value of the categorization attribute
- Get the color of that category class
- Assign the color to the feature
If a category is not found, a default value is set. Fuchsia (“ff00ff”), because I think that nobody will use that for a map (please, don’t).
def fill_color_attribute_categorizedsymbol_renderer(self,renderer): """ Set the color with a categorized symbol renderer """ layer = self.layer attribute = self.attribute provider = layer.dataProvider() attrvalindex = provider.fieldNameIndex(renderer.classAttribute()) feat = QgsFeature() categories = renderer.categories() provider.select(provider.attributeIndexes()) while provider.nextFeature(feat): fid = feat.id() attribute_map = feat.attributeMap() catindex = renderer.categoryIndexForValue(attribute_map[attrvalindex].toString()) if catindex != -1: colorval = categories[catindex].symbol().color().name() else: colorval = self.NOCOLOR newattrs = { attribute : QVariant(colorval)} provider.changeAttributeValues({ fid : newattrs })
>> Graduated
Finally, the graduated has the same idea as the categorized. But in this case there is no: renderer.categoryIndexForValue(...)
to help. So it is necessary to loop the ranges until the correct one (or none) is found.
- Get the graduation attribute index
- For each feature
- Get the value of the graduation attribute
- For all the renderer symbols (until something found)
- If the value is in range → store color
- Assign the color to the feature
def fill_color_attribute_graduatedsymbol_renderer(self,renderer): """ Set the color with a graduated symbol renderer """ layer = self.layer attribute = self.attribute provider = layer.dataProvider() attrvalindex = provider.fieldNameIndex(renderer.classAttribute()) feat = QgsFeature() provider.select(provider.attributeIndexes()) while provider.nextFeature(feat): fid = feat.id() attribute_map = feat.attributeMap() value = float(attribute_map[attrvalindex].toString()) colorval = self.NOCOLOR for r in renderer.ranges(): if value >= r.lowerValue() \ and value <= r.upperValue() \ and colorval == self.NOCOLOR: colorval = r.symbol().color().name() newattrs = { attribute : QVariant(colorval)} provider.changeAttributeValues({ fid : newattrs })
Final notes
And voilĂ ! The color is stored in an attribute.
If the attribute does not exist, is necessary to create it. And some input sanitizers are implemented (nobody should be able to name an attribute like |\/|1|)i7@).
More renderers exist, I don’t know if I will implement those. Maybe at least the Rule Based one.
References
Qgis ⇒ GO
Qgis API ⇒ GO
pyqgis-cookbook ⇒ GO
QT ⇒ GO
Kxtells Qgis Plugins ⇒ GO
Very helpful to me about the renderer classes. Thank you!
Pingback: Color2attribute in QGIS Plugin servers | Castells
Pingback: Color2Attribute for Qgis3.x | Castells