Arrays
Arrays in numpy
- have elements all of the same type and occupy the same amount of storage, an element can be composed of other simple types,
- have a fixed size (cannot grow like lists),
- have a shape specified with a tuple, the tuple gives the size of each dimension,
- are indexed by integers.
A numpy array is very similar to arrays in static languages like C , Fortran, and Java. Arrays in numpy are multi-dimensional. Operation are arrays are, in general, faster than lists. Why?
Python meets APL.
Creating arrays
Arrays can be created with python sequences or initialized with constant values of 0 or 1, or uninitialized. Some of the array element types are byte, int, float, complex, uint8, uint16, uint64, int8, int16, int32, int64, float32, float64, float96, complex64, complex128, and complex192.
>>> from numpy import * >>> zeros( (12), dtype=int8 ) array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype=int8) >>> zeros( (2,6), dtype=int16 ) array([[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], dtype=int16) >>> ones( (6,2), dtype=int32 ) array([[1, 1], [1, 1], [1, 1], [1, 1], [1, 1], [1, 1]]) >>> ones( (2,2,3), dtype=int64 ) array([[[1, 1, 1], [1, 1, 1]], [[1, 1, 1], [1, 1, 1]]], dtype=int64) >>> a = ones( (2,3,2) ) >>> a.dtype # type of each element dtype('float64') >>> a.ndim # number of dimension 3 >>> a.shape # tuple of dimension sizes (2, 3, 2) >>> a.size # total number of elements 12 >>> a.itemsize # number of bytes of storage per element 8 >>> array( [ [1,2,3], [4,5,6] ] ) array([[1, 2, 3], [4, 5, 6]]) >>> a = _ >>> a.dtype dtype('int32') >>> a.shape (2, 3) >>> array( range(7), float ) array([ 0., 1., 2., 3., 4., 5., 6.]) >>> array( [ [ int(i != j) for j in xrange(3)] for i in xrange(4)] ) array([[0, 1, 1], [1, 0, 1], [1, 1, 0], [1, 1, 1]]) >>> _.shape (4, 3) >>> empty( (2,3), dtype=int16) # uninitialized, what advantage array([[ 344, 20318, -4920], [ 2644, 16, 0]], dtype=int16) >>>Reshaping arrays
Arrays in numpy can be reshaped. The reshaped array must be the same size. Why?
>>> from numpy import * >>> a = array( range(12) ) # equivalent to arange( 12, dtype=int) >>> a array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) >>> a.shape (12,) >>> b = a.reshape(2, 6) # b still refers to a's memory >>> a.shape (12,) >>> b.shape (2, 6) >>> a[6] = 106 # access 7th element >>> b # changes in a are reflected in b array([[ 0, 1, 2, 3, 4, 5], [106, 7, 8, 9, 10, 11]]) >>> a array([ 0, 1, 2, 3, 4, 5, 106, 7, 8, 9, 10, 11]) >>> b[1,0] = 6 # changes in b are reflected in a >>> b array([[ 0, 1, 2, 3, 4, 5], [ 6, 7, 8, 9, 10, 11]]) >>> a array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) >>> c = b.transpose() # swaps the indices order >>> c.shape (6, 2) >>> b[1,4] 10 >>> c[4,1] 10 >>>Indexing and slicing arrays
Arrays are indexed with comma separated list of indices. Unlike list, slices do not copy the array, but provide another view into the same data.
>>> from numpy import * >>> t = array( range(24), uint8 ) # unsigned 8 bit integer >>> t array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23], dtype=uint8) >>> t = t.reshape(2,3,4) >>> t array([[[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]], [[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]]], dtype=uint8) >>> t[0,0,0] # index = i*(3*4) + j*4 + k 0 >>> t[1,1,1] 17 >>> t[1,2,3] # the last index advances serially 23 >>> # the transpose reverse the order of the indices >>> s = t.transpose() >>> s.shape (4, 3, 2) >>> s[3,2,1] # index i + j*4 + k*(3*4) 23 >>> s[0,1,0] 4 >>> s[0,0,1] # the first index advances serially 12 >>> t1 = t[1,2] # partial indices return slices >>> t1 array([20, 21, 22, 23], dtype=uint8) >>> t1.shape (4,) >>> t1[0] = 100 # in numpy a slice is similar to a reshape >>> t # t1 references the same array array([[[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]], [[ 12, 13, 14, 15], [ 16, 17, 18, 19], [100, 21, 22, 23]]], dtype=uint8) >>> t = array( range(24), uint8 ) ; t = t.reshape(2,3,4) # reset >>> t[0,1] array([4, 5, 6, 7], dtype=uint8) >>> t[0,1] = 200 # assignment to slices changes all elements >>> t array([[[ 0, 1, 2, 3], [200, 200, 200, 200], [ 8, 9, 10, 11]], [[ 12, 13, 14, 15], [ 16, 17, 18, 19], [ 20, 21, 22, 23]]], dtype=uint8) >>>Multi-dimensional indexing
More than one dimension can be indexed.
>>> from numpy import * >>> z = zeros((5,5),int); z # 5 x 5 integers array([[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]) >>> z[0] = 1; z # first row array([[1, 1, 1, 1, 1], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]) >>> z[:,0] = 2; z # first column array([[2, 1, 1, 1, 1], [2, 0, 0, 0, 0], [2, 0, 0, 0, 0], [2, 0, 0, 0, 0], [2, 0, 0, 0, 0]]) >>> z[2:4,2:5] = 3; z # (2,3) block array([[2, 1, 1, 1, 1], [2, 0, 0, 0, 0], [2, 0, 3, 3, 3], [2, 0, 3, 3, 3], [2, 0, 0, 0, 0]]) >>> z[:,-1] = 4; z # last column array([[2, 1, 1, 1, 4], [2, 0, 0, 0, 4], [2, 0, 3, 3, 4], [2, 0, 3, 3, 4], [2, 0, 0, 0, 4]]) >>> z[-1,:] = 5; z # last row array([[2, 1, 1, 1, 4], [2, 0, 0, 0, 4], [2, 0, 3, 3, 4], [2, 0, 3, 3, 4], [5, 5, 5, 5, 5]]) >>>arithmetic, vector and matrix operation
The standard math operators can be used with numpy arrays. Matrix operations are also defined.
>>> from numpy import * >>> i = identity( 3, int16 ) >>> i array([[1, 0, 0], [0, 1, 0], [0, 0, 1]], dtype=int16) >>> i + i # add element to element array([[2, 0, 0], [0, 2, 0], [0, 0, 2]], dtype=int16) >>> i + 4 # add a scalar to every entry array([[5, 4, 4], [4, 5, 4], [4, 4, 5]], dtype=int16) >>> a = array( range(1,10), int16 ) # equiv to arange(1,10,dtype=int16):w >>> a = a.reshape(3,3) >>> i * a # element to element array([[1, 0, 0], [0, 5, 0], [0, 0, 9]], dtype=int16) >>> x = array( [1,2,3], int32 ) >>> x array([1, 2, 3]) >>> y = array( [ [4], [5], [6] ], int32 ) >>> y array([[4], [5], [6]]) >>> x + y array([[5, 6, 7], [6, 7, 8], [7, 8, 9]]) >>> array([4]) + array([1,2,3]) # one element with three array([5, 6, 7]) >>> # 1 and 2d arrays can be turned into matrices with mat() >>> # matrices redefine * to be dot >>> mx = mat(x) >>> mx.shape (1, 3) >>> my = mat(y) >>> my.shape (3, 1) >>> mx * my matrix([[32]]) >>> my * mx matrix([[ 4, 8, 12], [ 5, 10, 15], [ 6, 12, 18]]) >>>Relational operators
Relational operators are also defined for numpy arrays. An array of booleans is returned.
>>> from numpy import * >>> a = array([3,6,8,9]) >>> a == 6 array([False, True, False, False], dtype=bool) >>> a >= 7 array([False, False, True, True], dtype=bool) >>> a < 5 array([ True, False, False, False], dtype=bool) >>> # count all the even numbers >>> sum( (a%2) == 0 ) 2 >>> b = array([2,6,7,10]) >>> a == b array([False, True, False, False], dtype=bool) >>> a < b array([False, False, False, True], dtype=bool) >>> # any is true if any value is true >>> any( a == 3 ) True >>> any( a == 10 ) False >>> # all is true if all values are true >>> a == a array([ True, True, True, True], dtype=bool) >>> all( a == a ) True >>> all( a != b ) False >>>Indexing with boolean arrays
In addition to slices, a numpy array can be indexed with an equivalently shaped boolean array (i.e., their shape are the same).
>>> from numpy import * >>> a = arange(1, 13).reshape(3,4); a array([[ 1, 2, 3, 4], [ 5, 6, 7, 8], [ 9, 10, 11, 12]]) >>> i1 = (a % 2) == 1; i1 # odd entries array([[ True, False, True, False], [ True, False, True, False], [ True, False, True, False]], dtype=bool) >>> a[ i1 ] # select all the odd entries array([ 1, 3, 5, 7, 9, 11]) >>> i2 = (a >= 1) & (a < 4) ; i2 # and array([[ True, True, True, False], [False, False, False, False], [False, False, False, False]], dtype=bool) >>> a[ i2 ] # values greater than or equal to 1 and less than 4 array([1, 2, 3]) >>>Math functions
Most of the math functions can be used with numpy arrays. These functions are actually redefined. Some of the redefined math functions are: arccos, arcsin, arctan, arctan2, ceil, cos, cosh, degrees, exp, fabs, floor, fmod, frexp, hypot, ldexp, log, log10, modf, pow, radians, sin, sinh, sqrt, tan, and tanh.
>>> from numpy import * >>> t = linspace(0, pi, 7) # 7 values linearly between 0 and pi >>> sin(t) array([ 0.00000000e+00, 5.00000000e-01, 8.66025404e-01, 1.00000000e+00, 8.66025404e-01, 5.00000000e-01, 1.22460635e-16]) >>> arcsin( sin( t ) ) array([ 0.00000000e+00, 5.23598776e-01, 1.04719755e+00, 1.57079633e+00, 1.04719755e+00, 5.23598776e-01, 1.22460635e-16]) >>> floor( t ) array([ 0., 0., 1., 1., 2., 2., 3.]) >>> log( t + 1 ) # adding 1 avoids log(0) array([ 0. , 0.42107515, 0.71647181, 0.94421571, 1.12959244, 1.28591969, 1.42108041]) >>>array to scalar operators
numpy also defines operators that reduce the number of elements. These operators are: max, mean, min, std, sum, var.
>>> from numpy import * >>> s = random.standard_normal( 10 ) # mu = 0.0 sigma = 1.0 >>> s.shape (10,) >>> s array([ 0.65711932, -1.19741536, 1.51470124, 0.60134355, 1.44631555, 1.25936877, -1.347354 , 0.33819449, 0.35765847, 0.84350667]) >>> s.max() # all elements 1.51470124183 >>> s.min() -1.34735399976 >>> s.sum() # sum of all elements 4.47343871645 >>> s.prod() # product of all elements 0.179456818521 >>> s.mean() 0.447343871645 >>> s.std() # square root of variance 0.946962388091 >>> s.var() # variance 0.896737764459 >>>The operator can also select an axis (direction) for grouping the elements to be operated on.
>>> from numpy import * >>> a = array( [[4, -9, 5, 7], [100, -100, 50, 21], [20, 40, 0, 11]] ) >>> a array([[ 4, -9, 5, 7], [ 100, -100, 50, 21], [ 20, 40, 0, 11]]) >>> a.max() 100 >>> a.min() -100 >>> a.sum() 149 >>> a.min(0) # along the columns, varies last index array([ 4, -100, 0, 7]) >>> a.max(0) # along the columns array([100, 40, 50, 21]) >>> a.sum(0) # along the columns array([124, -69, 55, 39]) >>> a.min(1) # along the rows, varies first index array([ -9, -100, 0]) >>> a.max(1) # along the rows array([ 7, 100, 40]) >>> a.sum(1) # along the rows array([ 7, 71, 71]) >>>polynomials
Polynomials are supported by numpy. Some examples are:
>>> from numpy import * >>> p1 = poly1d([2.0,1.0]) # 2*x + 1, using coefficients >>> print p1 2 x + 1 >>> # using the polynomials roots >>> p1a = poly1d([-0.5],r=1) # p1(-0.5) = 0 >>> print p1a 1 x + 0.5 >>> # quadratic with roots (x-5)(x-3) >>> p2 = poly1d( [5.0, 3.0], r=1 ) >>> print p2 2 1 x - 8 x + 15 >>> # polynomials can be multiplied >>> p3 = poly1d([1.0,-5]) * poly1d([1.0,3.0]) >>> print p3 2 1 x - 2 x - 15 >>> # or added >>> poly1d([1.0,-5]) + poly1d([1.0,3.0]) poly1d([ 2., -2.]) >>> # or subtracted >>> poly1d([3.0,1.0,-5]) - poly1d([1.0,3.0]) poly1d([ 3., 0., -8.]) >>> # or division with remainder >>> quot, rem = poly1d([3.0,1.0,-5]) / poly1d([1.0,3.0]) >>> print quot 3 x - 8 >>> print rem 19 >>> # polynomials can be evaluated >>> p3(-3) 0.0 >>> p3(5) 0.0 >>> p3(1) -16.0 >>> # the polynomials roots are given by >>> p3.r array([ 5., -3.]) >>> # its coefficients >>> p3.c array([ 1., -2., -15.]) >>> # its order >>> p3.o 2 >>> # the first derivative >>> print p3.deriv() 2 x - 2 >>> print p3.deriv(1) 2 x - 2 >>> # the second derivative >>> print p3.deriv(2) 2 >>>Course record
The students records for a course is stored in the following csv file.
course.csv
Name, Assignments, Midterm1, Midterm2, Final A Student, 80, 65, 72, 74 B Student, 75, 52, 62, 64 C Student, 100, 70, 80, 80 D Student, 94, 45, 65, 55The weights for the term work, midterm 1, midterm 2, and the final is 10, 20, 20, and 50.
Course report
A report giving statistics on each work product, and the student's course grade is generated by:
course_report.py
#!/usr/bin/env python from numpy import * import csv # get head and names f = file( 'course.csv' ) reader = csv.reader( f ) headings = reader.next() # get student names students = [] for row in reader : students.append( row[0] ) f.close() # get workproducts, skipping name column f = file( 'course.csv' ) wps = loadtxt( f, delimiter=",", usecols=(1,2,3,4), skiprows=1 ) f.close() # value of each workproduct item value = array( [10., 20., 20., 50.] ) # report final mark print 'Course mark' marks = [] # save the marks for i, name in enumerate( students ) : mark = dot( value, wps[i]/100.0 ) marks.append( mark ) print "%-20s: %5.1f" % (name, mark) marks = array( marks ) # convert to array print "\n"*4 print 'Statistics' # report on statistics of each workproduct wp_names = headings[1:] for i, w in enumerate( wp_names ) : print w.strip() print ' minimum %6.2f' % wps[:,i].min() print ' maximum %6.2f' % wps[:,i].max() print ' mean %6.2f' % wps[:,i].mean() print ' std %6.2f' % wps[:,i].std() # generated histogram of As, Bs, Cs, Ds, Fs bins = array([0.0, 49.5, 54.5, 64.5, 79.5, 100.0] ) # F,D,C,B,A N,bins = histogram(marks,bins) N = list(N) # convert to list N.reverse() N.pop( 0 ) # discard overflow, XXX could check for letter,n in zip( "ABCDF", N) : print letter, nThe produced report is:
Command:
- Output:
python course_report.py Course mark A Student : 72.4 B Student : 62.3 C Student : 80.0 D Student : 58.9 Statistics Assignments minimum 75.00 maximum 100.00 mean 87.25 std 10.13 Midterm1 minimum 45.00 maximum 70.00 mean 58.00 std 9.97 Midterm2 minimum 62.00 maximum 80.00 mean 69.75 std 6.94 Final minimum 55.00 maximum 80.00 mean 68.25 std 9.55 A 1 B 1 C 2 D 0 F 0Conway's game of life
The games consists of an infinite board composed of a grid of squares. Each square can contain a zero or a one. Each square has eight neighbours, the next square connected either horizontally, vertically, or on a diagonal. Give a board configuration, the next configuration is determined by:
- A square with a 1 and fewer than two neighbours with a 1 is set to 0.
- A square with a 1 and more than three neighbours with a 1 is set to 0.
- A square with a 1 and two or three neighbours with a 1, remains set to 0.
- A square with a 0, and exactly three neighbours with a 1 is set to a 0.
Conway's game of life in numpy
Conway's game can be easily implemented with numpy's array operations. A bounded implementation (i.e., the board is not infinite) where the borders are always zero is realized by:
simple_life.py
#!/usr/bin/env python from numpy import * # compute next generation of conway's game of life def next_generation( current, next ) : next[:,:] = 0 # zero out next board # bound examination area bend0 = (current.shape[0]-3)+1 bend1 = (current.shape[1]-3)+1 for i in xrange( bend0 ) : for j in xrange( bend1 ) : neighbours = sum( current[i:i+3, j:j+3] ) if current[i+1, j+1] == 1 : neighbours -= 1 # do not count yourself if 2 <= neighbours <= 3 : next[i+1, j+1] = 1 else: if neighbours == 3 : next[i+1,j+1] = 1 board = zeros( (5,5), uint8) next_board = zeros_like( board ) # same shape # create inital configuration board[2,1:4] = 1 # 3 squares for i in xrange(4) : next_generation( board, next_board ) board, next_board = next_board, board # swap boards print board[1:-1,1:-1]Four generation of this configuration yeilds:
Command:
- Output:
python simple_life.py [[0 1 0] [0 1 0] [0 1 0]] [[0 0 0] [1 1 1] [0 0 0]] [[0 1 0] [0 1 0] [0 1 0]] [[0 0 0] [1 1 1] [0 0 0]]Game of life with user input
An input string of ones and zeros can be used to initialize the board. This version is identical to the previous version with the exception of the command line arguments.
life.py
#!/usr/bin/env python from numpy import * import sys import math # compute next generation of conway's game of life def next_generation( current, next ) : next[:,:] = 0 # zero out next board # bound examination area bend0 = (current.shape[0]-3)+1 bend1 = (current.shape[1]-3)+1 for i in xrange( bend0 ) : for j in xrange( bend1 ) : neighbours = sum( current[i:i+3, j:j+3] ) if current[i+1, j+1] == 1 : neighbours -= 1 # do not count yourself if 2 <= neighbours <= 3 : next[i+1, j+1] = 1 else: if neighbours == 3 : next[i+1,j+1] = 1 if len(sys.argv) != 3 : print "usage:", sys.argv[0], "init-board generations" sys.exit( 1 ) init = sys.argv[1] generations = int( sys.argv[2] ) board_sz = math.ceil( math.sqrt(len(init)) ) # board_sz+2 includes the border of zeros board = zeros( (board_sz+2,board_sz+2), uint8) next_board = zeros_like( board ) # same shape # fill the board i = 0 j = 0 for index,ch in enumerate(init) : if ch == '1' : board[i+1,j+1] = 1 j = (j+1) % board_sz if ((index+1) % board_sz) == 0 : i += 1 for gen in xrange(generations) : next_generation( board, next_board ) board, next_board = next_board, board # swap boards print board[1:-1,1:-1] # do not print the borderSolving 2 unknowns with 2 linear equations
>>> from numpy import * >>> from numpy.linalg import solve >>> >>> # 1 * x0 - 2 * x1 = 1 >>> # 2 * x0 - 6 * x1 = -2 >>> a = array( [[1,-2], [2,-6]] ) >>> b = array( [1, -2 ] ) >>> x = solve( a, b ); x array([ 5., 2.]) >>> dot( a, x ) # check solution array([ 1., -2.]) >>>Solving 2 unknowns with 2 linear equations (2)
>>> from numpy import * >>> from numpy.linalg import solve >>> >>> # 1 * x0 - 2 * x1 = 1 >>> # 2 * x0 - 4 * x1 = 2 >>> # any problems with the above equations >>> a = array( [[1,-2], [2,-4]] ) >>> b = array( [1, 2 ] ) >>> x = solve( a, b ) Traceback (most recent call last): File "<console>", line 1, in <module> File "/usr/lib/python2.5/site-packages/numpy/linalg/linalg.py", line 184, in solve raise LinAlgError, 'Singular matrix' LinAlgError: Singular matrix >>>Solving 3 unknowns with 3 linear equations
>>> from numpy import * >>> from numpy.linalg import solve >>> from numpy.linalg import inv >>> >>> # 1 * x0 - 2 * x1 + 5 * x2 = 1 >>> # 2 * x0 - 6 * x1 - 10 *x2 = -2 >>> #-4 * x0 + 1 * x1 + 3 * x2 = 3 >>> a = array( [[1, -2, 5], [2,-6,-10], [-4,1,3] ] ) >>> b = array( [1, -2, 3 ] ) >>> x = solve( a, b ); x array([-0.64516129, -0.25806452, 0.22580645]) >>> dot( a, x ) # check solution array([ 1., -2., 3.]) >>> >>> # a * x = b >>> # inv(a) * a * x = inv(a) * b >>> # I * x = inv(a) * b >>> # x = inv(a) * b >>> x = dot( inv(a), b ); x array([-0.64516129, -0.25806452, 0.22580645]) >>> # the identity >>> dot( inv(a), a) array([[ 1.00000000e+00, 5.55111512e-17, 2.77555756e-17], [ -2.77555756e-17, 1.00000000e+00, 1.24900090e-16], [ 6.93889390e-18, -1.90819582e-17, 1.00000000e+00]]) >>> dot( a, inv(a)) array([[ 1.00000000e+00, 5.55111512e-17, 1.56125113e-17], [ -2.77555756e-17, 1.00000000e+00, 5.20417043e-17], [ 1.38777878e-17, 1.38777878e-17, 1.00000000e+00]]) >>>2D line segment intersection
Many geometric problems are solved using vector notation. Intesection of lines can be solved with:
lines.py
# # line segment intersection using vectors # see Computer Graphics by F.S. Hill # from numpy import * def perp( a ) : b = empty_like(a) b[0] = -a[1] b[1] = a[0] return b # line segment a given by endpoints a1, a2 # line segment b given by endpoints b1, b2 # return def seg_intersect(a1,a2, b1,b2) : da = a2-a1 db = b2-b1 dp = a1-b1 dap = perp(da) denom = dot( dap, db) num = dot( dap, dp ) return (num / denom)*db + b1 p1 = array( [0.0, 0.0] ) p2 = array( [1.0, 0.0] ) p3 = array( [4.0, -5.0] ) p4 = array( [4.0, 2.0] ) print seg_intersect( p1,p2, p3,p4) p1 = array( [2.0, 2.0] ) p2 = array( [4.0, 3.0] ) p3 = array( [6.0, 0.0] ) p4 = array( [6.0, 3.0] ) print seg_intersect( p1,p2, p3,p4)Its sample execution is:
Command:
- Output:
python lines.py [ 4. 0.] [ 6. 4.]Points on circle "without" sin/cos
All the points around a circle can be generated with matrix operations. Multiplication is usually cheaper than calculationg sin or cos.
circle.py
from numpy import * import math # sin/cos just once a = math.cos( math.radians(-30.0) ) b = math.sin( math.radians(-30.0) ) # rotation matrix, 30 degrees clockwise R = mat( [[a, -b], [b, a]] ) v = mat( [1,0] ) # unit vector along x-axis print "Repeated rotations by 30" # rotate (1,0) by 30 degree increments for i in xrange(12) : nv = v * R vx,vy = v.T # transpose x = math.cos( math.radians(30.0 * i ) ) y = math.sin( math.radians(30.0 * i ) ) print "%12.9f %12.9f -- %12.9f %12.9f" % (vx,vy, x,y) v = nv print print "Rotation by multiples of 30" # rotate (1,0) by 30, 60, 90, ... for i in xrange(12) : r = v * pow(R,i) vx,vy = r.T # transpose x = math.cos( math.radians(30.0 * i ) ) y = math.sin( math.radians(30.0 * i ) ) print "%12.9f %12.9f -- %12.9f %12.9f" % (vx,vy, x,y)The points are:
Command:
- Output:
python circle.py Repeated rotations by 30 1.000000000 0.000000000 -- 1.000000000 0.000000000 0.866025404 0.500000000 -- 0.866025404 0.500000000 0.500000000 0.866025404 -- 0.500000000 0.866025404 0.000000000 1.000000000 -- 0.000000000 1.000000000 -0.500000000 0.866025404 -- -0.500000000 0.866025404 -0.866025404 0.500000000 -- -0.866025404 0.500000000 -1.000000000 0.000000000 -- -1.000000000 0.000000000 -0.866025404 -0.500000000 -- -0.866025404 -0.500000000 -0.500000000 -0.866025404 -- -0.500000000 -0.866025404 -0.000000000 -1.000000000 -- -0.000000000 -1.000000000 0.500000000 -0.866025404 -- 0.500000000 -0.866025404 0.866025404 -0.500000000 -- 0.866025404 -0.500000000 Rotation by multiples of 30 1.000000000 -0.000000000 -- 1.000000000 0.000000000 0.866025404 0.500000000 -- 0.866025404 0.500000000 0.500000000 0.866025404 -- 0.500000000 0.866025404 0.000000000 1.000000000 -- 0.000000000 1.000000000 -0.500000000 0.866025404 -- -0.500000000 0.866025404 -0.866025404 0.500000000 -- -0.866025404 0.500000000 -1.000000000 0.000000000 -- -1.000000000 0.000000000 -0.866025404 -0.500000000 -- -0.866025404 -0.500000000 -0.500000000 -0.866025404 -- -0.500000000 -0.866025404 -0.000000000 -1.000000000 -- -0.000000000 -1.000000000 0.500000000 -0.866025404 -- 0.500000000 -0.866025404 0.866025404 -0.500000000 -- 0.866025404 -0.500000000
转载于:https://www.cnblogs.com/lexus/archive/2012/12/08/2808454.html