Plot coordinate pairs

From Rosetta Code
Revision as of 16:46, 13 November 2009 by A (talk | contribs) (→‎{{header|Python}}: added inline figure thumbnail)
Task
Plot coordinate pairs
You are encouraged to solve this task according to the task description, using any language you may know.

Plot a function represented as `x', `y' numerical arrays.

Post link to your resulting image for input arrays (see Example section for Python language on Query Performance page):

x = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
y = {2.7, 2.8, 31.4, 38.1, 58.0, 76.2, 100.5, 130.0, 149.3, 180.0};

This task is intended as a subtask for Measure relative performance of sorting algorithms implementations.

C

We could use the suite provided by Raster graphics operations, but those functions lack a facility to draw text.

Library: libplot

<lang c>#include <stdio.h>

  1. include <stdlib.h>
  2. include <math.h>
  3. include <plot.h>
  1. define NP 10

double x[NP] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; double y[NP] = {2.7, 2.8, 31.4, 38.1, 58.0, 76.2, 100.5, 130.0, 149.3, 180.0};

void minmax(double *x, double *y, double *minx, double *maxx, double *miny, double *maxy, int n) {

 int i;
 *minx = *maxx = x[0];
 *miny = *maxy = y[0];
 for(i=1; i < n; i++) {
   if ( x[i] < *minx ) *minx = x[i];
   if ( x[i] > *maxx ) *maxx = x[i];
   if ( y[i] < *miny ) *miny = y[i];
   if ( y[i] > *maxy ) *maxy = y[i];
 }

}

/* likely we must play with this parameter to make the plot looks better

  when using different set of data */
  1. define YLAB_HEIGHT_F 0.1
  2. define XLAB_WIDTH_F 0.2
  3. define XDIV (NP*1.0)
  4. define YDIV (NP*1.0)
  5. define EXTRA_W 0.01
  6. define EXTRA_H 0.01
  7. define DOTSCALE (1.0/150.0)
  1. define MAXLABLEN 32
  1. define PUSHSCALE(X,Y) pl_fscale((X),(Y))
  2. define POPSCALE(X,Y) pl_fscale(1.0/(X), 1.0/(Y))
  3. define FMOVESCALE(X,Y) pl_fmove((X)/sx, (Y)/sy)

int main() {

 int plotter, i;
 double minx, miny, maxx, maxy;
 double lx, ly;
 double xticstep, yticstep, nx, ny;
 double sx, sy;
 
 char labs[MAXLABLEN+1];
 plotter = pl_newpl("png", NULL, stdout, NULL);
 if ( plotter < 0 ) exit(1);
 pl_selectpl(plotter);
 if ( pl_openpl() < 0 ) exit(1);
 /* determines minx, miny, maxx, maxy */
 minmax(x, y, &minx, &maxx, &miny, &maxy, NP);
 lx = maxx - minx;
 ly = maxy - miny;
 pl_fspace(floor(minx) - XLAB_WIDTH_F * lx, floor(miny) - YLAB_HEIGHT_F * ly,

ceil(maxx) + EXTRA_W * lx, ceil(maxy) + EXTRA_H * ly);

 /* compute x,y-ticstep */
 xticstep = (ceil(maxx) - floor(minx)) / XDIV;
 yticstep = (ceil(maxy) - floor(miny)) / YDIV;
 pl_flinewidth(0.25);
 /* compute scale factors to adjust aspect */
 if ( lx < ly ) {
   sx = lx/ly;
   sy = 1.0;
 } else {
   sx = 1.0;
   sy = ly/lx;
 }
 pl_erase();
 /* a frame... */
 pl_fbox(floor(minx), floor(miny),

ceil(maxx), ceil(maxy));

 /* labels and "tics" */
 pl_fontname("HersheySerif");
 for(ny=floor(miny); ny < ceil(maxy); ny += yticstep) {
   pl_fline(floor(minx), ny, ceil(maxx), ny);
   snprintf(labs, MAXLABLEN, "%6.2lf", ny);
   FMOVESCALE(floor(minx) - XLAB_WIDTH_F * lx, ny);
   PUSHSCALE(sx,sy);
   pl_label(labs);
   POPSCALE(sx,sy);
 }
 for(nx=floor(minx); nx < ceil(maxx); nx += xticstep) {
   pl_fline(nx, floor(miny), nx, ceil(maxy));
   snprintf(labs, MAXLABLEN, "%6.2lf", nx);
   FMOVESCALE(nx, floor(miny));
   PUSHSCALE(sx,sy);
   pl_ftextangle(-90);
   pl_alabel('l', 'b', labs);
   POPSCALE(sx,sy);
 }
 /* plot data "point" */
 pl_fillcolorname("red");
 pl_filltype(1);
 for(i=0; i < NP; i++)
 {
   pl_fbox(x[i] - lx * DOTSCALE, y[i] - ly * DOTSCALE,
           x[i] + lx * DOTSCALE, y[i] + ly * DOTSCALE);
 }
 pl_flushpl();
 pl_closepl();

}</lang>

