santilland/plotty

Can we limit the range of values?

sakitam-fdd opened this issue · 5 comments

Whether it is possible to support range filtering, for example, by adding a new parameter:

  • Now, nodatavalue only supports single value filtering. We can add a parameter to support passing an array [min, Max] to specify the range of displayed values

  • Shaders need to be changed:

precision mediump float;
uniform sampler2D u_textureData;
uniform sampler2D u_textureScale;
uniform vec2 u_textureSize;
uniform vec2 u_domain;
uniform float u_noDataValue;
uniform vec2 u_data_range;
uniform bool u_clampRange;
uniform bool u_clampLow;
uniform bool u_clampHigh;
varying vec2 v_texCoord;

void main() {
    vec2 onePixel = vec2(1.0, 1.0) / u_textureSize;
    float value = texture2D(u_textureData, v_texCoord)[0];
    if (value == u_noDataValue)
        gl_FragColor = vec4(0.0, 0, 0, 0.0);
    else if (u_clampRange && (value < u_data_range[0] || value >= u_data_range[1]))
        gl_FragColor = vec4(0.0, 0, 0, 0.0);
    else if ((!u_clampLow && value < u_domain[0]) || (!u_clampHigh && value > u_domain[1]))
        gl_FragColor = vec4(0, 0, 0, 0);
    else {
        float normalisedValue = (value - u_domain[0]) / (u_domain[1] - u_domain[0]);
        gl_FragColor = texture2D(u_textureScale, vec2(normalisedValue, 0));
    }
}
  • The code needs to be modified:
this.dataRange = [min, max];

const positionLocation = gl.getAttribLocation(program, 'a_position');
const domainLocation = gl.getUniformLocation(program, 'u_domain');
const resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
const dataRange = gl.getUniformLocation(program, 'u_data_range');
const noDataValueLocation = gl.getUniformLocation(program, 'u_noDataValue');
const clampRangeLocation = gl.getUniformLocation(program, 'u_clampRange');
const clampLowLocation = gl.getUniformLocation(program, 'u_clampLow');
const clampHighLocation = gl.getUniformLocation(program, 'u_clampHigh');
const matrixLocation = gl.getUniformLocation(program, 'u_matrix');

gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
gl.uniform2fv(domainLocation, this.domain);
gl.uniform2fv(dataRange, this.dataRange);
gl.uniform1i(clampRangeLocation, this.clampRange); // true or false
gl.uniform1i(clampLowLocation, this.clampLow);
gl.uniform1i(clampHighLocation, this.clampHigh);
gl.uniform1f(noDataValueLocation, this.noDataValue);
gl.uniformMatrix3fv(matrixLocation, false, this.matrix);

The result:

image

image

Hello sakitam-fdd,
thank you for your idea. In principle a "no-data-range" could be introduced, but seeing your example i think you could just turn off clamping (which means maintaining the max/min color after values go above/below the specified range) and modify your range.
So from the screenshots you could then use the min and max value to modify the range, could look something like this:

plot = new plotty.plot({
    canvas: el, 
    width: width, height: height,
    domain: [min, max],
    clampLow: false,
    clampHigh: false
});

and then adapt the range and rerender on input change:

minRangeSlider.oninput=function(){
        minRange = parseFloat(this.value);
        plot.setDomain([minRange, maxRange]);
        plot.render();
};

If what you need is to not show a range of values inside of the specified min max range then you would need the approach you present. Is this what you are aiming for?

@santilland Thank you for your reply, I have tried to use domain to filter the displayed values, but this brings another problem. I give two minimum examples:

In this example, when we control the display of temperature, we expect the fixed temperature value to correspond to the fixed color display, In fact, for color, it's always related to the value field.
So we may want to keep the domain unchanged and introduce another parameter to achieve this purpose, or there's a better way

I see, I did not think about the relation of color to value shifting, you are right.
I can't really think about a better approach right now then to use an additional range. I will look into incorporating your approach in the coming days.

Hi @sakitam-fdd,
i just did a release, with the new release (d7d1116) you can use the setDisplayRange([min,max]) method to set the range that should be shown.
I changed a little the property names and made sure it also works for the javascript only fallback (if there is no webgl available).
Hope this works for you, let me know and i'll close the ticket.

@santilland Yes, I tested it. It works very well, thank you very much for your work. examples