amchart scatterplot change background of one quadrant - amcharts

Here I tried something like this but, It is colouring entire left side to right from 0 to 50.
function colourQuadrantX(start, end) {
var range = valueAxisX.axisRanges.create();
range.value = start;
range.endValue = end;
range.axisFill.fill = am4core.color("#396478");
range.axisFill.fillOpacity = 0.2;
range.grid.strokeOpacity = 0;
}
Please take a look how can solve this

Related

Showing an image and replacing it with another image if something happens

I use a color tracking code for processing.
What I want (example):
If red is detected show image 1
If green is detected show image 2
If blue is detected show image 3
The problem is, if the last color is detected and the last image is shown, and I track now the first color the first image is not in front (I can't see it).
The whole code:
import processing.video.*;
//import hypermedia.net.*;
PImage img;
PImage img2;
PImage img3;
Capture video;
final int TOLERANCE = 20;
float XRc = 0;// XY coordinate of the center of the first target
float YRc = 0;
float XRh = 0;// XY coordinate of the center of the second target
float YRh = 0;
float XRc2 = 0; // XY coordinate of the center of the third target
float YRc2 = 0;
float XRh2 = 0;// XY coordinate of the center of the fourth target
float YRh2 = 0;
int ii=0; //Mouse click counter
color trackColor; //The first color is the center of the robot
color trackColor2; //The second color is the head of the robot
color trackColor3; //The first color is the center of the robot 2
color trackColor4; //The first color is the center of the robot 2
void setup() {
img = loadImage("IMG_4700.JPG");
img2 = loadImage("2.JPG");
img3 = loadImage("3.JPG");
size(800,800);
video = new Capture(this,640,480);
video.start();
trackColor = color(94,164,126);
trackColor2 = color(60,110,194);
trackColor3 = color(197, 76,64);
trackColor4 = color(255,0,0);
smooth();
}
void draw() {
background(0);
if (video.available()) {
video.read();
}
video.loadPixels();
image(video,0,0);
float r2 = red(trackColor);
float g2 = green(trackColor);
float b2 = blue(trackColor);
float r3 = red(trackColor2);
float g3 = green(trackColor2);
float b3 = blue(trackColor2);
float r4 = red(trackColor3);
float g4 = green(trackColor3);
float b4 = blue(trackColor3);
float r5 = red(trackColor4);
float g5 = green(trackColor4);
float b5 = blue(trackColor4);
int somme_x = 0, somme_y = 0; // pour le calcul des baricentres
int compteur = 0;
int somme_x2 = 0, somme_y2 = 0; // pour le calcul des baricentres
int compteur2 = 0;
int somme_x3 = 0, somme_y3 = 0; // pour le calcul des baricentres
int compteur3 = 0;
int somme_x4 = 0, somme_y4 = 0; // pour le calcul des baricentres
int compteur4 = 0;
for(int x = 0; x < video.width; x++) {
for(int y = 0; y < video.height; y++) {
int currentLoc = x + y*video.width;
color currentColor = video.pixels[currentLoc];
float r1 = red(currentColor);
float g1 = green(currentColor);
float b1 = blue(currentColor);
if(dist(r1,g1,b1,r2,g2,b2) < TOLERANCE) {
somme_x += x;
somme_y += y;
compteur++;
}
else if(compteur > 0) {
XRc = somme_x / compteur;
YRc = somme_y / compteur;
}
if(dist(r1,g1,b1,r3,g3,b3) < TOLERANCE) {
somme_x2 += x;
somme_y2 += y;
compteur2++;
}
else if(compteur2 > 0) {
XRh = somme_x2 / compteur2;
YRh = somme_y2 / compteur2;
}
if(dist(r1,g1,b1,r4,g4,b4) < TOLERANCE) {
somme_x3 += x;
somme_y3 += y;
compteur3++;
}
else if(compteur3 > 0) {
XRc2 = somme_x3 / compteur3;
YRc2 = somme_y3 / compteur3;
}
if(dist(r1,g1,b1,r5,g5,b5) < TOLERANCE) {
somme_x4 += x;
somme_y4 += y;
compteur4++;
}
else if(compteur4 > 0) {
XRh2 = somme_x4 / compteur4;
YRh2 = somme_y4 / compteur4;
}
}
}
// track the color and show images
boolean c1 = false;
boolean c2 = false;
boolean c3 = false;
if(XRc != 0 || YRc != 0) { // color Green detected
c1 = true;
c2 = false;
c3 = false;
}
if(XRh != 0 || YRh != 0) { // color blue detected
c2 = true;
c1 = false;
c3 = false;
}
if(XRc2 != 0 || YRc2 != 0) { // color red detected
c3 = true;
c1 = false;
c2 = false;
}
if(c1 == true) {
image(img,0,0); // show image 1
} else if (c2 == true) {
image(img2,0,0); // show image 2
} else if (c3 == true) {
image(img3,0,0); // show image 3
}
}
The important snippet:
// detect color and show images
boolean c1 = false;
boolean c2 = false;
boolean c3 = false;
if(XRc != 0 || YRc != 0) { // color Green detected
c1 = true;
c2 = false;
c3 = false;
}
if(XRh != 0 || YRh != 0) { // color blue detected
c2 = true;
c1 = false;
c3 = false;
}
if(XRc2 != 0 || YRc2 != 0) { // color red detected
c3 = true;
c1 = false;
c2 = false;
}
if(c1 == true) {
image(img,0,0); // show image 1
} else if (c2 == true) {
image(img2,0,0); // show image 2
} else if (c3 == true) {
image(img3,0,0); // show image 3
}
Screenshots:
First object is tracked and image is shown
Second object is tracked and image is shown
Third object is tracked and image is shown
My Problem:
(the first object should be tracked and the first image should me shown)
There are few things that could be improved.
In terms of efficiency, a couple of minor suggestions:
you could pre-compute the RGB components of the colours you want to track once in setup() rather than many times per second in draw() (e.g.float r2 = red(trackColor); etc.)
You could use a flat 1D loop rather than a nested loop using video.pixels[]. One minor disadvantage is that you'd need to compute the x,y position from the pixel index. Since you need to display an image and it doesn't seem to matter where, you might not even need to compute x,y.(e.g. for(int currentLoc = 0; currentLoc < video.pixels.length; currentLoc++))
In terms of the algorithm itself:
You are using a single threshold value(TOLERANCE). This will cut out anything on the left of the value which is ok, but not cut a whole range of other colours that might mess with your counter. I recommend using a range (e.g. MIN_TOLERANCE,MAX_TOLERANCE).
You are using R,G,B colour space. R,G,B colours don't mix together as we'd expect. A more perceptual colour space will behave as you'd expect (e.g. orange will be closer to red and yellow). For that you would need to convert from RGB to CIE XYZ, then to Lab*, compute the euclidean distance between two colours, then convert the result back to RGB if you need to display it.You can find an example here. It's in OpenFrameworks (c++), but you should be able to see the similarities to Processing and port it.
There is another option: HSB colour space. More on that bellow
You could draw some visualisation of how your code is segmenting the image. It will be faster to get an idea of which values work better, which don't
I recommend trying the OpenCV for Processing library which uses a more modern OpenCV library under the hood and provides more functionalities and great examples. One of them is particularly useful for you: HueRangeSelection
Give it a go. Notice you can move the mouse to shift the range and if you hold a key pressed you can increase the range. For example, here's how the quick demo of it with your images. (The HSB range threshold result is displayed smaller in the bottom right corner):
From my own experience, I'd recommend not using shiny/reflective materials (e.g. the coke can). You can see in the image above the segmentation isn't as good as on the green and blue objects with flatter colours. Because the can is reflective, it will appear to have different colours not only with global lighting changes, but also it's position/rotation and objects close to it. It's a pain to cater to all these.
Also, to take the HueRange example further you can:
Apply a morphologic filter (for example erode(), then dilate()) to remove some of the noise (smaller white pixel patches). At this point you can count the number of white pixels per colour range and decide which image to display.
find contours on the filtered image which will can use to determine the x,y,width,height of the region that falls within a range of the colour you want to track.
Good luck and most importantly have fun!
Hummm... Without running the code, I'd bet the problem is that you rely on the coordinates (XRc and it's siblings) being zero to choose which image to use. They are all initiated to 0, so the first run goes fine, but... you never reset them to zero, do you? So after they all have being changed once by detecting the 3 colors your test became useless. Perhaps you can reset them all to zero whenever a color is detected.
And maybe you don't need the boolean at all...
What do think of this?
PSEUDO
//global
PImage imgs = new PImage[3];
int imageToDispaly = 0;
//all the stuff...
if(XRc != 0 || YRc != 0) { // color Green detected
// not sure this will work, but the idea is some thing like this.
XRh = YRh = XRc2 = YRc2 = 0;
imageToDispaly = 0;
}
if(XRh != 0 || YRh != 0) { // color blue detected
XRc = YRc = XRc2 = YRc2 = 0;
imageToDispaly = 1;
}
if(XRc2 != 0 || YRc2 != 0) { // color red detected
XRh = YRh = XRc = YRc = 0;
imageToDispaly = 2;
}
// at appropriated time...
image(imgs[imageToDispaly], x, y);

