GnuplotDraw.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. import os
  2. class GnuplotDraw:
  3. line_colors = {'red': 1, 'green': 2, 'blue': 3, 'cyan': 5,
  4. 'magenta': 4, 'aqua': 5, 'purple': 4,
  5. 'yellow': 7, 'black': -1}
  6. def __init__(self, xmin, xmax, ymin, ymax, axis=False,
  7. instruction_file=None):
  8. """
  9. Define the drawing area [xmin,xmax]x[ymin,ymax].
  10. axis: None or False means that axes with tickmarks
  11. are not drawn.
  12. instruction_file: name of file where all the instructions
  13. are recorded.
  14. """
  15. self.xmin, self.xmax, self.ymin, self.ymax = \
  16. float(xmin), float(xmax), float(ymin), float(ymax)
  17. self.axis = axis
  18. # Compute the right X11 geometry on the screen based on the
  19. # x-y ratio of axis ranges
  20. ratio = (self.ymax-self.ymin)/(self.xmax-self.xmin)
  21. self.xsize = 500
  22. self.ysize = 500*ratio
  23. geometry = '%dx%d' % (self.xsize, self.ysize)
  24. self.g = os.popen('gnuplot -geometry %s -persist' % geometry, 'w')
  25. if instruction_file is not None:
  26. # Collect all commands in __call__ in a file
  27. self.instruction_file = open(instruction_file, 'w')
  28. else:
  29. self.instruction_file = None
  30. if not axis:
  31. self("unset xtics; unset ytics\n")
  32. self("set xrange[%g:%g]; set yrange[%s:%s]\n" %
  33. (xmin, xmax, ymin, ymax))
  34. self("set size square") # equal aspect ratio
  35. self.erase()
  36. self.file_counter = 0
  37. self.set_linecolor('red')
  38. self.set_linewidth(2)
  39. self.filled_curves(False)
  40. def set_linecolor(self, color):
  41. """Change the color of lines."""
  42. self.linecolor = GnuplotDraw.line_colors[color]
  43. def set_linewidth(self, width):
  44. """Change the line width (int, starts at 1)."""
  45. self.linewidth = width
  46. def filled_curves(self, on=True):
  47. """Fill area inside curves with current line color."""
  48. self.filledcurves = on
  49. def erase(self):
  50. """Erase the current figure."""
  51. # Don't set self.counter=0 here because that will overwrite
  52. # older files being plotted by Gnuplot.
  53. self.plot_commands = []
  54. def define_curve(self, x, y):
  55. """Define a curve with coordinates x and y (arrays)."""
  56. self.file_counter += 1
  57. filename = '.tmp_%04d' % self.file_counter
  58. f = open(filename, 'w')
  59. for xi, yi in zip(x, y):
  60. f.write('%g %g\n' % (xi, yi))
  61. f.close()
  62. if self.filledcurves:
  63. with_value = 'filledcurves'
  64. else:
  65. with_value = 'lines'
  66. self.plot_commands.append('"%s" with %s title "" lt %s lw %s' %
  67. (filename, with_value, self.linecolor, self.linewidth))
  68. def display(self):
  69. """Display the figure."""
  70. if not self.plot_commands:
  71. return
  72. # The set output command is important because if hardcopy is
  73. # called and output is set to a file, a new set term x11 will
  74. # overwrite the file with empty content (see the resulting
  75. # set of commands to realize how PNG and x11 plots are made
  76. # in sequence).
  77. plotcommand = 'set output; set term x11; plot ' + \
  78. ', '.join(self.plot_commands) + '\n'
  79. self(plotcommand)
  80. #self('pause 2\n')
  81. def hardcopy(self, name):
  82. """Save figure in PNG file name.png."""
  83. # Ratio is preserved by setting size 10cm,10cm for example
  84. # (at least this works for postscript)
  85. # Important: just running replot will not work if not display
  86. # is called so we make the full plot command here.
  87. plotcommand = 'plot ' + ', '.join(self.plot_commands) + '\n'
  88. self("""
  89. set term png small size %d,%d
  90. set output "%s.png"
  91. %s
  92. """% (self.xsize, self.ysize, name, plotcommand))
  93. def text(self, text, position, alignment='center', fontsize=18):
  94. """
  95. Write text at a position (centered, left, right - according
  96. to the alignment string). position is a 2-tuple.
  97. """
  98. self('set label "%s" at %s,%s %s font "Helvetica,%d" front; replot\n' %
  99. (text, position[0], position[1], alignment, fontsize))
  100. def length_symbol(self, start, stop, symbol):
  101. #Divide arrow into two pieces, a textbox in the middle.
  102. #set arrow from 0,0 to 2,3 linewidth 1 heads
  103. #set label "..." at x,y center rotate by <degrees> font "Times,18" front
  104. pass
  105. def __call__(self, command):
  106. if self.instruction_file is not None:
  107. self.instruction_file.write(command)
  108. self.g.write(command)
  109. self.g.flush()