Gnuplot, problems with dates on the x-axis - date

I have (for me) a strange problem with the date on the x-axis.
I use the (imo) linux time in the first column like;
1385856000,1.69,0,10.33,0,1.69,10.33,-8.64,12.14,3.5
1385942400,0,0.94,3.33,8.51,0.94,11.84,-10.9,13.7,2.8
1386028800,0,0.51,4.96,8.65,0.51,13.61,-13.1,15.8,2.7
1386115200,0,0.01,3.42,6.49,0.01,9.91,-9.9,10.6,0.7
V
V
V
1388361600,0,0.63,4.21,7.65,0.63,11.86,-11.23,13.93,2.7
1388448000,0,0.18,4.47,8.29,0.18,12.76,-12.58,14.48,1.9
In this case december 2013 with 31 days. But the line begins with 30 (november?).
For now a draw a rectangle over de "30" but ofcourse thats not the way.
This is my script;
maand = "Dec"
jaar = "2013"
file = maand.jaar.'.txt'
set output maand.jaar.".png"
set datafile separator ","
set linestyle 1 lt 1 lc rgb "black"
set linestyle 2 lt 1 lc rgb "red"
set bmargin 2.2 # witruimte onder grafiek
set label font "arial, 7" # grootte font tbv labels in het grafiek
set boxwidth 0.8 relative
set terminal pngcairo truecolor enhanced size 1200, 500 background rgb "#FFF5F5"
stats file using 0 nooutput ; dagen = STATS_records
stats file using 10 nooutput ; zon = value(int(STATS_sum*1000))
stats file using 9 nooutput ; gebruikt = value(int(STATS_sum*1000))
afgenomen = gebruikt-zon
set timefmt "%s" ; fmt = "%s"
stats file using (strptime(fmt, stringcolumn(1))) every ::1::1 nooutput
maand = strftime("%B", STATS_max) ; jaar = strftime("%Y", STATS_max) ; datum = maand." ".jaar
set title 'Energie stromen '.datum font "arial bold, 14"
set xdata time ; set timefmt "%s" ; set format x "%d" # dit is de opmaak zoals je hem gaat zien
set xtics 86400 font "arial,12" offset -1.35,0.5
set mxtics 1
set grid ls 1 lc rgb "#dddddd"
set ytics font "arial, 12" offset 0.5,0
set ylabel "V e r m o g e n in kW" offset 3,1 font "helvetica, 12"
unset key
set key below left samplen 2
set key maxrows 1 # aantal regels onder het grafiek (met Watt/uur erin)
set style fill solid 1 border 0.5 # was transparent solid 0.5 border 0.5
set style rectangle fc linestyle 1 fs solid 0.5 noborder
set object rectangle front fillcolor rgb "#FFF5F5"
set object 2 rect from graph -.48, graph -1.5 to graph -0.004, graph 0.02 fc rgb "#FFF5F5"
plot file u ($1-43200):10 w boxes lc rgb "#00ff00" title "Deze maand zon: ".(zon/1000)." kW",\
file u ($1-43200):10:(sprintf("%2.1f",$10)) w labels offset 0.0,0.4 font "arial, 10" notitle,\
file u ($1-43200):(-1*$9) w boxes lc rgb "#ff0000" title "&{2}Verbruik: ".(gebruikt/1000)." kW",\
file u ($1-43200):(-1*$9):(sprintf("%2.1f",$9)) w labels offset 0,-0.4 font "arial, 10" notitle
Has some one a clou?

The 30 comes from november and the way you shift the xticlabels.
I think, the best way to have the labels below the boxes, but the tics and the grid lines between the boxes is the following:
Scale the major tics to 0
Add one minor xtic and draw the grid lines only for the minor xtics
Do not expand the automatic xrange to the next major tic (set autoscale xfix)
Plot the boxes at their actual time position (plot file u 1:... instead of plot file u ($1-43200):...)
...
set xtics 86400 font "arial,12" scale 0, 1
set mxtics 2
set grid mxtics ytics ls 1 lc rgb "#dddddd"
set autoscale xfix
...
plot file u 1:10 w boxes lc rgb "#00ff00"
...
With these modifications, your exemplary data and version 4.6.3 I get
BTW: You can compress your three stats calls to a single one:
stats file using 9:10 nooutput
dagen = STATS_records
zon = int(STATS_sum_y*1000)
gebruikt = int(STATS_sum_x*1000)