How can I draw an autoscaling D3.js graph that plots a mathematical function?

I have a working jsfiddle that I made using JSXGraph, a graphing toolkit for mathematical functions. I'd like to port it to D3.js for personal edification, but I'm having a hard time getting started.
The jsfiddle graphs the value of -ke(-x/T) + k, where x is an independent variable and the values of k and t come from sliders.
board.create('functiongraph',
[
// y = -k * e(-x/t) + k
function(x) { return -k.Value()*Math.exp(-x/t.Value()) + k.Value(); },
0
]
);
The three things I'm most stumped on:
Actually drawing the graph and its axes - it's not clear to me which of the many parts of the D3 API I should be using, or what level of abstraction I should be operating at.
Re-rendering the graph when a slider is changed, and making the graph aware of the value of the sliders.
Zooming out the graph so that the asymptote defined by y = k is always visible and not within the top 15% of the graph. I do this now with:
function getAestheticBoundingBox() {
var kMag = k.Value();
var tMag = t.Value();
var safeMinimum = 10;
var limit = Math.max(safeMinimum, 1.15 * Math.max(k.Value(), t.Value()));
return [0, Math.ceil(limit), Math.ceil(limit), 0];
}
What's the right way for me to tackle this problem?
I threw this example together really quick, so don't ding me on the code quality. But it should give you a good starting point for how you'd do something like this in d3. I implemented everything in straight d3, even the sliders.
As #LarKotthoff says, the key is that you have to loop your function and build your data:
// define your function
var func = function(x) {
return -sliders.k() * Math.exp(-x / sliders.t()) + sliders.k();
},
// your step for looping function
step = 0.01;
drawPlot();
function drawPlot() {
// avoid first callback before both sliders are created
if (!sliders.k ||
!sliders.t) return;
// set your limits
var kMag = sliders.k();
var tMag = sliders.t();
var safeMinimum = 10;
var limit = Math.max(safeMinimum, 1.15 * Math.max(kMag, tMag));
// generate your data
var data = [];
for (var i = 0; i < limit; i += step) {
data.push({
x: i,
y: func(i)
})
}
// set our axis limits
y.domain(
[0, Math.ceil(limit)]
);
x.domain(
[0, Math.ceil(limit)]
);
// redraw axis
svg.selectAll("g.y.axis").call(yAxis);
svg.selectAll("g.x.axis").call(xAxis);
// redraw line
svg.select('.myLine')
.attr('d', lineFunc(data))
}

