I am trying to display a scatterplot from a variable called data.
data should contain the x and y values for the scatterplot. The method below is what I am attempting to do to insert the x and y values, however the graph is showing up blank.
let data = []
for(var i = 0; i < sixth_x.length; ++i){
data.push({xField: sixth_x[i], yField: sixth_y[i]})
}
x is a string, and y is a number.
This is my method to display the graph
<ChartSeriesItem type="scatter" data={data} xField="sixth_x"
yField="sixth_y"/>
</ChartSeries>
ChartSeriesItem xField and yField expect property name of source array object. In your case source array object is {xField: <some string>, yField: <some number>}.
So you should pass these property names (xField, yField) to your props.
<ChartSeriesItem type="scatter" data={data} xField="xField" yField="yField"/></ChartSeries>
which looks strange.
I recommend rename properties to identify what exactly your chart about, ex. price growing per year chart, so you will do something like this
data.push({price: sixth_x[i], year: sixth_y[i]})
and <ChartSeriesItem type="scatter" data={data} xField="price" yField="year"/></ChartSeries>
I think you get the idea.
I'm trying to make an animation recorder that records x,y positions into an array and allow the animation to be recalled. I specifically have p5.js in mind as the graphics lib, but any should work. since this is just array work.
in p5.js to return the value of Sin() or Cos() you can pass them an angle, that angle can be ever incrementing since 2PI == 4PI (in terms of the direction the rotation is facing) etc. I'm looking to replicate this kind of function but to return the data stored in an array.
so for example you've got an array like the following
let demo = ['297', '298', '299', '300']
It would be easy to loop over the array once since it has 4 items, but I'd like to write a function where if we passed in 4, it would return index 0, '297' or if we fed in 11, it would return '300' or if we fed in 22 it would return '299'
this way the function could continually be fed in an ever increasing value that moves up each frame we could return the values of the array in a loop.
let survey = 0;
let demo = ['297', '298', '299', '300']
//a rendering loop
function draw(){
survey ++
let xPos = getPosition(survey) //this getPosition function is the one in question
ellipse(xPos,100,50)
}
I feel like this is some modulo math, but I cant quite get it sorted.
thanks for taking a look!
The solution to your problem is the modulus (%) operator. This operator will return the remainder of the division.
E.g. 11 % 4 = 3
const positions = [297, 298, 299, 300];
function getPosition(positions, i) {
return positions[i % positions.length];
}
console.log(getPosition(positions, 4)); // 297
console.log(getPosition(positions, 11)); // 300
console.log(getPosition(positions, 22)); // 299
In d3.js v4 the d3.transform method has been removed, without any hint about how to replace it.
Does anyone know how to replace the following d3.js v3 code?
d3.transform(String).translate;
Edit 2016-10-07: For a more general approach see addendum below.
According to the changelog it is gone. There is a function in transform/decompose.js, though, which does the calculations for internal use. Sadly, it is not exposed for external use.
That said, this is easily done even without putting any D3 to use:
function getTranslation(transform) {
// Create a dummy g for calculation purposes only. This will never
// be appended to the DOM and will be discarded once this function
// returns.
var g = document.createElementNS("http://www.w3.org/2000/svg", "g");
// Set the transform attribute to the provided string value.
g.setAttributeNS(null, "transform", transform);
// consolidate the SVGTransformList containing all transformations
// to a single SVGTransform of type SVG_TRANSFORM_MATRIX and get
// its SVGMatrix.
var matrix = g.transform.baseVal.consolidate().matrix;
// As per definition values e and f are the ones for the translation.
return [matrix.e, matrix.f];
}
console.log(getTranslation("translate(20,30)")) // simple case: should return [20,30]
console.log(getTranslation("rotate(45) skewX(20) translate(20,30) translate(-5,40)"))
This creates a dummy g element for calculation purposes using standard DOM methods and sets its transform attribute to the string containing your transformations. It then calls .consolidate() of the SVGTransformList interface to consolidate the possibly long list of transformation to a single SVGTransform of type SVG_TRANSFORM_MATRIX which contains the boiled down version of all transformations in its matrix property. This SVGMatrix per definition holds the values for the translation in its properties e and f.
Using this function getTranslation() you could rewrite your D3 v3 statement
d3.transform(transformString).translate;
as
getTranslation(transformString);
Addendum
Because this answer has gained some interest over time, I decided to put together a more general method capable of returning not only the translation but the values of all transformation definitions of a transform string. The basic approach is the same as laid out in my original post above plus the calculations taken from transform/decompose.js. This function will return an object having properties for all transformation definitions much like the former d3.transform() did.
function getTransformation(transform) {
// Create a dummy g for calculation purposes only. This will never
// be appended to the DOM and will be discarded once this function
// returns.
var g = document.createElementNS("http://www.w3.org/2000/svg", "g");
// Set the transform attribute to the provided string value.
g.setAttributeNS(null, "transform", transform);
// consolidate the SVGTransformList containing all transformations
// to a single SVGTransform of type SVG_TRANSFORM_MATRIX and get
// its SVGMatrix.
var matrix = g.transform.baseVal.consolidate().matrix;
// Below calculations are taken and adapted from the private function
// transform/decompose.js of D3's module d3-interpolate.
var {a, b, c, d, e, f} = matrix; // ES6, if this doesn't work, use below assignment
// var a=matrix.a, b=matrix.b, c=matrix.c, d=matrix.d, e=matrix.e, f=matrix.f; // ES5
var scaleX, scaleY, skewX;
if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX;
if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX;
if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY;
if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX;
return {
translateX: e,
translateY: f,
rotate: Math.atan2(b, a) * 180 / Math.PI,
skewX: Math.atan(skewX) * 180 / Math.PI,
scaleX: scaleX,
scaleY: scaleY
};
}
console.log(getTransformation("translate(20,30)"));
console.log(getTransformation("rotate(45) skewX(20) translate(20,30) translate(-5,40)"));
If you pull in d3 v4 through npm, you can import the src/transform/parse file directly and call parseSvg:
// using es2015 modules syntax
import { parseSvg } from "d3-interpolate/src/transform/parse";
parseSvg("translate(20, 20)");
On elements which have the d3.js zoom listener on them -- usually the <g> element appended to the svg element -- you can use this call to get the transformation attributes outside of the zoom function:
var self = this;
var t = d3.zoomTransform(self.svg.node());
// t = {k: 1, x: 0, y: 0} or your current transformation values
This returns the same values as when calling d3.event.transform within the zoom event function itself.
Calling d3.event.transform outside the zoom event function will error:
Uncaught TypeError: Cannot read property 'transform' of null
I have to use d3.zoomTransform to allow panning and zooming from buttons outside the graph.
I found a little bit simpler solution than that.
selection.node().transform.baseVal[0].matrix
In this matrix you have cordinates e and f witch are equivalent to x, y. (e === x, f === y). No need to implement your very own funtion for that.
baseVal is a list of transformations of the element. You can't use that for the object without previus transformation! (the list will be empty) Or if you done many tranformation to the object the last position will be under the last element of baseVal list.
I am a little late to the party, but I had some code that was beneficial to me, I hope it helps you out too.
The code above by #altocumulus is quite thorough and works like a charm. However it didn't quite meet my needs since I was doing the calculations by hand and needed to alter some transform properties as painlessly as possible.
This might not be the solution for everyone, but it was perfect for me.
function _getTokenizedTransformAttributeValue(transformStr) {
var cleanedUpTransformAttrArr = transformStr.split(')', ).slice(0,-1);
return cleanedUpTransformAttrArr.reduce(function(retObj, item) {
var transformPair = item.split('(');
retObj[transformPair[0]] = transformPair[1].split(',');
return retObj;
}, {});
}
function _getStringFromTokenizedTransformAttributeObj(transformAttributeObj) {
return Object.keys(transformAttributeObj).reduce(function(finalStr, key) {
// wrap the transformAttributeObj[key] in array brackets to ensure we have an array
// join will flatten the array first and then do the join so [[x,y]].join(',') -> "x,y"
return finalStr += key + "(" + [transformAttributeObj[key]].join(',') + ")";
}, '');
}
The really great thing with the first function is that I can manually alter a specific property (e.g. rotation), and not have to worry about how it affects translate or anything else (when rotating around a point), whereas when I rely on the built-in or even d3.transform methods they consolidate all the properties into one value.
Why is this cool?
Imagine a some HTML
<g class="tick-label tick-label--is-rotated" transform="translate(542.8228777985075,0) rotate(60, 50.324859619140625, 011.402383210764288)" style="visibility: inherit;"></g>
Using d3.transfrom I get:
In object form
jr {rotate: 59.99999999999999, translate: [577.8600589984691, -37.88141544673796], scale: [1, 1], skew: 0, toString: function}
In string form
"translate(577.8600589984691,-37.88141544673796)rotate(59.99999999999999)skewX(0)scale(1,1)"
Which is correct mathematically, but makes it hard for me to simply remove the angle of rotation and the translation that had to be introduced to rotate this element around a given point.
Using my _getTokenizedTransformAttributeValue function
In object form
{translate: ["542.8228777985075", "0"], rotate: ["60", " 50.324859619140625", " 011.402383210764288"]}
In string form using the function _getStringFromTokenizedTransformAttributeObj
"translate(542.8228777985075,0)rotate(60, 50.324859619140625, 011.402383210764288)"
Which is perfect because now when you remove the rotation, your element can go back to where it was
Granted, the code could be cleaner and the function names more concise, but I really wanted to get this out there so others could benefit from it.
I found a way do achieve something similar by using this:
d3.select(this).node().getBBox();
this will give you access to the x/y position and width/height
You can see an example here: https://bl.ocks.org/mbostock/1160929
I've been reading the documentation & source to try and find out a way to compute the length of a vector and then set it to a defined value.
my code:
if (viewerPosition !== null && placementPosition !== null) {
var vectorDiff = placementPosition.sub(viewerPosition);
placementPosition.setY(0);
placementPosition.multiplyScalar(100000);
console.log(placementPosition)
the log returns:
Object { x: -23.658385352970377, y: 0, z: 9.121675219786463 }
Ive tried adding the line:
placementPosition.length (32);
to see if that would change the length of the vector to 32m, but unfortunately this did not work.
Any advice would be greatly appreciated. Thanks
// make the length of the vector 1.0
placementPosition.normalize();
// make the length of the vector 32
placementPosition.multiplyScalar(32);
I'm writing a 2D gravity simulation game and I'm trying to add save/load functionality. In the game I store all of the current planets in an array. Each planet is represented by a Body object which contains the coordinates, mass, and motion vector of the planet. It also stores an array of the last 100 coordinates of the planet in order to draw the planet's trail on the screen.
I want to use JSON.stringify() to serialize the planets array. I'd like to save the first attributes of each planet (mass, location, motion) but I don't need to save the last 100 coordinates (the trail array). I don't want to completely delete the coordinates otherwise the trails will disappear from the screen. Can I stringify only a portion of each object? If not, can I remove that portion of the JSON string after it's been encoded? Or should I move the coordinates elsewhere during the save process then copy them back into each planet once it's been saved?
In modern web browsers you can use Array#map.
var serialized = JSON.stringify(planets.map(function(planet){
return {
mass: planet.mass,
location: planet.location,
motion: planet.motion
};
}));
Or, the equivalent using a for loop.
try it this way
var saved = JSON.stringify( {mass:body.mass,location:body.location,motion:body.motion} );
it shall give you just the three parts as a json string.
A bit more extended you could provide your body class such an export function.
For example:
Bodyclass.export = function( toexport ) {
if ( undefined === toexport || toexport.constructor != Array ) {
var toexport = [ 'mass', 'location', 'motion' ];
}
var export = {};
for ( var i = 0; i < toexport; i++) {
export[ toexport[ i ] ] = this[ toexport[ i ] ];
]
}
var saved = JSON.stringify( body.export() );
The best would be to create both a serialization and deserialization method. This will allow you to create the most efficient storage format while still allowing you to reconstruct as much of the objects as you deem necessary.
You can use export/import, save/restore, serialize/deserialize terminology, whichever you see fit.
Having methods like this will increase you maintainability in the long run as well.
You can use second parameter of JSON.stringify (replacer)
const planet = {
name: "Pluto",
lastCoords: [[0, 0], [1,1,]]
}
const json = JSON.stringify(planet, (key, value) => key === "lastCoords" ? undefined : value)
// json === {"name":"Pluto"}