Tengo un conjunto de datos en una matriz que varía de 0.00164737 a 0.0021966

Lo que estoy tratando de hacer es fijar la forma mediante una escala logarítmica y luego normalizarla para dibujarla en el lienzo. Digamos normalizado a 0,100 o -100,0,100 para que pueda trabajar en píxeles

Para simplemente normalizar (sin hacer una función de registro) entre 0-100, esto funciona perfectamente en un bucle for:

normalized[i] = ( ( close[i] - min ) / dif ) * 100;

Dif es el max de la matriz cercana menos su min toFixed (7)

Normalized

No soy matemático, pero creo que estoy `` un poco cerca '' con la parte de registro, aunque solo veo una diferencia visual cuando aplico una función de registro durante normalización. Obviamente, esto estropea la normalización y también produce infinito o infinito y números innecesariamente grandes

Out of view

Tenga en cuenta que el gráfico ya no es manejable en píxeles ya que no se encuentra en el lienzo correctamente, por lo que para ver lo que he hecho, agrego 150 a todos los puntos y para que se vea

Pushed into view

Entonces, cuando hago esto, estoy interrumpiendo / cambiando cosas en la misma línea aplicando una función logarítmica (sé que esta parte está mal)

function logWithBase(n,b){return Math.log(n)/Math.log(b);}

Cambiando la línea así:

normalized[i] = logWithBase( ( close[i] - min ) / dif , 10 ) * 100;

Aquí hay una pequeña parte de los datos antes y después de intentar hacerlo logarítmico:

Antes:

0: "0.00168927"
1: "0.00168742"
2: "0.0016818"
3: "0.00168124"
4: "0.00168067"
5: "0.0016805"
6: "0.00168657"
7: "0.00168362"
8: "0.00166886"
9: "0.00165052"    // < why does 0.00165 cause -Infinity
10: "0.0016647"
11: "0.00166251"
12: "0.00166664"
13: "0.00167196"
14: "0.00167084"
15: "0.00167667"

Mismo conjunto después:

0: 38.93017025063121
1: 36.805636182304255
2: 29.629674005179268
3: 28.845120702345767
4: 28.03173121401521
5: 27.786162417624155
6: 35.79352647194307
7: 32.08579894397015
8: 6.4429326997987175
9: -Infinity             // < WOW!!
10: -4.729377348896662
11: -12.015082123716525
12: 0.8395033133056131
13: 13.225477668471285
14: 10.8953699275865
15: 21.850168886727374

Tal vez una pista relacionada aquí

Si obtengo la diferencia entre min y max / 2 (probablemente obtendré una mala nota por esto) y la uso como base (antes de hacer la normalización simple) veo el gráfico al revés ...

var logclose = [];

var base = ( Math.max.apply(this,close) - Math.min.apply(this,close) ) / 2;

for( var i = close.length - 1; i >= 0; i-- ){

    logclose[i] = logWithBase( close[i] , base );

    }

close=logclose;

Upside down

Conclusión; Creo que el último ejemplo dice que la base debería estar relacionada de alguna manera con el rango de números de las matrices, ya que tiene un efecto.

¿Cómo puedo domar el logaritmo para que no sea un número ridículamente grande y luego normalizarlo para que se ajuste al área del lienzo?

No recomiendo que use una biblioteca (prefiero JavaScript vainilla donde pueda usarse, además, me gustaría mucho entender este proceso)

Editar, aquí está el código:

var close=[data]; // for example data see this question (line: 19) as the full data will not fit here (over 10000 entries)

//###

var max=Math.max.apply(this,close);
var min=Math.min.apply(this,close);
var dif=(max-min).toFixed(7);

var normalclose=[];
var logAttemptClose=[];

function logWithBase(n,b){return Math.log(n)/Math.log(b);}

for(var i=close.length-1;i>=0;i--){

    normalclose[i]=((close[i]-min)/dif)*100;

    logAttemptClose[i]=logWithBase( ( close[i] - min ) / dif , 10 ) * 100; // <-- here bad code
    }

//drawing to canvas
var top=100;
var x=1000-100;
var pen=[];

pen[0]=document.getElementById("chart");
pen[0]=pen[0].getContext("2d");
pen[0].clearRect(0,0,1000,300);
pen[0].beginPath();
pen[0].moveTo(x,normalclose[normalclose.length-1]+top);

for(var i=close.length-1;i>=0;i--){
    x=x-(2);
    pen[0].lineTo(x,normalclose[i]+top);
    }

pen[0].strokeStyle='#000000';
pen[0].stroke();
3
8DK 4 sep. 2014 a las 17:31

2 respuestas

La mejor respuesta

¡Te tengo!

Ok, esta no es la mejor solución, ¡pero funciona! Si alguien puede hacerlo mejor, por favor publique ...

Agregue esto a la línea 2 del código anterior (donde está el comentario '###'):

var Lmax=Math.max.apply(this,close);
var Lmin=Math.min.apply(this,close);
var Ldif=(Lmax-Lmin);
var Logar=[];
var infinity=[];
for(var i=close.length-1;i>=0;i--){
    Logar[i]=Math.log((close[i]-Lmin)/Ldif);
    if(Logar[i]===-Infinity){infinity.push(i);}
    }
close=Logar;

Ahora tenemos la matriz a escala logarítmica, pero SIEMPRE siempre hay -Infinito en algún lugar, por lo que lo eliminamos. En la siguiente línea escribe ...

for(var i=0;i<=infinity.length-1;i++){close.splice(infinity[i],1);

Luego podemos continuar con el código pasando a la normalización simple y tenemos un nuevo gráfico de registro agradable:

Hacked

1
8DK 4 sep. 2014 a las 21:54

Su problema es que está normalizando los datos en el espacio lineal (restando el mínimo) y luego convirtiendo en espacio logarítmico.

Uno de sus valores inevitables se convierte en cero, por lo tanto, log(0) == -Infinity.

En su lugar, tome el logaritmo primero de los datos no normalizados y luego determine los rangos de su eje Y para el trazado.

Ver http://jsfiddle.net/alnitak/r71s8cex/

0
Alnitak 15 sep. 2014 a las 13:49