PROBLEM STATEMENT
Hello Guys. I am new to Web Development. I am working on a project that involves showing uptime charts of certain websites for website monitoring. The kind of chart needed is as follows:
Uptime Chart
As we can see, it's a time series chart and in the same chart the successful calls to the site are in green and the unsuccessful ones are shown in red. My problem is I am unable to get this in the same chart. So can someone tell me what has to be done ?
I am currently using Chart.js for showing realtime charts on the webpage.
Methods Tried
Let's say my time series dummy dataset looks like this:
data: [
{ x: "2021-03-08 00:08:46", y: 1 },
{ x: "2021-03-08 00:38:46", y: 0 },
{ x: "2021-03-08 01:08:46", y: 1 },
{ x: "2021-03-08 01:38:46", y: 0 },
{ x: "2021-03-08 02:08:46", y: 1 },
{ x: "2021-03-08 02:38:46", y: 0 },
{ x: "2021-03-08 03:08:46", y: 1 },
{ x: "2021-03-08 03:38:46", y: 0 },
{ x: "2021-03-08 04:08:46", y: 1 },
{ x: "2021-03-08 04:38:46", y: 0 },
{ x: "2021-03-08 05:08:46", y: 1 },
{ x: "2021-03-08 05:38:46", y: 0 },
{ x: "2021-03-08 06:08:46", y: 1 },
{ x: "2021-03-08 06:38:46", y: 0 },
{ x: "2021-03-08 07:08:46", y: 1 },
{ x: "2021-03-08 07:38:46", y: 0 },
{ x: "2021-03-08 08:08:46", y: 1 },
{ x: "2021-03-08 08:38:46", y: 0 },
{ x: "2021-03-08 09:08:46", y: 1 },
{ x: "2021-03-08 09:38:46", y: 0 },
{ x: "2021-03-08 10:08:46", y: 1 },
{ x: "2021-03-08 10:38:46", y: 0 }
]
What I tried is separating the 1's and 0's and in the same chart showing the 1's in green and 0's in red having value as 1. My code from chart.js looks like this:
var ctx = document.getElementById("myChart");
ctx.height = 500;
ctx.width = 500;
var data = {
datasets: [
{
fill: true,
label: "Completed",
borderColor: "#4BB543",
backgroundColor: "#4BB543",
borderColor: "#4BB543",
data: [
{ x: "2021-03-08 00:08:46", y: 1 },
{ x: "2021-03-08 01:08:46", y: 1 },
{ x: "2021-03-08 02:08:46", y: 1 },
{ x: "2021-03-08 03:08:46", y: 1 },
{ x: "2021-03-08 04:08:46", y: 1 },
{ x: "2021-03-08 05:08:46", y: 1 },
{ x: "2021-03-08 06:08:46", y: 1 },
{ x: "2021-03-08 07:08:46", y: 1 },
{ x: "2021-03-08 08:08:46", y: 1 },
{ x: "2021-03-08 09:08:46", y: 1 },
{ x: "2021-03-08 10:08:46", y: 1 },
],
},
{
fill: true,
label: "Issues",
borderColor: dangerColor,
backgroundColor: "#FF0000",
borderColor: "#FF0000",
data: [
{ x: "2021-03-08 00:38:46", y: 1 },
{ x: "2021-03-08 01:38:46", y: 1 },
{ x: "2021-03-08 02:38:46", y: 1 },
{ x: "2021-03-08 03:38:46", y: 1 },
{ x: "2021-03-08 04:38:46", y: 1 },
{ x: "2021-03-08 05:38:46", y: 1 },
{ x: "2021-03-08 06:38:46", y: 1 },
{ x: "2021-03-08 07:38:46", y: 1 },
{ x: "2021-03-08 08:38:46", y: 1 },
{ x: "2021-03-08 09:38:46", y: 1 },
{ x: "2021-03-08 10:38:46", y: 1 },
],
},
],
};
var lineChart = new Chart(ctx, {
type: "line",
data: data,
options: {
scales: {
xAxes: [
{
type: "time",
time: {
unit: "hour",
},
display: true,
scaleLabel: {
display: true,
labelString: "Time",
},
ticks: {
major: {
fontStyle: "bold",
fontColor: "#FF0000",
},
},
},
],
yAxes: [
{
display: true,
scaleLabel: {
display: true,
labelString: "Response Time(s)",
},
ticks: {
beginAtZero: true,
},
},
],
},
maintainAspectRatio: false,
bezierCurve: false,
},
});
Here's how my output chart looks like:
Obtained Chart using the code
As we can see the green is overpowering the red. I tried with other shades of green but the results are still not good. Please take a look and let me know how can make the uptime chart as the one shown in the first image. Thanks.
Can be done using visavail.js library. From the description:
The Visavail.js chart allows a quick insight into which periods of time a time-dependent dataset covers. It is visually similar to a Gantt chart and allows easy identification of missing pieces and gaps in large datasets. Missing periods of data are marked in red while blocks of complete periods of data are marked in green. The user discovers dates that define start and end of such periods by tooltips, as shown in the picture below.
[...] The Visavail.js library takes single data points with dates and information about data availability as inputs, combines them into time blocks, and visualizes these blocks.
The dataset should be in the following format:
var dataset = [{
"measure": "Series", // name of the data series, will become y-axis label
"measure_description": "Description", // description of y-axis label, visible with mouse over
"interval_s": 1800, // time period in seconds a single data point is expected to cover (30 minutes in your example)
"data": [
["2021-03-08 00:08:46", 1],// data as arrays of period start data string and bit determining
["2021-03-08 00:38:46", 0],
["2021-03-08 01:08:46", 1],
["2021-03-08 01:38:46", 0],
["2021-03-08 02:08:46", 1],
["2021-03-08 02:38:46", 0],
["2021-03-08 03:08:46", 1],
["2021-03-08 03:38:46", 0],
["2021-03-08 04:08:46", 1],
["2021-03-08 04:38:46", 0],
["2021-03-08 05:08:46", 1],
["2021-03-08 05:38:46", 0],
["2021-03-08 06:08:46", 1],
["2021-03-08 06:38:46", 0],
["2021-03-08 07:08:46", 1],
["2021-03-08 07:38:46", 0],
["2021-03-08 08:08:46", 1],
["2021-03-08 08:38:46", 0],
["2021-03-08 09:08:46", 1],
["2021-03-08 09:38:46", 0],
["2021-03-08 10:08:46", 1],
["2021-03-08 10:38:46", 0]
]
}];
In the following links you can see several examples of how to use the library CodeSandbox Demo.
Related
I am using LightningChart JS and would like to implement a virtual measurement device, where I can click on point A and then drag to point B and obtain the x,y values of both point A and point B.
As far as I have looked into the event handlers they just return a mouse event with start and stop positions in terms of screen positions. Please, correct me if I'm wrong. Also please suggest an efficient way to do this.
Thanks in advance.
The mouse events return the mouse coordinates in the same coordinate space as normal JS mouse events. To get the click location in the series coordinate space, a couple of steps need to be taken.
First the mouse coordinates need to be converted to the engine coordinate space. The engine coordinate space is the canvas area with 0,0 on the bottom left of the canvas. This can be done with chart.engine.clientLocation2Engine(ev.clientX,ev.clientY). This returns the event coordinate in the engine coordinate space using the chart engine scale.
This needs to be then converted to the series coordinate. This can be done with translatePoint method. translatePoint can be used to convert points between two different scales. Scale in LightningChart JS is basically a coordinate space.
const m = chart.engine.clientLocation2Engine(ev.clientX, ev.clientY)
const translated = translatePoint(m, chart.engine.scale, lineSeries.scale)
Now the translated variable contains the click location in the series coordinate space.
See a full code snippet below where you can drag on the series area and when drag is stopped markers are placed to the start and end locations of the drag.
const {
lightningChart,
SolidLine,
SolidFill,
ColorRGBA,
AxisTickStrategies,
UIOrigins,
DataPatterns,
translatePoint,
ColorHEX
} = lcjs
const chart = lightningChart().ChartXY()
const diesel = [
{ x: 0, y: 1.52 },
{ x: 1, y: 1.52 },
{ x: 2, y: 1.52 },
{ x: 3, y: 1.58 },
{ x: 4, y: 2.00 },
{ x: 5, y: 2.00 },
{ x: 6, y: 2.00 },
{ x: 7, y: 2.00 },
{ x: 8, y: 2.26 },
{ x: 9, y: 1.90 },
{ x: 10, y: 1.90 },
{ x: 11, y: 1.90 },
{ x: 12, y: 1.90 },
{ x: 13, y: 1.60 },
{ x: 14, y: 1.60 },
{ x: 15, y: 1.60 },
{ x: 16, y: 1.00 },
{ x: 17, y: 1.00 },
{ x: 18, y: 1.00 },
{ x: 19, y: 1.74 },
{ x: 20, y: 1.47 },
{ x: 21, y: 1.47 },
{ x: 22, y: 1.47 },
{ x: 23, y: 1.74 },
{ x: 24, y: 1.74 },
{ x: 25, y: 1.74 },
{ x: 27, y: 1.5 },
{ x: 28, y: 1.5 },
{ x: 29, y: 1.5 }
]
const gasoline = [
{ x: 0, y: 1.35 },
{ x: 1, y: 1.35 },
{ x: 2, y: 1.35 },
{ x: 3, y: 1.35 },
{ x: 4, y: 1.90 },
{ x: 5, y: 1.90 },
{ x: 6, y: 1.90 },
{ x: 7, y: 1.92 },
{ x: 8, y: 1.50 },
{ x: 9, y: 1.50 },
{ x: 10, y: 1.3 },
{ x: 11, y: 1.3 },
{ x: 12, y: 1.3 },
{ x: 13, y: 1.3 },
{ x: 14, y: 1.3 },
{ x: 15, y: 1.32 },
{ x: 16, y: 1.40 },
{ x: 17, y: 1.44 },
{ x: 18, y: 1.02 },
{ x: 19, y: 1.02 },
{ x: 20, y: 1.02 },
{ x: 21, y: 1.02 },
{ x: 22, y: 1.02 },
{ x: 23, y: 1.02 },
{ x: 24, y: 1.02 },
{ x: 25, y: 1.02 },
{ x: 27, y: 1.30 },
{ x: 28, y: 1.30 },
{ x: 29, y: 1.30 }
]
const lineSeries = chart.addLineSeries({ dataPattern: DataPatterns.horizontalProgressive })
const lineSeries2 = chart.addLineSeries({ dataPattern: DataPatterns.horizontalProgressive })
lineSeries2.add(diesel.map((point) => ({ x: point.x, y: point.y })))
lineSeries.add(gasoline.map((point) => ({ x: point.x, y: point.y })))
const markerA = chart.addChartMarkerXY()
.setPointMarker((marker) => marker.setFillStyle((f => f.setColor(ColorHEX('#f00')))))
.setMouseInteractions(false)
const markerB = chart.addChartMarkerXY()
.setPointMarker((marker) => marker.setFillStyle((f => f.setColor(ColorHEX('#0f0')))))
.setMouseInteractions(false)
function getClickInSeriesScale(point, scale) {
const m = chart.engine.clientLocation2Engine(point.x, point.y)
return translatePoint(m, chart.engine.scale, scale)
}
chart.onSeriesBackgroundMouseDragStop((obj, ev, b, start) => {
let pointA = getClickInSeriesScale(start, lineSeries.scale)
let pointB = getClickInSeriesScale({x:ev.clientX,y:ev.clientY}, lineSeries.scale)
// move markes to start and end points
markerA.setPosition(pointA)
markerB.setPosition(pointB)
})
<script src="https://unpkg.com/#arction/lcjs#1.3.1/dist/lcjs.iife.js"></script>
I have a dataset like this:
const dataset = [
{ 'color': 'red', 'data': [{ x: 0, y: 600 }, { x: 2, y: 900 }, { x: 4, y: 650 }, { x: 6, y: 700 }, { x: 9, y: 600 }] },
{ 'color': 'blue', 'data': [{ x: 0, y: 400 }, { x: 2, y: 300 }, { x: 4, y: 450 }, { x: 6, y: 900 }, { x: 9, y: 400 }] },
{ 'color': 'yellow', 'data': [{ x: 0, y: 200 }, { x: 2, y: 100 }, { x: 4, y: 550 }, { x: 6, y: 600 }, { x: 9, y: 400 }] }
];
I want to find domain values for max and min x-axis. I try this code but it doesn't work:
.domain([d3.min(arrangedata, (array) => array.x), d3.max(arrangedata, (array) => array.x)])
I also tried d3.extend, but I couldn't handle it. Any idea ?
For using either d3.max/min or d3.extent, you have to merge the inner arrays, which you can do with Array.prototype.reduce. Then, specify the x property in the accessor.
All together, it's just this:
const extent = d3.extent(dataset.reduce((a, c) => a.concat(c.data), []), d => d.x);
Here is the demo:
const dataset = [{
'color': 'red',
'data': [{
x: 0,
y: 600
}, {
x: 2,
y: 900
}, {
x: 4,
y: 650
}, {
x: 6,
y: 700
}, {
x: 9,
y: 600
}]
},
{
'color': 'blue',
'data': [{
x: 0,
y: 400
}, {
x: 2,
y: 300
}, {
x: 4,
y: 450
}, {
x: 6,
y: 900
}, {
x: 9,
y: 400
}]
},
{
'color': 'yellow',
'data': [{
x: 0,
y: 200
}, {
x: 2,
y: 100
}, {
x: 4,
y: 550
}, {
x: 6,
y: 600
}, {
x: 9,
y: 400
}]
}
];
const extent = d3.extent(dataset.reduce((a, c) => a.concat(c.data), []), d => d.x);
console.log(extent)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
You can try applying Math. min/max to the mapped series data.
d3.minValue = function(dataset, field) {
return d3.min(dataset, series => Math.min.apply(Math, series.data.map(data => data[field])))
}
d3.maxValue = function(dataset, field) {
return d3.max(dataset, series => Math.max.apply(Math, series.data.map(data => data[field])))
}
const dataset = [{
'color': 'red',
'data': [{ x: 0, y: 600 }, { x: 2, y: 900 }, { x: 4, y: 650 }, { x: 6, y: 700 }, { x: 9, y: 600 }]
}, {
'color': 'blue',
'data': [{ x: 0, y: 400 }, { x: 2, y: 300 }, { x: 4, y: 450 }, { x: 6, y: 900 }, { x: 9, y: 400 }]
}, {
'color': 'yellow',
'data': [{ x: 0, y: 200 }, { x: 2, y: 100 }, { x: 4, y: 550 }, { x: 6, y: 600 }, { x: 9, y: 400 }]
}]
//let domain = d3.domain([ d3.minValue(dataset, 'x'), d3.maxValue(dataset, 'x') ])
console.log(d3.minValue(dataset, 'x'), d3.maxValue(dataset, 'x')) // 0, 9
console.log(d3.minValue(dataset, 'y'), d3.maxValue(dataset, 'y')) // 100, 900
.as-console-wrapper { top: 0; max-height: 100% !important; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
I have tried to show 2 series of data in Area chart | Highcharts. Its working fine but there is a whitespace between the series. How to remove the space?
Fiddle : http://jsfiddle.net/alagarrk/0jcg5047/1/
series: [{
name: 'Educated people',
data: [{
x: 0,
y: 20000
}, {
x: 1,
y: 19000
}, {
x: 2,
y: 19000
}, {
x: 3,
y: 18000
}, {
x: 4,
y: 17000
}, {
x: 5,
y: 16000
}, {
x: 6,
y: 15000
}, {
x: 7,
y: 14000
}]
}, {
name: 'Uneducated people',
data: [{
x: 8,
y: 13000
}, {
x: 9,
y: 12000
}, {
x: 10,
y: 11000
}, {
x: 11,
y: 10000
}]
}]
Please check and guide me to fix this issue
There is no "fixing" this issue, you don't have any data between point 7 and 8. What you can do is start series 2 (uneducated people) on point 7. That way it will look connected.
name: 'Uneducated people',
data: [{
x: 7,
y: 13000
}, {
x: 8,
y: 12000
...
Working example: http://jsfiddle.net/0jcg5047/2/
Is there a way to plot 2 graphs together with different Y axes?
I have some data (page views, stacked area by referrer) which I'd like to plot with an overlayed line graph of number of actions over time.
I already have both graphs separately, but just wondering if there's a way to combine them into 1.
You should be able to draw both graphs by passing in the element you're outputting to as the target for each. Are you using SVG for output? Can you post some of the code you're working with?
Sure.
Here's the simplest of examples.
var graph = new Rickshaw.Graph({
element: document.getElementById("chart"),
renderer: 'multi',
series: [{
name: 'one',
data: [{
x: 0,
y: Math.random()
}, {
x: 1,
y: Math.random()
}, {
x: 2,
y: Math.random()
}, {
x: 3,
y: Math.random()
}, {
x: 4,
y: Math.random()
}, {
x: 5,
y: Math.random()
}],
color: 'blue',
renderer: 'stack'
}, {
name: 'two',
data: [{
x: 0,
y: Math.random()
}, {
x: 1,
y: Math.random()
}, {
x: 2,
y: Math.random()
}, {
x: 3,
y: Math.random()
}, {
x: 4,
y: Math.random()
}, {
x: 5,
y: Math.random()
}],
renderer: 'line',
color: 'red'
}]
});
graph.render();
Is there a way to add title to the axis? Typically, it is useful to have the y-axis display units. For example: http://code.shutterstock.com/rickshaw/examples/y_axis.html has just numbers, but in any kind of plot you would need to specify: %, $, km/s, etc. How to do that?
Thank you!
var graph = new Rickshaw.Graph( {
element: document.getElementById("chart"),
renderer: 'line',
height: 300,
width: 800,
series: [
{
data: [ { x: 0, y: 120 }, { x: 1, y: 890 }, { x: 2, y: 38 }, { x: 3, y: 70 }, { x: 4, y: 32 } ],
color: "#c05020"
}, {
data: [ { x: 0, y: 80 }, { x: 1, y: 200 }, { x: 2, y: 100 }, { x: 3, y: 520 }, { x: 4, y: 133 } ],
color: "#30c020"
}, {
data: [ { x: 0, y: 200 }, { x: 1, y: 390 }, { x: 2, y: 1000 }, { x: 3, y: 200 }, { x: 4, y: 230 } ],
color: "#6060c0"
}
]
} );
var y_ticks = new Rickshaw.Graph.Axis.Y( {
graph: graph,
orientation: 'left',
tickFormat: Rickshaw.Fixtures.Number.formatKMBT,
element: document.getElementById('y_axis'),
} );
graph.render();