Ordering map legend items in Wikidata Query Service - leaflet

Wikidata provides a cool way to render SPARQL results on OpenStreetMap. For example:
#Big cities, grouped into map layers by population
#defaultView:Map
SELECT DISTINCT ?city ?cityLabel (SAMPLE(?location) AS ?location) (MAX(?population) AS ?population) (SAMPLE(?layer) AS ?layer)
WHERE
{
?city wdt:P31/wdt:P279* wd:Q515;
wdt:P625 ?location;
wdt:P1082 ?population.
FILTER(?population >= 500000).
BIND(
IF(?population < 1000000, "<1M",
IF(?population < 2000000, "1M-2M",
IF(?population < 5000000, "2M-5M",
IF(?population < 10000000, "5M-10M",
IF(?population < 20000000, "10M-20M",
">20M")))))
AS ?layer).
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
GROUP BY ?city ?cityLabel
I'm wondering if there is a way to control the order of the items in the legend (top right).

It seems that leaflet tries to parse layer names as numbers. In case of failure, the order of layers in the legend corresponds to the order of the first appearance in the table (switch between "Map" and "Table" views).
Thus, you should bind additional variable with naturally sortable values (and then sort results by those values). Perhaps this is possible using REPLACE, but I'd prefer to use simple dictionary.
#--Big cities, grouped into map layers by population--
#defaultView:Map
SELECT DISTINCT ?city ?cityLabel
(SAMPLE(?location) AS ?location) (MAX(?population) AS ?population)
(SAMPLE(?layer) AS ?layer) {
VALUES (?layer ?order) {
("<1M" 1) ("1M-2M" 2) ("2M-5M" 3) ("5M-10M" 4) ("10M-20M" 5) (">20M" 6)}
?city wdt:P31/wdt:P279* wd:Q515;
wdt:P625 ?location;
wdt:P1082 ?population.
FILTER(?population >= 500000).
BIND(
IF(?population < 1000000, "<1M",
IF(?population < 2000000, "1M-2M",
IF(?population < 5000000, "2M-5M",
IF(?population < 10000000, "5M-10M",
IF(?population < 20000000, "10M-20M",
">20M")))))
AS ?layer).
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
} GROUP BY ?city ?cityLabel ORDER BY (SAMPLE(?order))
Try it!

Related

Drools: how to use abbreviated condition notation together with further conditions?

Using Drools 6.5.0.Final
I want to use abbreviated combined relation condition (e.g. Person( age > 30 && < 40 )) in combination with additional conditions.
I tried it, but the resulting rules are executed more than once.
I have a small example, where temperature deviation from a setpoint is checked and the allowed deviations depend on the setpoint. The allowed deviations are configured with Param facts, see below.
If I execute the example (fire-all-rules):
rule 1 fires two times (bug?)
rule 2 fires once as expected (without abbreviated notation).
Is my usage of the abbreviated notation wrong or is this a bug?
Example rules:
declare Param
from : float
to : float
low : float
high : float
end
declare TemperatureEvent
#role( event )
id : String
setpoint : float
t : float
end
rule "Init abbreviated conditions test"
when
then
insert(new Param(0, 10, 1, 1));
insert(new Param(10,20, 2, 3));
insert(new TemperatureEvent("id1", 13.7f,11.5f));
// rule 1 and rule 2 should fire exactly once
end
rule "rule 1"
when
$p: Param()
$x : TemperatureEvent($p.from <= setpoint && < $p.to, (t < setpoint+$p.low || t > setpoint+$p.high))
then
System.out.println("rule 1: "+$x.getId()+" "+$x.getSetpoint()+" "+$x.getT());
end
rule "rule 2"
when
$p: Param()
$x : TemperatureEvent($p.from <= setpoint, setpoint < $p.to, (t < setpoint+$p.low || t > setpoint+$p.high))
then
System.out.println("rule 2: "+$x.getId()+" "+$x.getSetpoint()+" "+$x.getT());
end
The abbreviated restriction
$p.from <= setpoint && < $p.to
is equivalent to
$p.from <= setpoint && $p.from < $p.to
What you want is
setpoint >= $p.from && < $p.to

Compare the time duration of two movies

I am going to make a function that takes starting timing of two movies: hr1,hr2,min1,min2, and their durations, durmin1,durmin2 and decides whether we can binge and watch both movies.
The criteria are that they must not overlap and that we are not going to wait more than 30 minutes between the end of one and the beginning of the next. It returns true if the criteria are both met and returns false otherwise. Movie start times are always after 1 pm and before midnight. The first one always starts earlier. The order of the input arguments is: hr1, min1, durmin1, hr2, min2, durmin2
I am unable to understand what will my function will do. What are these timing hr1,hr2? Why duration has been given?
I have tried this:
function mymovies=movies(hr1,min1,dur1,hr2,min2)
h1=hr1+min/60+dur1;
h2=hr2+min/60;
if h2-h1>=30/60 && h2-h1~=0
disp('Ture')
else
disp('False')
end
end
well, with proper variables and a little thinking just one if is sufficient to solve this problem.As far as I have understood, you definitely do not need to consider the duration for the second movie. you only need to worry about the details of the first movie and the start time of the second movie. You also need to "return" the boolean result not display it. So here is what you should do, given the instructions in your question:
First: Convert the total time from when movie one starts till it ends to minutes
Second: convert the total start time of movie two to minutes
Finally, just use the difference to meet the conditions given in the instructions in a simpe if statement. Try that with your grader then let me know what happens then. (preferably of movie2 - movie1) since you are free to assume that movie1 will always start first)
Given your level, this should suffice.
-step 1: convert hr, min to only minutes (past 1pm if you want...)
so:
start_movie_1 = hr1*60 + min1
end_movie_1 = start_movie_1 + durmin1
Similar for movie 2.
-step 2: find if they overlap.
if start_movie_1 < start_movie_2 and end_movie_1 > end_movie_2 => there is overlapping (whole movie 2 is inside movie 1)
if start_movie_1 < start_movie_2 and end_movie_1 > start_movie_2 => there is overlapping (movie 2 will start before movie 1 finish)
if start_movie_2 < start_movie_1 and end_movie_2 > end_movie_1 => there is overlapping (whole movie 1 is inside movie 2)
if start_movie_2 < start_movie_1 and end_movie_2 > start_movie_1 => there is overlapping (movie 1 will start before movie 2 finish)
-step 3: now we know they don't overlap, so we need to check the time inbetween
if start_movie_1 < start_movie_2 => return (start_movie_2 - end_movie_1) <= 30
else (start_movie_2 < start_movie_1)
return (start_movie_1 - end_movie_2) <= 30
Edited for an even more simple answer
function mymovies=movies(hr1,min1,dur1,hr2,min2,dur2)
start_movie_1 = hr1*60 + min1;
end_movie_1 = start_movie_1 + dur1;
start_movie_2 = hr2*60 + min2;
end_movie_2 = start_movie_2 + dur2;
if start_movie_1 < start_movie_2 && end_movie_1 > end_movie_2
disp('FALSE');
else if start_movie_1 < start_movie_2 && end_movie_1 > start_movie_2
disp('FALSE');
else if start_movie_2 < start_movie_1 && end_movie_2 > end_movie_1
disp('FALSE');
else if start_movie_2 < start_movie_1 && end_movie_2 > start_movie_1
disp('FALSE');
else
if start_movie_1 < start_movie_2 && (start_movie_2 - end_movie_1) <= 30
disp('TRUE');
else if (start_movie_2 < start_movie_1) && (start_movie_1 - end_movie_2) <= 30
disp('TRUE');
else
disp('FALSE');
end
end
end

