Search code examples
gnuplot

Generation of pie chart using gnuplot


I have a CSV file with data like:

name,age
raju,23
anju,34
manju,56
sanju,56

I'm trying to generate a pie chart using gnuplot. Here's the command I'm executing:

#!/usr/bin/gnuplot -persist
reset
set terminal wxt
unset key
set datafile separator ","
set xlabel "USERS"
set ylabel "AGE"

plot 'file.csv' using ($0):2:($0):xticlabels(1) with circles lc variable notitle

What am I doing wrong?


Solution

  • Apparently, Gnuplot does not support pie charts yet; but we can draw it by hand.

    First, we need to obtain the angles and percentages related to the second column in your datafile:

    set datafile separator ','
    stats 'file.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
    

    Then configure the canvas:

    set size square                 # square canvas
    set xrange [-1:1.5]
    set yrange [-1.25:1.25]
    set style fill solid 1
    
    unset border
    unset tics
    unset key
    

    and draw the pie chart:

    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
    
    plot 'file.csv' u (0):(0):(1):(Ai):(Ai=Ai+ang($2)):(i=i+1) with circle linecolor var,\
         'file.csv' u (1.5):(yi=yi+0.5/STATS_records):($1) w labels,\
         'file.csv' u (1.3):(yi2=yi2+0.5/STATS_records):(j=j+1) w p pt 5 ps 2 linecolor var,\
         'file.csv' u (mid=Bi+ang($2)*pi/360.0, Bi=2.0*mid-Bi, 0.5*cos(mid)):(0.5*sin(mid)):(sprintf('%.0f (%.1f\%)', $2, perc($2))) w labels
    

    The first line in the plot command draws the pie chart, where the columns (0):(0):(1):(Ai):(Ai=Ai+ang($2)):(i=i+1) are:

    • columns 1-2: x and y coordinates of the center of the disk
    • column 3: radius of the disk
    • column 4-5: begin and end angles of the region
    • column 6: color of the region

    The second and third lines in the plot command place the labels, and the last line puts the percentages in the middle of each region.

    The result: Pie chart in Gnuplot

    References: (1) Gnuplot surprising (2) Gnuplot tricks


    EDIT:

    Based on two related questions (this and this), a new script is proposed:

    filename = 'test.csv'
    
    rowi = 1
    rowf = 7
    
    # obtain sum(column(2)) from rows `rowi` to `rowf`
    set datafile separator ','
    stats filename u 2 every ::rowi::rowf noout prefix "A"
    
    # rowf should not be greater than length of file
    rowf = (rowf-rowi > A_records - 1 ? A_records + rowi - 1 : rowf)
    
    angle(x)=x*360/A_sum
    percentage(x)=x*100/A_sum
    
    # circumference dimensions for pie-chart
    centerX=0
    centerY=0
    radius=1
    
    # label positions
    yposmin = 0.0
    yposmax = 0.95*radius
    xpos = 1.5*radius
    ypos(i) = yposmax - i*(yposmax-yposmin)/(1.0*rowf-rowi)
    
    #-------------------------------------------------------------------
    # now we can configure the canvas
    set style fill solid 1     # filled pie-chart
    unset key                  # no automatic labels
    unset tics                 # remove tics
    unset border               # remove borders; if some label is missing, comment to see what is happening
    
    set size ratio -1              # equal scale length
    set xrange [-radius:2*radius]  # [-1:2] leaves space for labels
    set yrange [-radius:radius]    # [-1:1]
    
    #-------------------------------------------------------------------
    pos = 0             # init angle
    colour = 0          # init colour
    
    # 1st line: plot pie-chart
    # 2nd line: draw colored boxes at (xpos):(ypos)
    # 3rd line: place labels at (xpos+offset):(ypos)
    plot filename u (centerX):(centerY):(radius):(pos):(pos=pos+angle($2)):(colour=colour+1) every ::rowi::rowf w circle lc var,\
         for [i=0:rowf-rowi] '+' u (xpos):(ypos(i)) w p pt 5 ps 4 lc i+1,\
         for [i=0:rowf-rowi] filename u (xpos):(ypos(i)):(sprintf('%05.2f%% %s', percentage($2), stringcolumn(1))) every ::i+rowi::i+rowi w labels left offset 3,0
    

    This new code results in: new plot