order of evaluation issue react native vs browser - javascript

I have an issue with, what I think it may be, an order of evaluation issue - but I can't figure it out exactly.
The code runs in a react-native environment, but the function is pure JS, so it can be run in browsers as well.
So, I have made a small function that creates a color representation in hsla() format. It does not return the string value directly, instead, it returns a function that uses the initial h,s,l,a values, and it accepts further overrides for l and a so I can tweak them in place. The function is below:
function Color(h, s, l, a) {
return (L, A) => {
let LL = (l || 0) + (L || 0);
if (LL < 0) { LL = 0; }
if (LL > 100) { LL = 100 }
return `hsla(${h || 0},${s || 0}%,${LL}%,${A || a || 1.0})`;
}
};
The problem is it behaves differently over the alpha value between the browser environment and the react-native environment. Specifically, when I try to do this:
var blue=Color(240,100,50);
var semiTransparentBlue = blue(0, 0.5); // 0 lightness adjustment, 0.5 alpha opacity
console.log("The hsla representation of the color is:",semiTransparentBlue);
in a browser environment, it correctly returns the string "hsla(240,100%,50%,0.5)".
In react-native however:
import React from "react";
import { View, Text } from "react-native";
import Color from "../libs/Color.js"; // the Color function is exported as-is in this file
export default class coloredComponent extends React.Component{
render = ()=>{
var blue=Color(240,100,50);
var semiTransparentBlue = blue(0, 0.5); // 0 lightness adjustment, 0.5 alpha opacity
// the above color function returns `"hsla(240,100%,50%,1)"`
// instead of `"hsla(240,100%,50%,0.5)"`, wrong alpha value
console.log("The hsla representation of the color is:",semiTransparentBlue);
return <View style={{ flex: 1, backgroundColor: semiTransparentBlue }} />
}
it returns "hsla(240,100%,50%,1)".
Adding console.log()s in the returned function shows that I do not get undefined values for either the L or A params (in the returned color function). Actually, it does not return at all any different alpha value than 1, I tried with 0.0, 0.1, and others, it always returns 1 for the alpha.
Can anyone help me figure out what's wrong ?

Related

GIF.js flashing on addFrame

I am using GIF.js and am trying to get rid of this flashing of the logo in the bottom left corner of the image (example attached below or can be reproduced at this link. I have confirmed that each frame passed to the gif object is indeed the right color. I am using the following constructor :
var tempGIF = new GIF({
workers: 4,
quality: quality,
height: this.mapHeight + this.infoCanvas.height,
width: this.mapWidth,
workerScript: 'gif.worker.js',
globalPalette: true
});
and adding frames using gif.addFrame(composedCnv, { delay: delayInput }); and although I experimented with background and transparent I am unable to get rid of the flashing behaviour. Can anyone help me please?
EDIT : Using globalPalette and a large quality (20), I still get this weird pulsating of the logo but the colors are consistent.
EDIT 2 : I dug in the source code of GIF.js and found in this link the following piece of information :
/*
Sets quality of color quantization (conversion of images to the maximum 256
colors allowed by the GIF specification). Lower values (minimum = 1)
produce better colors, but slow processing significantly. 10 is the
default, and produces good color mapping at reasonable speeds. Values
greater than 20 do not yield significant improvements in speed.
*/
and indeed my flashing issue disappears if the quality is equal to 1. I will leave this question open in case there is a workaround and if someone can explain to me how come this quality issue only affects the logo and not the map portion of the canvas.
EDIT : Add more code for context. I loop over visible layers of a OpenLayers map and compose a HTMLCanvasElement which I addFrame to a GIF object. I have verified that the passed canvas elements are always correctly colored and have isolated the issue to be something that happens between me adding them to the GIF and the GIF being rendered.
async createGIFHandler ( layer , addAllTitles , quality , delay , range ) {
...
var tempGIF = new GIF({
workers: 4,
quality: quality,
height: this.mapHeight + this.infoCanvas.height,
width: this.mapWidth,
workerScript: 'gif.worker.js'
});
let progressCounter = 1;
for ( let i = range[0] ; i < range[1] ; i++, progressCounter++ ) {
this.setDateTime( driver , driverDA[i] );
for ( let j = 0 ; j < visibleLayers.length ; j++ ) {
if ( visibleLayers[j].get('layerName') !== layer.Name ) {
var tempDA = visibleLayers[j].get('layerDateArray');
for ( let k = 0 ; k < tempDA.length ; k++ ) {
if ( driverDA[i].getTime() === tempDA[k].getTime() ) {
this.setDateTime( visibleLayers[j] , tempDA[k] );
}
}
}
}
await new Promise(resolve => this.map.once('rendercomplete', resolve));
await this.composeCanvas( tempGIF , driverDA[i] , visibleLayers , delay , widths )
this.$store.dispatch('Layers/setGIFPercent', Math.round(((progressCounter / gifLength) * 100)))
}
tempGIF.on('finished', (blob) => {
const tempURL = URL.createObjectURL( blob )
this.$store.dispatch( 'Layers/setGIFURL' , tempURL )
console.log('GIF Finished');
});
tempGIF.render();
},
async composeCanvas( gif , timeStep , visibleLayers , delayInput , widths ) {
const mapCnv = this.getMapCanvas();
await this.updateInfoCanvas( timeStep , widths )
const composedCnv = await this.stitchCanvases( mapCnv , visibleLayers.length );
await new Promise((resolve) => {
gif.addFrame(composedCnv, { delay: delayInput });
resolve();
})
},
gif.js computes the color palette per frame, but there's an undocumented option that lets you define a global palette.
To reuse the palette of the first frame, instantiate with:
new GIF({
// ...
globalPalette: true,
})
You can also pass in your own palette as a flat array of RGB values. E.g., to only assign black, grey and white, instantiate with:
new GIF({
// ...
globalPalette: [0, 0, 0, 127, 127, 127, 255, 255, 255],
})
I recommend you pick the latter option and include the logo color.

Where is the variable 'line' declared?

I've been given the script below on Google Earth Engine to extract data along a transect. (https://code.earthengine.google.com/e31179d9e7143235092d6b4fa29a12fd) In the GEE code editor the top of the scipt has an import flag (picture attached).
Multiple references to 'line' are made, which I understand to be a variable that has been declared, but I can't find it. I've looked in the GEE documentation, and in a JavaScript reference to determine if it's a method or some such like but I can't work it out.
The imported data is declared as 'transect', so it's not that.
/***
* Reduces image values along the given line string geometry using given reducer.
*
* Samples image values using image native scale, or opt_scale
*/
function reduceImageProfile(image, line, reducer, scale, crs) {
var length = line.length();
var distances = ee.List.sequence(0, length, scale)
var lines = line.cutLines(distances, ee.Number(scale).divide(5)).geometries();
lines = lines.zip(distances).map(function(l) {
l = ee.List(l)
var geom = ee.Geometry(l.get(0))
var distance = ee.Number(l.get(1))
geom = ee.Geometry.LineString(geom.coordinates())
return ee.Feature(geom, {distance: distance})
})
lines = ee.FeatureCollection(lines)
// reduce image for every segment
var values = image.reduceRegions( {
collection: ee.FeatureCollection(lines),
reducer: reducer,
scale: scale,
crs: crs
})
return values
}
// Define a line across the Olympic Peninsula, USA.
// Import a digital surface model and add latitude and longitude bands.
var elevImg = ee.Image('JAXA/ALOS/AW3D30/V2_2').select('AVE_DSM');
var profile = reduceImageProfile(elevImg, transect, ee.Reducer.mean(), 100)
print(ui.Chart.feature.byFeature(profile, 'distance', ['mean']))
line isn't a variable, it's a parameter. Parameters are very similar to local variables within the function, but instead of being declared with var, let, or const, they're declared in the function's parameter list:
function reduceImageProfile(image, line, reducer, scale, crs) {
// here −−−−−−−−−−−−−−−−−−−−−−−−−−−^
The parameter's value is filled in each time the function is called using the corresponding argument in the function call. Let's take a simpler example:
function example(a, b) {
// ^−−^−−−−−−−−−− parameter declarations
return a + b;
}
// vv−−−−−−−−− argument for `a`
console.log(example(40, 2));
// ^−−−−−− argument for `b`
// vv−−−−−−−−− argument for `a`
console.log(example(60, 7));
// ^−−−−−− argument for `b`
In the first call to example, the a parameter receives the value 40 and the b parameter receives the value 2 from the call arguments. In the second call, the a parameter receives the value 60 and the b parameter receives the value 7 from the call arguments.

Filling d3.js map with colors depending on data from json

So new to d3, this is my first project using the library. Currently, I'm having issues with filling the map with different colours depending on the data. I found lots of examples on the web but they are not really working for me.
What I have is a JSON file with data in this format
"Aska": {
"opening_bal": 138000,
"total_funds": 1030574000,
"expenditure_wages": 796017000,
"expenditure_materials": 234236000,
"total_expenditure": 1030491000,
"unspent_bal": 78000,
"payment_due": 12780000
},
"Balasore": {
"opening_bal": 4660000,
"total_funds": 233869000,
"expenditure_wages": 203883000,
"expenditure_materials": 57571000,
"total_expenditure": 262518000,
"unspent_bal": 28658000,
"payment_due": 2118000
},
I'm able to create the map using GeoJson file. Here is the link to the map: https://mgnregs-d3.vercel.app/filter
I'm thinking of creating an object using the initial category, "opening_bal" eg:
{
"Aska": 138000,
"Balasore": 4660000
},
and on click, I'll update the category to "total_funds" and so on, eg:
{
"Aska": 1030574000,
"Balasore": 233869000
},
but first I need to visualise the initialise the first data. I am not able to do that.
Something like this worked on some projects, but not on my case...
d3.json('data.json', function (d) {
budget.d.properties.pc_name = d.properties.pc_name['opening_bal']
})
var color = d3
.scaleThreshold()
.domain(d3.range(2, 18))
.range(d3.schemeBlues[6])
Here is the repo on GitHub: https://github.com/PixeledCode/MGNREGS_D3
Map Component: https://github.com/PixeledCode/MGNREGS_D3/blob/main/src/components/Filter/Filter.js
data.json: https://github.com/PixeledCode/MGNREGS_D3/blob/main/src/assets/data.json
Map GeoJson: https://github.com/PixeledCode/MGNREGS_D3/blob/main/src/assets/odihsa.js
Any help is appreciated.
You have a data object in the following form:
const data = {
"Aska": 138000,
"Balasore": 4660000,
...
},
Find minimum and maximum values of the object:
const range = Object.values(data).reduce((r, v) => r ?
({min: Math.min(r.min, v), max: Math.max(r.max, v}) :
({min: v, max: v})), null);
Now, you can write a function translating any value between minimum and maximum to a color. If your color for minimum value is green (0, 255, 0), and the color for maximum value is blue (0, 0, 255), the function will look like this:
const colorUnit = 255 / (range.max - range.min);
const getColorByValue = val => {
const delta = val - range.min;
return `rgb(0, ${255 - delta * colorUnit}, ${delta * colorUnit})`;
};

How to assume two union types as the same

I'm making a function with two same union type as arguments.
How can they be assumed as the same type in switch statement?
I'm trying this using Typescript#3.5.1
interface Square {
kind: 'square'
size: number
}
interface Rectangle {
kind: 'rectangle'
width: number
height: number
}
type Shape = Square | Rectangle
function areas(s: Shape, ss: Shape) {
if (s.kind !== ss.kind) return // check if the kind of them are the same
switch (s.kind) {
case 'square':
return s.size * s.size + ss.size * ss.size // error
case 'rectangle':
return s.height * s.width + ss.height * ss.width // error
}
}
This stetement makes an error such as
Property 'size' does not exist on type 'Shape'.
Property 'size' does not exist on type 'Rectangle'.ts(2339)
but I expect no error occurs because equivalence of s.kind
and ss.kind is already checked.
You are getting the error because both s and ss are just a Shape the entire time. The compiler knows that both have a value called "kind" but still does not know the actual type of each. A Square might have a "size" but a Shape does not and the compiler knows it.
Creating a function that needs to know the details of a Shape defeats the purpose of using an interface in the first place. You could achieve what you want much more cleanly like so:
interface Square {
area(): number
size: number
}
interface Rectangle {
area(): number
width: number
height: number
}
type Shape = Square | Rectangle
function areas(s: Shape, ss: Shape) {
return s.area() + ss.area()
}
However if you really want to do it you could do it by explicitly casting each object to the desired type before you access it's properties
interface Square {
size: number
}
interface Rectangle {
width: number
height: number
}
type Shape = Square | Rectangle
function areas(s: Shape, ss: Shape) {
if (typeof s != typeof ss) {
return
}
switch (typeof s) {
case 'Square': {
s = s as Square; ss = ss as Square
return s.size * s.size + ss.size * ss.size
}
case 'Rectangle': {
s = s as Rectangle; ss = ss as Rectangle
return s.width * ss.height + s.width * ss.height
}
}
}
Note that this second example won't actually work (even if you explicitly declare something as one of your union types), despite the fact that is compiles since typeof will return "object", but it demonstrates how to tell the compiler which type to use (using as)
class SquareImpl implements Square {
size: number = -1
constructor(size : number) {
this.size = size
}
}
let s : Square = new SquareImpl(10)
console.log(typeof s) // logs "object"
You might try and implement it using instanceof:
if (s instanceof Square && ss instanceof Square) {
s = s as Square; ss = ss as Square
return s.size * s.size + ss.size * ss.size
}
// similar code for Rectangle etc
However Typescript won't let you use check if an object implements an interface at runtime, so you're back to using a custom type guard:
interface Square {
kind: string
sameShape(obj: Shape): boolean
area(): number
size: number
}
class SquareImpl implements Square {
kind: string = "square"
size: number = -1
area() { return this.size * this.size }
sameShape(obj: Shape): obj is Square {
return obj.kind == "square"
}
constructor(size: number) { this.size = size }
}
// similar for Rectangle
...
let r : Rectangle = new RectangleImpl(1, 2)
let s : Square = new SquareImpl(3)
let ss : Square = new SquareImpl(2)
if (s.sameShape(ss)) {
console.log('s + ss: '+ s.area() + ss.area())
}
if (s.sameShape(r)) {
console.log('s + r: '+ s.area() + r.area())
}
Convincing the compiler that two variables of union types are correlated is not really easy or even possible in the general case. The compiler will almost always think two such values are independent, unless you test them separately. Meaning: the only solutions here are going to look like: you only do enough work to convince yourself that the types are the same, and you have to tell the compiler not to worry about it via something like a type assertion:
function areas(s: Shape, ss: Shape) {
if (s.kind !== ss.kind) return; // check if the kind of them are the same
switch (s.kind) {
case "square":
return s.size * s.size + (ss as typeof s).size * (ss as typeof s).size;
case "rectangle":
return (
s.height * s.width + (ss as typeof s).height * (ss as typeof s).width
);
}
}
Or, you will have to do more work than you think should be necessary so that the compiler is convinced that the only possibilities are the ones you expect. Meaning you'll do what feels to you like redundant type guards. I think in this case, I'd refactor your code to be like this, which only adds one more check:
function areas2(s: Shape, ss: Shape) {
if (s.kind === "square" && ss.kind === "square") {
return s.size * s.size + ss.size * ss.size;
}
if (s.kind === "rectangle" && ss.kind === "rectangle") {
return (
s.height * s.width + ss.height * ss.width
);
}
return;
}
Okay, hope that helps. Good luck!
Link to code
Replace your if condition as
if (s.kind !=== ss.kind)
Hope it will work for you
So I see a few ways to improve your code.
In my opinion, Union Types should only be used when the two type are disparate types. For example, CSS allows values for some properties to either be a string or a number. So how do you convey to the consumer of your function that you only want them to pass one of those two? That's a good case for a Union Type:
var element: HtmlElement;Z
function bad(width: any) {
element.style.width = width;
}
// no typescript error about the wrong type being passed in
bad(new Date());
type widthType = string | number | null;
function good(width: widthType) {
element.style.width = widthType
}
// typescript error about the wrong type being passed in
good(new Date());
Typescript Playground Example.
While many people decide to go the route of using a kind property, I avoid it as much as possible since it's a Magic String. If two types are compatible, someone must know the inter workings of your square to build there own square (yikes). You can technically avoid that by moving to abstract classes:
abstract class Square {
static kind = 'square'
}
But then you can just use instanceOf, so no real point to that.
However, in Object Oriented Programming, we need to be aware of Inheritence (is-a) and Composition (has-a). Since both Rectangle is-a shape, and Square is-a shape, then we should be modeling our objects as such:
interface Shape { }
interface Rectangle : Shape { }
interface Square : Shape { }
Now that we have a good staring point for the models we need to take a look at the method. What is an area? An Area is the quantity that expresses the extend of a two dimensional figure or shape. So we should now modify our inheritance chain/tree/whatever to require this functionality:
interface Shape {
areas(shape: Shape): number;
}
interface Rectangle : Shape { }
interface Square : Shape { }
We encapsulate that method at the shape level, because all shapes (2D or larger assuming) have an area (0 is still a size).
It's easy to review this and thing, why should the shapes do this calculation and I would simply suggest many frameworks (if not most OOP frameworks) do this exact thing. When you compare two objects in .Net via Equals you should always test that the types are the same. But notice that the method is at the root of object, not a disconnect/global method.
So this might be a good result of that improvement:
interface Shape {
// null would indicate we can't join the two
// I prefer null to indicate a known invalid value
// and only use undefined to indicate an unknown (always invalid) value
areas(shape: Shape): number | null;
}
interface Rectangle : Shape { }
interface Square : Shape { }
class MyRectangle : Rectangle {
width: number;
height: number;
area(shape: Shape){
if (!(shape instanceOf Rectangle)) {
return null;
}
return this.height * this.width + shape.height * shape.width;
}
}
class MySquare : Square {
size: number;
area(shape: Shape){
if (!(shape instanceOf Square)) {
return null;
}
return this.size * this.size + shape.size * shape.size;
}
}
// Example call:
const mySquare = new MySquare();
const mySquare2 = new MySquare();
const areas = mySquare2.area(mySquare); // fully type checked.
The previous examples are good if the interfaces are a separate library then the classes, where someone might actually want to express those values differently. If that's not the case, and there should only be 1 type of square and 1 type of rectangle, then interfaces are not the best choice, and I would suggest using classes instead. Because implementing Circle in the previous example would be very difficult (both the interfaces and the classes need to change). Uses classes would look like:
abstract class Shape {
area(shape: Shape);
}
class Rectangle : Shape {
width: number;
height: number;
area(shape: Shape){
if (!(shape instanceOf Rectangle)) {
return null;
}
return this.height * this.width + shape.height * shape.width;
}
}
class Square: Shape {
size: number;
area(shape: Shape){
if (!(shape instanceOf Square)) {
return null;
}
return this.size * this.size + shape.size * shape.size;
}
}
Now implementing Circle becomes trivial.
class Circle: Shape {
radius: number;
area(shape: Shape){
if (!(shape instanceOf Circle)) {
return null;
}
return this.size * this.size + shape.size * shape.size;
}
}

Crossfilter - Double Dimensions (second value linked to daily max)

Quite an oddly specific question here but something I've been having a lot of trouble with over the past day or so. Broadly, I'm trying to calculate the maximum of an array using crossfilter and then use this value to find a maximum.
For example, I have a series of Timestamps with an associated X Value and a Y Value. I want to aggregate the Timestamps by day and find the maximum X Value and then report the Y Value associated with this Timestamp. In essence this is a double dimension as I understand it.
I'm able to do the first stage simply to find the maximum values. But am having a lot of difficulty getting through to the second value.
Working code for the first, (using Crossfilter and Reductio). Assuming that each row has the following four values.
[(Timestamp, Date, XValue, YValue),
(2015-05-15 16:00:00, 2015-05-15, 30, 15),
(2015-05-15 16:45:00, 2015-05-15, 25, 33)
... (many thousand of rows)]
First Dimension
ndx = crossfilter(data);
dailyDimension = ndx.dimension(function(d) { return d.date; });
Get the max of the X Value using reductio
maxXValue = reductio().max(function(d) { return d.XValue;});
XValues = maxXValue(dailyDimension.group())
XValues now contains all of the maximum X Values on a Daily Basis.
I would now like to use these X Values to identify the corresponding Y Values on a date basis.
Using the same data above the appropriate value returned would be:
[(date, YValue),
('2015-05-15', 15)]
// Note, that it is 15 as it is the max X Value we find, not the max Y Value.
In Python/Pandas I would set the index of a DataFrame to X and then do an index match to find the Y Values
(Note, it can safely be assumed that the X Values are unique in this case but in reality we should really identify the Timestamp linked to this period and then match on that as they are strictly guaranteed to be unique, not loosely).
I believe this can be accomplished by modifying the reductio maximum code which I don't fully understand properly Source Code is from here
var reductio_max = {
add: function (prior, path) {
return function (p, v) {
if(prior) prior(p, v);
path(p).max = path(p).valueList[path(p).valueList.length - 1];
return p;
};
},
remove: function (prior, path) {
return function (p, v) {
if(prior) prior(p, v);
// Check for undefined.
if(path(p).valueList.length === 0) {
path(p).max = undefined;
return p;
}
path(p).max = path(p).valueList[path(p).valueList.length - 1];
return p;
};
},
initial: function (prior, path) {
return function (p) {
p = prior(p);
path(p).max = undefined;
return p;
};
}
};
Perhaps this can be modified so that there is a second valueList of Y Values which maps 1:1 with the X Values associated in the max function. In that case it would be the same index look up of both in the functions and could be assigned simply.
My apologies that I don't have any more working code.
An alternative approach would be to use some form of Filtering Function to remove entries which don't satisfy the X Criteria and then group by day (there should only be one value in this setting so a simple reduceSum for example will still return the correct value).
// Pseudo non working code
dailyDimension.filter(function(p) {return p.XValue === XValues;})
dailyDimension.group().reduceSum(function(d) {return d.YValue;})
Eventual results will be plotted in dc.js
Not sure if this will work, but maybe give it a try:
maxXValue = reductio()
.valueList(function(d) {
return ("0000000000" + d.XValue).slice(-10) + ',' + d.YValue;
})
.aliasProp({
max: function(g) {
return +(g.valueList[g.valueList.length - 1].split(',')[0]);
},
yValue: function(g) {
return +(g.valueList[g.valueList.length - 1].split(',')[1]);
}
});
XValues = maxXValue(dailyDimension.group())
This is kind of a less efficient and less safe re-implementation of the maximum calculation using the aliasProp option, which let's you do pretty much whatever you want to to a group on every record addition and removal.
My untested assumption here is that the undocumented valueList function that is used internally in max/min/median will properly order. Might be easier/better to write a Crossfilter maximum aggregation and then modify it to also add the y-value to the group.
If you want to work through this with Reductio, I'm happy to do that with you here, but it will be easier if we have a working example on something like JSFiddle.

Categories