No one would use the previous code to produce a plot (that looks this way; instead, normally we produce data through a program, then we plot the data using e.g. gnuplot or other powerful tools; the result (with gnuplot and without enhancement) could look like this instead.

gnuplot

Example gnuplot output

<lang gnuplot>unset key # Only one data set, so the key is uninformative

plot '-' # '-' can be replaced with a filename, to read data from that file.

 0   2.7
 1   2.8
 2  31.4
 3  38.1
 4  68.0
 5  76.2
 6 100.5
 7 130.0
 8 149.3
 9 180.0

e</lang>


J

Library: plot
   load 'plot'
   magnitudes =: 2.7 2.8 31.4 38.1 58.0 76.2 100.5 130.0 149.3 180.0
   'dot; pensize 2.4' plot magnitudes

Output of plot.

Mathematica

<lang Mathematica>

x={0,1,2,3,4,5,6,7,8,9};
y={2.7,2.8,31.4,38.1,58.0,76.2,100.5,130.0,149.3,180.0};
ListPlot[{x, y} // Transpose]

</lang> Output: [1]

Maxima

(%i1) ".." (m, n) := makelist (i, i, m, n); infix ("..")$
(%i2) x: 0 .. 9$ y:[2.7, 2.8, 31.4, 38.1, 58.0, 76.2, 100.5, 130.0, 149.3, 180.0]$
(%i3) plot2d(['discrete, x, y], [style, [points,5,1,1]], [gnuplot_term, png], [gnuplot_out_file, "qsort-range-10-9.png"])$

qsort-range-10-9.png

OCaml

<lang ocaml>#load "graphics.cma" open Graphics

let round x = int_of_float (floor(x +. 0.5))

let x = [0; 1; 2; 3; 4; 5; 6; 7; 8; 9] and y = [2.7; 2.8; 31.4; 38.1; 58.0; 76.2; 100.5; 130.0; 149.3; 180.0]

let () =

 open_graph "";
 List.iter2
   (fun x y ->
     (* scale to fit in the window *)
     let _x = x * 30
     and _y = round(y *. 2.0) in
     plot _x _y)
   x y;
 ignore(wait_next_event [Key_pressed]);
 close_graph();
</lang>

Octave

<lang octave>x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; y = [2.7, 2.8, 31.4, 38.1, 58.0, 76.2, 100.5, 130.0, 149.3, 180.0]; plot(x,y,"o"); pause;</lang>

Perl

<lang perl>

use GD::Graph::points;

@data = (
  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
  [2.7, 2.8, 31.4, 38.1, 58.0, 76.2, 100.5, 130.0, 149.3, 180.0],
);
$graph = GD::Graph::points->new(400, 300);
$gd = $graph->plot(\@data) or die $graph->error;

# Save as image.
open(OUF, ">qsort-range-10-9.png");
binmode OUF;
print OUF $gd->png;
close(OUF);

</lang>

Library: Imager

<lang perl>

use Imager;
use Imager::Plot;

@x = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
@y = (2.7, 2.8, 31.4, 38.1, 58.0, 76.2, 100.5, 130.0, 149.3, 180.0);
$plot = Imager::Plot->new(
  'Width' => 400,
  'Height' => 300,
  'GlobalFont' => 'PATH_TO_TTF_FONT',
);
$plot->AddDataSet(
  'X' => \@x,
  'Y' => \@y,
  'style' => {
    'marker' => {
      'size' => 2,
      'symbol' => 'circle',
      'color' => Imager::Color->new('red'),
    },
  },
);
$img = Imager->new(
  'xsize' => 500,
  'ysize' => 400,
);
$img->box('filled' => 1, 'color' => 'white');
$plot->Render('Image' => $img, 'Xoff' => 50, 'Yoff' => 350);
$img->write('file' => 'qsort-range-10-9.png');

</lang>

Python

Library: matplotlib
matplotlib plot of x,y arrays
>>> x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> y = [2.7, 2.8, 31.4, 38.1, 58.0, 76.2, 100.5, 130.0, 149.3, 180.0]
>>> import pylab
>>> pylab.plot(x, y, 'bo')
>>> pylab.savefig('qsort-range-10-9.png')

qsort-range-10-9.png (23 KiB)

R

R has several different plotting paradigms. First we define the data. <lang R> x <- c(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) y <- c(2.7, 2.8, 31.4, 38.1, 58.0, 76.2, 100.5, 130.0, 149.3, 180.0) </lang>

Base graphics

<lang R> plot(x,y) </lang>

Lattice/grid graphics

Library: lattice

<lang R> library(lattice) xyplot(y~x) </lang>

Grammar of graphics

Library: ggplot2

<lang R> library(ggplot2) qplot(x,y) </lang>

Tcl

Library: Tk
Library: Img

This solution does not use existing plotting packages, but constructs the graphics from bare-metal Tk code. <lang Tcl>package require Tk

  1. The actual plotting engine

proc plotxy {canvas xs ys} {

   global xfac yfac
   set maxx [tcl::mathfunc::max {*}$xs]
   set maxy [tcl::mathfunc::max {*}$ys]
   set xfac [expr {[winfo width $canvas] * 0.8/$maxx}]
   set yfac [expr {[winfo height $canvas] * 0.8/$maxy}]
   scale $canvas x 0 $maxx $xfac
   scale $canvas y 0 $maxy $yfac
   foreach x $xs y $ys {
       dot $canvas [expr {$x*$xfac}] [expr {$y*$yfac}] -fill red
   }

}

  1. Rescales the contents of the given canvas

proc scale {canvas direction from to fac} {

   set f [expr {$from*$fac}]
   set t [expr {$to*$fac}]
   switch -- $direction {
       x {
           set f [expr {$from * $fac}]
           set t [expr {$to * $fac}]
           $canvas create line $f 0 $t 0
           $canvas create text $f 0 -anchor nw -text $from
           $canvas create text $t 0 -anchor n -text $to
           
       }
       y {
           set f [expr {$from * -$fac}]
           set t [expr {$to * -$fac}]
           $canvas create line 0 $f 0 $t
           $canvas create text 0 $f -anchor se -text $from
           $canvas create text 0 $t -anchor e -text $to
       }
   }

}

  1. Helper to make points, which are otherwise not a native item type

proc dot {canvas x y args} {

   set id [$canvas create oval [expr {$x-3}] [expr {-$y-3}] \
               [expr {$x+3}] [expr {-$y+3}]]
   $canvas itemconfigure $id {*}$args

}

pack [canvas .c -background white] update set xs {0 1 2 3 4 5 6 7 8 9} set ys {2.7 2.8 31.4 38.1 58.0 76.2 100.5 130.0 149.3 180.0} plotxy .c $xs $ys .c config -scrollregion [.c bbox all] .c move all 20 20

  1. Save image (this is the only part that requires an external library)

package require Img set im [image create photo -data .c] $im write plotxy.png -format PNG</lang> Of course, if we were generating an encapsulated postscript version, we would be able to do that directly.

TI-89 BASIC

TI-89 screenshot
FnOff
PlotsOff
NewPlot 1, 1, x, y
ZoomData

Ursala

Ursala doesn't plot anything directly, but has libraries to generate LaTeX code for 2D and 3D graphics. The output file has to be run through LaTeX or included into a LaTeX document. Here's the way to do it just as a quick check (all default settings and dots connected with straight lines). <lang Ursala>

  1. import std
  2. import flo
  3. import fit
  4. import plo

x = <0., 1., 2., 3., 4., 5., 6., 7., 8., 9.> y = <2.7, 2.8, 31.4, 38.1, 58.0, 76.2, 100.5, 130.0, 149.3, 180.0>

  1. output dot'tex' latex_document+ plot

main = visualization[curves: <curve[points: ~&p/x y]>] </lang> (output)

Here's one way you might do it if you were interested in publication quality graphics. The dots are connected with a cubic spline interpolating function sampled at 200 points, and the axes are nicely labeled.

<lang Ursala> main =

visualization[

  abscissa: axis[
     variable: 'problem size',
     hats: printf/*'%0.0f' ari10/0. 9.],
  ordinates: ~&iNC axis[
     variable: 'execution time ($\mu$s)',
     hats: printf/*'%0.1f' ari6/0. 180.],
  curves: <
     curve[
        points: ^(~&,chord_fit0@p/x y)* ari200/0. 9.,
        attributes: {'linecolor': 'lightgray'}],
     curve[
        scattered: true,
        points: ~&p/x y,
        attributes: {'linecolor': 'black'}]>]

</lang> (output)