I have a simple map "objects" lets assume this :
{
ServoP180V1: {X: 100.0, Y: 0.0},
ServoP180V3: {X: 100.0, Y: 0.0}
ServoP180V5: {X: 100.0, Y: 0.0}
}
How I can sort the keys in such way that they will be in an order, like this:
{
ServoP180V1: {X: 100.0, Y: 0.0},
ServoP180V2: {X: 100.0, Y: 0.0}
ServoP180V3: {X: 100.0, Y: 0.0}
}
I tried this code but it has problems with returning null sometimes, not sure Im in right way
sortObjects() {
int i = 1;
for (var key in objects.keys) {
objects.update(
key.substring(0, key.length - 1) + i.toString(),
null,
);
i++;
}
}
The method 'call' was called on null.
Receiver: null
Tried calling: call()
also this way
sortObjects() {
int i = 1;
objects.forEach((key, value) {
objects.update(
key.substring(0, key.length - 1) + i.toString(),
(existingValue) => value,
ifAbsent: () => value,
);
i++;
});
}
giving such an error
Exception: Concurrent modification during iteration:
Thank you in advance !
So you are changing the key during the foearch loop, this is illegal. I would change the keys by generating another map and then replacing the old one. It is an answer.
Map.update()
Update method of the map only updates the content of the key and only if it exists, but does not change the key itself. I didn't find anything related to changing keys for maps at runtime.
Map<String, dynamic> oldMap = {
"ServoP180V1": {"X": 100.0, "Y": 0.0},
"ServoP180V3": {"X": 100.0, "Y": 0.0},
"ServoP180V5": {"X": 100.0, "Y": 0.0}
};
Map<String, dynamic> newMap = {};
int i = 1;
oldMap.keys.toList().forEach((key) {
newMap.addAll({
"${key.substring(0, key.length - 1)}$i":
oldMap[key]
});
i++;
});
print(oldMap);
print(newMap);
result:
{ServoP180V1: {X: 100.0, Y: 0.0}, ServoP180V3: {X: 100.0, Y: 0.0}, ServoP180V5: {X: 100.0, Y: 0.0}}
{ServoP180V1: {X: 100.0, Y: 0.0}, ServoP180V2: {X: 100.0, Y: 0.0}, ServoP180V3: {X: 100.0, Y: 0.0}}
void main(List<String> args) {
final objects = {
'ServoP180V1': {'X': 100.0, 'Y': 0.0},
'ServoP180V3': {'X': 100.0, 'Y': 0.0},
'ServoP180V5': {'X': 100.0, 'Y': 0.0}
};
var keys = objects.keys.toList()..sort();
var newData = <String, Map<String, double>>{};
keys.forEach((k) => newData[k] = objects[k]);
print(newData);
}
Result:
{ServoP180V1: {X: 100.0, Y: 0.0}, ServoP180V3: {X: 100.0, Y: 0.0}, ServoP180V5: {X: 100.0, Y: 0.0}}
Map<String, dynamic> oldMap = {
"ServoP180V1": {"X": 100.0, "Y": 0.0},
"ServoP180V3": {"X": 100.0, "Y": 0.0},
"ServoP180V5": {"X": 100.0, "Y": 0.0}
};
int j = 1;
Map<String, dynamic> newMap2 = oldMap
.map((key, value) => MapEntry('ServoP180V${j++}',value);
);
print(newMap2); // {ServoP180V1: {X: 100, Y: 0}, ServoP180V2: {X: 100, Y: 0}, ServoP180V3: {X: 100, Y: 0}}
Related
I'm having few documents which is of the form
{
...id information and so on,
coordinates: [{x, y}]
...few other indexes
}
I want to generate an elastic search aggregation which will combine whole coordinates array into a single array. For example
The documents are
[
{
...
coordinates: [
{x: 20, y: 30},
{x: 50, y: 10},
{x: 40, y: 20}
],
...
},
{
...
coordinates: [
{x: 10, y: 5},
{x: 20, y: 15},
{x: 60, y: 90},
{x: 70, y: 50}
],
...
},
{
...
coordinates: [
{x: 90, y: 20},
{x: 80, y: 70}
],
...
},
]
In the output I need to generate something like this using the aggregation
[
{x: 20, y: 30},
{x: 50, y: 10},
{x: 40, y: 20},
{x: 10, y: 5},
{x: 20, y: 15},
{x: 60, y: 90},
{x: 70, y: 50},
{x: 90, y: 20},
{x: 80, y: 70}
]
Is it possible in lightningchart js to rotate ticks text on axis? Ticks text does not fit or overlaps adjacent text.
As of LightningChart JS v3.1.0 it's possible to set tick label rotation.
You can use axis.setTickStyle to set style settings for current tick strategy. Alternatively this can be done through axis.setTickStrategy's styler parameter.
The VisibleTicks class has setLabelRotation method which can be used to define tick rotation in degrees. Positive angle rotates clockwise and negative angle counter-clockwise. So to rotate labels on X axis to be rotated vertically.
chart.getDefaultAxisX()
.setTickStyle((s) => s
.setMajorTickStyle((m) => m.setLabelRotation(-90))
.setMinorTickStyle(m => m.setLabelRotation(-90)),
)
See full example below.
const {
lightningChart,
PointShape,
} = lcjs
const pointSize = 10
const chart = lightningChart().ChartXY()
chart.addPointLineSeries()
.setPointSize(pointSize)
.add([{
x: 0,
y: 0
},
{
x: 50,
y: 10
},
{
x: 80,
y: 20
},
{
x: 100,
y: 30
},
{
x: 150,
y: 40
},
{
x: 180,
y: 50
},
{
x: 230,
y: 60
},
{
x: 290,
y: 70
}
])
chart.addPointLineSeries({
pointShape: PointShape.Circle
})
.setPointSize(pointSize)
.add([{
x: 0,
y: 0
},
{
x: 100,
y: 10
},
{
x: 230,
y: 20
},
{
x: 390,
y: 30
},
{
x: 470,
y: 40
},
{
x: 540,
y: 50
},
{
x: 600,
y: 60
},
{
x: 800,
y: 70
}
])
chart.getDefaultAxisX()
.setInterval(0, 1000, false, true)
.setTickStyle((s) =>
s.setMajorTickStyle((m) => m.setLabelRotation(-90)).setMinorTickStyle(m => m.setLabelRotation(-90)),
)
chart.getDefaultAxisY()
.setInterval(0, 100, false, true)
<script src="https://unpkg.com/#arction/lcjs#3.1.0/dist/lcjs.iife.js"></script>
As of current version (v3.0.1) there is no API for configuring text.
I see this as a very potential feature improvement. It would help us in introducing it to the library, if you would describe your usage case for rotated tick text.
Screenshots are gold.
I use canvasJS to make a line graph report, the issue now is it didn't show properly in tooltip using yValueFormatString.
my goal is to display the value:
{
type:"stepLine",
name: "title",
showInLegend: true,
connectNullData: true,
yValueFormatString: "##.## %",
dataPoints: [
{ x: new Date(2019, 1, 20), y: 12.78 },
{ x: new Date(2019, 1, 19), y: 12.79 },
{ x: new Date(2019, 1, 18), y: 12.80 },
]
}
in tooltip, it shows
1278 %
1279 %
1280 %
I think there's something wrong with it, I wanted to display like:
12.78 %
12.79 %
12.80 %
any idea?
According to documentation, "%" Multiplies a number by 100 i.e. 12.78("##.## %") => 1278%. Instead setting yValueFormatString to "##.#0 '%'" should work fine in this case.
Here is an example:
var chart = new CanvasJS.Chart("chartContainer", {
data: [{
type:"stepLine",
name: "title",
showInLegend: true,
connectNullData: true,
yValueFormatString: "##.#0 '%'",
dataPoints: [
{ x: new Date(2019, 1, 20), y: 12.78 },
{ x: new Date(2019, 1, 19), y: 12.79 },
{ x: new Date(2019, 1, 18), y: 12.80 },
]
}]
});
chart.render();
<script src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>
<div id="chartContainer" style="width: 100%; height: 260px"></div>
I'm trying a line chart for several years with month names in the xaxis. xaxis seems to be an integer so I used the function from this answer: https://stackoverflow.com/a/30325918
The problem is that the chart is cut off by number 9 (which stands for "Okt") and I don't know why. So the 10 and 11 are missing. Also the tooltips are not shown, maybe that's a subsequent fault.
Style for the svg:
#chart svg {
height: 600px;
width: 1456px;
}
Code for the Chart:
nv.addGraph(function() {
var chart = nv.models.lineChart()
.margin({left: 50}) //Adjust chart margins to give the x-axis some breathing room.
.useInteractiveGuideline(true) //We want nice looking tooltips and a guideline!
.showLegend(true) //Show the legend, allowing users to turn on/off line series.
.showYAxis(true) //Show the y-axis
.showXAxis(true) //Show the x-axis
;
var Monate = ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez']
chart.xAxis //Chart x-axis settings
.axisLabel('Monat')
.tickValues([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]).tickFormat(function(d){
return Monate[d]
});
chart.forceY([0, 55000]);
d3.select('#chart svg').datum([{ values: [{ x:'0', y: '0'},{ x:'1', y: '0'},{ x:'2', y: '7147.75'},{ x:'3', y: '5567.75'},{ x:'4', y: '8307.75'},{ x:'5', y: '7680.75'},{ x:'6', y: '10416.75'},{ x:'7', y: '15119.25'},{ x:'8', y: '6654.75'},{ x:'9', y: '7670.75'},{ x:'10', y: '8535.75'},{ x:'11', y: '25978.5'}], key: '2012'},
{ values: [{ x:'0', y: '4397.5'},{ x:'1', y: '14542.5'},{ x:'2', y: '18652.5'},{ x:'3', y: '18027.5'},{ x:'4', y: '10123.5'},{ x:'5', y: '11686.25'},{ x:'6', y: '10451.5'},{ x:'7', y: '17918'},{ x:'8', y: '11013.25'},{ x:'9', y: '11598.25'},{ x:'10', y: '12179'},{ x:'11', y: '54450.75'}], key: '2013'},
{ values: [{ x:'0', y: '13257.75'},{ x:'1', y: '10050.25'},{ x:'2', y: '17530'},{ x:'3', y: '16684'},{ x:'4', y: '10437.25'},{ x:'5', y: '31956.5'},{ x:'6', y: '24343.75'},{ x:'7', y: '24026.5'},{ x:'8', y: '24754.5'},{ x:'9', y: '17423'},{ x:'10', y: '27284.75'},{ x:'11', y: '50121.25'}], key: '2014'},
...and so on...
{ values: [{ x:'0', y: '954'},{ x:'1', y: '0'},{ x:'2', y: '0'},{ x:'3', y: '0'},{ x:'4', y: '0'},{ x:'5', y: '0'},{ x:'6', y: '0'},{ x:'7', y: '0'},{ x:'8', y: '0'},{ x:'9', y: '0'},{ x:'10', y: '0'},{ x:'11', y: '0'}], key: '2019'}]).transition().duration(500).call(chart);
//Update the chart when window resizes.
nv.utils.windowResize(function() { chart.update() });
return chart;
});
All your x and y are strings.
Remove all the ' characters.
I have set the size style on the div#chart because nvd3.css has a style for the svg with width and height set to 100%.
Using d3 I am attempting to create an animation between two lines that have a different number of data points.
I have referenced Mike Bostock's post: https://bl.ocks.org/mbostock/3916621 which contains a pathTween method for two paths described in "M0..." format.
The data I am trying to plot is raw data points.
For instance:
var line = d3.svg.line().interpolate("monotone")
.x(function(d){ return d.x; })
.y(function(d){ return d.y; });
low_res = [
{x: 0 , y: 4 },
{x: 5 , y: 14 },
{x: 10 , y: 11 },
{x: 85 , y: 14 },
{x: 90 , y: 11 },
{x: 95 , y: 7 },
{x: 100 , y: 4 },
];
var high_res = [[
{x: 0 , y: 4 },
{x: 1 , y: 12 },
{x: 2 , y: 11 },
{x: 3 , y: 11 },
{x: 4 , y: 14 },
{x: 5 , y: 14 },
{x: 6 , y: 12 },
{x: 7 , y: 4 },
{x: 8 , y: 3 },
{x: 9 , y: 1 },
{x: 10 , y: 11 },
{x: 11 , y: 11 },
{x: 12 , y: 1 },
{x: 13 , y: 13 },
{x: 14 , y: 1 },
{x: 15 , y: 5 },
{x: 16 , y: 13 },
{x: 17 , y: 10 },
]]
var lines = svg.selectAll(".line").data(high_res)
.enter()
.append("path")
.attr("class","line")
.attr("d", line)
.style("stroke", "blue");
This works find for displaying the high_res plot. Mike Bostock's example is as follows:
var d0 = "M0,0c100,0 0,100 100,100c100,0 0,-100 100,-100",
d1 = "M0,0c100,0 0,100 100,100c100,0 0,-100 100,-100c100,0 0,100 100,100";
svg.append("path")
.attr("transform", "translate(180,150)scale(2,2)")
.attr("d", d0)
.call(transition, d0, d1);
function transition(path, d0, d1) {
path.transition()
.duration(2000)
.attrTween("d", pathTween(d1, 4))
.each("end", function() { d3.select(this).call(transition, d1, d0); });
}
function pathTween(d1, precision) {
return function() {
var path0 = this,
path1 = path0.cloneNode(),
n0 = path0.getTotalLength(),
n1 = (path1.setAttribute("d", d1), path1).getTotalLength();
// Uniform sampling of distance based on specified precision.
var distances = [0], i = 0, dt = precision / Math.max(n0, n1);
while ((i += dt) < 1) distances.push(i);
distances.push(1);
// Compute point-interpolators at each distance.
var points = distances.map(function(t) {
var p0 = path0.getPointAtLength(t * n0),
p1 = path1.getPointAtLength(t * n1);
return d3.interpolate([p0.x, p0.y], [p1.x, p1.y]);
});
return function(t) {
return t < 1 ? "M" + points.map(function(p) { return p(t); }).join("L") : d1;
};
};
}
I am struggling to figure out how to create a native path object, such as d0, d1 in the second example from my set of raw data which can be passed into the transition function ie:
.call(transition, d0, d1);
Many thanks in advance for any advice.
Your question seems to boil down to:
How can I generate a path for my datapoints?
This is actually what the line function is doing. It's as simple as:
var low_res = [
{x: 0 , y: 4 },
{x: 5 , y: 14 },
{x: 10 , y: 11 },
{x: 85 , y: 14 },
{x: 90 , y: 11 },
{x: 95 , y: 7 },
{x: 100 , y: 4 },
],
high_res = [
{x: 0 , y: 4 },
{x: 1 , y: 12 },
{x: 2 , y: 11 },
{x: 3 , y: 11 },
{x: 4 , y: 14 },
{x: 5 , y: 14 },
{x: 6 , y: 12 },
{x: 7 , y: 4 },
{x: 8 , y: 3 },
{x: 9 , y: 1 },
{x: 10 , y: 11 },
{x: 11 , y: 11 },
{x: 12 , y: 1 },
{x: 13 , y: 13 },
{x: 14 , y: 1 },
{x: 15 , y: 5 },
{x: 16 , y: 13 },
{x: 17 , y: 10 },
];
var line = d3.svg.line().interpolate("monotone")
.x(function(d){ return d.x; })
.y(function(d){ return d.y; });
var d0 = line(low_res),
d1 = line(high_res);
console.log(d0);
console.log(d1);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>