Python 2.7.6 dictionaries
Question: I'm having a bit of trouble with Python 2.7.6, getting information from a
dictionary and doing something useful with it. I have attached my entire code
below, as I'm not sure what specifically is wrong, it might not be something
I'm expecting.

I am trying to generate some test data; a bunch of randomly distributed
sources (1's) across an image that move a small amount from their correct
positions. I track each source individually using dictionaries, and use
dictionaries within a dictionary for each image containing shifted sources.

My problem is when I want to take the average motion of the sources within an
image. I have made the spot I believe the problem to be in clear (about
halfway down). I have left in a few different techniques I have tried, they
are commented out. Currently I am only using 3 images, but I intend to
increase this number significantly. If I was sticking to only 3, I would have
gone with a different method and written a lot of this out the long way.

I've had a look for other questions like this but have not found anything
specific to my issue, which could be because I don't know the lingo for what
it is I am trying to do. Apologies if this has been asked before and solved.

    
    
    # Source position-offset tracker
    
    import math
    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.image as mpimg
    import copy
    import random
    from pylab import boxplot
    
     #FUNCTIONS
    
    
    def random_movement(source_positions):
        source_positions_changed={}
        for n in range(len(source_positions)): # n = [0,1]
            key = source_positions.keys()[n]
            del_x = source_positions[key][0]+random.randint(0,1)
            del_y = source_positions[key][1]+random.randint(0,1)
            source_positions_changed[key] = (del_x,del_y)
        return source_positions_changed
    
     #OTHER CODE
    
     # put in original positions
     # -> randomly distributed
     # -> of values 0 or 1 only
    
    original_positions = np.random.randint(2,size=(10,10))
    
    
    
     # Tag each source within the image to keep track of them
    source_positions = {}
    source_count=0
    for x in range(len(original_positions)):
        for y in range(len(original_positions[0])):
            if original_positions[x,y] == 1: # finding all sources
                source_count += 1
                index = 'S'+str(source_count)
                source_positions[index] = (x,y) 
                        # attach a source name to its position
    
    source_numbers = len(source_positions)
    number_timesteps = 2 # how many images were taken NOT including the original
    
     # create a dictionary for the timesteps of shifted sources
     # timesteps are the images where the sources have moves from the correct position
    dictionary = {}
    for x in range(1,number_timesteps+1):
        #exec('dictionary%s = copy.copy(random_movement(source_positions))'%x)
        dictionary['position_changed{0}'.format(x)] = copy.copy(random_movement(source_positions))
    
    
     # finding the distances from the sources original positions
     #source_distance_sum = {}
    
    #################################################
    ### THIS IS WHERE I THINK I'M HAVING PROBLEMS ###
    #################################################
    
    # this should take make the motion of any sources that appear outside the range of the image -1
    # and for sources that remain in range should find the motion from the correct position
    # using equation: a^2 = b^2 + c^2
    # should end up with source_distance_sum1 and source_distance_sum2 that have the motions from the correct positions of each source for the images, whose positional information was stored in dictionary['position_changed1'] and dictionary['position_changed2'] respectively
     #source_distance_sum=[]
    #distance_moved=[]
    for source in range(1,source_numbers+1):
        #source_distance_sum['S{0}'.format(source)]=0
        for tstep in range(1,number_timesteps+1):
            exec('source_distance_sum%s=[]'%tstep)
            if dictionary['position_changed{0}'.format(tstep)]['S{0}'.format(source)][0]>=len(original_positions) or dictionary['position_changed{0}'.format(tstep)]['S{0}'.format(source)][1]>=len(original_positions[0]):
            #if 'dictionary%s[S%s][0]>=len(original_positions) or dictionary%s[S%s][1]>=len(original_positions[0])'%(tstep,source,tstep,source)
                #source_distance_sum['S{0}'.format(source)]=-1
                exec('source_distance_sum%s.append(-1)'%tstep)
                #print 'if 1: '+str(source_distance_sum1)
                #print 'if 2: '+str(source_distance_sum2)
            # dealing with sources moved out of range
            else:
                distance_moved=np.sqrt((source_positions['S{0}'.format(source)][0]-dictionary['position_changed{0}'.format(tstep)]['S{0}'.format(source)][0])**2+(source_positions['S{0}'.format(source)][1]-dictionary['position_changed{0}'.format(tstep)]['S{0}'.format(source)][1])**2)
    # I have tried changing distance_moved as well, in similar ways to source_distance_sum, but I have as yet had no luck. 
                #source_distance_sum['S{0}'.format(source)]=distance_moved
                exec('source_distance_sum%s.append(distance_moved)'%tstep)
    # why does this not work!!!!????? I really feel like it should...
            # for movement that stays in range
                #print 'else 1: '+str(source_distance_sum1)
                #print 'else 2: '+str(source_distance_sum2)
    
    # then I want to use the information from the source_distance_sum1 & 2 and find the averages. I realise the following code will not work, but I cannot get the previous paragraph to work, so have not moved on to fixing the following. 
     # average distance:
    source_distance = []
    for source in range(1,len(source_distance_sum)+1):
        if source_distance_sum['S{0}'.format(source)] > -1:
            source_distance.append(source_distance_sum['S{0}'.format(source)])
    
    average = sum(source_distance)/float(len(source_distance))
    
     # set range of graph 
     #axx_max = np.ceil(max(distance_travelled))
     #axy_max = np.ceil(max(number_of_sources))
    
     # plot graph
    fig = plt.figure()
     #plt.axis([-1,axx_max+1,-1,axy_max+1])
    plt.xlabel('Data set')
    plt.ylabel('Average distance travelled')
    plt.title('There are %s source(s) with %s valid' % (source_count,len(source_distance)))
    
    ax1 = fig.add_subplot(111)
    ax1.scatter(1, average, s=10, c='b', marker="+", label='First timestep')
     #ax1.scatter(x[40:],y[40:], s=10, c='r', marker="o", label='second')
    plt.legend(loc='upper left');
    
    plt.show()
    
     # NOTES AND REMOVED CODE
    
     # Move sources around over time
     # -> keep within a fixed range of motion
     # -> randomly generate motion
    
     # Calculate motion of sources from images
     # -> ignore direction
     # -> all that move by same magnitude get stored together
     # -> Number of sources against magnitude of motion
    
     # Make dictionary of number of sources that have moved a certain amount. 
     #source_motion_count = {} # make length of sources, values all 0
     #for elem in range(len(source_distance)):
     #  if type(source_distance[elem])!=str and source_distance[elem]>-1:
     #      source_motion_count[source_distance[elem]] = 0
    
     #for elem in range(len(source_distance)):
     #  if type(source_distance[elem])!=str and source_distance[elem]>-1:
     #      source_motion_count[source_distance[elem]] += 1
    
     # Compile count of sources based on movement into graph
    
     #number_of_sources = []
     #distance_travelled = []
    
     #for n in range(len(source_motion_count)):
     #  key=source_motion_count.keys()[n]
     #  number_of_sources.append(source_motion_count[key])
     #  distance_travelled.append(key)
    


Answer: I fixed it by turning that section into its own function. I also changed my
mind on some of what I wanted it to do, so there is a little variation from
the original idea to what is below.

    
    
    import math
    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.image as mpimg
    import copy
    import random
    from pylab import boxplot
    
    #------------------------------------------------------------------------#
    #--------------------------FUNCTIONS-------------------------------------#
    #------------------------------------------------------------------------#
    
    def original_image():
        # create image
        original_positions = np.random.randint(2,size=(11,11))
        # make sure image has uneven lengths - will be useful later
        y = original_positions.shape[0]
        x = original_positions.shape[1]
        if y%2 == 0:
            y-=1
    
        if x%2 == 0:
            x-=1
    
        original_positions = original_positions[0:y,0:x]
        return original_positions
    
    def random_movement(source_positions):
        source_positions_changed={}
        # create some random movement in x and y axis, within a certain range
        for n in range(len(source_positions)):
            key = source_positions.keys()[n] # original source positions
            del_x = source_positions[key][0]+random.randint(-1,1)
            del_y = source_positions[key][1]+random.randint(-1,1)
            source_positions_changed[key] = (del_x,del_y)
        return source_positions_changed
    
    def tag_sources(original_positions):
        source_positions = {}
        source_count=0
        # keeping track of all the sources (1's) from original image
        for x in range(len(original_positions)):
            for y in range(len(original_positions[0])):
                if original_positions[x,y] == 1: # finding all sources
                    source_count += 1
                    index = 'S'+str(source_count)
                    source_positions[index] = (x,y) 
        return source_positions
    
    def calc_motion(position_dict_changed, position_dict_original,xaxis_len,yaxis_len):
        position_dict_motion = {}
        for source_num in range(1,len(position_dict_original)+1):
            # make sources that go outside the image range -1
            if position_dict_changed['S{0}'.format(source_num)][1]>=yaxis_len or position_dict_changed['S{0}'.format(source_num)][0]>=xaxis_len:
                position_dict_motion['S{0}'.format(source_num)] = -1
            else:
                # determine x and y motion from original position
                # this is the main difference from the original idea as do not want to average the motion
                x_motion = position_dict_original['S{0}'.format(source_num)][1] - position_dict_changed['S{0}'.format(source_num)][1]
                y_motion = position_dict_original['S{0}'.format(source_num)][0] - position_dict_changed['S{0}'.format(source_num)][0]
                position_dict_motion['S{0}'.format(source_num)] = (y_motion,x_motion)
        return position_dict_motion
    
    #------------------------------------------------------------------------#
    #--------------------------OTHER CODE------------------------------------#
    #------------------------------------------------------------------------#
    
    # creating random distribution of sources
    original_positions = original_image()
    
    orig_xaxis_len = len(original_positions[0])
    orig_yaxis_len = len(original_positions)
    
    # tag sources in original_positions
    source_positions = tag_sources(original_positions)
    
    source_numbers = len(source_positions)
    # how many images were taken NOT including the original
    number_timesteps = 2 
    
    # create a dictionary for the timesteps of shifted sources
    positions_dict = {}
    for x in range(1,number_timesteps+1):
        positions_dict['position_changed{0}'.format(x)] = copy.copy(random_movement(source_positions))
    
    # create a dictionary of the motion from the original position for each image
    for x in range(1,number_timesteps+1):
        motion_dict['position_changed{0}'.format(x)] = copy.copy(calc_motion(positions_dict['position_changed{0}'.format(x)],source_positions,orig_xaxis_len,orig_yaxis_len))
    
    
    print motion_dict
    

