Calculating relative point coordinates for a graph? - javascript

I'm making a simple JavaScript graphing library using the canvas element. I really suck at math so I'm stuck with a simple issue.
If I have a number - for example 30000, and I want to plot it relatively to graph's height which is 400. How do I calculate the y value for that?

You would want to figure out your max for the graph. Say, in this case 50000. Then, take your height and divide it by the max (so 400/50000) to get a ratio multiplier. Any number you want to plot you multiply by that ratio and that should give you a number that fits on your space. Is that what you're asking for?

For that you need to first find out the maximum and minimum values that you need to plot. For example, in this list of (x,y) coordinates: [(1,3),(2,10),(3,0),(4,-10)], the max value is 10 and the min value is -10. This gives you a span of (max-min = 10-(-10) = ) 20.
Notice that you can now translate the set of y values into a number in the range [0,max-min] (i.e. [0,20] in this case). Here, a value of 0 will get plotted as a 0 in the graph and a value of 20 will get plotted as 400. Also, a value of 20/2 will be plotted as 400/2. Thus, a value of 20/x is plotted as 400/x. This means that any value can now be plotted as 400*value/20.
So, to translate a given value n to its corresponding y value on the graph, simply convert n to (n-min)*400/(max-min).

Related

Chart JS - Points and Tooltips Only at Specific Data Values

I am currently using chart.js to plot spectral data from a EMI receiver. There are over 16000 (x,y) data indexes within each dataset and therefore I have made it so only the lines show without any points.
I now have a list of a few certain (x,y) value pairs that I would like to put points/markers on and add tooltips for. Is there a way to add tooltips and/or points or markers to only certain (x,y) value pairs within each dataset?
Any help would be appreciated. I will update with any photos/code if needed as I currently do not have an attempt at a solution for this.
EDIT1:
As you can see, it is very difficult to select the maximum point of the peaks due to how many data points make up the chart. I want to select only the local maximums and display tooltips for those points.
options.elements.point has a prop called radius. Radius can take either a number or an array of numbers. A single number will determine the radius for all of the points in your chart but the array will be able to determine each element's radius. This way you are able to selectively determine each point's radius with full control.
A solution for your example might look like this:
const options = {
elements: {
radius: allPoints.map(point => {
const maxPoint = Math.max(allPoints)
// return radius 0 for every point that is not the max and radius 1 (or bigger if needed) for the maximum point
return point == maxPoint ? 1 : 0
})
}
}

Highcharts minimum value for area charts y-axis

I have 2 charts that use identical data, one line and one area.
If the data only has positive values, the area chart shows '0' as the minimum value
However, the line chart y axis starts with a negative value instead of 0, even though the data contains no negative values
Question: How can I have the line chart y-axis start at 0 but still maintain the ability to show negative values when the data has such values? (I tried using a combination of setting min + setExtremes after the chart is rendered, but the values are sometimes incorrect, but I would assume the solution is much simpler since the area chart can do this automatically).
There is no setting that will do this, currently.
There is a feature request to achieve this that has languished for some time, here:
http://highcharts.uservoice.com/forums/55896-highcharts-javascript-api/suggestions/1848953-extend-the-axis-max-property-to-act-like-css-mi
Right now, you have to check your data, and if there are no negative values, set the min to 0, if there are negative values, do nothing.
It works by default for the area chart, because the area type has an explicit min value of 0 by default, and ignores that min if there are negative values
I suppose another workaround would be to use an area series, but set the fillOpacity to 0 - thereby displaying only a line, but using the area's axis scaling settings.

Angular-nvd3: same distance between data on x scale

By default scale of x axis is calculated from values. This gives uneven distance between two adjasted points. Like for example if I have an array of values like [1,2,5], there will be different distance on x axis for point, and also x axis labels will contain some other values, like 1,2,3,4,5. In case on dates displayed on x axis there may be cases when two equal dates are printed, looks ugly.
Take a look at this plunker. If you maximize your browser window, you could see that x axis labels have duplicates (like 02/09/2015 is visible 2 times on my screen). Also the distance between point is different.
How can I:
Make so that no duplicate x axis labes are present?
Distance between points is equaly distributed based in graph's width (not scaled based on values)?
You can explicitly set tickValues() and specify what ticks you want to show.
Alternatively, ticks() is more flexible, but gives you less control.
(Search for "D3 duplicate dates". This one may be helpful for example).
The reason the dates are repeating is that they are in fact different (equally spaced) timestamps that occur on the same day, since the spacing is < 24 hours. If you want to label with distinct dates, you could select a specific time on each day for the tick to fall on.

