How to use a predefined function with R.zipWith - ramda.js

This is the initial data set.
const Main = {
  ratio : [ 0.5, 1, 2 ],
focusPoint : [ 0.1, 0.2, 0.3 ],
}
I want this object calculated with a predefined function.
const width =  window.innerWidth
const height = window.innerHeight
const ratioViewport = width / height
const resultY = ( x, y ) => 0.5 * ( x / ratioViewport ) - y
Here is the final part with R.zipWith to evaluate the function.
const getPositionMain = applySpec ( {
ratio : R.prop ('ratio'),
resultY : R.zipWith ( resultY, R.prop ('ratio') , R.prop ('focusPoint') ),
} )
const positionMain = getPositionMain ( Main )
console.log( 'positionMain : ', positionMain )
// Desired output (positionMain) : [ 0.5 * (1 / ratioViewport) - 0.1, 0.5 * (2 / ratioViewport) - 0.2, 0.5 * (3 / ratioViewport) - 0.3 ]
But, I am not getting it right.
What am I doing wrong at here?
REPL

It's not quite clear to me what you want. Are you looking for something like this?
const getPositionMain = (w, ratioViewport = w.innerWidth / w.innerHeight) => main =>
zipWith ((x, y) => 0.5 * (x / ratioViewport) - y) (main .ratio, main .focusPoint)
const _window = {innerWidth: 600, innerHeight: 400}
const Main = {
ratio : [ 0.5, 1, 2 ],
focusPoint : [ 0.1, 0.2, 0.3 ],
}
console .log (getPositionMain (_window) (Main))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js"></script>
<script> const {zipWith} = R </script>
Or something more like this?:
const getPositionMain = (w, ratioViewport = w.innerWidth / w.innerHeight) => (main) => ({
ratio: main .ratio,
resultY: zipWith ((x, y) => 0.5 * (x / ratioViewport) - y) (main .ratio, main .focusPoint)
})
const _window = {innerWidth: 600, innerHeight: 400}
const Main = {
ratio : [ 0.5, 1, 2 ],
focusPoint : [ 0.1, 0.2, 0.3 ],
}
console .log (getPositionMain (_window) (Main))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js"></script>
<script> const {zipWith} = R </script>
In either case, the code is much the same, just with a different format for the output results.
The working version I can get to closest to your attempt would look like this:
const getPositionMain = (w, ratioViewport = w.innerWidth / w.innerHeight) => applySpec ({
ratio : prop ('ratio'),
resultY : lift (zipWith ((x, y) => 0.5 * (x / ratioViewport) - y))
(prop ('ratio') , prop ('focusPoint'))
})
Note that zipWith takes a function and two lists. You were passing it the initial function and two functions that would resolve to lists when called properly. Functions that will resolve to specific types can be thought of as containers of those types. lift takes a function that operates on values and lifts it up to become a function that operates on containers of those values. So lift (resultY) (f, g) is approximately main => resultY (f (main), g (main)), and we can then use it in applySpec.
In every version here, I avoid the global variables you have of ratioViewport, calculating it from a Window object as a parameter. I find this much cleaner, but YMMV.
But we could skip that variable altogether by performing the inexpensive viewport calculation inside the main function, like this:
const getPositionMain = ({innerWidth, innerHeight}) => ({ratio, focusPoint}) =>
zipWith ((x, y) => 0.5 * (x / innerWidth * innerHeight) - y, ratio, focusPoint)
or like this:
const getPositionMain = ({innerWidth, innerHeight}) => ({ratio, focusPoint}) => ({
ratio,
resultY: zipWith ((x, y) => 0.5 * (x / innerWidth * innerHeight) - y, ratio, focusPoint)
})
Those are the versions I prefer.

Related

React native SVG building pie chart with Path

