Flot graph shifting upwards when trying to hide the second axis ticks - javascript

I am currently working on some flot graphs that display single and multiple sets of data relating to time. Below is an example image of a single set of data on the graph.
Single data set
A date time picker allows a user to compare two time ranges where the second data set draws over the initial set. The issue I'm having is that when the second dataset is drawn over the first the whole graph shifts upwards revealing a large white space where the hidden ticks should be, see the example image below.
Multiple dataset
As you can see the data sets are different time ranges therefore can't be on the same axis as they are a comparison. Here's my options for the axes.
xaxes: [{
tickColor: "#fff",
mode: "time",
timeformat: timeFormat,
minTickSize: tickSize,
font: {
style: "normal",
color: "#666666"
},
axisLabel: xLabel,
axisLabelUseCanvas: true,
axisLabelFontSizePixels: 11,
axisLabelColour: "#666666",
axisLabelFontFamily: 'Open Sans',
axisLabelPadding: 20
},
{
ticks: [],
mode: "time",
timeFormat: timeFormat
}],
applying the option show: false on the second xaxis removes the shifting completely however because it is false my tooltips for the graph points are also removed.
I m using flot.time, flot.tooltip and flot.axislabels if needed to know.
This is my first question so any feedback would be great :)

My example on JSFiddle.
It all comes down to 2 main changes. Assign your compare graph data to second x-axis:
var dataSet = [{
data: [
[1467669600000, 12],
[1467709200000, 14]
],
label: 'data1',
xaxis: 1
}, {
data: [
[1467583200000, 15],
[1467622800000, 13],
[1467662400000, 16]
],
label: 'data2',
xaxis: 2
}];
For aesthetics, you should hide the second x-axis, so it won't mirror the same hours (set show: false)
{
"show": false,
"mode": "time",
"timeformat": "%H:%M",
"tickSize": [2, "hour"],
"min": 1467583200000,
"max": 1467666000000,
"timezone": "browser"
}

Related

flot xaxis ticks for stacked horizontal bar chart scale

