I have a code that creates a 3D array of values
from a minimum to a maximum in X and Z with constant Y

Right now I make it in normal python, and then I transform it
in a `np.array`, is there a way to make it directly a numpy array?
how can I translate the code in numpy to make it faster ?

    targets = []
    
    X = Y = 0
    STEP_X = 0.1
    STEP_Y = 0.2
    MIN_X = X
    
    for i in range (1000):
        for j in range (1000):
    
            targets = targets + [[X, Y, Z]]
            X += STEP_X
    
        X = MIN_X
        Z += STEP_Z
    
    # Make it a np.array
    targets = np.array(targets)



EDIT:

Now that this part is optimized (I didn't chnage the code yet but I will in a few hours), I have a larger code with another problem of vectorization, any help would be appreciated!



In my code, I used the symbol `#___________PART TO BE VECTORIZED` to highlight the slow parts.

This code is an already optimized version of something 5 times slower that I wrote before:

- It takes a list of colors in the CIE XYZ colorspace 
- calculates the sRGB color values of the XYZ colors
- generates a convex hull of the colors by Delaunay tetrahedralization 
- then creates a list of `targets`, checks if the targets are inside the hull 
- and finally generates a dithered SVG file containing a grid of circles (sRGB colors, random dither)

The two parts I could'nt find a way to vectorize with numpy are: 

- the loop where I generate the `targets`

- and the loop where I associate RGB colors with a random dither algorithm at the end


Could you please have a look and orient me towards a better optimization? 

Thanks


PS, the `import GEO` is a module of mine to write a SVG file, it is documenter after the main code, bottom of this page.

    '''
    Created on 12 juin 2014
    
    @author: gary
    thanks to a lot of help by Gareth Rees:
    http://codereview.stackexchange.com/questions/41024/faster-computation-of-barycentric-coordinates-for-many-points
    http://codereview.stackexchange.com/questions/41316/python-numpy-optimize-module-to-handle-big-file
    '''
    import GEO
    import numpy as np
    import scipy.spatial
    
    #___________________________________________________________
    #__________FUNCTIONS________________________________________
    
    def iround(x):
        """iround(number) -> integer
        Round a number to the nearest integer.
        http://www.daniweb.com/software-development/python/threads/299459/round-to-nearest-integer"""
        return int(round(x) - .5) + (x > 0)
    
    
    def XYZ2sRGB(X,Y,Z):
        """transforms CIE XYZ tristimulus values
        into sRGB values with gamma = 2.4"""
    
        X = float(X)
        Y = float(Y)
        Z = float(Z)
        
        var_X = X / 100        #X from 0 to  95.047      (Observer = 2deg, Illuminant = D65)
        var_Y = Y / 100        #Y from 0 to 100.000
        var_Z = Z / 100        #Z from 0 to 108.883
        
        var_R = var_X *  3.2406 + var_Y * -1.5372 + var_Z * -0.4986
        var_G = var_X * -0.9689 + var_Y *  1.8758 + var_Z *  0.0415
        var_B = var_X *  0.0557 + var_Y * -0.2040 + var_Z *  1.0570
        
        if ( var_R > 0.0031308 ): 
            var_R = 1.055 * ( var_R ** ( 1 / 2.4 ) ) - 0.055
        else:                     
            var_R = 12.92 * var_R
        if ( var_G > 0.0031308 ): 
            var_G = 1.055 * ( var_G ** ( 1 / 2.4 ) ) - 0.055
        else:                     
            var_G = 12.92 * var_G
        if ( var_B > 0.0031308 ): 
            var_B = 1.055 * ( var_B ** ( 1 / 2.4 ) ) - 0.055
        else:                     
            var_B = 12.92 * var_B
        
        R = var_R * 255
        if (R > 255):
            R = 255
        if (R < 0):
            R = 0
        
        G = var_G * 255
        if (G > 255):
            G = 255
        if (G < 0):
            G = 0
        
        B = var_B * 255 
        if (B > 255):
            B = 255
        if (B < 0):
            B = 0
            
        return iround(R), iround(G), iround(B)
    
    #________________________________________________________________
    #__________CODE__________________________________________________
    
    
    # Configuration
    POINTS_FILENAME = 'colors.csv'
    
    
    # Load XYZ tristimulus colors values
    XYZ = np.loadtxt(POINTS_FILENAME, usecols=(2,3,4), delimiter=',')
    print "XYZ colors loaded"
    
    # Load color names
    colornames = np.loadtxt(POINTS_FILENAME, usecols=(1,), delimiter=',',
                            converters={0:lambda s:s.split()}, dtype=np.str)
    print "colornames loaded"
    
    # Make sRGB values of XYZ tristimulus colors values
    sRGB = []
    
    for i in range(len(XYZ)):
        
        rgb = XYZ2sRGB(XYZ[i][0],XYZ[i][1],XYZ[i][2])
        sRGB = sRGB + [rgb]
    
    # Make it a np.array
    sRGB = np.array(sRGB)
    print "sRGB colors computed"
    
    # Encode XYZ color of the support
    SUPPORT = np.array([86.83449926, 90.41826972, 101.2739682])
    
    
    # Average XYZ colors with a weighted amount of support 
    # Parameters
    SUPPORT_AMOUNT   = .3333333333333
    REST             = 1 - SUPPORT_AMOUNT
    SUPPORT_WEIGHTED = np.multiply(SUPPORT, SUPPORT_AMOUNT)
    XYZ_WEIGHTED     = np.multiply(XYZ, REST)
    
    # Resulting list of points
    XYZplusSUPPORT   = np.add(SUPPORT_WEIGHTED, XYZ_WEIGHTED)
    
    
    # Compute Delaunay tetrahedralization of the new points
    tri = scipy.spatial.Delaunay(XYZplusSUPPORT, furthest_site=False) 
    
    # indices of vertices
    indices = tri.simplices
    
    # vertices for each tetrahedron
    vertices = XYZplusSUPPORT[indices]
    print "tetrahedralization OK"
    
    # Make XYZ target values
    
    # Limits of the cube containing XYZ+SUPPORT values
    MIN_X, MAX_X   = np.min(XYZplusSUPPORT[:,0]), np.max(XYZplusSUPPORT[:,0])
    MIN_Z, MAX_Z   = np.min(XYZplusSUPPORT[:,2]), np.max(XYZplusSUPPORT[:,2])
    
    # custom limits
    print "custom limits for X/Z? (Y+ENTER)"
    
    INFO = raw_input()
    
    if INFO == 'Y':
        print 'MIN_X'
        MIN_X = float(raw_input())
        print 'MAX_X'
        MAX_X = float(raw_input())
        print 'MIN_Y'
        MIN_Y = float(raw_input())
        print 'MAX_Y'
        MAX_Y = float(raw_input())
    
    
    # Target Y
    #87.618, 76.303, 66, 56.681, 48.278, 40.749, 34
    Y = 34
    X, Z = MIN_X, MIN_Z
    
    # Size of the canvas to project targets
    SIZE_X, SIZE_Z = 48, 54
    
    # Diameter of points of color, and frequency of the grid
    DIAM = .15
    FREQ = DIAM + (np.sqrt(np.pi)*(DIAM+((DIAM*np.sqrt(REST)-DIAM*REST)/REST))-2*DIAM)/2 
    
    # Amount of steps on the canvas
    STEPS_X = SIZE_X/FREQ
    STEPS_Z = SIZE_Z/FREQ
    
    # Range of axis X and axis Z
    RANGE_X = MAX_X - MIN_X
    RANGE_Z = MAX_Z - MIN_Z
    
    # Size of a step in the colorspace
    XYZ_STEP_X = RANGE_X/STEPS_X
    XYZ_STEP_Z = RANGE_Z/STEPS_Z
    
    # integer rounded amount of steps
    ROUND_X = iround(STEPS_X+1)
    ROUND_Z = iround(STEPS_Z+1)
    
    # Targets container
    targets = []
    
    # Make targets
    # _________PART TO BE VECTORIZED______
    for i in range (ROUND_Z+1):
        for j in range (ROUND_X+1):
            
            targets = targets + [[X, Y, Z]]
            X += XYZ_STEP_X
            
        X = MIN_X
        Z += XYZ_STEP_Z
    
    # Make it a np.array
    targets = np.array(targets)
    print "targets OK"
    
    # Find the tetrahedron containing each target (or -1 if not found)
    tet = tri.find_simplex(targets)
    
    # Affine transformation for tetrahedron containing each target
    U = tri.transform[tet, :3]
    
    # Offset of each target from the origin of its containing tetrahedron
    V = targets - tri.transform[tet, 3] 
    
    # Barycentric coordinates of each target in its tetrahedron.
    b = np.einsum('ijk,ik->ij', U, V)
    bcoords = np.c_[b, 1 - b.sum(axis=1)]
    print "bcoords OK"
    
    
    # Get the sRGB color corresponding to each vertex 
    C = sRGB[tri.simplices]

    
    
    # A uniform random number in [0, 1] for each target.
    RAND = np.random.uniform(0, 1, size=(len(targets)))
    print "random OK"
    
    # SVG file header
    FILENAME = str(Y)+'.svg'
    GEO.header(FILENAME, SIZE_X, SIZE_Z)
    
    
    # Transpose the targets in Centimeters
    TARGETS_CM_X = np.subtract(targets[:,0], MIN_X)
    TARGETS_CM_X = np.divide(TARGETS_CM_X, RANGE_X)
    TARGETS_CM_X = np.multiply(TARGETS_CM_X, SIZE_X)
    
    TARGETS_CM_Z = np.subtract(targets[:,2], MIN_Z)
    TARGETS_CM_Z = np.divide(TARGETS_CM_Z, RANGE_Z)
    TARGETS_CM_Z = np.multiply(TARGETS_CM_Z, SIZE_Z)
    
    print "target transposed to cm"
    
    #_________________________________________
    # PART TO BE VECTORIZED
    
    for i in range(len(tet)):
         
        if(tet[i] != -1):
     
            R = RAND[i]
             
            x = TARGETS_CM_X[i]
            z = TARGETS_CM_Z[i]
            
            if R <= bcoords[i][0]:
                R,G,B = C[tet][i][0][0], C[tet][i][0][1], C[tet][i][0][2]
                
            elif R <= bcoords[i][0]+bcoords[i][1]:
                R,G,B = C[tet][i][1][0], C[tet][i][1][1], C[tet][i][1][2]
                
            elif R <= bcoords[i][0]+bcoords[i][1]+bcoords[i][2]:
                R,G,B = C[tet][i][2][0], C[tet][i][2][1], C[tet][i][2][2]
                
            else:
                R,G,B = C[tet][i][3][0], C[tet][i][3][1], C[tet][i][3][2]
    
     
            GEO.DISC(FILENAME, x, z, DIAM/2, R, G, B)
    
    GEO.END(FILENAME)
     
    print "file written"



The `GEO` module:

    def header(filename,Xmax,Ymax):
    """ header of a SVG file"""
  
            Xmax = float(Xmax)
            Ymax = float(Ymax)
            
            # SVG Header 
            f = open(str(filename), "w")
            f.write('<svg version="1.1"'+'\n')
            f.write('    baseProfile="full"'+'\n')
            f.write('    width="'+ str(Xmax*1/2.54*72) + '" '+'height="'+ str(Ymax*1/2.54*72) +'"'+'\n')
            f.write('    xmlns="http://www.w3.org/2000/svg">'+'\n')
            f.close()
            print "header written, filename is:", filename
            return None
        
    def DISC(filename,x,y,radius, R, G, B):
                '''
                circle path in a SVG file
                x,y = center of the disk
                http://stackoverflow.com/questions/5737975/circle-drawing-with-svgs-arc-path
                '''
        
                radius = radius*1/2.54*72
                f = open(str(filename), "a")
                f.write('<path d="M'+str(x*1/2.54*72)+" "+str(y*1/2.54*72)+" \n") #moveto
                f.write('    m '+str(-radius)+ ',0 \n')
                f.write('    a '+str(radius)+','+str(radius)+ ' 0 1,0 ' + str(radius*2)+',0 \n')
                f.write('    a '+str(radius)+','+str(radius)+ ' 0 1,0 ' + str(-radius*2)+',0 \n')      
                f.write('    " fill = "rgb('+str(R)+','+str(G)+','+str(B)+')"/> \n')
                f.close()
                return None
            
    def END(filename):
    """ closing the svg file"""

                f = open(str(filename), "a")
                f.write('</svg>')
                f.close()
                return None