I have a code that builds a SVG figure for a pie chart, using this function:
export const generateArc = (percentage: number, radius: number) => {
const a = (percentage * 2 * Math.PI) / 100 // angle (in radian) depends on percentage
const r = radius // radius of the circle
const rx = r
const ry = r
const xAxisRotation = 0
let largeArcFlag = 1
const sweepFlag = 1
const x = r + r * Math.sin(a)
const y = r - r * Math.cos(a)
if (percentage <= 50) {
largeArcFlag = 0
} else {
largeArcFlag = 1
}
return `A${rx} ${ry} ${xAxisRotation} ${largeArcFlag} ${sweepFlag} ${x} ${y}`
}
Everything works fine, except when percentage is 100, the chart disappears, you can look here
I feel like that there's some miscalculation, but i don't have much experience in such things with SVGS, and i can't figure it out.
The workarounds I've found are:
iOS: check if percentage is 100, then use 99.9, but that doesn't work for android (i've tested on real device, there's a little gap that's not filled, but on some emulators 99.9999 gives the full circle), you can check it in a snack
For both platform just use a full circle SVG instead, if percentage is 100, but i don't like that workaround
Thanks to #Robert Longson I've modified the function that generates arc a bit, so now it generates 2 arcs if percentage is 100
const generatePath = (percentage: number, radius: number) => {
if (percentage === 100) {
const x = radius
const y = radius
// in path x has to be 0 = starting point
return `M ${0}, ${y}
a ${x},${y} 0 1,1 ${radius * 2},0
a ${x},${y} 0 1,1 -${radius * 2},0
`
}
const a = (percentage * 2 * Math.PI) / 100 // angle (in radian) depends on percentage
const r = radius // radius of the circle
const rx = r
const ry = r
const xAxisRotation = 0
let largeArcFlag = 1
const sweepFlag = 1
const x = r + r * Math.sin(a)
const y = r - r * Math.cos(a)
if (percentage <= 50) {
largeArcFlag = 0
} else {
largeArcFlag = 1
}
return `M${radius} ${radius} L${radius} 0 A${rx} ${ry} ${xAxisRotation} ${largeArcFlag} ${sweepFlag} ${x} ${y} Z`
}

SVGPointList length changes using svg.js

Hi I am using the function createPoint to animate a polygon using gsap. I am also using svg.js
If I use vanilla javascript to get the points of the svg with
var polygon = document.querySelector("polygon");
var points = polygon.points;
it returns 3 points which correspond to the number of times the createPoint function is run. This logs out as:
0: SVGPoint {x: 105.30396270751953, y: 143.0928955078125}
1: SVGPoint {x: 348.09027099609375, y: 97.7249984741211}
2: SVGPoint {x: 276.54010009765625, y: 327.56372070}
If I use the svg.js code
const draw = SVG().addTo('body')
var svg = draw.node;
const polygon = draw.polygon().node;
var points = polygon.points;
the same function logs a list of 4 SVGPoints with the first point being {x:0,y:0} even though I am only running the function 3 times. Where is the additional (index 0) svg point coming from? Thanks in advance
0: SVGPoint {x: 0, y: 0}
1: SVGPoint {x: 93.79865264892578, y: 124.19292449951172}
2: SVGPoint {x: 346.3572082519531, y: 97.5942153930664}
3: SVGPoint {x: 227.08517456054688, y: 269.97042846
given the following html
<svg>
<polygon points="">
</svg>
And the code below
TweenLite.defaultEase = Sine.easeInOut;
const draw = SVG().addTo('body')
var svg = draw.node;
const polygon = draw.polygon().node;
var points = polygon.points;
console.log('points',points)
var offset = 75;
createPoint(100, 100);
createPoint(300, 100);
createPoint(300, 300);
// createPoint(100, 300);
function createPoint(x, y) {
var minX = x - offset;
var maxX = x + offset;
var minY = y - offset;
var maxY = y + offset;
var point = points.appendItem(svg.createSVGPoint());
point.x = x;
point.y = y;
moveX();
moveY();
function moveX() {
TweenLite.to(point, random(2, 4), {
x: random(minX, maxX),
delay: random(0.5),
onComplete: moveX
});
}
function moveY() {
TweenLite.to(point, random(2, 4), {
y: random(minY, maxY),
delay: random(0.5),
onComplete: moveY
});
}
}
function random(min, max) {
if (max == null) { max = min; min = 0; }
if (min > max) { var tmp = min; min = max; max = tmp; }
return min + (max - min) * Math.random();
}
Just found out that by adding an empty array to the polygon i.e
const polygon = draw.polygon([]).node
it removes the default {x:0,y:0} object. Dont ask me why :)