I am working with a sample here:
var startDate = new Date(Date.UTC(2016, 6, 28, 0, 0, 0, 0));
var endDate = new Date(Date.UTC(2016, 6, 28, 0, 0, 0, 0));
endDate.setHours(startDate.getHours() + 9);
var dataSet = [{"data":[[1469664000000,0]],"color":"#FF0700"},
{"data":[[1469667600000,0]],"color":"#FF0700"},
{"data":[[1469671200000,0]],"color":"#FF0700"},
{"data":[[1469674800000,0]],"color":"#FF0700"},
{"data":[[1469678400000,0]],"color":"#FF0700"},
{"data":[[1469682000000,0]],"color":"#FF0700"},
{"data":[[1469685600000,0]],"color":"#FF0700"},
{"data":[[1469689200000,0]],"color":"#FF7400"},
{"data":[[1469692800000,0]],"color":"#006900"}];
var options = {
series: {
stack: true,
bars: {
show: true
}
},
bars: {
lineWidth: 0,
align: "center",
barWidth: 1,
horizontal: true,
fill: 1,
},
yaxis: {
axisLabel: "MachineName",
axisLabelUseCanvas: true,
axisLabelFontSizePixels: 12,
axisLabelFontFamily: 'Verdana, Arial',
axisLabelPadding: 3,
ticks: []
},
xaxis: {
axisLabelUseCanvas: true,
axisLabelFontSizePixels: 12,
axisLabelFontFamily: 'Verdana, Arial',
axisLabelPadding: 3,
//ticks: [[0, "1:00"], [1, "2:00"], [2, "3:00"], [3, "4:00"], [4, "5:00"], [5, "6:00"], [6, "7:00"], [7, "8:00"], [8, "9:00"]],
//labelWidth: 10,
//tickLength: 10,
//tickFormatter: formatXAxis,
//tickSize: 360000,
//minTickSize: 1,
//min: 0,
//max: 10
//mode: "time",
//timeformat: "%H:%M",
//minTickSize: [1, "hour"],
////color: "black",
//min: startDate.getTime(),
//max: endDate.getTime()
}
};
$.plot($("#machineStatus"), dataset, options);
I end up with a graph where the xaxis labels are not anything like they should be. See below
The design is an hourly status of a machine (red = not running, green = running, etc.) So the intent was to have the last 9 hours of runtime showing and put x axis labels for the top of the hour (1:00, 2:00, etc.).
Since this is a horizontal stack of multiple data sets, this appears to really confuse the xaxis tick calculation. I tried setting the min/max to equal the start and end times of the dataset, but I would get no graph.
I stopped using the "time" mode, hoping I could use the ticks array and force a set of ticks and labels, but that doesn't work. I tried the tickFormatter to force calculating the ticks, but that didn't work either.
You can see all the things I've tried on the xaxis and have commented out. I actually don't want the ticks to have any relationship to the actual data. I am testing this graph at the hour and minute level, so theoretically my data sets are either 9 or 540 bits of granular information. I still want the xaxis ticks to stay at a fixed set of 9 values spread evenly. Any ideas how I can do that?
FYI, I apologize for no jsfiddle. I've never been able to get one to work.
Update. Selected answer works! Here's a screenshot of a 540 datapoint to the minute level. The dataset is too big to post. Thanks again Raidri
I got it to work with time mode and a vertical bar chart:
Relevant options:
series: {
stack: true,
bars: {
lineWidth: 0,
align: "left",
barWidth: 3600000,
//horizontal: true,
fill: 1,
show: true,
}
},
...
xaxis: {
min: startDate.valueOf(),
max: endDate.valueOf(),
mode: "time",
timeformat: "%H:%M",
...
Also the values for your datapoints are changed to 1 so the bars here have a height of one.
If you change it to minute values, you have to change the barWidth option accordingly.
See this fiddle for the full example.

AmCharts parseDates unexpected behavior and merges all bars from the chart

I'm using AmCharts to display a chart. It's a floating bar chart displaying sent out surveys to a user. The bars are representing the openFrom to openUntil time, the time window a user has to submit the survey. They're listed in a timeline. I want AmCharts to understand the x-axis has dates as datatype so I can leverage the date functions (relative spacing, showing change of year bold, scrolling in time etc)
The following data is used to plot the chart as seen in the screenshots:
[{
"survey":"Survey DEF",
"openFrom":"05-04-2016",
"openUntil":"04-05-2016",
"status":"Nog niet geopend.", // translates to Not opened yet
"color":"#ededed"
},{
"survey":"Survey DEF",
"openFrom":"01-01-2016",
"openUntil":"31-01-2016",
"status":"Nog niet geopend.",
"color":"#ededed"
},{
"survey":"Survey GHI",
"openFrom":"06-12-2015",
"openUntil":"31-12-2015",
"status":"Ingestuurd op 07-12-2015", // Translates to Submitted at 07-12-2015
"color":"#27ae60"
},{
"survey":"Survey ABC",
"openFrom":"01-12-2015",
"openUntil":"15-12-2015",
"status":"Geopend, nog geen reactie.", // Translates to Opened, not submitted yet
"color":"#e67e22"
},{
"survey":"Survey GHI",
"openFrom":"31-01-2015",
"openUntil":"05-05-2015",
"status":"Geen reactie ontvangen", // Translates to Not submitted
"color":"#c0392b"
}]
Using this code:
var chart = AmCharts.makeChart('chart-container', {
'type': 'serial',
'dataLoader': {
'url': urlToJSONFetchScript
},
'language': 'nl',
'categoryAxis': {
'position': 'right',
'axisAlpha': 0.2,
'gridAlpha': 0.05
},
'valueAxes': [{
'type': 'date',
'minimumDate': '31-01-2015',
'maximumDate': '04-05-2016',
'axisAlpha': 0.2,
'gridAlpha': 0.05
}],
'categoryField': 'survey',
'graphs': [{
'balloonText': '<div style="text-align: left"><strong>[[survey]]</strong><small><br/>[[openFrom]] - [[openUntil]]<br/>[[status]]</small></div>',
'type': 'column',
'dateFormat': 'DD-MM-YYYY',
'openField': 'openFrom',
'valueField': 'openUntil',
'colorField': 'color',
'lineColorField': 'color',
'fillAlphas': 0.65,
'lineAlpha': 0.95
}],
'rotate': true,
'dataDateFormat': 'DD-MM-YYYY'
});
It get's me this chart:
This all looks good, but I'd like to use parseDates zo the x-axis doesn't have string-labels, but relatively spreads the dates and also displaying year changes. When I add 'parseDates': true to categoryAxis the chart rotates and is rendered all wrong. I've been searching in the API documentation for a while but I can't find any solution. What am I missing?
Result with parseDates set to true in categoryAxis options:
If I understand you correctly, the issue is that you need to display all month labels, as well as the year on January.
For this, you will need to set boldPeriodBeginning: true as well as markPeriodChange: true to display year instead of January label.
To make the chart display all months, you'll also need to disable auto grid by setting autoGridCount: false, as well as set gridCount to some larger number, say 25.
Please note that this is all for Value Axis. Enabling parsing of dates for category axis does not make a lot of sense, since you have arbitrary categories,
like "Survey DEF".
'valueAxes': [ {
'type': 'date',
'minimumDate': '31-01-2015',
'maximumDate': '04-05-2016',
'autoGridCount': false,
'gridCount': 25,
'boldPeriodBeginning': true,
'markPeriodChange': true,
'axisAlpha': 0.2,
'gridAlpha': 0.05
} ]
Here's the live chart with the above changes.
As of V3.18 of JavaScript Charts, it is also possible to make the value axis scrollable. To enable that, use valueScrollbar property of the chart. I.e.:
"valueScrollbar": {
"oppositeAxis": false,
"offset": 50,
"scrollbarHeight": 10
}
It's an instance of ChartScrollbar, so you can use any properties available in this class.

How to stop Flot Charts from re-ordering my data?

I am using a line chart. I feed the data the following:
var scheduled = [[51,1700],[52, 1750],[1,1600],[2,1675]];
var actual = [[51,1320],[52, 1550],[1,1575],[2,1600]];
In the above the first number of each set is the week of the year and I am trying to show the last 4 months of data.
However, when the chart is drawn Flot charts re-sorts the data by the first value (lowest to highest) which creates all kinds of issues. Instead of 4 columns in the series there are now 52, and the lines are quite out of whack.
I don't see anything in the documentation that says this is supposed to happen, nor do I see anything that says I can prevent it. However, for the data to be meaningful, the data must not be re-ordered.
Is there a setting I'm unaware of that can stop this behavior?
Edit : Adding plot code
var plot = $.plot('#scheduled-actual-flot-line', [
{
label: 'Scheduled Hours',
data: scheduled,
lines: { show: true, lineWidth: 2, fill: true, fillColor: { colors: [{ opacity: 0.5 }, { opacity: 0.5 }] } },
points: { show: true, radius: 4 }
},
{
label: 'Actual Hours',
data: actual,
lines: { show: true, lineWidth: 2, fill: true, fillColor: { colors: [{ opacity: 0.5 }, { opacity: 0.5 }] } },
points: { show: true, radius: 4 }
}],
{
series: {
lines: { show: true },
points: { show: true },
shadowSize: 0 // Drawing is faster without shadows
},
colors: ['#afd2f0', '#177bbb'],
legend: {
show: true,
position: 'nw',
margin: [15, 0]
},
grid: {
borderWidth: 0,
hoverable: true,
clickable: true
},
yaxis: { ticks: 4, tickColor: '#eeeeee' },
xaxis: { ticks: 12, tickColor: '#ffffff' }
}
);
Flot takes the x values as numbers and displays / sorts them accordingly. If you don't want that, you can use the category mode (see this example and this fiddle with your data).
xaxis: {
//ticks: 12,
tickColor: '#ffffff',
mode: 'categories'
}
PS: 12 ticks are not possibly with your data, as there are only 4 datapoints defined.
That flot reads all data as numbers by default is described here in the documentation.
Flotr examples use a for loop to create random data, so the first index will always be sequential.
[[51,1700],[52, 1750],[1,1600],[2,1675]];
Your arrays show that flotr must be doing a sort on the array before painting the data sets as lines, bar-graphs or whatever.
I can only suggest you create a timestamp from the months and there's a time setting you can in flotr settings to format the dates as you want.
The other way is replace your anomalous data (months) with sequential indices:
var arr = [[51,1700],[52, 1750],[1,1600],[2,1675]];
for(var i=0; i<arr.length; i++) arr[1][0] = i;
Flot is doing exactly what it should do for a line chart (or any type of x-y graph). It's showing the last two points of your dataset on the left because 1 and 2 are indeed less than 51 and 52. I'm guessing that you're trying to show data that crosses a year boundary. You need to make the first two weeks of the second year later than the last two of the first. You could use actual dates instead of week numbers, in which case Flot would handle it fine. That would also give you more flexibility in labeling the x-axis. But as a quick fix, just add 52 to the second year's data, e.g.:
var scheduled = [[51,1700],[52, 1750],[53,1600],[54,1675]];
var actual = [[51,1320],[52, 1550],[53,1575],[54,1600]];

Time Graph in Flot issue?

I am trying to graph a month out in flot (per day) or possibly every other day, have a tick.
To get my time values, i am doing this:
$date = strtotime($rowData[0]); // 2013-01-01
$myData = json_encode(array($date*1000, 1234));
// I Then echo it out as an array into the javascript var.
For some reason, i can change the line: minTickSize: [1, day] to 2 (label every other tick i think) and nothing will change. Also, the time values are not showing up as well? What am i doing wrong?
Here is a JSFIDDLE
Here is an update with every two days...is there a rendering issue? Also, why is Oct 10, the only date shown? : JSFIDDLE UPDATE
Here is what i have as far as the javascript goes:
var myData = [[1380603600000,0],[1380690000000,0],[1380776400000,0],[1380862800000,0],[1380949200000,0],[1381035600000,0],[1381122000000,0],[1381208400000,0],[1381294800000,0],[1381381200000,0],[1381467600000,0],[1381554000000,0],[1381640400000,1],[1381726800000,0],[1381813200000,0],[1381899600000,0],[1381986000000,0],[1382072400000,0],[1382158800000,0],[1382245200000,0],[1382331600000,0],[1382418000000,0],[1382504400000,0],[1382590800000,0],[1382677200000,0],[1382763600000,0],[1382850000000,0],[1382936400000,0],[1383022800000,0],[1383109200000,0],[1383195600000,0]];
var plot = $.plot($(".subsChart"),
[ { data: myData, label: "myData"} ], {
series: {
lines: { show: true,
lineWidth: 2,
fill: true, fillColor: { colors: [ { opacity: 0.5 }, { opacity: 0.2 } ] }
},
points: { show: true,
lineWidth: 2
},
grow: { active: true,
steps: 30
},
shadowSize: 0
},
grid: { hoverable: true,
clickable: true,
tickColor: "#DDD",
borderWidth: 1,
borderColor: "#DDD"
},
colors: ["#FF0000"],
xaxis: {mode: "time", timeformat: "%b %m", ticks: myData, minTickSize: [5, "day"]},
yaxis: {ticks:3, tickDecimals: 0},
tooltip: true,
});
UPDATE
When i remove the ticks: myData option, the labels do show up, but all of them are on the same date? Also, none of the points even land on the dates.
As #Smokie suggested, you need to remove the ticks option. When you provide ticks, Flot skips any tick generation that it would normally do and uses what you provided instead, which in this case is invalid.
Once you do that, you'll notice that you have labels, but they all show Oct. 10. That's because your date format is %b (short month name) %m (month number). I'd guess that what you actually want is %b %d.
Note that you probably won't get a tick for every day because, depending on the size of your window, they wouldn't all fit. That's why minTickSize is a minimum rather than an exact value; Flot will ensure that at least one day (or however many you specify) separates the ticks, but may choose to spread them out further to ensure that they all fit.

How to stop zooming out in Flot bar chart?

I am using Flot to draw some bar charts. How do I configure the zoom so that when a user zooms out, the chart will look like the one at the top and not like the one at the bottom? In other words, I don't want the user to continue zooming out when all of the data for the chart is shown. I also want to restrict the chart from displaying anything below 0 on the X axis. See my code and pictures of the charts below:
<#macro barChart2 var formatFunction ticks="" optionLegend="{ show: false }">
var options = {
yaxis: {
tickFormatter: ${formatFunction}
},
series: {
stack: 0,
bars: {
show: true,
barWidth: 0.9,
align: "center"
}
},
grid : {
hoverable: true
},
xaxis: {
<#if "${ticks}" != "">
ticks: ${ticks}
</#if>
mode: "time",
timeformat: "%b %d, %H:%M %P"
},
pan : {
interactive: true
},
legend: ${optionLegend}
};
var plot${var} = $.plot($("#chart${var}"), data, options);
$("#zoomIn${var}").click(function(e) {
e.preventDefault();
plot${var}.zoom();
});
$("#zoomOut${var}").click(function(e) {
e.preventDefault();
plot${var}.zoomOut();
});
</#macro>
I suggest you take a look at the zoomRange and panRange parameters that you can set with the navigation plugin. You specify those for the axes like:
xaxis: { zoomRange: [0.1, 10], panRange: [-10, 10] },
yaxis: { zoomRange: [0.1, 10], panRange: [-10, 10] }
where zoomRange sets the limit for zooming. In this case, the difference between the min and max will never go below 0.1, and it will never exceed 10. panRange tells the content to stay in a certain range, so in this case, neither axis will pan below -10 or above 10.
I'm not sure how you do this with time series data, but try with javascript timestamps to begin with.

Categories