D3: What does the scale do when passed an axis?

In d3, if you want to create an axis you might do something like this:
var xAxis = d3.svg.axis()
.scale(x)
where x is a scale function. I understand that the domain of x defines the start and ending values for the ticks. I'm having trouble understanding how the range of x changes the resulting axis. What does the domain map to in the context of an axis.
Think about what one must do to create a visual representation of any data set. You must convert each data point (e.g. 1 million dollars) into a point on the screen. If your data has a minimum value of $0 and maximum value of $1000000, you have a domain of 0 to 1000000. Now to represent your data on a computer screen you must convert each data point (e.g. $25) into a number of pixels. You could try a simple 1 to 1 linear conversion ($25 converts to 25 pixels on the screen), in which case your range would be the same as your domain = 0 to 1000000. But this would require a bloody big screen. More likely we have an idea of how large we want the graphic to appear on the screen, so we set our range accordingly (e.g. 0 to 600).
The d3 scale function converts each data point in your dataset into a corresponding value within your range. That enables it to be presented on the screen. The previous example is a simple conversion so the d3.scale() function is not doing much for you, but spend some time converting data points into a visual representation and you will quickly discover some situations where the scale function is doing a lot of work for you.
In the particular case of an axis, the scale function is doing exactly the same thing. It is doing the conversion (to pixels) for each 'tick' and placing them on the screen.

How do we change the tick values generated by a linear scale in a d3.js line plot?

I only had 5 values[1,2,3,4,5] as my y - coordinates in the d3.js line plot. But, I end up getting more values [0.5,1,1.5,2,2.5,3,3.5,4,4.5,5] Is there a way to edit the d3.js file or the html file inorder to plot the values as per my requirement?
The tick marks created by a d3 axis can be controlled in two ways:
Using axis.tickValues(arrayOfValues) you can explicitly set the values that you want to show up on the axis. The ticks are positioned by passing each value to the associated scale, so the values should be within your scale's domain. This works for any type of scale, including ordinal scales, so long as the values you give are appropriate to that scale.
Alternately, using axis.ticks(parameters) you can modify the way the scale calculates tick marks. The types of parameters you can use depends on the type of scale you're using -- the values you specify will be passed directly to the scale's .ticks() method, so check the documentation for each scale type. (Parameters will be ignored for ordinal scales, which don't have a ticks() method.)
For linear scales, the scale.ticks() method accepts a number as a parameter; the scale then generates approximately that many ticks, evenly spaced within the domain with round number values. If you do not specify a tick count, the default is to create approximately 10 ticks, which is why you were getting ticks on 0.5 intervals when your domain was from 0 to 5.
So how do you get the behaviour you want (no decimal tick values)?
Using .tickValues(), you would create an array of unique Y-values to be your ticks:
var yValues = data.map(function(d){return d.y;});
//array of all y-values
yValues = d3.set(yValues).values();
//use a d3.set to eliminate duplicate values
yAxis.tickValues( yValues );
Be aware that this approach will use the specified y values even if they aren't evenly spaced. That can be useful (some data visualization books suggest using this approach as an easy way of annotating your graph), but some people may think your graph looks messy or broken.
Using .ticks(), you would figure out the extent of your Y domain, and set the number of ticks so that you do not have more tick marks then you have integers available on your domain:
var yDomain = yScale.domain();
yAxis.ticks( Math.min(10, (yDomain[1] - yDomain[0]) );
This will create the default (approximately 10) ticks for wide domains, but will create one tick per integer value when the difference between the max and min of your domain is less than 10. (Although the tick count is usually approximate, the scale will always prefer integer values if that matches the tick count specified.)
Yes you can also try
yAxis.ticks(5).tickFormat(D3.numberFormat(",d"));
It does the trick of eliminating the decimal numbers, does not effect number of ticks
Here is a good resource for the format of the numbers using D3.

Categories