Get max and min values of a facet in Algolia - javascript

I'm trying to use the algolia javascript api to create a pretty simple page with some basic filters.
I'm also trying to implement a range slider similar to this one here made by algolia - https://community.algolia.com/instantsearch.js/
I need the min and max values because 'facets_stats' returns the min and max for the current query (but I need the absolute minimum and absolute maximum so I can keep them constant at the edges of the slider)
After digging through the code for that instantsearch widget, I see they are using the algoliasearch helper to get the values (I think) but after playing around with the helper for a bit, I wasn't able to get the values I needed.
I've almost completed my project so it would be a huge waste of time to rewrite it using those components but I can't seem to figure out how to get the min and max values for a facet.
Is there any simple way to get the maximum/minimum value for a numeric facet using a single api call?

What you can do is performing an initial empty (blank) query to retrieve the facets_stats and therefore the underlying min/max values for all the records.
index.search('' /* match all */, {facets: 'myfacet', hitsPerPage: 0}).then(function(content) {
console.log(content.facets_stats.myfacet.min, content.facets_stats.myfacet.max);
});
You could then save those values and setup your slider accordingly.

Related

Check Validity of Data Before Update Phase in D3.js

I have data which updates every 10 seconds and I would like to check that all the data is valid before progressing with updates. I am currently getting false data intermittently which occurs as a negative number in one of the values. If one of the objects has a negative value then I don't trust the whole set and don't want to update any elements.
Ideally I don't want to update some items and then bail once the incorrect value occurs, but rather, determine if the whole set is good before updating anything
I'm not sure how d3 can manage this but I've tried with this and it seems to work. But it doesn't seem particularly in keeping with the elegance of D3 so I think there's probably a correct and better way to do it. But maybe not?!
var dataValid = true;
abcItems.each(function (d, i) {
if (0 > dd.Number1 - dd.Number2) dataValid = false;
});
if (dataValid) {
abcItems.each(function (d, i) {
// updating elements here
});
} else {
console.log("negative value occurred");
}
Is there a better way to manage this through D3?
A little bit more context:
The data (JSON provided via a RESTful API) and visualisation (a bar chart) are updating every 10 seconds. The glitch in the API results in incorrect data once every hour or so at the most (sometimes it doesn't happen all day). The effect of the glitch is that the bars all change dramatically whereas the data should only change by ones or twos each iteration. In the next fetch of data 10 seconds later the data is fine and the visualisation comes right.
The data itself is always "well-formed" it's just that the values provided are incorrect. Therefore even during the glitch it is safe to bind the data to elements.
What I want to do, is skip the entire iteration and update phase if the data contains one of these negative values.
Perhaps also worth noting is that the items in the data are always the same, that is to say the only "enter" phase that occurs is on page load and there are no items that exit (though I do include these operations to capture any unexpected fluctuations in the data). The values for these items do change though.
Looking at your code it seams you already have bound the dataset to your DOM elements abcItems.each(...).
Why not bail out of the update function when the data is not valid.
d3.json("bar-tooltip.json", function(dataset) {
if (!dataset.every(d => d.Number2 <= d.Number1)) return;
// do the update of the graph
});
The example assumes you call d3.json() froma function that is called every update interval, but you can use a different update method.

Ember Computed Property Slow and Inconsistent

I have an app that displays videos and allows users to rate the videos. An average rating and the number of times the video has been rated are displayed beneath it. To calculate these I have added computed properties to each model. The average property relies on the sum and length computed properties.
/*global Ember */
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
url: DS.attr('string'),
ratings: DS.hasMany('userrating'),
users: DS.hasMany('user'),
rated: DS.attr('boolean'),
// maps through ratings objects and pulls out the rating property
// returns an array of integers that represent all of one videos ratings
numRatings: Ember.computed.mapBy('ratings', 'rating'),
// returns the sum of a videos ratings
sum: Ember.computed.sum('numRatings'),
// returns the number of ratings a video has
length: Ember.computed('numRatings', function () {
return this.get('numRatings').length;
}),
// returns true if the video has only been rated once
// this is used to determine if '1 user' or '2 users' etc.
// should be displayed
one: Ember.computed('length', function () {
if (this.get('length') === 1) {
return true;
}
}),
// returns the average rating of a video
avg: Ember.computed('length', 'sum', function () {
return Math.round(this.get('sum') / this.get('length'));
})
});
I have noticed that sometimes the sum is displayed in place of the average. This usually happens only for a second and then the average correctly displays, but every once in a while the average does not display. Today, all videos except for one were displaying correctly, but that one video was displaying ’33/5’ as the average rating.
Why is this happening?
Should I not build Ember computed properties to rely on each other?
Is this just a problem with the browser being slow? I am loading a bunch of videos and images.
I am pretty new to web development in general and this is my first Ember app.
Thanks!
It's difficult to really know where there may be performance issues without seeing your entire architecture, but I can see the following:
You have a relationship with userrating and user models associated with your video model
Both your sum and length computed properties are based off of another computed value, which itself is performing a map to pull out rating values out of ratings objects
You have another computed watching length, that is purely determining the plurality of the word "user" somewhere else in the code
Lastly, you have an avg computed that is watching those other two computed properties as well
Now, again, I can't really provide an exact answer why, but here are a few suggestions to (maybe) lighten to load on your model here.
Eliminate the one computed altogether. You can perform this calculation on the component/controller side if you really want to know if a single one is selected, but you can do something else like Ember.computed.equal('numRatings', 1)
length property can be eliminated in favour of this.get('numRatings.length')
Have avg watch just numRatings so that it will only recalculate if that particular number changes, because you already know that sum will update as well anyway, so might as well reduce the number of observed properties
That said, if it's still acting wonky, you may want to make sure the data found in userrating entries are correct. If it still feels slow or takes its time calculating, you can also try changing mapBy into a plain vanilla JS for loop, as those are significantly faster (albeit less readable) than using Array methods.
Good luck!
length: Ember.computed('numRatings', needs to be length: Ember.computed('numRatings.[]', -- you need to observe the length of the array, not the array itself (which will only raise a flag if the value changes as a whole)
you can also use the alias property -- Ember.computed.alias('numRatings.length')

Cesium large number of entity updates

I am working on a project dealing with sensor data. In my backend everything is stored in a database which is getting polled by a controller and converted into kml to display on the cesium globe. This poll happens every 5-10 seconds and contains around 4000-8000 objects (we store up to 1 minute worth of data so we are looking at somewhere like 20k - 50k points). Following this I have an update function which slowly fades the markers out which updates every 5 seconds.
To load the kml on the map I use the following function:
var dataSource = new Cesium.KmlDataSource();
dataSource.load('link').then(function(value);
viewer.dataSources.add(dataSource);
});
On the update color function I am iterating over all of the objects within the datasources entity collection and updating them like so (this is very inefficient):
var colorUpdate = Cesium.Color.fromAlpha(newColor, .4);
dataSource.entities.values[i].billboard.color = colorUpdate;
When I do and add or color update I see a large amount of lag and was curious if there was anything you would suggest to fix this? Generally I get a freeze up for a few seconds. After 60 seconds of the data being on the map it gets removed like so (just a different if case within the color update loop)
dataSource.entities.remove(dataSource.entities.values[i]);
Is there potentially a way to set a propertiy for an entire entity collection so when this collection becomes 30 seconds old it updates the color to a new one? It seems that I just need to find a way to set a property for the entire collection vs individual entities. Does anyone know how to do that or have a suggestion for something better?

JQDateRangeSlider change bounds issue

I'm working with the DateRangeSlider for the first time and I'm using it as a TimeSlider: FiddleJS
The problem is that when a button is pressed the min bounded value, or the max one, should change, but it doesn't do anything for min or broke the slider when pressing the button for max.
The default values are for January 1st:
var minDateStr = "2014-01-01T00:00:00Z";
var maxDateStr = "2014-01-01T23:59:00Z";
to display the hours:minutes for one day and the button bounded values are from January 5th:
min :new Date("2016-01-05T05:00:00Z")
Is there a way to change the min and max bounds properly to "2016-01-05T05:00:00Z" without changing the default values (January 1st)?
I'm not sure if the task you're trying to achieve is practical or is even possible.
According to the documentation, slider values can be changed by code only at initialization. It means that even if you set either min2 or max2 to either end to the bound, then the slider can't "jump" there to properly represent the area you've originally selected. This is not practical.
Moreover, in the documentation, I couldn't find any way to get the values at which the labels are "standing". Apparently, min2 and max2 are not modified but serve rather as regular and unmodified JS constants.
You can modify the bounds but if you desire to do so, you have to use HTML inputs for dates. It doesn't seem to be possible by defining new bounds with the selected range.

Adding dynamic mean to time series chart

I will try to explain my problem as much accurate as possible. I am looking for a javascript chart library filling the two following conditions:
From an ajax request retrieving time series,
display dynamically data when changing the time window.
such as it is perfectly done on highstocks: http://www.highcharts.com/stock/demo/basic-line
And
plot an horizontal line corresponding to the mean,
changing when the user update the time window on the chart.
Actually it is possible to display an horizontal line. But they are fixed on the whole data and do not change accordingly when the time window is modified:
http://www.highcharts.com/stock/demo/yaxis-plotlines
I am quite new to the topic and would like to know if it'sp ossible to modify Highstock classes to have such a result. Or maybe some other js libraries exists?
Using a combination of the answer here:
Highchart, get total of visible series data after setExtremes
And an example of dynamic average using all visible series that I made for a previous question, here:
http://jsfiddle.net/jlbriggs/gweuLegq/
I put together this example, using the afterSetExtremes event, like this:
xAxis : {
events:{
afterSetExtremes:function() {
var ext = this.getExtremes();
getAverage(this.chart, ext.min, ext.max, show, width, avgColor, dashStyle);
}
}
},
Working example here:
http://jsfiddle.net/jlbriggs/c93543yL/
The idea is:
1) capture the afterSetExtremes event
2) get the resulting axis min and max
3) loop through the series data
4) if a point is between the min and max, increment the count, and add the
point's y value to the sum
5) calculate the average accordingly, check for existence of average series, if exists, update, if not, add
It could as easily use a plot line that you add/remove as needed instead of a series, but I like having it as a series so that it has a legend entry.

Categories