All values should become expressions #828

Closed
artemp opened this Issue Oct 11, 2011 · 11 comments

Projects

None yet

8 participants

@artemp
Member
artemp commented Oct 11, 2011

To allow for less complex styles, every symbolizer attribute should become an expression. There are some properties that already have a notion of being an expression, e.g. the polygon-pattern-file and text-name has token replacement and the marker-width is an expression too.

How to implement

When rendering, create a pseudo-stylesheet for each layer that contains only the rules for that layer. This is already happening in [https://github.com/mapnik/mapnik2/blob/f3061554c97e80520da45870d86ae7ed6cc5c7ee/include/mapnik/feature_style_processor.hpp#L262-297 apply_to_layer()]. Instead of just creating a new set, we clone each rule and pre-evaluate it; i.e. evaluate all expressions as much as possible, leaving the parts that reference feature-specific values intact. In some cases, this might already yield a constant value, in other cases we still have an expression. This is an optional step and should be implemented last to improve performance should the following changes turn out to slow down rendering dramatically.

Every attribute of a symbolizer becomes an expression. The renderer passes the feature to the attribute getter of a symbolizer to obtain the actual value. In case the value is static, the expression object just returns that value, otherwise it evaluates the expression taking the current feature into account. In addition to the feature's attributes, the scale denominator is also an available attribute.

As a next step, we'd add ''value gradients'': a function that transforms a float in the range of 0.0 to 1.0 to an actual value, e.g. you could create a color gradient from #000 to #FFF and using an expression, calculate a value between 0 and 1 (e.g. by using statistics about the datasource) and resolve that value to a color. This could come in two flavors, a gradient() function that returns continuous values and a levels() that returns only discrete values.

Related tickets: #816, #827, #704, #810

@artemp
Member
artemp commented Oct 11, 2011

[kkaefer] Backwords compatiblity with current symbolizer values: first try to parse as constant/static value, if that fails, try to parse as expression

@artemp
Member
artemp commented Oct 11, 2011

[kkaefer] Duplicate: #359

@artemp
Member
artemp commented Oct 11, 2011

[kkaefer] Implementation happens in https://github.com/kkaefer/mapnik2/compare/expressions

I benchmarked <PolygonExpressionSymbolizer fill="black" fill-opacity="1" /> vs. <PolygonSymbolizer fill="black" fill-opacity="1" />. The difference is that in the PolygonExpressionSymbolizer, "1" is compiled to an expression and evaluated when drawing each feature; in PolygonSymbolizer, it's parsed to the double 1 when loading the map and just used as a plain value. When drawing processed_p on 1200x800, evaluating expressions was about 1% slower. I used https://gist.github.com/8162aa04a4ba20e26ecf for benchmarking.

On world_merc, the difference wasn't measurable. I also created a stylesheet that actually takes advantage of the fact that we can reference the data in values: <PolygonExpressionSymbolizer fill="black" fill-opacity="[POP2005] / 100000000.0" />. Again, for world_merc, the difference between that expression and a plain value isn't measurable. However, when expanding the expression to a stylesheet with rules for each feature, expression evaluation is about 10% faster. The stylesheets I used are https://gist.github.com/c17a99796b66d93302b6 and https://gist.github.com/dfb27e00c201980a8227. Note that we currently still need <Filter>[POP2005] > -100</Filter> to make Mapnik load the column from the shapefile. The resulting image is in both cases: http://i.kkaefer.com/out-20110822-170348.png

@rory
rory commented Nov 28, 2011

This would be very cool, and could allow things like "change the colour of this object based on a column".

@jatorre
jatorre commented Jul 12, 2012

Big fan of having this. Gradients, levels and in general functions would be cool, but expressions themselves are already a huge win. In CartoDB most of the functions can be precalculated via SQL and inject with the expression.

@dbrgn
dbrgn commented Aug 13, 2012

Yes please! :)

@yvecai
yvecai commented Oct 31, 2012

A syntax allowing a fallback value would be great, too.

@manelclos
Member

Hi, is there a list of attributes supporting expressions?

@plepe
Contributor
plepe commented Jul 11, 2014

Not as far as I know, but I just added information about support to the following wiki pages:

You can also use expressions with TextSymbolizer by using ExpressionFormat. I haven't found documentation in the Wiki about this feature, but see https://github.com/mapnik/mapnik/blob/master/tests/visual_tests/styles/text-expressionformat-color.xml as an example. As far as I know you can use ExpressionFormat from Mapnik 2.2 with the following attributes: size, halo-radius, character-spacing, opacity, wrap-character. from Mapnik 3.0 ExpressionFormat also supports the attributes fill and halo-fill.

I don't know about other symbolizers, but as far as I know they don't support expreesions yet. I hope I was right about all changes ... please correct me.

@springmeyer
Member

This is now in place in master (upcoming 3.0.0 release). 95% of symbolizer properties are expressions with only a few holdouts/todos. If you find one that does not respond as an expression please file a new issue :)

@plepe - ExpressionFormat was removed because now it is redundant because the normal Format supports expressions for all properties except fontsets. See https://github.com/mapnik/mapnik/wiki/Api-changes-between-v2.3-and-v3.0 that notes the removal.

@springmeyer
Member

closing, followup tickets at #2237 and #2224

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment