plepe/pgmapcss

Waiting for Mapnik to implement Expressions for all values

Closed this issue · 11 comments

An important requirement for pgmapcss to work is, that Mapnik can read all Symbolizer values from database columns. e.g.
<LineSymbolizer stroke="[color]" stroke-width="[width]" />

See Mapnik issue mapnik/mapnik#828.

Hope there's a test-branch soon ...

there is a branch that does stroke-width: mapnik/mapnik@master...stroke-width-expr but this is a very big endeavour to make all properties expressions without a refactoring in core to make it easier to do (which is where things are somewhat stuck). My best sense is that after we move to requiring c++11 features this will become more feasible.

I know about stroke-width-expr, in fact I'm already using it for testing purposes. And it works fine :-)

If it would be possible to also read line/polygon/text colors from db columns, pgmapcss would start to be usable.

thinking out loud: what format(s) for colors should be supported? should colors be forced to be read from a single column or multiple? what happens if the data contains 7 million rows and the stylesheet contains a typo and every single 7 million rows a color is attempted to be parsed and fails? Should mapnik throw an exception on the first one or print a warning for every 7 million or be silent?

formats: not sure; i guess mapnik should be able to read the same formats in expressions as it can read right now. In the case of pgmapcss it would be sufficient to read hex-values (like #ff0000) (pgmapcss could convert other formats).

single column / multiple column: I don't actually now which formats of expressions will be finally implemented, I guess something like "[foo] + [bar]" will be possible. Actually, I don't care, as for pgmapcss single columns are sufficient.

typo: I guess, that remembering whether mapnik already threw a warning on a failed parsed color would be really difficult. Printing a warning every time should be ok - maybe a configuration option to ignore invalid values could be possible - or map them to a default color. The same applies for other expressions too, doesn't it? Like reading a string for a width.

A few color transformations would be great too: for Opensnowmap, I need to decrease the color luminance or 'luma' for proper rendering of yellow pistes, for instance.
Something like:

def deluma(color,factor):
    # reduce color luma by a given factor.
    r,g,b,a=(color.r, color.g, color.b, color.a)
    r=int(r*(1-0.3*factor))
    g=int(g*(1-0.59*factor))
    b=int(b*(1-0.11*factor))

    return mapnik.Color(r,g,b,a)

http://github.com/yvecai/mapnik-opensnowmap.org/blob/master/offset-style/build-relations-style.py

Yeah, only reason why I haven't implemented that, is that Mapnik does not support Expressions for Colors yes (pgmapcss would need to guess all resulting colors). As soon as Mapnik does (and I think it can be only a short period of time, in fact I was already partly successful using the 'expr-v2' branch, I will add those functions).

So, after the release of pgmapcss 0.5.0 I started testing the expr-v2 branch of Mapnik. Mapnik still can't read many values for symbolizers directly from the database, but at least it can read them on LineSymbolizers, PolygonSymbolizers and TextSymbolizers. Therefore the 'expr-v2' template (compile with pgmapcss -texpr-v2) can handle colors on 'color', 'casing-color', 'text-color', 'text-halo-color' and 'fill-color'. I also added eval()-functions for rgb(), rgba(), deluma() and lighten() as requested (use the 'master' branch).

Now you should be able to do something like:

line[piste=ski] {
  width: 5;
  color: eval(tag('piste:color')); // the tag 'piste:color' has to be in hex notation (e.g. #ffff00).
  casing-width: 2;
  casing-color: eval(deluma(tag('piste:color'), 0.5));
}

more examples:

{
  color: eval(rgb(190, 150, 30));
  casing-color: eval(lighten(prop('color'), 1)); // copy prop color to casing-color
}

Have fun!

@plepe - thrilled so see you are testing the expr-v2 branch already. You'll hopefully see a lot more movement on it within about 2 weeks.

@springmeyer - Yeah, I knew, when I read the name "symbolizer-expressions", that something big is comping up :) I'm thrilled that it's finally happening!

The experimental expr-v2 branch has been merged to Mapnik master: mapnik/mapnik#2222

pgmapcss supports the upcoming Mapnik release when using the "mapnik-3.0" template.

I forgot: pgmapcss 0.7 (for Mapnik 2.x) tries to predict possible results of eval()-expressions at compile time and will therefore include possible results in the Mapnik stylesheet. This works e.g. for things like eval(cond(zoom() > 6; zoom() * 2; 15)) or eval(lighten(rgb(0.5, 30, 20), 1)).