Date: | 2005/09/27 |
---|---|
Author: | Bill Binko |
Contact: | bill at binko.net |
Last Edited: | $Date: 2008-12-23 13:34:31 -0800 (Tue, 23 Dec 2008) $ |
Status: | Proposed |
Id: | $Id: ms-rfc-6.txt 8278 2008-12-23 21:34:31Z hobu $ |
Description: This proposal addresses the need to be able to easily map continuous feature values to a continuous range of colors. This RFC is the result of (and my interpretation of) the discussion that surrounded Bug #1305.
A preliminary patch has already been applied to Mapserver 4.6+ (before the RFC process was in place), however, there is little consensus on the format being used and there is no support for proper display of legends for classes using ColorRanges.
This work started as a patch that I created to be able to quickly visualize data with a large range of values. In particular, I was wishing to map property values, and various ratios that could take on a large range of values. To me, the natural way to do this was to set a max value, a min value and what colors those mapped to. The patch I wrote had Mapserver do a linear interpolation of the value for each feature on to that color range.
The initial syntax for this feature simply added 5 new keywords to the STYLE block and looked as follows:
STYLE
COLOR 60 60 60
MINCOLOR 0 0 0
MAXCOLOR 255 255 0
MINVALUE 0.0
MAXVALUE 300000.0
GRADIENTITEM "sale_price"
END
After some discussion, the term Gradient was shown to be problematic. Also, the number of new keywords seemed high. After some discussion, the syntax was changed to this format:
STYLE
COLORRANGE 0 0 0 255 255 0 # black to yellow
DATARANGE 0.0 100.0
RANGEITEM "foobar"
END
While this is still just a set of keywords under a Style, it seemed simpler and is now working in the Mapserver 4.6 branch.
Several people pointed out that the current syntax could be improved by:
To meet the above needs, I propose the following new Block Syntax:
COLORRANGE
RANGEITEM 'itemname' #required
MINCOLOR 0 0 0 #optional - default = Black
MAXCOLOR 255 255 0 #optional -default = White
MINVALUE 0.0 #optional - default = 0
MAXVALUE 100.0 #optional - default = 1
INTERVALS 10 #optional - default = 0 (unlimited)
METHOD LINEAR #optional - default = 'LINEAR'
END
I propose that this block lives at the CLASS level. My reasons for putting it at the CLASS, rather than the LAYER (or above) level are as follows:
(If we wish to provide this capability on the OUTLINECOLOR, then I would suggest we create a OUTLINECOLORRANGE block with identical format.)
Note: I am (and have always been) flexible on all of the keyword names and formats here. However, given the discussion that’s gone on around (and around) this, I thought I’d put a straw man up and start here.
I have posted a mockup of how I believe legends should look at
http://trac.osgeo.org/mapserver/ticket/324
The format only changes the height of the legend (which is already dynamic) so it should not have major layout implications. (Nit-picking about how tall the colorbar should be can be worked out during implementation.)
I have not started the legend support, and would like some help in this area. However, I do believe it is straightforward, and I will do it on my own if there are no volunteers.
As Sean Gillies mentioned in the discussion, this should be encapsulated in MapScript as a class. While I disagree with his putting it on the LAYER (see above), the rest of his suggestions all seem right in line.
I Propose a class named ColorRamp with the following read/write attributes:
Color minColor
Color maxColor
double minValue
double maxValue
String rangeItem
String method
int intervals
and two methods
Color findColor(double value)
double findValue(Color color)
ColorRamps can be obtained through an appropriate constructor or through a new (read/write) attribute on the ClassObj object:
ColorRange colorRange
Note: I will need help in adding these to MapScript as I do not have the SWIG experience to do it well.
I will update this list as the RFC evolves, but right now, these are what I see:
Right now, certain code _requires_ that there is a COLOR attribute set on any layer that is going to be displayed. Either this will need to be changed, or we will have to decide what that means if both a COLOR and a COLORRANGE are defined. One option is to use the COLOR for any values that are outside of the range.
The system will allow new color mapping methods to be added with as little effort as possible. If a new color mapping method uses only the keywords defined by this RFC, it should be a simple as:
int mappingFn(colorRangeObj\* range, shapeObj\* shape, colorObj \*color)
This function should use the shape and range parameters to determine the
shapes color, and modify the color parameter accordingly.
Note
Whether the msMapColorRamp() method uses if/then logic or dispatches by function pointer can be determined later. For now, I believe the simplest approach would be to move all of the mapping logic + all current methods into a mapColorRange.c file.
Currently this is being tracked by http://trac.osgeo.org/mapserver/ticket/1305
None