Is it possible to make echarts line chart with 1 line painted in different colors? For example if value <= 0 the color is red, if > 0 the color is green?
Echarts has an option called visualMap that does exactly what you are looking for.
visualMap doc
visualMap code example (I selected the example that fits best, but there are others)
In your case you'll have something like that :
visualMap: {
show: false, // Wether to show the legend or not (default: true)
pieces: [
{
min: -9999, // Normally not needed but doesn't work without that (1)
max: 0,
color: '#F35E07' // Red
},
{
min: 0,
color: '#93CE07' // Green
},
],
outOfRange: {
color: '#F35E07'
}
},
It'll split your line in 2 pieces :
below 0 (written max: 0) : red
above 0 (written min: 0) : green
In addition, the visualMap option has more to offer : you can have more than 2 pieces (like in this example), have a smooth gradient instead of pieces (using type: 'continuous' like in this example), and many other things that are explained in its doc.
(1) Note about the bug: Normally if you don't specify min or max,
it's set to -Infinity or Infinity. But here you have to specify
min AND max in one of the two pieces (I don't know why).
If you consider plotting two charts and ignoring some of its points with '-', you can achieve the same visual result of a multicolored line chart.
Although the documentation does not provide an immediate example of how to color specific segments of a line chart, it actually instructs about how you can use empty data,
While there are empty elements, the lines chart will ignore that point without passing through it----empty elements will not be connected by the points next. In ECharts, we use '-' to represent null data, It is applicable for data in other series.
With that in mind, by overlaying two equal charts and emptying some points, you can actually construct the logic of a multicolored chart. Notice that it is better if you can do it programmatically so that you can vary the number of line segments to be colored.
var chartDom = document.getElementById('main');
var myChart = echarts.init(chartDom);
var option;
option = {
xAxis: {},
yAxis: {},
series: [
{
data: [
[-20, -20],
[-10, 30],
[0, 40],
['-', '-'],
['-', '-']
],
type: 'line',
lineStyle: {
color: "red"
}
},
{
data: [
['-', '-'],
['-', '-'],
[0, 40],
[10, 100],
[20, 60]
],
type: 'line',
lineStyle: {
color: "green"
}
}
]
};
option && myChart.setOption(option);
.as-console-wrapper { max-heght: 100% !important }
<script src="https://cdn.jsdelivr.net/npm/echarts#5.3.2/dist/echarts.js"></script>
<body>
<div id="main" style="width: 225px;height:225px;"></div>
</body>
Related
I'm trying to create a chart that looks like this using ChartJS, D3.js, NVD3 or c3.js but I'm having trouble. Is this even possible with any of these libraries?
You can use C3.js bar charts and hide some of the x-axis but that may require extra JS to do so unless you make the x axis label ' '. If you want all the bars the same colour you'll need to use CSS (unless you declare a pattern). It will not be generated to look identical to that in C3.js without extra manipulation of the code.
You can edit data around on https://c3js.org/samples/chart_bar.html to see how your data would look if you would like to.
You can add
color: {
pattern: ['#0e9999','#06754b','#eb7a02','#9734b0']
},
To your generation of the chart with whatever pattern of colours you would like (you can have as many or as few colours as you would like. I just happened to need 4 for my code)
In your case you can do
color: {
pattern: ['#FFA500']
},
In data you can declare an 'x' to have your supplied x labels
data: {
x: 'x',
columns: [your data goes here including x labels],
type: 'bar'
}
I'm not sure about the other libraries but C3.js is essentially a wrapper for D3.js so anything that can be done in one is most likely theoretically possible in both. C3.js is just easier to understand the code for. (see: https://c3js.org/)
Update:
If this wasn't clear enough you can do:
var chart = c3.generate({
data: {
x: 'x',
columns: [
['x', '1',' .','3','. ','. ','6'],
['data1', 30, 200, 100, 400, 150, 250],
['data2', 130, 100, 140, 200, 150, 50]
],
type: 'bar'
},
axis: {
x: {
type: 'category',
}},
color: {
pattern: ['#FFA500']
},
bar: {
space: 0.05, //sets the gap between the bars
width: {ratio:1}
},
grid: { //the lines (remove if you didn't want grid lines)
y: {
show: true
},
x: {
show: true
}
},
legend: { //hides the legends
show: false
}
});
To do something similar to what you have (you'll need to edit the data to be the exact data you want but that'll be a simple edit on your part)
If you don't want dashed grid lines add:
.c3 .c3-grid line {
stroke-dasharray: 0!important;
stroke: #808080 !important;
}
to your CSS file
I use recharts with React. I think it's the best charting library out there.
I am trying to make chart, sort of like a pie chart, but with each slice being the same size, and having a percentage of it filled.
Something like this.
My question is similar to this one: Pie chart with different fill percentage.
But it is 4 years old so I thought I would ask again.
I have tried using Canvasjs, Google charts, and highcharts but none of them support anything similar. I also want to have the slices functioning as buttons that can rotate the chart, having the selected one being positioned in the bottom.
You can achieve that result in Highcharts. Each slice should be a different series with different size. Each series should have points in the number of the series, all points should be invisible except the one - also, it is needed for disabling ignoreHiddenPoint so empty space will be drawn.
For example, you have an array of points ['20%', '30%'] - you need to map the points to series array:
[{
size: '20%',
keys: ['y', 'visible'],
data: [[1/2, true], [1/2, false]]
}, {
size: '30%',
keys: ['y', 'visible'],
data: [[1/2, false], [1/2, true]]
}]
You also might create an additional series which will be the background of the pie
const backgroundSeries = [{
size: '100%',
data: [{y: 1, color: 'rgba(0, 0, 0, 0.4)'}],
enableMouseTracking: false,
borderWidth: 0,
}];
For rotating the pie, you need to update startAngle property
chart.update({
plotOptions: {
pie: {
startAngle: startAngle
}
}
});
Live example and output
http://jsfiddle.net/1yjc4ogb/
I have a couple of pie/doughnut charts displayed using ChartJS. Usually, they contain data like [200, 1200, 300] and [30, 500] to give an estimate, but at rare occasions, they will contain [0, 0, 0] and [0, 0]. The problem then, is that the chart disappears, even though I have a border enabled. I have solved this by adding dummy values to the first element in the arrays, but I don't like how the code looks and want a better way.
Is it possible to make the border visible (a circle) when the array contains only zeroes?
Edit:
I don't seem to get any answers to this question. Is it considered a bug when the border is not showing on empty data or is this intended behavior? I don't know if anyone else has had this problem. I still need to find an elegant way to deal with this issue, and I haven't found one yet.
This is not a bug, as the borders are rendered per data item. If all the data is 0s, then every slice has no width, so no border can show (the only other way to handle this scenario for ChartJS would be to give each item equal sizing, which isn't better).
You can add a dummy value without a label and filter the legend and tooltips so that the data is treated like a blank space to the user. In the example below, a check before rendering the chart ensures that if all data points are 0, a data point with a value of 1 is added to the chart with no label. Two datasets are shown to highlight the difference.
let ctx = document.getElementById('chartContainer').getContext('2d');
let data = [[0, 0, 0], [1,2,3]];
let labels = ["A", "B", "C"];
let bgColors = ['yellow', 'orange', 'aquamarine'];
let options = {
borderWidth: 1,
borderColor: 'black',
legend: {
labels: {
// Prevent items with undefined labels from appearing in the legend
filter: (item) => item.text !== undefined
}
},
tooltips: {
// Prevent items with undefined labels from showing tooltips
filter: (item, chart) => chart.labels[item.index] !== undefined
}
}
let chartConfig = {
type: 'pie',
data: {
labels: labels,
datasets: [{
data: data[0],
backgroundColor: bgColors,
label: "data",
borderColor: 'black',
borderWidth: 2
}, {
data: data[1],
backgroundColor: bgColors,
label: "data",
borderColor: 'black',
borderWidth: 2
}]
},
options: options
}
// Check if data is all 0s; if it is, add dummy data to end with empty label
chartConfig.data.datasets.forEach(dataset => {
if (dataset.data.every(el => el === 0)) {
dataset.backgroundColor.push('rgba(255,255,255,0)');
dataset.data.push(1);
}
})
let pieChart = new Chart(ctx, chartConfig);
.chartContainer {
height: 200px;
width: 200px;
}
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0/dist/Chart.min.js"></script>
<div class="chartContainer">
<canvas id="chartContainer" width="200" height="200"></canvas>
</div>
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]];
I have tested the HighCharts heatmap (heatmap.js) charts. They work fine for me, but there is one situation where I would like to set the cell colors myself, individually - i.e. NOT using the colorAxis settings.
Is there an easy way to do that without messing with the colorAxis stops ? E.G. by setting the color directly in the data series ?
Arguably this defeats the idea of a real "heatmap" but would be the shortest route for me to address a specific requirement (instead of building a HTML table with colored cells).
"
Note finally this is not the same question as "how do you change the color of cells in highcharts heatmap?"
Yes, you can always set color directly in the point config, see: http://jsfiddle.net/c2WgP/
$('#container').highcharts({
chart: {
type: 'heatmap',
inverted: true
},
colorAxis: {
stops: [
[0, '#3060cf'],
[0.5, '#fffbbc'],
[0.9, '#c4463a']
],
min: -5
},
series: [{
data: [
[0, 0, -0.3],
[0, 1, 0.6],
[0, 2, 1.8], {
x: 0,
y: 3,
z: 0.5,
color: 'green'
}]
}]
});
Just an FYI, the above code works, but the linked fiddle is broken because of something in that linked version of Highcharts. If you make the small tweak of using the latest Highcharts.js, it worked for me:
Simply replace:
<script src="http://code.highcharts.com/3.0.10/highcharts.js"></script>
with
<script src="http://code.highcharts.com/highcharts.js"></script>
Seen here: http://jsfiddle.net/joelhnatow/bnL77dr8/