How to paginate and group in MongoDB?

My objects are of the following structure:
{id: 1234, ownerId: 1, typeId: 3456, date:...}
{id: 1235, ownerId: 1, typeId: 3456, date:...}
{id: 1236, ownerId: 1, typeId: 12, date:...}
I would like to query the database so that it returns all the items that belong to a given ownerId but only the first item of a given typeId. IE the typeId field is unique in the results. I would also like to be able to use skip and limit.
In SQL the query would be something like:
SELECT * FROM table WHERE ownerId=1 SORT BY date GROUP BY typeId LIMIT 10 OFFSET 300
I currently have the following query (using pymongo) but it is giving my errors for using $sort, $limit and $skip:
search_dict['ownerId'] = 1
search_dict['$sort'] = {'date': -1}
search_dict['$limit'] = 10
search_dict['$skip'] = 200
collectionName.group(['typeId'], search_dict, {'list': []}, 'function(obj, prev) {prev.list.push(obj)}')
-
I have also tried the aggregation route but as I understand grouping will touch all the items in the collection, group them, and then limit and skip. This will be too computationally expensive and slow. I need an iterative grouping algorithm.
search_dict = {'ownerId':1}
collectionName.aggregate([
{
'$match': search_dict
},
{
'$sort': {'date': -1}
},
{
'$group': {'_id': "$typeId"}
},
{
'$skip': skip
},
{
'$limit': 10
}
])
Your aggregation looks correct. You need to include the fields you want in the output in the $group stage using $first.
grouping will touch all the items in the collection, group them, and then limit and skip. This will be too computationally expensive and slow.
It won't touch all items in the collection. If the match + sort is indexed ({ "ownerId" : 1, "date" : -1 }), the index will be used for the match + sort, and the group will only process the documents that are the result of the match.
The constraint is hardly ever cpu, except in cases of unindexed sort. It's usually disk I/O.
I need an iterative grouping algorithm.
What precisely do you mean by "iterative grouping"? The grouping is iterative, as it iterates over the result of the previous stage and checks which group each document belongs to!
I am not to sure how you get the idea that this operation should be computational expensive. This isn't really true for most SQL databases, and it surely isn't for MongoDB. All you need is to create an index over your sort criterium.
Here is how to prove it:
Open up a mongo shell and have this executed.
var bulk = db.speed.initializeOrderedBulkOp()
for ( var i = 1; i <= 100000; i++ ){
bulk.insert({field1:i,field2:i*i,date:new ISODate()});
if((i%100) == 0){print(i)}
}
bulk.execute();
The bulk execution may take some seconds. Next, we create a helper function:
Array.prototype.avg = function() {
var av = 0;
var cnt = 0;
var len = this.length;
for (var i = 0; i < len; i++) {
var e = +this[i];
if(!e && this[i] !== 0 && this[i] !== '0') e--;
if (this[i] == e) {av += e; cnt++;}
}
return av/cnt;
}
The troupe is ready, the stage is set:
var times = new Array();
for( var i = 0; i < 10000; i++){
var start = new Date();
db.speed.find().sort({date:-1}).skip(Math.random()*100000).limit(10);
times.push(new Date() - start);
}
print(times.avg() + " msecs");
The output is in msecs. This is the output of 5 runs for comparison:
0.1697 msecs
0.1441 msecs
0.1397 msecs
0.1682 msecs
0.1843 msecs
The test server runs inside a docker image which in turn runs inside a VM (boot2docker) on my 2,13 GHz Intel Core 2 Duo with 4GB of RAM, running OSX 10.10.2, a lot of Safari windows, iTunes, Mail, Spotify and Eclipse additionally. Not quite a production system. And that collection does not even have an index on the date field. With the index, the averages of 5 runs look like this:
0.1399 msecs
0.1431 msecs
0.1339 msecs
0.1441 msecs
0.1767 msecs
qed, hth.

