How to split Map into two maps based on a condition - immutable.js

I'm relatively new to React using Immutable.js.
Let's say I have a (Ordered) Map of 30 items, in which some have the color green and some the color red.
Now I want to split this Map into two Maps, one containing the first five green items and the other containing the rest (rest of the green items and red items).
If I had an array, I would just define two result-arrays, iterate through my src-array and put the items in their according result-array. If I did that with immutable.js, I would need to create a new Map every time something changes. Is that still the way to go, or are there faster / more elegant ways to achieve that?
Thanks in advance!

If I get the question right, most elegant way is to use Map.filter
const { Map } = Immutable;
const sourceMap = new Map({
key1: { color: "red" },
key2: { color: "green" },
});
const filterMap = c => sourceMap.filter(({ color }) => color === c);
const greenMap = filterMap("green");
const redMap = filterMap("red");
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.min.js"></script>

Related

Remove spacing between bar in bar graph( react-chart-js)

issue that i am facing is, i have my bar graph made using react-chart-js. i want to remove space between the bar and center align the bar's . The bar's should have Thickness equal to 50
I try using dummy data ,that way i got the desired output but that is not the correct way of doing . Also I try using barPercentage , categoryPercentage option but didnt get the desired output
Link for CodeSandbox
I don't know if this actually works out of the box. There is nothing in the documentation about this use case either.
You could do it with ghost values to extend the chart in general.
This is not really a solution, but it may be an option.
const labels = ["","","January", "February", "March","",""];
export const data = {
labels,
datasets: [
{
label: "Dataset 1",
data: labels.map((elem, index) => {
if (index > 1 && index < 5)
return faker.datatype.number({ min: 0, max: 1000 })
}),
backgroundColor: "rgba(255, 99, 132, 0.5)",
barThickness: 50
}
]
};

TypeORM conditional querying many to many relations

Let's say I've a colors table and an items table, with a #ManyToMany relation between these 2 tables (an item can have many colors and a color can have many items).
Using TypeORM, I would like to get all items that match only one or more provided colors.
If an item has an additional color that is not specified in the query, it should not be retrieved.
const matchingColors = ['green', 'blue'];
const query = await this.itemRepository
.createQueryBuilder('item')
.innerJoin('item.colors', 'color', 'color.name IN (:...matchingColors)', { matchingColors })
.getMany();
In my example above I would like to get all items that match the matchingColors array, so all items that have green, or blue, or green and blue color(s). So if an item has the blue and red colors, or only red (or no color), it should be excluded from the results.
Currently, I didn't find a proper way to do it. The query in my example above doesn't work correctly. My dream is to make it work using only 1 SQL query. Thanks for your help!
Try this:
const matchingColors = ['green', 'blue'];
const items = await this.itemRepository
.createQueryBuilder('item')
.innerJoinAndSelect(
'item.colors',
'color',
'"color"."name" IN (:...matchingColors)',
{ matchingColors }
)
.getMany();

Angular 6 with Openlayers drawLine

I want to draw a routing line from Land of Canaan to Waipu but After I compile the line become like this,
What I expect is like this,
My code:
routing.forEach((obj, index) => {
const line_point = [];
obj.waypoints.forEach((pos, i) => {
const lng = Number(pos.lon);
const lat = Number(pos.lat);
line_point.push(ol.proj.fromLonLat([lng, lat]));
});
const routeLayer = new ol.layer.Vector({
source: new ol.source.Vector({
features: [new ol.Feature({
geometry: new ol.geom.LineString(line_point, 'XY'),
name: 'Line'
})]
}),
style: new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#bc0000',
width: 2
})
})
});
routeLayer.setZIndex(55);
this.mapLayer.push(routeLayer);
this.map.addLayer(routeLayer);
});
May I know what happened to this and how to solve it?
One of your LineString ist crossing the antimeridian (180° W/E). A solution is to split the LineString at the antimeridian.
Your algorithm is have issues. You have to consider split the line in as many chunks as be needed. As you did not provided the code, I am able only to include cases in conceptual way.
Your array variable could be an array of arrays with all line chunks needed to draw.
line_point
Includes a draw with border cases:
Line a-b is similar to your case with two chunks.
Line c-d is other case with two chunks.
Line e-f is an complex case where there is three chunks.
The dotten light green line represent the union between the chunks

How to add legend for a bar chart with different colors in dc.js?

