generate color from number - colors

There is a way for get color from a number? it's mathematically possible?
I have an array of positive number like this:
array(1, 2, 1000, 564, 30, 113) and I need a color (humanly distinguishable) for each of these. I can use PHP or JS for this purpose.
I need this because i'm using http://www.chartjs.org/ with dynamic values.
edit:
this is an example from chartjs documentation:
<canvas id="myChart" width="400" height="400"></canvas>
<script>
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});
</script>
In this example are defined 6 bars (red, blue, yellow, green, purple and orange)
In my case this bars are dynamically generated and I don't know how many bars I have to show.
How I can associate a color for each bar? (this color must be the same everytime page refresh)

Using a method from https://stackoverflow.com/a/2262117/2737978 you can convert an integer into an rgb value.
$("#slider1").on("input", function() {
var value = $(this).val();
var rgbColor = intToRGB(value);
$(".number").html(value);
$(".example").css('background-color', rgbColor);
});
var intToRGB = function(value) {
//credit to https://stackoverflow.com/a/2262117/2737978 for the idea of how to implement
var blue = Math.floor(value % 256);
var green = Math.floor(value / 256 % 256);
var red = Math.floor(value / 256 / 256 % 256);
return "rgb(" + red + "," + green + "," + blue + ")";
}
#slider1 {
width: 100%
}
.example {
width: 50px;
height: 50px;
margin 0 auto;
background-color: #000000;
transition: background-color 100ms ease-in;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="slider1" type="range" min="0" max="16777215" step="1" value="0" />
<div class="number">0</div>
<div class="example"></div>
You would just need to use the intToRGB function in your code. Perhaps though if your numbers are all between 1-1000 you might not see such a gradient so would need to adjust the values (either the 256 or adjust the value going in by a certain factor)
---UPDATE
and here is a live example using your graph and a large factor to give a nice range of colour. You would probably want to add some validation into this to ensure the data does not go above the max but here is a quick go.
Here the int to RGB function has been updated to take in a max value that you would like to represent the top colour. On this a scale can more easily be created to give more diversity between ints, depending on your max the colours will be different as they land on a different part of the overall scale of what can be represented.
var intToRGB = function(value, alpha, max) {
var valueAsPercentageOfMax = value / max;
// actual max is 16777215 but represnts white so we will take a max that is
// below this to avoid white
var MAX_RGB_INT = 16600000;
var valueFromMaxRgbInt = Math.floor(MAX_RGB_INT * valueAsPercentageOfMax);
//credit to https://stackoverflow.com/a/2262117/2737978 for the idea of how to implement
var blue = Math.floor(valueFromMaxRgbInt % 256);
var green = Math.floor(valueFromMaxRgbInt / 256 % 256);
var red = Math.floor(valueFromMaxRgbInt / 256 / 256 % 256);
return "rgba(" + red + "," + green + "," + blue + "," + alpha + ")";
}
var data = [12, 19, 3, 5, 2, 3];
var MAX = 19;
var backgroundColors = data.map(function(item) {
return intToRGB(item, 0.8, MAX);
});
var borderColors = data.map(function(item) {
return intToRGB(item, 1, MAX);
});
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: data,
backgroundColor: backgroundColors,
borderColor: borderColors,
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.6/Chart.bundle.js"></script>
<canvas id="myChart" width="400" height="400">
</canvas>

Related

Can highcharts heatmap zone pattenObjects respect colors applied by color axis?

I'm trying to meet a style requirement for highcharts heatmaps. Currently, we style 'incomplete' data with a highcharts pattern fill by applying zones to x axis.
the chart currently looks like this, with the pattern fill applied to the zones on the right:
jsfiddle heatmap with incomplete zones
config for color axis:
colorAxis: {
dataClasses: [
{to: 3.33325, name: "<3.3", color: "#FFC4FF"},
{from: 3.33325, to: 5, name: "3.3 to 5.0", color: "#FF70FF"},
{from: 5, to: 6.66675, name: "5.0 to 6.7", color: "#D500F9"},
{from: 6.66675, to: 8.33325, name: "6.7 to 8.3", color: "#550075"},
{from: 8.33325, name: ">8.3", color: "#330046"},
]
}
series:
series: {
data: {
[
{x: 0, y: 0, z: 1},
{x: 0, y: 1, z: 2},
{x: 0, y: 2, z: 3},
{x: 1, y: 0, z: 4},
{x: 1, y: 1, z: 5},
{x: 1, y: 2, z: 6},
{x: 2, y: 0, z: 7}
{x: 2, y: 1, z: 8}
{x: 2, y: 2, z: 9}
]
}
zones: [
{value: 2},
{
color: {
pattern:
{
backgroundColor: "#CCCCCC",
height: 45,
path: {
d: "M-1,1 l2,-2 M0,45 l45,-45 M44,46 l2,-2",
stroke: "#FFFFFF",
strokeWidth: 3
}
width: 45
}
}
}
]
}
Right now the pattern fill is gray for all of them but I'm trying to figure out if there is a way to set up the config so the background color will respect the color set by dataClasses. I tried setting it to currentColor, but the colorAxis color isn't applied to the parent element so that didn't work. I'm trying to avoid using classNames/styled mode if possible
Any suggestions? Thanks
The most efficient way is to opt out of zones and change how colors for points are generated by overwriting translateColors method:
(function(H) {
H.Series.prototype.translateColors = function() {
var series = this,
points = this.data.length ? this.data : this.points,
nullColor = this.options.nullColor,
colorAxis = this.colorAxis,
colorKey = this.colorKey;
points.forEach(function(point) {
var value = point[colorKey],
color;
color = point.options.color ||
(point.isNull ?
nullColor :
(colorAxis && typeof value !== 'undefined') ?
(
point.x < 2 ?
colorAxis.toColor(value, point) : {
pattern: {
backgroundColor: colorAxis.toColor(value, point),
height: 45,
width: 45,
path: {
d: "M-1,1 l2,-2 M0,45 l45,-45 M44,46 l2,-2",
stroke: '#FFFFFF',
strokeWidth: 3
}
}
}
) :
point.color || series.color);
if (color) {
point.color = color;
}
});
}
}(Highcharts));
Live demo: http://jsfiddle.net/BlackLabel/Lygwz16j/
Docs: https://www.highcharts.com/docs/extending-highcharts/extending-highcharts

Chart JS change pointBackgroundColor based on data value

So I have created a basic line chart using Chartjs. How would I go about changing the color of the points (pointBackgroundColor) depending on the value of the data? For example, if the data point is less than 10 it changes to red, or if the data point is between 10 and 20 it changes to blue?
const CHART = document.getElementById("lineChart");
let lineChart = new Chart(CHART, {
type: 'line',
data: {
labels: ["5/10/2010", "5/11/2010", "5/12/2010", "5/13/2010", "5/14/2010", "5/15/2010", "5/16/2010"],
datasets: [
{
label: "Theta",
fill: false,
lineTension: 0,
backgroundColor: "rgba(75,192,192,0.4)",
borderColor: "rgba(9,31,62)",
borderCapStyle: 'butt',
borderDash: [],
borderDashOffset: 0.0,
borderJoinStyle: 'miter',
pointBorderColor: "rgba(0,191,255)",
pointBackgroundColor: "rgba(0,191,255)",
pointBorderWidth: 5,
pointBorderRadius: 5,
pointHoverBackgroundColor: "rgba(75,192,192,1)",
pointHoverBorderColor: "rgba(220,220,220,1)",
pointHoverBorderWidth: 2,
pointRadius: 1,
pointHitRadius: 10,
data: [15, 28, 11, 3, 34, 65, 20],
}
]
},
options: {
maintainAspectRatio: false,
responsive: true,
legend: {
display: false,
},
scales: {
yAxes:[{
ticks: {
fontColor: "#091F3e",
beginAtZero: true,
steps: 10,
stepSize: 10,
max: 100
},
gridLines: {
display: false
}
}],
xAxes:[{
ticks: {
fontColor: "#091F3e",
fontSize: "10",
},
gridLines: {
display: false
}
}]
}
}
});
You can use a closure on any option and manipulate the returned value according to the context. In the example bellow I'm the pointBackgroundColor is red when the current value is greater then 0 and blue otherwise.
pointBackgroundColor: function (context) {
let value = context.dataset.data[context.dataIndex];
return value > 0
? 'red'
: 'blue';
},
Here is another thing that may help you Change bar color depending on value.
Its original answer from Tot Zam
Adding the code sample in case the link doesn't work.
var colorChangeValue = 50; //set this to whatever is the decidingcolor change value
var dataset = myChart.data.datasets[0];
for (var i = 0; i < dataset.data.length; i++) {
if (dataset.data[i] > colorChangeValue) {
dataset.backgroundColor[i] = chartColors.red;
}
}
myChart.update();
Its about bars background, but you can try work around and find same solution.

Flot line graph messing up data for x-axes and y-axes

I am making a line graph in Flot, but i can't manage to put x-axes and y-axes to display data normally, they are stick together. How can i make it to be over whole graph. I didn't find in any documentation how to fix that.
This need to be on left side outside of graph : [0.24, "0.24 USD"], [2085.95, "2085.95 USD"]
and this on bottom of a graph
[0, "0"], [1, "Jan"], [275, "Aug"], [549, "Mar"], [823, "Oct"], [1097, "Jun"], [1371, "Dec"], [1372, "Dec"]
Here is an image how it looks now, all is grouped on bottom left corner
And this is how it need to looks like, this is image from Flot website
Here is a code:
var data1 = [{chart_data_money}];
var dataset = [{
data: data1,
color: '#ffa500',
label: 'Loss in USD',
points: { symbol: "circle", fillColor: "#FF000;", show: true}
}];
var options = {
series: {
lines: { show: true },
points: {
radius: 1,
fill: true,
show: true
}
},
xaxes: [{
position: "bottom",
ticks: '{chart_xticks_money}',
color: "black",
axisLabel: "Sin(x)",
axisLabelUseCanvas: true,
axisLabelFontSizePixels: 12,
axisLabelFontFamily: 'Verdana, Arial',
axisLabelPadding: 3
}],
yaxes: [{
position: "left",
color: "red", // lines colors for y axes
ticks: '{chart_yticks_money}',
axisLabel: "Sin(y)",
axisLabelUseCanvas: true,
axisLabelFontSizePixels: 12,
axisLabelFontFamily: 'Verdana, Arial',
axisLabelPadding: 3
}],
legend: {
noColumns: 0,
labelFormatter: function (label, series) {
return "<font color=\"white\">" + label + "</font>";
},
// legend postion and color
backgroundColor: "#000",
backgroundOpacity: 0.9,
labelBoxBorderColor: "orange",
position: "nw"
},
grid: {
hoverable: true,
borderWidth: 3,
mouseActiveRadius: 50,
backgroundColor: { colors: ["#ffffff", "#EDF5FF"] }, // 2 colors gradient for bg of chart
axisMargin: 20
}
};
$(document).ready(function () {
$.plot($("#graph-line"), dataset, options);
});
The problem is that you give Flot your axis ticks as string instead of array:
ticks: '{chart_xticks_money}',
needs to be
ticks: {chart_xticks_money},
and the same for the other axis.
This fiddle has the same error as your image, and this is the correct version without the '.

2 different font sizes for text inside basic Rect, jointjs

I have a basic Rect shape like this:
var rectShape = new joint.shapes.basic.Rect({
position: { x: 60, y: 10 },
size: { width: 160, height: 35 },
attrs: {
rect: {
fill: '#F5F5F5'
},
text: {
fill: '#FC8A26',
'font-size': 12,
'font-weight': 'bold',
'font-variant': 'small-caps'
}
}
});
I use clone() to create more rectangles like that one:
var rect1 = rectShape.clone().translate(520, 10).attr('text/text','rect1');
I want to have 2 different words inside the rect, one at the size 12 and the other at the size 8. Any idea on how I can do that?
Thank you!
you need to create a custom shape with new SVG markup containing a text element that contains a <tspan> for each word that you want. You could adapt the markup from the standard Rect element. Give each element a different class name, for example replace the <text/> element in the Rect markup with <text><tspan class="word1"/><tspan class="word2"/></text>. The shape definition would look like this:
joint.shapes.my.twoTextRect = joint.shapes.basic.Generic.extend({
markup: '<g class="rotatable"><g class="scalable"><rect/></g><text><tspan class="word1"></tspan> <tspan class="word2"></tspan></text></g>',
defaults: joint.util.deepSupplement({
type: 'my.twoTextRect',
attrs: {
rect: { fill: 'white', stroke: 'black', 'stroke-width': 1, 'follow-scale': true, width: 160, height: 35 },
text: { ref: 'rect' },
'.word1': { 'font-size': 12 },
'.word2': { 'font-size': 8 }
},
size: { width: 160, height: 35 }
}, joint.shapes.basic.Generic.prototype.defaults)
});
Then to create your shape instance:
var rectShape = new joint.shapes.my.twoTextRect();
To set the text of the <tspan> SVG elements you can use
rectShape.attr('.word1/text', 'word 1');
rectShape.attr('.word2/text', 'word 2');
This results in an element that looks like this:
You can clone the element like this:
var clone = rectShape.clone().translate(520, 10).attr({'.word1': {text: 'clone1'}, '.word2': {text: 'clone2' }});
And this makes a new element:

Paths and subpath don't manage the arc curve the same way

I'm having issue with generating arc curves with Raphael.
I created a reduced example here: http://jsfiddle.net/vaxilart/m6cHw/3/
As you can see, the first path drawn isn't the same as the second one, and the second one is only a subpath of the first.
Do you know why both are different? And how could I resolve this issue?
Here's the code:
function drawpath( canvas, bg, pathstr, duration, attr, callback ) {
var guide_path = bg;
var path = canvas.path( guide_path.getSubpath( 0, 1 ) ).attr( attr );
var total_length = guide_path.getTotalLength( guide_path );
var last_point = guide_path.getPointAtLength( 0 );
var start_time = new Date().getTime();
var interval_length = 50;
var result = path;
var run = function run() {
var elapsed_time = new Date().getTime() - start_time;
var this_length = elapsed_time / duration * total_length;
var subpathstr = guide_path.getSubpath( 0, this_length );
path.attr({ path: subpathstr });
if ( elapsed_time >= duration ) {
if ( callback != undefined ) callback();
} else {
requestAnimationFrame(run);
}
};
run();
return result;
}
var sequence_path = [
[ "M", 200, 0 ],
[ "V", 200 ],
[ "A", 100, 100, 90, 0, 0, 300, 300 ],
[ "H", 400 ],
[ "A", 100, -100, 90, 0, 0, 500, 400 ],
[ "V", 500 ],
[ "A", 100, -100, 90, 0, 0, 400, 600 ],
[ "H", 200 ],
[ "A", 100, 100, 90, 0, 0, 100, 700 ],
[ "V", 800 ]
];
var paper = Raphael(10, 50, 700, 1000);
var bg = paper.path(sequence_path).attr({
stroke: 'white',
'stroke-width': 64,
'stroke-opacity': 1,
fill: 'none',
'fill-opacity': 0
});
drawpath( paper, bg, sequence_path, 3500, {
stroke: 'orange',
'stroke-width': 64,
'stroke-opacity': 1,
fill: 'none',
'fill-opacity': 0
});
Looks like Raphael's getSubpath method has a bug where it misinterprets the Large Arc Flags and Sweep Flags of a couple of those curves. I might be wrong.
Edit: OK I was wrong. You have some bad Arcs (A) that are breaking something somewhere between Raphael and the browser, not sure where. But the problem is:
You are setting negative y-radius on the two Arcs that get messed up. Radius cant be negative. in your sequence_path definition, change those two -100's to 100 (positive 100 y radius). updated fiddle: http://jsfiddle.net/m6cHw/4/
If you're going to be hand-writing a lot of paths, I suggest you read the standards specs on how to define them: http://www.w3.org/TR/SVG/paths.html. I tried to avoid reading that for a while but eventually I bit the bullet and went through it. It's weird stuff but you need to understand it if you want to make paths do what you want.

Resources