I am using Angular with highcharts boxplot API.
I know I could set the max value of y-axis in the chart config, something like this.
max: 100,
tickInterval: 10.
But now I need to change the max value by the return value.
For example, if the maximum return value is around 60%, then I should set the max to 60.
max:60,
tickInterval: 10.
Is there any way to add some method/function to fit the maximum return value?
For example:
max: funticon(){ xxxxx; return A},
tickInterval: 10
The above function is a method by myself to check the API maximum value.
After checking then return to the chart config to set the max.
Using chart.events.load you will be able to update and set these values for yAxis.max:
https://api.highcharts.com/highcharts/chart.events.load
https://api.highcharts.com/class-reference/Highcharts.Chart#update
Demo:
https://stackblitz.com/edit/highcharts-angular-basic-line-wtoktb
chart: {
events: {
load: function() {
const chart = this;
chart.update({
yAxis: {
max: (chart.yAxis[0] as any).dataMax
}
})
}
}
}
Related
I just started using Chart.js, and I have an issue.
First of all, what I need to display in my simple line chart is something like this:
This is my current chart, on the Y-axis I have possible grades (for student's exams), ranging from 1 to 6.
On the X-axis I have the possible Points that can be achieved in a given exam.
Now it gets more complicated, this chart is being updated based on the inputs and selection of a dropdown.
Grades (Y-axis) can be of 5 increment types: Integer, Halves, Quarters, Decimal and Hundredths
This is chosen with a dropdown, default value is Quarters, meaning with Quarters selected my Array of Numbers for the grades would look like:
grades = [1, 1.25, 1.50, 1.75, 2....., 5.75, 6]
meanwhile with Hundredths selected, it would look like:
grades = [1, 1.01, 1.02, 1.03, .... 5.97, 5.98, 5.99, 6]
And for each grade, a set amount of Points (X-axis) is needed to achieve it.
The points needed are calculated with a formula that I put in a function:
mySecretFormula(grades: Array<Number>) {
grades.forEach(g => {
const currentPoints = g * mySecretFormula;
this.points.push(currentPoints);
}
so basically I pass my Grades in this function, and it returns another Array of numbers with the same number of elements (as each grade corresponds to a score)
example, if I had selected Integer Grades, meaning my grade array looks like:
grades = [1, 2, 3, 4, 5, 6]
the return I would get for my scores would be:
scores = [0, 5, 10, 15, 25, 30]
if the max points were set to 30 (the max score is defined in an input)
Then finally I used chart.js to display my data like this:
this.canvas.data.labels = this.points;
this.canvas.data.datasets[0].data = this.grades;
this.canvas.update();
so everytime I change the dropdown regarding the increments of the grades, this function gets fired and updates the chart.
Let's say it's working, but it's far from optimal.
What I want to achieve is simple.
It should look like this:
This is what the Chart looks like when I select Integer grades, so only 6 different grades and 6 different scores.
I want the Chart to always look like this, no matter what increment is selected,
so always 5 or 6 grid lines and always the same tick points for the X-axis.
Then if the current increment selected is Integer, I'll have only 6 intersection, but if I were to swap to Decimal or Hundredths, so with a lot of intersections, the chart looks exactly like this, BUT when you hover on the line with the mouse, I'll get the tooltip for each valid intersection.
Now if I swap to Decimal increments, my Chart updates into this:
(ignore the rounding, forgot to round them to 2 decimals)
so as you see the tickpoints change, the grid width changes, and the height of the whole chart changes.
But the intersections work correctly, if I hover the mouse along the line, I ll get a tooltip for each point for these pairs:
decimal increments equal to:
grades = [1, 1.1, 1.2, 1.3, 1.4, .... 5.9, 6]
points = [0, 0.7, 1.4, 2.1, 2.8, .... 34.3, 35]
so to achieve this same result, BUT with the chart that is always the same, always the same tick points and height and width, because the range of the grades and the scores will always be the same, but depending on the increment chosen, there could be from a minimum of 6 intersection (integer) to over 500 intersections (hundredths)!
Hope I made myself clear, thank you very much
Edit: managed with your help to add a custom tooltip on 2 lines with this:
afterBody: function([tooltipItem], data): any {
const multistringText = ["Points: " + tooltipItem.xLabel];
multistringText.push("Grade: " + tooltipItem.yLabel);
return multistringText;
}
works perfectly, but how can I now remove the original tooltip string above it? look the image, above my 2 lines custom tooltip I have another line that I want to hide!
And finally, always looking at this image, how can I make the grid lines on the X-axis of the same width? as you can see the first 4 are bigger than the last! I want them to be always the same width! thank you
I advise to convert your chart to xy chart, set axis options and customize tooltips
var ctx = document.getElementById("myChart").getContext('2d');
var precision = 0;
var data = getData();
var myChart = new Chart(ctx, {
type:"scatter",
data: {
datasets: [{
label: 'grades',
data: data,
fill: false,
pointRadius: 0,
pointHitRadius: 3
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true,
max:6
}
}],
xAxes: [{
ticks: {
beginAtZero:true,
max:35,
stepSize: 1,
callback: function(value){
if (value < 5){
return value;
} else {
if (value% 5 === 0){
return value;
}
}
}
}
}]
},
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
var label = [
'X: ' + tooltipItem.xLabel.toFixed(precision),
'Y: ' + tooltipItem.yLabel.toFixed(precision)
];
return label;
}
}
}
}
});
function getData(){
var step = 10**-precision;
var arr = [];
for (var i=0; i<=6; i+=step){
arr.push({y: i, x: 35*i/6})
}
return arr;
}
setTimeout(function(){
precision = 1;
myChart.data.datasets[0].data = getData();
myChart.update();
}, 2000)
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.js"></script>
<canvas id="myChart" width="100" height="100"></canvas>
I'm trying to set max value axis using dataprovider, since I'm dynamically loading data in my bar chart I need to see the "progress" on one of the bars compared to the one that is supposed to be the total.
How do I achieve this?
I' tried with:
"valueAxes": [
{
"id": "ValueAxis-1",
"stackType": "regular",
"maximum": myDataProviderAttribute
}
But no luck.
Any suggestion will be much apreciated.
I've submited a ticket to AmCharts support and got this feedback:
You can set max before the chart is initialized based on the data you have, inside addInitHandler. Here is an example for a simple column chart:
AmCharts.addInitHandler(function(chart) {
// find data maximum:
var min = chart.dataProvider[0].visits;
for (var i in chart.dataProvider) {
if (chart.dataProvider[i].visits > max) {
max = chart.dataProvider[i].visits;
}
}
// set axes max based on value above:
chart.valueAxes[0].maximum = max + 100;
chart.valueAxes[0].strictMinMax = true;
});
You may need to use strictMinMax as above to enforce the value:
https://docs.amcharts.com/3/javascriptcharts/ValueAxis#strictMinMax
Example of setting minimum inside addInitHandler:
https://codepen.io/team/amcharts/pen/b4be8cb4e3c073909860720e0909a876?editors=1010
If you refresh the data, or use live data, then before you animate or validate the chart to show the updated data, you should recalculate the max and, if you want the axis to change then use chart.valueAxes[0].maximum = max; where max is something you calculate based on data input.
Here is an example:
function loop() {
var data = generateChartData();
chart.valueAxes[0].maximum = max;
// refresh data:
chart.animateData(data, {
duration: 1000,
complete: function () {
setTimeout(loop, 2000);
}
});
}
The lines above were used in this example:
https://codepen.io/team/amcharts/pen/d0d5d03cfdcc2cc256e28ec52ad8b95c/?editors=1010
I'm trying to graph out metrics that don't have any relation to one another, so instead of plotting out the actual values, I've calculated an alternate set of values that are scaled between 0-1 like a percentage.
For example: [1, 2, 5] => [0.2, 0.4, 1]
So now I have 2 sets of data - the original and scaled versions. I have the scaled version plotting on to my graph just fine, but I want the tooltip to show the original value to the user. See what I mean?
I checked out http://c3js.org/samples/tooltip_format.html, which shows you can set tooltip as a function when you initially generate the C3 object. But I want to change the tooltip later on after I recalculate my original/scaled values and re-load() the graph.
All attempts I've made to explicitly change myGraph.tooltip.format.value = function (...) {...} after initially setting myGraph = C3.generate({...}) have been unsuccessful.
Any ideas how I can accomplish this without having to regenerate the graph from scratch every time?
You need to override internal.getTooltipContent
var data = ['data1', 30000, 20000, 10000, 40000, 15000, 250000];
// simple fake data
var fakeData = data.map(function (d, i) {
return i ? (d / 100) : d;
})
var chart = c3.generate({
data: {
columns: [
fakeData,
['data2', 100, 200, 100, 40, 150, 250]
],
}
});
// do code to take over mars and plant potatoes
// save the original
var originalGetTooltipContent = chart.internal.getTooltipContent;
chart.internal.getTooltipContent = function (data, defaultTitleFormat, defaultValueFormat, color) {
// we modified the first series, so let's change that alone back
var originalValue = {
id: data[0].id,
index: data[0].index,
name: data[0].name,
// unfaked
value: data[0].value * 100,
x: data[0].x
};
var originalValues = data.map(function (d, i) {
return i ? d : originalValue;
})
return originalGetTooltipContent.call(this, originalValues, defaultTitleFormat, defaultValueFormat, color)
}
I assume you are already doing something about the scaled y axis label?
Fiddle - http://jsfiddle.net/puf248en/
Thanks potatopeelings,
I did turn out solving this one by simply loading the form data in all at once, and then programmatically show/hide certain metrics. So that allowed me to use all the generate() options as intended.
Did try out your solution, and it seemed to do the trick till I found the simpler option. Thanks!
I want to plot a graph with the following as the xaxis:
var xaxis = [31.1,31.2,31.3,31.4,31.5, 32.1,32.2,32.3,32.4,32.5];
notice how there is a skip between 31.5 and 32.1. However, when I plot my line graph, there is a large space between these two points. Here's my code:
$(document).ready(function(){
var cust1 = [[31.1,10],[31.2,15],[31.3,25],[31.4, 60],[31.5,95]];
var cust2 = [[31.1,0],[31.2,15],[31.3,30],[31.4, 50],[31.5,85]];
var data = [];
data.push(cust1);
data.push(cust2);
var xaxis = [31.1,31.2,31.3,31.4,31.5, 32.1,32.2,32.3,32.4,32.5];
var plot3 = $.jqplot('line-chart', data,
{
title:'Design Progress',
axes: {
xaxis: {
//renderer: $.jqplot.LineRenderer,
label: 'Work Weeks',
ticks: xaxis
},
yaxis: {
label: "Percent Complete",
max: 100,
min: 0
}
}
}
);
});
I think it's because I'm not specifying a renderer option in my xaxis options. However, I've tried to use $.jqplot.LineRenderer and $.jqplot.CategoryAxisRenderer without any luck (I even set my xaxis values as strings but that didn't work). Anybody know what's going on?
Here's a pic to further clarify:
Reason why it happens : jQuery flot library is building the graph with values that determined by your data.
When you provide such data, the plugin will set the axis values to be as same as the text and with the borders of the numbers you gave.
what you can do, is set the text to be different than the axis value.
You can easily do it by options.xaxis.ticks.push([value, "the text"]).
Pay attention that you are the one who is going to set which label will have which axis value, and this calls for setting the options parameter before calling the $plot
I have one long unixtime, value Array which is used to initiate a flot chart, and some buttons to change the scale, what I can't seem to be able to do is get Y-axis to scale with the change in X-scale.
Here is an example chart:
http://jsfiddle.net/U53vz/
var datarows = //Data Array Here
var options = { series: { lines: { show: true }, points: { show: true } },
grid: { hoverable: true,clickable: false, },
xaxis: { mode: "time", min: ((new Date().getTime()) - 30*24*60*60*1000), max: new Date().getTime(), }
};
function castPlot() {
window.PLOT = $.plot("#placeholder", [{ data: dataRows }], options
);
};
In the official example scaling is automatic and unspecified on the Y-axis:
http://www.flotcharts.org/flot/examples/axes-time/index.html
The only alternative I can think of is looping through the dataset and calculating new Y min/max on each button press. Unless I am breaking some very obvious default function.
When calculating y-scale, flot does not look at only the "viewable" data but the whole dataset. Since the data points are still present, the y min/max respects them. So your options are:
Subset the series data down to the desired range and let flot scale both x and y.
As you suggested, calculate your own min/max on the y axis.
If you plot get any more complicated than it is now (especially if you start setting up click/hover events on it), I would also recommend you switch to redrawing instead of reiniting your plot.
var opts = somePlot.getOptions();
opts.xaxes[0].min = newXMin;
opts.xaxes[0].max = newXMax;
opts.yaxes[0].min = newYMin;
opts.yaxes[0].max = newYMax;
somePlot.setupGrid();
somePlot.draw();
EDITS
Here's one possible solution.