Quantile regressing using RcppEnsmallen diverge

I am trying RcppEnsmallen to estimate quantile regression models. I noticed that the results seemed not convergent. Every time it pops up different results. I set up its first order condition in my code. I guess the divergence may be owing to the fact that the objective function is not differentiable at zero. I am not sure about that.
Here the code
#include <RcppEnsmallen.h>
// [[Rcpp::depends(RcppEnsmallen)]]
class QuantileRegressionFunction
{
public:
// Construct the QuantileRegressFunction with the given data.
QuantileRegressionFunction(const arma::mat& X,
const arma::colvec& y,
const double tau
) : X(X),y(y),tau(tau){}
// Define the objective function.
double EvaluateWithGradient(const arma::mat& beta, arma::mat& gradient ){
const arma::mat fit = y - X * beta;
const arma::vec eval =0.5* arma::abs(fit) + (tau - 0.5 )*fit;
const arma::vec v= tau - arma::ones<arma::vec>(y.n_rows) % ( fit < 0 ) ;
gradient = - (X.t() * v)*(1/X.n_rows) ;
return arma::accu( (1/y.n_rows) *eval ) ;
}
private:
const arma::mat& X;
const arma::vec& y;
const double tau;
};
// [[Rcpp::export]]
arma::mat qr_reg(const arma::mat& X, const arma::vec& y,const double& tau){
QuantileRegressionFunction qrf(X,y,tau);
ens::L_BFGS lbfgs;
lbfgs.MaxIterations()= 1000 ;
//lbfgs.MaxLineSearchTrials() = 10000;
//lbfgs.ArmijoConstant() = 1e-18;
arma::mat beta(X.n_cols, 1 , arma::fill::randn);
lbfgs.Optimize(qrf,beta);
return beta;
}
Here is a simple simulation exercise:
n <- 1000
beta <- c(-2, 1.5, 3, 8.2, 6.6)
p <- length(beta)
X <- cbind(1, matrix(rnorm(n), ncol = p - 1))
y <- X %*% beta + rnorm(n / (p - 1))
qr_reg(X,y,0.1)
Every time qr_reg(X,y,.1) report divergent estimates.

Simplifying calculation of arrays with Ramda