Related

Is there a way to have 3 different Y axes on one graph using gnuplot?

I'm making a weather display graph using GNUplot with a weather API. I'm currently plotting the next 48 hours of temperature and rainfall.
As you can see in the above image, the temperature is the line with the axis defined on the left; while the rainfall is depicted by the bar graph (bottom left) and its axis is defined on the right. (0, 0.5, 1).
I would however like to include other data in the graph as well. The first thing I want to include is cloud cover at the top of the graph. Again as a bar graph.
I'm including a mockup that I made is a graphic editor:
Is there a way to do this with gnuplot, or will I have to use another program to accomplish it?
You have y1-axis on the left and y2-axis on the right. If you want to have a 3rd y-axis you have to shift it somehow. One way to achieve this is with multiplot, basically several plots on top of each other.
You have to make sure that all plots are using the same (fixed) margins on the canvas (automargin probably won't work) and the same xrange (the second plot takes it from the first plot). Check the following example with some random data. Certainly, some fine tuning could be done. Adapt it to your needs.
Code:
### Three y-axes
reset session
# create some test data
myTimeFmt = "%d.%m.%Y %H:%M:%S"
set print $Data
do for [i=1:48] {
myTime(i) = strftime(myTimeFmt, time(0)+i*3600)
myTemp(i) = sin(i/5.)*5 + 20 + rand(0)
myRain(i) = int(rand(0)+0.3) * rand(0)*20
myCloud(i) = rand(0)*50
print sprintf("%s %g %g %g",myTime(i),myTemp(i),myRain(i),myCloud(i))
}
set print
set key off
set margins screen 0.1, screen 0.8, screen 0.1, screen 0.94
set multiplot
set format x "%H:%M" timedate
set xtics 3600*6
set grid xtics, mxtics, ytics, mytics
##### first plot
set ylabel "Temperature °C" tc "red"
set yrange[10:30]
set ytics nomirror tc "red"
set y2label "Rain / mm" offset -1,0 textcolor rgb "blue"
set y2range[0:40]
set y2tics nomirror tc "blue"
set style fill solid 1.0
plot $Data u (timecolumn(1,myTimeFmt)):3 axes x1y1 w l lc "red", \
'' using (timecolumn(1,myTimeFmt)):4 axes x1y2 w boxes lc "blue"
unset xlabel
unset ylabel
unset y2label
unset tics
##### Second plot
set bmargin screen 0.73
set border 4
set xrange[GPVAL_X_MIN:GPVAL_X_MAX] # identical xrange like 1st plot
set y2range[100:0] reverse
plot $Data u (timecolumn(1,myTimeFmt)):5 axes x1y2 w boxes lc rgbcolor "grey"
##### Third plot (just for 3rd y-axis)
set rmargin at screen 0.9
set border 8 # only right border visible
set y2label "Cloud coverage" offset -1,0 textcolor rgb "black"
set y2tics nomirror offset 0,0
plot NaN # plot some dummy
unset multiplot
### end of code
Result:

Gnuplot, pie chart, placing labels on left, can't see them all

I need to make some pie charts using Gnuplot. I used the code I found here, on SO. My data file looks like this:
Województwo Suma
Dolnośląskie 3.6
Kujawsko-Pomorskie 7.5
Lubelskie 4.7
Lubuskie 3.3
Łódzkie 8.1
Małopolskie 6.9
Mazowieckie 12.5
Opolskie 2.6
Podkarpackie 6
Podlaskie 3.4
Pomorskie 8
Śląskie 14
And my Gnuplot script:
#!/usr/bin/gnuplot
set encoding utf8
set datafile separator "\t"
set termoption enhanced
set terminal epscairo enhanced color dashed rounded size 8.5, 5.5
set output '2008-2015procent_pie.eps'
stats '2008-2015procent_pie.csv' u 2 noout # get STATS_sum (sum of column 2)
ang(x)=x*360.0/STATS_sum # get angle (grades)
perc(x)=x*100.0/STATS_sum # get percentage
set size square # square canvas
set xrange [-1:1.5]
set yrange [-1.25:1.25]
set style fill solid 1
unset border # remove axis
unset tics # remove tics on axis
unset colorbox # remove palette colorbox
unset key # remove titles
Ai = 0.0; Bi = 0.0; # init angle
mid = 0.0; # mid angle
i = 0; j = 0; # color
yi = 0.0; yi2 = 0.0; # label position
set palette defined (1 1 0.788 0.055, 2 0.090 0.161 0.659)
plot for [i=1:STATS_records] '2008-2015procent_pie.csv' u (0):(0):(1):(Ai):(Ai=Ai+ang($2)):(i) every ::i::i with circle linecolor palette,\
'2008-2015procent_pie.csv' u (mid=(Ai+ang($2)), Ai=2*mid-Ai, mid=mid*pi/360.0, -0.5*cos(mid)):(-0.5*sin(mid)):(sprintf('%.1f\%', $2, perc($2))) ever\
y ::1 w labels center font ',10',\
for [i=1:STATS_records] '2008-2015procent_pie.csv' u (1.45):(i*0.25):1 every ::i::i with labels left,\
for [i=1:STATS_records] '+' u (1.3):(i*0.25):(i) pt 5 ps 4 lc palette
I have 2 problems with this script:
I don't see all labels, is it possible to move the labels somehow that I could see them all?
Colours: here, on my pie chart I have basically only 2 colours - yellow and blue. How to make it so I could have a variety of colours, different colour for different value?
My chart looks like this now:
Thank you.
-----------------------------------------------------------------------------------------------------------------------------------EDIT
-----------------------------------------------------------------------------------------------------------------------------------
I changed a bit my script, as suggested by #RolandSmith, also, I modified a little my data file, Now it looks like this:
Województwo Suma
Dolnośląskie 3.6
Kujawsko-Pomorskie 7.5
Lubelskie 4.7
Lubuskie 3.3
Łódzkie 8.1
Małopolskie 6.9
Mazowieckie 12.5
Opolskie 2.6
Podkarpackie 6
Podlaskie 3.4
Pomorskie 8
Śląskie 14
Świętokrzyskie 2.8
Warmińsko-Mazurskie 4
Wielkopolskie 7.9
Zachodniopomorskie 4.6
And the modified script:
#!/usr/bin/gnuplot
set encoding utf8
set datafile separator "\t"
set termoption enhanced
set terminal epscairo enhanced color dashed rounded size 8.5, 5.5
set output '2008-2015procent_pie.eps'
stats '2008-2015procent_pie.csv' u 2 noout # get STATS_sum (sum of column 2)
ang(x)=x*360.0/STATS_sum # get angle (grades)
perc(x)=x*100.0/STATS_sum # get percentage
set size square # square canvas
set xrange [-1:1.5]
set yrange [-1.25:1.25]
set style fill solid 1
unset border # remove axis
unset tics # remove tics on axis
unset colorbox # remove palette colorbox
unset key # remove titles
Ai = 0.0; Bi = 0.0; # init angle
mid = 0.0; # mid angle
i = 0; j = 0; # color
yi = 0.0; yi2 = 0.0; # label position
set palette rgb 33,13,10;
plot for [i=1:STATS_records] '2008-2015procent_pie.csv' u (0):(0):(1):(Ai):(Ai=Ai+ang($2)):(i) every ::i::i with circle linecolor palette,\
'2008-2015procent_pie.csv' u (mid=(Ai+ang($2)), Ai=2*mid-Ai, mid=mid*pi/360.0, -0.5*cos(mid)):(-0.5*sin(mid)):(sprintf('%.1f\%', $2, perc($2))) every ::1 w labels center font ',10',\
for [i=1:STATS_records] '2008-2015procent_pie.csv' u (1.45):(i*0.25)-1.9:1 every ::i::i with labels left,\
for [i=1:STATS_records] '+' u (1.3):(i*0.25)-1.9:(i) pt 5 ps 4 lc palette
Now the problem is with labels - I still can't see all of them. There should be 16 labels, as you can see from the CSV file. I tried to change the page size, with no success. Thank you for help.
Current pie:
To move the labels in the pie-chart inwards or outwards, change the "-0.5" in front of the sin and cos. To move the labels and the color-squares, change (i*0.25) to (i*0.25)-1.2 in the third and fourth plot.
Update: Change (i*0.25) to e.g. (i*0.18) to make the distance between the labels smaller. And change ps 4 to e.g. ps 3 to make the squares smaller.
Define a larger palete. Your current one only has two entries. Get one with as least as much colors as you have entries. You could use colorbrewer to generate palette colors.
Some other points.
While this is really very clever, you're probably pushing gnuplot way beyond what it was intended. Consider using another tool like e.g. Python's matplotlib.
Your data doesn't add up to 100, but only to 80.6. So you should scale your figure properly using the ang and perc functions. I can't put my finger on it, but it doesn't look right.
In the sprintf, you should only use the percentage:sprintf('%.1f\%', perc($2))

Colormaps custom using cbfit matlab

Hi I am trying to costomize my colormap according to tick values of the of the colorbar. I defined my own colorbar with 5 colors eg 5 colors from blue to red
cmap_my=[0 0 1;0 1 1;0 1 0; 1 1 0; 1 0 0];
than i would like that the colour changes for every tick i put. By using cbfit the colors are changing according to the ticks if ticks are evenly distributed in the range of 0:40, but my ticks are
h = colorbar;
set(h,'YTick',[5,10,15,22,30,35,40]);
and my range is up to 45. In addition to that the colors i have defined dont show anymore when i use cbfit. Is there a possibility to give certain ranges for colors and eg from 5 to 10 dark blue 10 to 15 light blue 15 to 22 green 22 to 30 lightyellow 30 to 35 yellow 35 to 40 orange and over 40 red and than makes clear cuts at the ticks?
I hope I understood your problem. Here goes one example. You can work from here for you specific colors.
mri=load('mri');
mri=double(mri.D(:,:,1,13));
%making my image within the same range as yours
mri=(mri-min(mri(:)))./(max(mri(:))-min(mri(:)))*45;
figure,imagesc(mri),axis off,axis image,h_bar=colorbar;
%h_map(1) is related with the min(mri), and h_map(end) with max(mri)
h_map=colormap;
min_mri=0;
max_mri=45;
lim=eps*100;
my_map_int=[0-lim,5-lim,5+lim,10-lim,10+lim,40-lim,40+lim,45+lim];
my_map_color=[0,0,0;0,0,0;0,0,1;0,0,1;0,1,0;0,1,0;1,0,0;1,0,0];
new_map_color(:,1)=interp1(my_map_int,my_map_color(:,1),linspace(min_mri,max_mri,64),'nearest');
new_map_color(:,2)=interp1(my_map_int,my_map_color(:,2),linspace(min_mri,max_mri,64),'nearest');
new_map_color(:,3)=interp1(my_map_int,my_map_color(:,3),linspace(min_mri,max_mri,64),'nearest');
figure,imagesc(mri),axis off,axis image
colormap(new_map_color)
colorbar

Selecting pixels within a range of color in MATLAB

I am working on a project that consists in using a camera to detect if an electronic component has been soldered or not. The program has to be able to trigger the snapshot when a PLC asks for it, analize it and send a pass/fail sign back to the plc.
As I'm a MATLAB begginer I have been searching for information to know if it's feasible and to get a basic idea of where to start.
My idea would be to count how many pixels have a silver or gold tone in a defined zone. If it's mainly gold it means that it hasn't been soldered.
My question is, how would you do it to obtain the number of pixels that have a color inside a defined range inside a region of a webcam image?
I have found this but it's for an exact color instead of a range.
count = sum(im(:, :, 1) == 255 & im(:, :, 3) == 255 & im(:, :, 3) == 255);
In the end I used the function I posted but using a small region of interest.
I need to draw a square arround the yellow zones, any suggestions?
I'm attaching the code so there is some feedback (I'm not sure how to attach it, maybe you are not going to see it). The comments are in catalan but you won't have trouble understanding what I've done.
Thank you all!
clear all
clc
info = imaqhwinfo('winvideo') %Defineix origen de video
dev=info.DeviceInfo
vid=videoinput('winvideo',1)
vid.ROIPosition=[200 300 355 400]; %Zona a analitzar [iniciX, iniciY, ampladaX,
alçadaY]
vid.FramesPerTrigger=5; %Millora la qualitat de la foto
src.Sharpness=5;
img=getsnapshot(vid); %Dispara foto
count = sum((img(:, :, 1) >= 150 & img(:, :, 1) <= 255) & (img(:, :, 2) >= 100 & img(:,
:, 2) <= 255) & (img(:, :, 3) >= 0 & img(:, :, 3) <= 100));
numP=sum(count(1,:)) %Nombre de píxels en el rang de color donat
%ARA DETECTA GROC/DAURAT
dimT=size(img(:,:,1)); %Nombre de píxels total en la imatge
numT=dimT(1)*dimT(2)
Percentatge=numP/numT*100 %Percentatge de color en la imatge
%Hold on
%Draw square
%imshow(img)
%Hold off
Here are two methods to pick pixels within a pre-defined color range.
By comparing the hue only, in HSV space. So "Golden" is to be treated as "yellow", while "silver" should be "gray" (but "gray" is not a hue). May not be accurate if the solder is really "gray", thus it's hard to tell its hue.
By computing Euclidean distance in RGB space. More straightforward to think, and likely more powerful to tackle with "gray".
_
clear;clc;close all
I_rgb = imread('peppers.png');
figure(1)
imshow(I_rgb)
% hue distance in HSV space
I_hsv = rgb2hsv(I_rgb);
red_h = 358/360; % (normalized) hue for the red color
O_select = abs(I_hsv(:,:,1)-red_h)<=.05;
figure(2)
imshow(O_select)
O_hsv = I_hsv;
O_hsv(:,:,2) = O_hsv(:,:,2).*O_select;
O_rgb = hsv2rgb(O_hsv);
figure(3)
imshow(O_rgb)
% Euclidean distance in RGB space
red_rgb = reshape([188;28;38],[1,1,3]); % rgb coordinates for the red color
O_distance = sqrt(sum(bsxfun(#minus, double(I_rgb), red_rgb).^2, 3));
O_select = O_distance < 50;
figure(4)
imshow(O_select);
O_hsv = I_hsv;
O_hsv(:,:,2) = O_hsv(:,:,2).*O_select;
O_rgb = hsv2rgb(O_hsv);
figure(5)
imshow(O_rgb)
You can define multiple colors to pick, and combine several O_select's using things like or into your final result.
No need for epensive MATLAB, you can do that really easily in ImageMagick which is free and available here
So, basically you use this command:
convert yourpicture.jpg -colorspace rgb -colors 256 -depth 8 txt:
and it gives you this - a listing of all the pixels and their values:
# ImageMagick pixel enumeration: 32,32,255,rgb
0,0: (255,255,0) #FFFF00 rgb(255,255,0)
1,0: (255,255,0) #FFFF00 rgb(255,255,0)
2,0: (255,255,0) #FFFF00 rgb(255,255,0)
Then you can get rid of all the superfluous stuff and just look at the RGB values like this:
convert yourimage.jpg -colorspace rgb -colors 256 -depth 8 txt: | \
awk -F'[()]' '/^[0-9]/{print $4}' | \
awk -F, '{R=$1;G=$2;B=$3; print R,G,B}'
Sample Output
0 255 255
0 255 255
8 156 8
8 156 8
0 55 0
0 55 0
0 55 0
8 156 8
The above code will take your image, whether JPEG or PNG or TIFF and list all the RGB values of all the pixels.
If we now assume gold is RGB 255,215,0 we can do this:
# Find gold pixels +/- fuzz factor of 25
#
convert yourpicture.jpg -colorspace rgb -colors 256 -depth 8 txt: | \
awk -F'[()]' '/^[0-9]/{print $4}' | \
awk -F, 'BEGIN {gold=0}
{R=$1;G=$2;B=$3; if((R>230) && (G>190) && (G<240) && (B<25))gold++}
END {print "Gold pixels found: ",gold}'
If you want to work with hue/saturation and value, you can equally do that in ImageMagick like this:
# Find gold pixels +/- fuzz Hue=14
#
convert yourpicture.jpg -colorspace hsv -depth 8 txt:| \
awk -F'[()]' '/^[0-9]/{print $4}' | \
awk -F, 'BEGIN {gold=0}
{H=$1; if((H>11)&&(H<16))gold++}
END {print "Gold pixels found: ",gold}'
I should point out that the range of Hue is 0-360, so if we search for 14 (+/- fuzz) we are looking for a Hue of 14% of 360, i.e. Hue=50 which corresponds to gold.
If you want to visualise which pixels are selected and counted, you can do this:
convert pcb.jpg -channel R -fx "hue>0.09&&hue<0.11?1:0" -separate -background black -channel R -combine pcb_gold.jpg
which, given this input image, will produce this result:
Even easier than the foregoing, is this little script that does all you want!
#!/bin/bash
# Define our gold colour
#
gold="rgb(255,215,0)"
# Convert all pixels in the image that are gold +/-35% into red. Write output to "out.jpg"
# ... and also in text format so we can count the red pixels with "grep -c"
convert pcb.jpg -fuzz 35% -fill red -opaque "$gold" -depth 8 -colorspace rgb -write txt: out.jpg | grep -c FF0000
which produces this image, and the gold pixel count of 1076.

Visualization of Nelder-Mead algorithm in gnuplot

does anyone know how I can achieve drawing triangle on level sets of some 3d function (something like on this image in gnuplot? When I tried doing this after reading some tutorials:
gnuplot> set border 15 front linetype -1 linewidth 1.000
gnuplot> set logscale z 10
gnuplot> set view map
gnuplot> set isosamples 60, 60
gnuplot> unset surface
gnuplot> set contour base
gnuplot> unset clabel
gnuplot> set style data lines
gnuplot> set ticslevel 0
gnuplot> set noztics
gnuplot> set title "Trwa symulacja"
gnuplot> set xlabel "x"
gnuplot> set xrange [ * : * ] noreverse nowriteback
gnuplot> set ylabel "y"
gnuplot> set zlabel ""
gnuplot> set yrange [ * : * ] noreverse nowriteback
gnuplot> set zrange [ * : * ] noreverse nowriteback
gnuplot> splot [-10.5:10.5] [-10.5:10.5] x**2 +y**2 with lines lc rgb "#000000"
notitle,\
>'-' with lines notitle
input data ('e' ends) > 5.39703780733842 0.424994542694183 29.3086374551602
input data ('e' ends) > -4.80045950473308 -8.66307635892326 98.0933034571172
input data ('e' ends) > -3.56740563691939 3.31903046267993 23.7423461905216
input data ('e' ends) > 5.39703780733842 0.424994542694183 29.3086374551602
input data ('e' ends) > e
But I'm still getting warning: "Cannot contour non grid data. Please use "set dgrid3d".".
You need to have surface turned on for the whole splot and to turn it off for the parts where you don't want it. (You can't do it the other way round; the splot syntax only allows suppression of surfaces and not re-enabling them.)
# All the other settings you were using...
set surface
splot [-10.5:10.5] [-10.5:10.5] \
x**2 +y**2 with lines lc rgb "#000000" notitle nosurface, \
'-' with lines notitle
5.39703780733842 0.424994542694183 29.3086374551602
-4.80045950473308 -8.66307635892326 98.0933034571172
-3.56740563691939 3.31903046267993 23.7423461905216
5.39703780733842 0.424994542694183 29.3086374551602
e