Below is the code snippet for a barchart with colored bars:
var Dim2 = ndx.dimension(function(d){return [d.SNo, d.something ]});
var Group2 = Dim2.group().reduceSum(function(d){ return d.someId; });
var someColors = d3.scale.ordinal().domain(["a1","a2","a3","a4","a5","a6","a7","a8"])
.range(["#2980B9","#00FFFF","#008000","#FFC300","#FF5733","#D1AEF1","#C0C0C0","#000000"]);
barChart2
.height(250)
.width(1000)
.brushOn(false)
.mouseZoomable(true)
.x(d3.scale.linear().domain([600,800]))
.elasticY(false)
.dimension(Dim2)
.group(Group2)
.keyAccessor(function(d){ return d.key[0]; })
.valueAccessor(function(d){return d.value; })
.colors(someColors)
.colorAccessor(function(d){return d.key[1]; });
How do I add a legend to this chart?
Using composite keys in crossfilter is really tricky, and I don't recommend it unless you really need it.
Crossfilter only understands scalars, so even though you can produce dimension and group keys which are arrays, and retrieve them correctly, crossfilter is going to coerce those arrays to strings, and that can cause trouble.
Here, what is happening is that Group2.all() iterates over your data in string order, so you get keys in the order
[1, "a1"], [10, "a3"], [11, "a4"], [12, "a5"], [2, "a3"], ...
Without changing the shape of your data, one way around this is to sort the data in your legendables function:
barChart2.legendables = function() {
return Group2.all().sort((a,b) => a.key[0] - b.key[0])
.map(function(kv) {
return {
chart: barChart2,
name: kv.key[1],
color: barChart2.colors()(kv.key[1]) }; }) };
An unrelated problem is that dc.js takes the X domain very literally, so even though [1,12] contains all the values, the last bar was not shown because the right side ends right at 12 and the bar is drawn between 12 and 13.
So:
.x(d3.scale.linear().domain([1,13]))
Now the legend matches the data!
Fork of your fiddle (also with dc.css).
EDIT: Of course, you want the legend items unique, too. You can define uniq like this:
function uniq(a, kf) {
var seen = [];
return a.filter(x => seen[kf(x)] ? false : (seen[kf(x)] = true));
}
Adding a step to legendables:
barChart2.legendables = function() {
var vals = uniq(Group2.all(), kv => kv.key[1]),
sorted = vals.sort((a,b) => a.key[1] > b.key[1] ? 1 : -1);
// or in X order: sorted = vals.sort((a,b) => a.key[0] - b.key[0]);
return sorted.map(function(kv) {
return {
chart: barChart2,
name: kv.key[1],
color: barChart2.colors()(kv.key[1]) }; }) };
Note that we're sorting by the string value of d.something which lands in key[1]. As shown in the comment, sorting by x order (d.SNo, key[0]) is possible too. I wouldn't recommend sorting by y since that's a reduceSum.
Result, sorted and uniq'd:
New fiddle.

Use only the 5 higher values in amCharts pie?

My data call can have lots of small elements (in percentage) that I would like to ignore, I only need the top 5 in my amCharts pie.
Can this be accomplished with amCharts or I should treat the data before?
please see my [jsfiddle][1]
[1]: http://jsfiddle.net/pbarros/xznxbnc7/3/
thanks
You can use the hideLabelsPercent property to set a threshold for the lowest allowed percentage you want a label for. If you want to do this dynamically, you can set this in the init event by finding the 5th largest percents value in the chart's chartData array and use it as your hideLabelsPercent threshold. I've updated your handleInit method to do this:
function handleInit(e) {
if (e.chart.chartData.length > 5) {
//sort the copy of the chartData array from largest to smallest
//if your data is pre-sorted, then you can skip this step
var sortedData = e.chart.chartData.slice().sort(function(lhs, rhs) {
return rhs.percents - lhs.percents;
});
//set the threshold equal to the 5th largest slice's percents value so that the rest are hidden
e.chart.hideLabelsPercent = sortedData[4].percents;
//redraw the chart
e.chart.validateNow();
}
}
Updated fiddle: http://jsfiddle.net/xznxbnc7/9/
Edit since I misread the question
If you only want to show the top five slices from your dataset, you can filter on your backend or use the init method to sort and modify your dataProvider to contain only the top five.
function handleInit(e) {
if (e.chart.chartData.length > 5) {
//sort the copy of the chartData array from largest to smallest
//if your data is pre-sorted, then you can skip this step
var sortedData = e.chart.dataProvider.slice().sort(function(lhs, rhs) {
return rhs[e.chart.valueField] - lhs[e.chart.valueField];
});
//only put in the top 5.
e.chart.dataProvider = sortedData.slice(0, 5);
// redraw the chart
e.chart.validateData();
}
}
Fiddle: http://jsfiddle.net/g3cchyjg/1