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

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))

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:

Matlab 2017b heatmap, make zero values white

In Matlab 2017b, the default heapmap color ranges from light blue to dark blue. How can I make zero values white instead of light blue (it is difficult to distinguish between low numbers and zero in the current form).
cdata = [0 0.005 1; 1 0 0.0006; 0.4 0.20 0.1];
h = heatmap(cdata);
You can change the color map zero values to white by changing the colormap values by
map=colormap(heatmap(cdata));
map(1,:)=1;
And when plotting the figure map use the defined color map as follows
h = heatmap(cdata,'Colormap',map);

Label text truncated after increasing font size

I followed the procedures in this question, and also tried setting individual text object with larger fonts. Here is my sample code:
hf = figure;
set(hf, 'DefaultAxesFontSize', 14)
hx = axes('Parent',hf);
[hx,hp1,hp2] = plotyy(hx, rand(10,1),rand(10,1),rand(10,1),rand(10,1),'scatter');
hlx = xlabel(hx(1), 'Only half of this line show up');
hl1 = ylabel(hx(1), 'Not usually truncated but less border');
hl2 = ylabel(hx(2), 'Only part of this line show up');
ht = title(hx(1), 'Too close to border');
As can be seen in the picture, the labels get truncated by the border of the figure. I have to drag the figure to very large - contrary to desired - in order to reveal all text.
How can I automatically set the text box according to the text font size, so that even for small graphs they don't get cut?
I know I can do it manually by setting Position of the axes but it's kind of manual and guess-and-try. Is there any automatic way to calculate the margins?
One thing that can be done is to calculate increased margin according to new text font size. Assume we know Matlab's default font size is 10, or otherwise get it by get(hf,'DefaultAxesFontSize').
Then get the relative position of the axes by get(hx, 'Position'), which gives four percentage values. First two define left and bottom margin. Since it's for the labels, increasing the font size from 10 to 14 means the text box should grow by 1.4 times. The next two numbers define the size of the axis. Since text boxes on both sides grow by 1.4 times, assuming original size being x, then new size is 1-[(1-x)*1.4] = 1.4x - 0.4.
Suggested workaround:
hf = figure;
set(hf, 'DefaultAxesFontSize', 14)
hx = axes('Parent',hf);
set(hx, 'Position', [1.4 1.4 1.4 1.4].*get(hx, 'Position')+ [0 0 -.4 -.4])
[hx,hp1,hp2] = plotyy(hx, rand(10,1),rand(10,1),rand(10,1),rand(10,1),'scatter');
hlx = xlabel(hx(1), 'Only half of this line show up');
hl1 = ylabel(hx(1), 'Not usually truncated but less border');
hl2 = ylabel(hx(2), 'Only part of this line show up');
ht = title(hx(1), 'Too close to border');
You may replace the manually entered number 1.4 with the ratio between newly assigned (bigger, hopefully) font size and the original size which is 10.

Normalized units for annotations dont add up

I am creating a color map for data of size(7x24) that I have , lets replace it with some random numbers
b = randi(50,7,24);
t = imagesc(b,[min(min(b)) max(max(b))]);
now inorder to add annotations I have to know the exact starting and ending point of my axes so that i can add a rectangle to select each point in the image
xPOSITION = get(gca,'Position')
xPOSITION =
0.1300 0.1100 0.7750 0.8150
annotation('rectangle',[0.13 0.11 (0.7750 - 0.13)/24 (0.8150 -0.11)/7],'FaceColor','blue','FaceAlpha',.2)
ok now when i try to add an annotation to the exact starting point of the data , the starting point seem to be fine but the size of the rectangular which should actually be equal to each point is alot smaller
according to my calculation each box is equal to (0.7750 - 0.13)/24 X(0.8150 -0.11)/7 , because the units are normalized , am I doing any mistake in calculation ? or the annotation works in a different way ? any help would be highly appreciated
UPDATE just to test I added 0.11 to each dimension of the annotation and it seem to be the exact size for the reason i cannot figure out
annotation('rectangle',[0.13 0.11 ((0.7750 - 0.13) +0.11)/24 ((0.8150 -0.11)+0.11)/7],'FaceColor','blue','FaceAlpha',.2)
The Position property is the [left bottom width height] not [left bottom right top] as it seems that you're treating it (since you're subtracting element 1 from 3 and 2 from 4). To correctly compute the rect for displaying you'll just want to divide the width and height components by the number of elements in those dimensions.
annotation('rectangle', [xPOSITION(1), xPOSITION(2), ...
xPOSITION(3)/size(b, 2), xPOSITION(4) / size(b,1)])
Or more simply:
annotation('rectangle', xPOSITION ./ [1 1 fliplr(size(b))])
That being said, if you're simply wanting to draw rectangles on your data, you're likely better off just creating a rectangle object which is automatically in the units of your data
rectangle('Position', [0.5 6.5 1 1], 'LineWidth', 5)

Gnuplot, problems with dates on the x-axis

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)