In mongoDB can I efficiently group documents into groups of a set size?

I need to group data into subgroups of a set size. Like if there are 6 records, ordered by date.
[1,2,3,4,5,6]
and I have a subgroup size of 2. I would end up with an array(length of 3) of arrays(each length 2):
[[1,2],[3,4],[5,6]]
Nothing about the record factors into the grouping, just how they are ordered over all and the subgroup size.
Does the aggregation framework have something that would help with this?
The best way to currently do this is with mapReduce:
db.collection.mapReduce(
function() {
var result = [];
var x = 0;
for ( x=0; x < Math.floor( this.array.length / 2 ); x+2 ) {
result.push( this.array.slice( x, x+2 ) );
}
var diff = Math.ceil( this.array.length )
- Math.floor( this.array.length );
if ( diff != 1 )
result.push( this.array.slice( x, x+diff ) );
emit( this._id, result );
},
function(){},
{
"out": { "inline": 1 }
}
);
Or basically something along those lines.
The aggregation framework does not do slice type operations well, but JavaScript processes do, especially in this case.

How to implement a List as a value in Mongo DB

My requirement is to store a list of (Location ID + BITMAP) for each client. Example row is as follows:
Key: Client ID
Value: < (Location 1, Bitmap 1), (Location 2, Bitmap 2), ... , (Location N, Bitmap N) >
where
'Bitmap k' contains the history of which dates a client visited that location k.
The number of elements in Value could be varying from Client to Client, it could be 0 for some, could be 100 for some. I'd like to know how should this data be stored in MongoDB such that the following operations could be efficient:
Reset a particular BIT in all the Value pairs for all the rows
Update a particular BIT for some of the Value pairs for a row
An example for query 2 is as follows:
ROW KEY: Client A
ROW VALUE: < (Loc 1, BITWISE 1), (Loc 2, BITMASK 2), (Loc 3, BITMASK 3) >
Query: Update Row with Key = 'Client A' set BIT # 8 for Loc IN (Loc 1, Loc 3)
Ultimately, I'd like to run a map-reduce query which should be able to iterate on each of the row value pairs.
What about something like this ?
{
"_id" : ObjectId("51da846d9c34549b45432871"),
"client_id" : "client_a",
"values" : [
{
"location" : "loc_1",
"bitmap" : [
"000...",
"111..."
]
}
]
}
db.collection.find( { client_id: 'client_a', 'values.location': 'loc_1' } )