Differences between ePiX and Pyepix =================================== * The picture size variables in ePiX are functions in Pyepix: x_min ==> x_min() x_max ==> x_max() y_min ==> y_min() y_max ==> y_max() x_size ==> x_size() y_size ==> y_size() * ePiX macros without parentheses do have parentheses (i.e., are function calls) in Python. Thus: red; (In C) red() (In Python) Note that as of ePiX 0.8.9, these have been changed from macros to functions so there is no difference between ePiX and Python. * The pair and triple types are implemented and are accepted anywhere a 2-tuple or 3-tuple are. For example: In C: line(P(0,1), P(3,5)) In Python: epix.line( (0,1), (3,5) ) epix.line(P(0,1),P(3,5) ) Both are equally valid, although the tuples have less overhead and will be faster. The benefit of using the P(,) object is that it has dot-product, Kronecker product, etc. semantics defined, as do pairs in ePiX. Python tuples do not. Have a look at epix.py for more details on the implementation. Note especially that P() is a factory function that returns either a Pair() object or Triple() object, depending upon whether it is called with a 2-tuple or 3-tuple. There are lots of ways of constructing pairs. The following are equivalent: P(0,1) # Initialized from components, calls Pair(0,1) Pair(0,1) # Calling the class initializer directly P( (0,1) ) # Initialized from 2-tuple P( P(0,1) ) # Initialized from another Pair object P( 0+1j ) # Initialized from complex number The triple type is called Triple, and may be constructed in the same way as Pair() objects, but not with complex numbers: P(1,2,3) Triple(1,2,3) P( (1,2,3) ) P( P(1,2,3) ) To see the penalty for using the high-level operations on pairs and triples, have a look at the slopefield.py and flow-plot.py sample files (in the samples directory). You can choose (using an if-statement) between two versions of the same functions. One use high-level operations on Pair objects, the other expands them out to tuples. There is a big speed difference in the implementations. These are the only two sample files, however, that have a noticeable performance penalty. It is up to you to decide how to trade off the expressive power of pairs and triples against performance. * Python doesn't know a function's return type ahead of time. For this reason, different function names are used when a pair-valued or triple-valued function is used in some routines. For example, the 'plot' function can either be called (in C) as: plot(f1, f2, f3, ...) or plot(triple f, ...) where 'f' returns a triple. In Python there is: plot(f1, f2, f3, ...) plot_triple(f, ...) The new name 'plot_triple' is used to indicate that the Python function 'f' returns a length-3 sequence instead of a simple floating-point number. Functions so affected are: plot_pair plot_triple adplot_pair clipplot_pair clipplot_triple multiplot1_pair wiremesh_triple tan_line_pair envelope_pair tan_field_pair slope_field_pair dart_field_pair vector_field_pair ode_plot_pair flow_plot_pair sliceplot1_pair sliceplot2_pair plot_R_triple frontplot_R_triple backplot_R_triple * The various constants (like CIRC, and rt (label position)) defined by ePiX are available as constants in the Python module. For example: import epix epix.marker( (1,-1), epix.OPLUS ) epix.label( (4,0), (2,4), "t", epix.tr ) or from epix import * marker( (1,-1), OPLUS ) label( (4,0), (2,4), "t", tr ) * ePiX functions that take function parameters (like 'plot') take Python callable function parameters in Pyepix. See 'samples/weierstrass.py' for an example, or just about any other sample file in the samples directory. When a C function is expected to return a pair, the Python function must return something that looks like a pair: a 2-tuple, a Pair object, a complex number. Same goes for triples...the function must return a 3-tuple or a Triple object. As mentioned above, staying away from formal Pair and Triple objects greatly improves speed. Otherwise, Python functions are expected to return floating-point scalars. * ePiX functions which take function parameters (like 'plot') are not thread safe. In a multi-threaded Python program, you must ensure that no more than one such ePiX function is active at the same time. There are various ways around this (define a global lock, implement thread-local-storage) but none of this seems to be worth it given the intended uses of ePiX. If you really really have a valid use for Pyepix in a threaded environment, let me know! * Some functions formally take an integer as an argument, but Pyepix allows them to take a float so that, for example, the common idiom: h_axis(P(x_min(), 0), P(x_max(), 0), 2*x_size()) works correctly. In this example, x_size() is a floating-point value but the last parameter of h_axis is an integer. Internally, Pyepix rounds the last parameter to the nearest integer before calling the ePiX library function. The only functions that are NOT float-tolerant are those which require an integer to indicate some constant, like CIRC (essentially, enumerations), or for which non-integers just don't make sense (like gcd). * The ePiX integer-valued abs() function is not implemented as it conflicts with the (more useful) abs() built-in Python function. Note that as of ePiX version 0.8.7, the ePiX abs() function has been removed so this change is invisible as of the 0.8.7 version. * In the contrib module, the CartesianStyle structure is implemented as a class. Instead of calling initCartesianStruct() (which doesn't exist in Pyepix) you simply instantiate an object of the class. For example: In C++: struct CartesianStyle cs; initCartesianStruct(&cs); In Python: cs = CartesianStyle() You still call the cartesianCoord() function as usual, passing it the cs object, to create the Cartesian grid. Most of the fields of the CartesianStyle object are as expected. For example: cs.xn = 6 cs.x1 = -2 The xlabels and ylabels fields must be sequences of strings: cs.xlabels = ('12', '13, '14') cs.ylabels = ["-1", "", "1", "2"] Note that there is NO NULL TERMINATOR required, as there is in C++. You may continue to use the constants CENTER, ABOVE, BELOW, LEFT, RIGHT for positions: import epix cs.xmrkpos = epix.ABOVE * In the contrib module, the hatch_polygon() function has a calling convention that is slightly different from C++: In C++: hatch_polygon(v, d, n, pair1, pair2, pair3, ...) In Python: hatch_polygon(v, d, [pair1, pair2, pair3, ...]) Note that you need not specify the number of polygon corners as it is deduced from the length of the list of pairs.