How do I get a random number to stay fixed with slick?

I'm a beginner in Java as well as with the slick tools. I want to make a game that has different coloured cubes randomly placed within a certain area of the window.
I use two for-loops and call for a random number in render. I get the cubes placed exactly as I want, but the problems is that they flicker in all colours. I guess it has to do with how I call for a random number and that it gets updated with FPS?!
Please help me!!
public void render(GameContainer gc, StateBasedGame sdg, Graphics g) throws SlickException {
//set background
Image background = (new Image("res/background.png")).getScaledCopy(800, 500);
g.drawImage(background, 0, 0);
//set gamescape
blue = (new Image("res/blue.png")).getScaledCopy(20,20);
green = (new Image("res/green.png")).getScaledCopy(20,20);
red = (new Image("res/red.png")).getScaledCopy(20,20);
int xvalue = 300;
int yvalue = 400;
for (int a = 1; a < 20; a++) {
for (int i = 1; i < 10; i++) {
r = rand.nextInt(3);
if(r==0){g.drawImage(blue,xvalue,yvalue);}
else if(r==1){g.drawImage(red, xvalue, yvalue);}
else{g.drawImage(green, xvalue, yvalue);}
xvalue = xvalue+20;
}
yvalue = yvalue - 20;
xvalue = xvalue -180;
}
}
Your problem is that you generate a new random number each time you redraw the scene.
To resolve this, you may have to create an array in which you store the generated color of each cube. And each time you redraw your images, you just read each color value in the array.

Flot - display labels on top of stacked bars

