@@ -116,7 +116,8 @@ class gnuplotlib has a gnuplot process associated with it, which has (usually) a
116116 plot, the axis labels, the extents, 2d/3d selection, etc. All the plot options
117117 are described below in "Plot options".
118118
119- - Curve options: parameters that affect only a single curve
119+ - Curve options: parameters that affect only a single curve. Each is described
120+ below in "Curve options".
120121
121122** Data arguments
122123
@@ -224,6 +225,69 @@ class gnuplotlib has a gnuplot process associated with it, which has (usually) a
224225colors plotted with an implicit domain, set tuplesize=3 as before (x,y,color),
225226but pass in only 2 arrays (y, color).
226227
228+ ** Symbolic equations
229+
230+ Gnuplot can plot both data and equations. This module exists largely for the
231+ data-plotting case, but sometimes it can be useful to plot equations together
232+ with some data. This is supported by the 'equation' plot option. This plot
233+ option is either a string (for a single equation) or a list/tuple containing
234+ multiple strings for multiple equations. Note that plotting only equations
235+ without data is not supported (and generally is better done with gnuplot
236+ directly). An example:
237+
238+ #+BEGIN_SRC python
239+ import numpy as np
240+ import numpy.random as nr
241+ import numpy.linalg
242+ import gnuplotlib as gp
243+
244+ # generate data
245+ x = np.arange(100)
246+ c = np.array([1, 1800, -100, 0.8]) # coefficients
247+ m = x[:, np.newaxis] ** np.arange(4) # 1, x, x**2, ...
248+ noise = 1e4 * nr.random(x.shape)
249+ y = np.dot( m, c) + noise # polynomial corrupted by noise
250+
251+ c_fit = np.dot(numpy.linalg.pinv(m), y) # coefficients obtained by a curve fit
252+
253+ # generate a string that describes the curve-fitted equation
254+ fit_equation = '+'.join( '{} * {}'.format(c,m) for c,m in zip( c_fit.tolist(), ('x**0','x**1','x**2','x**3')))
255+
256+ # plot the data points and the fitted curve
257+ gp.plot(x, y, _with='points', equation = fit_equation)
258+ #+END_SRC
259+
260+ Here I generated some data, performed a curve fit to it, and plotted the data
261+ points together with the best-fitting curve. Here the best-fitting curve was
262+ plotted by gnuplot as an equation, so gnuplot was free to choose the proper
263+ sampling frequency. And as we zoom around the plot, the sampling frequency is
264+ adjusted to keep things looking nice.
265+
266+ Note that the various styles and options set by the other options do NOT apply
267+ to these equation plots. Instead, the string is passed to gnuplot directly, and
268+ any styling can be applied there. For instance, to plot a parabola with thick
269+ lines, you can issue
270+
271+ #+BEGIN_SRC python
272+ gp.plot( ....., equation = 'x**2 with lines linewidth 2')
273+ #+END_SRC
274+
275+ As before, see the gnuplot documentation for details. You can also do fancy
276+ things:
277+
278+ #+BEGIN_SRC python
279+ x = np.arange(100, dtype=float) / 100 * np.pi * 2;
280+ c,s = np.cos(x), np.sin(x)
281+
282+ gp.plot( c,s,
283+ square=1, _with='points',
284+ set = ('parametric', 'trange [0:2*3.14]'),
285+ equation = "sin(t),cos(t)" )
286+ #+END_SRC
287+
288+ Here the data are points evently spaced around a unit circle. Along with these
289+ points we plot a unit circle as a parametric equation.
290+
227291** Interactivity
228292
229293The graphical backends of Gnuplot are interactive, allowing the user to pan,
@@ -306,6 +370,13 @@ class gnuplotlib has a gnuplot process associated with it, which has (usually) a
306370
307371These specify axis labels
308372
373+ - equation
374+
375+ This option allows equations represented as formula strings to be plotted along
376+ with data passed in as numpy arrays. This can be a string (for a single
377+ equation) or an array/tuple of strings (for multiple equations). See the
378+ "Symbolic equations" section above.
379+
309380- hardcopy
310381
311382Instead of drawing a plot on screen, plot into a file instead. The output
@@ -717,7 +788,7 @@ class gnuplotlib has a gnuplot process associated with it, which has (usually) a
717788knownPlotOptions = frozenset (('3d' , 'dump' , 'ascii' , 'log' ,
718789 'cmds' , 'set' , 'unset' , 'square' , 'square_xy' , 'title' ,
719790 'hardcopy' , 'terminal' , 'output' ,
720- 'with' ,
791+ 'with' , 'equation' ,
721792 'xmax' , 'xmin' , 'xrange' , 'xinv' , 'xlabel' ,
722793 'y2max' , 'y2min' , 'y2range' , 'y2inv' , 'y2label' ,
723794 'ymax' , 'ymin' , 'yrange' , 'yinv' , 'ylabel' ,
@@ -974,8 +1045,13 @@ def _getPlotOptionsCmds(self):
9741045 self .plotOptions ['output' ] = outputfile
9751046
9761047
977- if 'terminal' in self .plotOptions and not 'output' in self .plotOptions :
978- sys .stderr .write ('Warning: defined gnuplot terminal, but NOT an output file. Is this REALLY what you want?\n ' )
1048+ if 'terminal' in self .plotOptions :
1049+ if self .plotOptions ['terminal' ] in ('x11' , 'wxt' , 'qt' , 'aquaterm' ):
1050+ if 'output' in self .plotOptions :
1051+ sys .stderr .write ("Warning: requested a known-interactive gnuplot terminal AND an output file. Is this REALLY what you want?\n " )
1052+ else :
1053+ if not 'output' in self .plotOptions :
1054+ sys .stderr .write ("Warning: requested a gnuplot terminal (not a known-interactive one), but NOT an output file. Is this REALLY what you want?\n " )
9791055
9801056 # add the extra global options
9811057 if 'cmds' in self .plotOptions :
@@ -1323,6 +1399,13 @@ def getTestDataLen(curve):
13231399 if self .plotOptions .get ('3d' ): basecmd += 'splot '
13241400 else : basecmd += 'plot '
13251401
1402+ # send all equations
1403+ if 'equation' in self .plotOptions :
1404+ if isinstance (self .plotOptions ['equation' ], (list , tuple )):
1405+ basecmd += '' .join ( eq + ', ' for eq in self .plotOptions ['equation' ])
1406+ else :
1407+ basecmd += self .plotOptions ['equation' ] + ', '
1408+
13261409 plotCurveCmds = []
13271410 plotCurveCmdsMinimal = [] # same as above, but with a single data point per plot only
13281411 testData = '' # data to make a minimal plot
0 commit comments