I would like to calculate the three arrays like this.
const Data = {
x : [2,4,6],
y : [10,10,10],
z : [5,5,5]
}
const XtimesYplusZ = zipWith (add, (zipWith (multiply, Data.x, Data.y)), Data.z)
console.log(XtimesYplusZ);//[25,45,65]
This code works ok, but not very good in terms of readability.
So, now I created calculation patterns that could be applied later on:
const calc1 = ({x, y, z}) => x * y + z
console.log(calc1(Data)); //ERROR
This is not working. I have many different patterns such as ({x, y, z}) => x / y - z, ({x, y, z}) => (x + y) * z and so on. What is the standard calculation method for arrays something like this?
REPL
In this example:
const calc1 = ({x, y, z}) => x * y + z
console.log(calc1(Data)); //ERROR
You are trying to add and multiply arrays, and not the arrays' items.
Using R.zipWith won't work as well, since it requires actual arrays, and is limited to zipping 2 arrays at a time.
An easier solution would be to get the sub-arrays using R.props, transpose them ([[2, 10, 5], [4, 10, 5]]...), and then map and combine the values using your calc function (I've replace the object destructuring with array destructuring):
const { pipe, props, transpose, map } = R
const calc = ([x, y, z]) => x * y + z
const fn = pipe(props(['x', 'y', 'z']), transpose, map(calc))
const Data = {
x : [2,4,6],
y : [10,10,10],
z : [5,5,5]
}
const XtimesYplusZ = fn(Data)
console.log(XtimesYplusZ) // [25,45,65]
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous"></script>
This example show Scott's suggestion of extracting out the combination of R.transpose, and R.map to create a zipAllWith function:
const { curry, map, apply, transpose, pipe, props } = R
const zipAllWith = curry((fn, xss) => map(apply(fn), transpose(xss)));
const fn = pipe(props(['x', 'y', 'z']), zipAllWith((x, y, z) => x * y + z))
const Data = {
x : [2,4,6],
y : [10,10,10],
z : [5,5,5]
}
const XtimesYplusZ = fn(Data)
console.log(XtimesYplusZ) // [25,45,65]
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous"></script>

How to get/set weights for a supervised model in tensorflow.js?

I'd like to change the weights of a supervised model but I get the same exact result after changing the weights. What am I doing wrong?
const model = tf.sequential();
model.add(tf.layers.dense({...}));
model.add(tf.layers.dense({...}));
model.add(tf.layers.dense({...}));
model.compile({...});
model.fit({});
const result1 = model.predict(tf.tensor2d(...)).dataSync();
const newWeights = [];
model.layers.map((layer, i) => {
newWeights[i] = []
const weights = layer.getWeights();
newWeights[i][0] = weights[0].arraySync()
newWeights[i][1] = weights[1].arraySync()
newWeights[i][0].map(tensor => tensor.map(x => {
if (random(1) < 0.5) {
return x + offset();
}
return x;
})
layer.setWeights([tf.tensor2d(newWeights[i][0], [newWeights[i][0].length, newWeights[i][0][0].length]), tf.tensor(newWeights[i][1])])
})
const result2 = model.predict(tf.tensor2d(...)).dataSync();
Code snippets:
const random = (max) => {
return floor(Math.random() * Math.floor(max), 2);
}
const floor = (num, toDecimal) => {
let dec = Math.pow(10, toDecimal);
return Number(Math.floor(num * dec) / dec);
}
const offset = () => {
randomGaussian() * 0.5
}
let previous = false;
let y2 = 0;
const randomGaussian = (mean, sd) => {
let y1, x1, x2, w;
if (previous) {
y1 = y2;
previous = false;
} else {
do {
x1 = random(2) - 1;
x2 = random(2) - 1;
w = x1 * x1 + x2 * x2;
} while (w >= 1);
w = Math.sqrt(-2 * Math.log(w) / w);
y1 = x1 * w;
y2 = x2 * w;
previous = true;
}
let m = mean || 0;
let s = sd || 1;
return y1 * s + m;
};
result1 === result2 but why?
Most likely that the new weights are identical to that of the first model.
Example: Simple example to change weights of a model
(async() => {
const model = tf.sequential({
layers: [tf.layers.dense({units: 1, inputShape: [10]})]
});
model.compile({optimizer: 'sgd', loss: 'meanSquaredError'});
for (let i = 1; i < 5 ; ++i) {
const h = await model.fit(tf.ones([8, 10]), tf.ones([8, 1]), {
batchSize: 4,
epochs: 3
});
console.log("Loss after Epoch " + i + " : " + h.history.loss[0]);
}
const p = await model.predict(tf.zeros([1, 10]))
p.print()
const layers = model.layers
layers[0].setWeights([tf.zeros([10, 1]), tf.zeros([1])])
const q = await model.predict(tf.zeros([1, 10]))
q.print()
})()
<html>
<head>
<!-- Load TensorFlow.js -->
<script src="https://cdn.jsdelivr.net/npm/#tensorflow/tfjs#latest"> </script>
</head>
<body>
</body>
</html>
Issue of the code
The newWeights created is not assigned to newWeights. map is not an in-place operator. The array returned by map should be assigned back to newWeights.
newWeights[i][0] = newWeights[i][0].map(tensor => tensor.map(x => {
if (random(1) < 0.5) {
return x + offset();
}
return x;
})