I am using the code snippet from this stackoverflow question to label my flot data points. So far this has served me well, but now I have to label the overall values of stacked bars. There are two data series and so far I've managed to calculate the sums, but I can't seem to work out a proper positioning for my labels. I'd like to place them on top of the stacks, but pointOffset only gives me the offsets based on non-stacked bars.
This is the code I am currently using, it places the labels where the second series' data points would be, if the bars weren't stacked, which puts them somewhere in the top bars.
$.each(p.getData()[1].data, function(i, el){
var series0 = p.getData()[0].data;
sum = el[1] + series0[i][2]
var o = p.pointOffset({x: el[0], y: el[1]});
$('<div class="data-point-label">' + sum + '</div>').css( {
position: 'absolute',
left: o.left - 5,
top: o.top ,
display: 'none'
}).appendTo(p.getPlaceholder()).fadeIn('slow');
});
Edit #1: So far I've tried using c2p/p2c, calculating the top value using the single data points' top values and finding more documentation on the stack plugin. I am afraid none of this has helped me much.
Edit #2: I've also tried the code given in this stackoverflow answer but it doesn't work for me. I suspect the author is using some label plugin ...
The solution to put the labels in the top of the bars in stack usinjg canvas is that you have to calculate the xPoint in base of the sum of the values in the complete stack.
Here is a example of code
var sumaArr = [];
for (var u = 0; u < p.getData().length; u++) {
$.each(p.getData()[u].data, function (i, el) {
sumaArr[i] > 0 ? sumaArr[i] = sumaArr[i] + el[1] : sumaArr[i] = el[1];
});
}
var ctx = p.getCanvas().getContext("2d");
var data = p.getData()[p.getData().length - 1].data;
var xaxis = p.getXAxes()[0];
var yaxis = p.getYAxes()[0];
var offset = p.getPlotOffset();
ctx.font = "12px 'Segoe UI'";
ctx.fillStyle = "gray";
for (var i = 0; i < data.length; i++) {
var text = sumaArr[i];
var metrics = ctx.measureText(text);
var xPos = (xaxis.p2c(data[i][0]) + offset.left) - metrics.width / 2;
var yPos = yaxis.p2c(sumaArr[i]) + offset.top - 5;
ctx.fillText(text, xPos, yPos);
}
The var yPos use the sume of the values that make the complete stack.

Snapping vertical line cursor to data point in jqPlot

I have just started using jqPlot for a line chart with multiple series. It seems great.
I have added the Cursor plugin with the intention of showing a vertical line on the nearest data point on the x axis. In other words, it snaps to the nearest point. The Cursor plugin, however always shows the vertical cursor right where the mouse is.
It seems like I just want to "override" or replace moveLine to change the current functionality.
What's the most appropriate way of doing so?
It seems a little much to copy/past all of the cursor plugin just to modify a very small subset.
Thanks!
I know I'm a kind of archaeologist by edited this post but I think the following can be useful for someone (I hope).
I've made a piece of code which allow to draw a vertical line following the cursor and displaying a tooltip on the nearest point (according to the cursor). You can find a demo of it on this JSFiddle.
I also post the corresponding code below (only the part which calculate nearest point and display tooltip):
//Show nearest point's tooltip
$("#chart1").bind('jqplotMouseMove', function(ev, gridpos, datapos, neighbor, data){
var c_x = datapos.xaxis;
var index_x = -1;
var pos_index = 0;
var low = 0;
var high = data.data[0].length-1;
while(high - low > 1){
var mid = Math.round((low+high)/2);
var current = data.data[0][mid][0];
if(current <= c_x)
low = mid;
else
high = mid;
}
if(data.data[0][low][0] == c_x){
high = low;
index_x = high;
}else{
var c_low = data.data[0][low][0];
var c_high = data.data[0][high][0];
if(Math.abs(c_low - c_x) < Math.abs(c_high - c_x)){
index_x = low;
}else{
index_x = high;
}
}
//Display marker and tooltip
if(data.series[0].data[index_x]){
var x = data.series[0].gridData[index_x][0];
var y = data.series[0].gridData[index_x][1];
var r = 5;
var highlightCanvas = $(".jqplot-highlight-canvas")[0];
var context = highlightCanvas.getContext('2d');
context.clearRect(0,0,highlightCanvas.width,highlightCanvas.height);
context.strokeStyle = 'rgba(47,164,255,1)';
context.fillStyle = 'rgba(47,164,255,1)';
context.beginPath();
context.arc(x,y,r,0,Math.PI*2,true);
context.closePath();
context.stroke();
context.fill();
//Display tooltip on nearest point
var highlightTooltip = $(".jqplot-highlighter-tooltip");
var val_x = data.data[0][index_x][0];
var val_y = data.data[0][index_x][1];
highlightTooltip.html("X : "+val_x+"<br/>Y : "+val_y);
highlightTooltip.css({'left': x+'px', 'top': (y-10)+'px', 'display': 'block'});
}
});
Feel please to use it and to modify it as you need it.
Try a bar graph series on top of everything else that has alpha set to 0.

Resources