################################################################################
################################################################################
##                                                                            ##
##  Plotter.py                                                                ##
##                                                                            ##
##      This is a collection of routines designed to plot the dictionary      ##
##      object generated by the Parser.py routines.  There are many different ##
##      parameter combinations possible, so there may need to be many         ##
##      independent array combination routines.                               ##
##                                                                            ##
################################################################################
################################################################################

import scipy
import cPickle as pickle
import copy
import pylab
from mpl_toolkits.mplot3d import Axes3D

#   Module constants
MEASUREMENT_INFO_FILE = 'TrialArrayDic.pkl'

R = 0
SZ = 1
SZ2 = 2
SIZSCZ = 3
SIPSCM = 4
SIMSCP = 5
SIDOTSC = 6

LABEL_DIC = {
R:'$R$',
SZ:'$S_i^z$',
SZ2:'$(S_i^z)^2$',
SIPSCM:'$S_i^+S_c^-$',
SIMSCP:'$S_i^-S_c^+$',
SIZSCZ:'$S_i^zS_c^z$',
SIDOTSC:'$S_i \cdot S_c$'
}

TEX_LABEL_DIC = {
R:'$R$',
SZ:'$\left \langle S_i^z \\right \\rangle$',
SZ2:'$\left \langle (S_i^z)^2 \\right \\rangle$',
SIPSCM:'$\left \langle S_i^+S_c^- \\right \\rangle$',
SIMSCP:'$\left \langle S_i^-S_c^+ \\right \\rangle$',
SIZSCZ:'$\left \langle S_i^zS_c^z \\right \\rangle$',
SIDOTSC:'$\left \langle S_i \cdot S_c \\right \\rangle$'
}

BEST_GEN = {
(1.0, -10.0, 1.0, 0.0): 16,
(1.0, -10.0, 1.0, 1.0): 17,
(1.0, -0.95, 1.0, 0.0): 16,
(1.0, -0.9, 1.0, 0.0): 16,
(1.0, -0.85, 1.0, 0.0): 16,
(1.0, -0.8, 1.0, 0.0): 17,
(1.0, -0.75, 1.0, 0.0): 17,
(1.0, -0.7, 1.0, 0.0): 17,
(1.0, -0.65, 1.0, 0.0): 17,
(1.0, -0.6, 1.0, 0.0): 17,
(1.0, -0.55, 1.0, 0.0): 17,
(1.0, -0.5, 1.0, 10.0): 20,
(1.0, -0.5, 1.0, 0.0): 16,
(1.0, -0.45, 1.0, 0.0): 8,
(1.0, -0.4, 1.0, 0.0): 5,
(1.0, -0.35, 1.0, 0.0): 6,
(1.0, -0.3, 1.0, 0.0): 6,
(1.0, -0.25, 1.0, 0.0): 6,
(1.0, -0.20, 1.0, 0.0): 4,
(1.0, -0.15, 1.0, 0): 4,
(1.0, -0.1, 1.0, 0.0): 10,
(1.0, -0.09, 1.0, 0.0): 7,
(1.0, -0.05, 1.0, 0.0): 5,
(1.0, -0.05, 1.0, 0.5): 6,
(1.0, -0.01, 1.0, 0.0): 4,
(1.0, 0.0, 1.0, -10.0): 4,
(1.0, 0.0, 1.0, -1.0): 2,
(1.0, 0.01, 1.0, -1.0): 4,
(1.0, 0.01, 1.0, 0.0): 2,
(1.0, 0.01, 1.0, 1.0): 4,
(1.0, 0.05, 1.0, 0.0): 4,
(1.0, 0.1, 1.0, 0.0): 4,
(1.0, 0.1, 1.0, 1.0): 15,
(1.0, 0.15, 1.0, 0.0): 4,
(1.0, 0.20, 1.0, 0.0): 7,
(1.0, 0.25, 1.0, 0.0): 4,
(1.0, 0.30, 1.0, 0.0): 4,
(1.0, 0.6, 1.0, 0.0): 6,
(1.0, 0.65, 1.0, 0.0): 4,
(1.0, 0.7, 1.0, 0.0): 17,
(1.0, 0.75, 1.0, 0.0): 17,
(1.0, 0.80, 1.0, 0.0): 17,
(1.0, 0.85, 1.0, 0.0): 17,
(1.0, 0.9, 1.0, 0.0): 17,
(1.0, 0.9, 1.0, 1.0): 15,
(1.0, 0.91, 1.0, 0.0): 17,
(1.0, 0.92, 1.0, 0.0): 17,
(1.0, 0.93, 1.0, 0.0): 17,
(1.0, 0.94, 1.0, 0.0): 17,
(1.0, 0.95, 1.0, 0.0): 17,#9,
(1.0, 0.95, 1.0, 1.0): 17,
(1.0, 0.96, 1.0, 0.0): 17,
(1.0, 0.96, 1.0, 1.0): 7,
(1.0, 0.97, 1.0, 0.0): 4,#7,
(1.0, 0.98, 1.0, 0.0): 17,
(1.0, 0.99, 1.0, 0.0): 17,
(1.0, 0.99, 1.0, 1.0): 9,
(1.0, 0.995, 1.0, 0.0): 17,
(1.0, 0.995, 1.0, 1.0): 4,
(1.0, 1.0, 1.0, -10.0): 4,
(1.0, 1.0, 1.0, -1.0): 3,   
(1.0, 1.0, 1.0, -0.01): 5,
(1.0, 1.0, 1.0, 0.0): 13,#4,
(1.0, 1.0, 1.0, 0.01): 13,
(1.0, 1.0, 1.0, 0.1): 17,
(1.0, 1.0, 1.0, 1.0): 9,
(1.0, 1.0, 1.0, 10.0): 15,
(1.0, 1.005, 1.0, 0.0): 17,
(1.0, 1.01, 1.0, 0.0): 17,
(1.0, 1.01, 1.0, 1.0): 4,
(1.0, 1.02, 1.0, 0.0): 13,
(1.0, 1.03, 1.0, 0.0): 15,#12,
(1.0, 1.04, 1.0, 0.0): 16,#12,
(1.0, 1.05, 1.0, 0.0): 16,#12,
(1.0, 1.06, 1.0, 0.0): 16,#12,
(1.0, 1.07, 1.0, 0.0): 16,#12,
(1.0, 1.08, 1.0, 0.0): 15,#12,
(1.0, 1.09, 1.0, 0.0): 16,#12,
(1.0, 1.1, 1.0, 0.0): 16,#12,
(1.0, 1.1, 1.0, 1.0): 9,
(1.0, 1.15, 1.0, 0.0): 16,#17,
(1.0, 1.2, 1.0, 0.0): 16,#17,
(1.0, 1.25, 1.0, 0.0): 16,#17,
(1.0, 1.3, 1.0, 0.0): 16,#17,
(1.0, 1.35, 1.0, 0.0): 16,#9,
(1.0, 1.4, 1.0, 0.0): 16,#17,
(1.0, 10.0, 1.0, -1.0): 7,
(1.0, 10.0, 1.0, 0.0): 3,
(1.0, 10.0, 1.0, 1.0): 4,
(1.0, 20.0, 1.0, 0.0): 9,
(1.0, 20.0, 1.0, 1.0): 9,
(2.0, 0.9, 1.0, 0.0): 9,
(2.0, 1.0, 1.0, 0.0): 5,#10,
(2.0, 1.1, 1.0, 0.0): 10,
(3.0, 0.9, 1.0, 0.0): 17,#20,
(3.0, 1.0, 1.0, 0.0): 3,#4,
(3.0, 1.1, 1.0, 0.0): 3,#8,
(4.0, 0.9, 1.0, 0.0): 3,
(4.0, 1.0, 1.0, 0.0): 3,
(4.0, 1.1, 1.0, 0.0): 3#8
}


class Plotter():
    """
    This class carries around a measurement information dictionary as pickled at
    MEASUREMENT_INFO_FILE.  The various sub-functions manipulate that dictionary
    and return the desired plots with the best formatting necessary
    """
    
    ############################################################################
    #                                                                          #
    #   Constructor / Destructor                                               #
    #                                                                          #
    ############################################################################
    
    def __init__(self):
        """
        Load the dictionary at MEASUREMENT_INFO_FILE
        """
        with open( MEASUREMENT_INFO_FILE, 'rb' ) as f:
            self.x = pickle.load( f )
        self.InvertNodeValues()
    
    def __del__(self):
        """
        Just a destructor (for fun)
        """
        print "Goodbye cruel world!"
    
    
    
    ############################################################################
    #                                                                          #
    #   Overloaded Operators                                                   #
    #                                                                          #
    ############################################################################
    
    def __getitem__(self, key):
        """
        Overload the [] operator
        """
        return self.x[key]
    
    
    def __iter__(self):
        """
        The overloaded __getitem__ function messes up iteration.  We need to
        create our own routine for this process
        """
        keyList = self.x.keys()
        keyList.sort()
        return (trial for trial in keyList)
    
    
    
    ############################################################################
    #                                                                          #
    #   Other functions                                                        #
    #                                                                          #
    ############################################################################
    
    def InvertNodeValues(self):
        """
        Current paradigm:  node 0 is the farthest away, node R_Max is the center
        Flip that
        """
        for trial in self.x:
            for gen in self.x[trial]:
                for sz in self.x[trial][gen]:
                    A = self.x[trial][gen][sz]
                    if A[0,R] != 0.0:
                        A[:,R] = A[:,R].max() - A[:,R]
                        
                        #   Use argsort to invert this now-backwards list
                        nodeOrder = A[:,R].argsort()
                        A = A[nodeOrder]
    
    
    def CompareBestGenAll( self, allDifs = True, skipBest = False ):
        """
        Four-part plot of the four options below
        """
        
        f = pylab.figure()
        
        trialList = sorted( self.x.keys() )
        
        for trial in trialList:
            
            if (trial in BEST_GEN) and skipBest:
                pass
            else:
                try:
                    genList = sorted( self.x[trial].keys() )
                    
                    #   Bond Energies
                    p1 = f.add_subplot( 2, 2, 1 )
                    
                    y1 = [ self.x[trial][gen][0][1, SIDOTSC] for gen in genList ]
                    p1.plot( genList, y1 )
                    yl1 = p1.get_ylim()
                    if trial in BEST_GEN:
                        p1.vlines( BEST_GEN[ trial ], yl1[0], yl1[1] )
                        
                    p1.set_xlabel( 'generation' )
                    p1.set_ylabel( '$S_i \cdot S_j$' )
                    
                    
                    #   Bond energy differences
                    p2 = f.add_subplot( 2, 2, 2 )
                    y2_PM = [ abs( self.x[trial][gen][-1][1, SIDOTSC] - self.x[trial][gen][1][1, SIDOTSC] ) for gen in genList ]
                    y2_0M = [ abs( self.x[trial][gen][-1][1, SIDOTSC] - self.x[trial][gen][0][1, SIDOTSC] ) for gen in genList ]
                    y2_0P = [ abs( self.x[trial][gen][0][1, SIDOTSC] - self.x[trial][gen][1][1, SIDOTSC] ) for gen in genList ]
                    p2.plot( genList, y2_PM, label = '$\Delta E$ for $S_z = +1, -1$' )
                    
                    if allDifs:
                        p2.plot( genList, y2_0M, label = '$\Delta E$ for $S_z = 0, -1$' )
                        p2.plot( genList, y2_0P, label = '$\Delta E$ for $S_z = 0, +1$' )
                    
                    yl2 = p2.get_ylim()
                    p2.legend()
                    
                    if trial in BEST_GEN:
                        p2.vlines( BEST_GEN[ trial ], yl2[0], yl2[1] )
                        print '\tBest gen = ' + str(BEST_GEN[trial])
                    
                    p2.set_xlabel( 'generation' )
                    p2.set_ylabel( '$\Delta E$' )
                    #p2.set_title( '$(S, J_x, J_z, d) = ' + str(trial) + '$' )
                    
                    
                    #   S_z sector differences
                    p3 = f.add_subplot( 2, 2, 3 )
                    y3_PM = [ abs( self.x[trial][gen][-1][1, SZ] + self.x[trial][gen][1][1, SZ] ) for gen in genList ]
                    y3_0M = [ abs( abs(self.x[trial][gen][-1][1, SZ]) - self.x[trial][gen][0][1, SZ] ) for gen in genList ]
                    y3_0P = [ abs( self.x[trial][gen][0][1, SZ] - self.x[trial][gen][1][1, SZ] ) for gen in genList ]
                    p3.plot( genList, y3_PM, label = '$\Delta S_z$ for $S_z = +1, -1$' )
                    
                    if allDifs:
                        p3.plot( genList, y3_0M, label = '$\Delta S_z$ for $S_z = 0, -1$' )
                        p3.plot( genList, y3_0P, label = '$\Delta S_z$ for $S_z = 0, +1$' )
                    
                    yl3 = p3.get_ylim()
                    p3.legend()
                    
                    if trial in BEST_GEN:
                        p3.vlines( BEST_GEN[ trial ], yl3[0], yl3[1] )
                    
                    p3.set_xlabel( 'generation' )
                    p3.set_ylabel( '$\Delta S_z$' )
                    #p3.set_title( '$(S, J_x, J_z, d) = ' + str(trial) + '$' )
                    
                    
                    #   \sum_i <S_i^z> ^ 2
                    p4 = f.add_subplot( 2, 2, 4 )
                    y4 = [ scipy.sqrt( scipy.sum( (self.x[trial][gen][0][1, SZ])**2. ) ) for gen in genList ]
                    
                    p4.plot( genList, y4, label = '$\sum_i \left\langle S_i^z \\right \\rangle$ in the $S_z = 0$ sector.' )
                    
                    yl4 = (0.0, 0.1)
                    p4.legend()
                    
                    if trial in BEST_GEN:
                        p4.vlines( BEST_GEN[ trial ], yl4[0], yl4[1] )
                    
                    p4.set_xlabel( 'generation' )
                    p4.set_ylabel( '$\sum_i \left\langle S_i^z \\right \\rangle$' )
                    #p4.set_title( '$(S, J_x, J_z, d) = ' + str(trial) + '$' )
                    p4.set_ylim( yl4 )
                    
                    #   Show it off!
                    f.suptitle( '$(S, J_x, J_z, d) = ' + str(trial) + '$' )
                    f.show()
                    raw_input( str(trial) )
                    f.clf()
                
                except KeyError:
                    print '\tBusted trial: ' + str(trial)
                
                except EOFError:
                    print '\n'
                    pylab.close()
                    return
        
    
    def CompareBestGen( self ):
        """
        Plot the central bond energies as a function of generation, comparing
        the value of the cutoff generation as determined by eye (via these
        plots)
        """
        f = pylab.figure()
        for trial in self.x:
            p = f.add_subplot( 111 )
            genList = sorted( self.x[trial].keys() )
            y = [ self.x[trial][gen][0][-2, SIDOTSC] for gen in genList ]
            p.plot( genList, y )
            yl = p.get_ylim()
            if trial in BEST_GEN:
                p.vlines( BEST_GEN[ trial ], yl[0], yl[1] )
            f.show()
            raw_input( str(trial) )
            f.clf()
        
        pylab.close()
        
    
    def CompareBestGen2( self, allDifs = False ):
        """
        Another approach -- plot the difference between the +1 and -1 sector
        energies
        """
        f = pylab.figure()
        for trial in self.x:
            p = f.add_subplot( 111 )
            genList = sorted( self.x[trial].keys() )
            try:
                yPM = [ abs( self.x[trial][gen][-1][-2, SIDOTSC] - self.x[trial][gen][1][-2, SIDOTSC] ) for gen in genList ]
                y0M = [ abs( self.x[trial][gen][-1][-2, SIDOTSC] - self.x[trial][gen][0][-2, SIDOTSC] ) for gen in genList ]
                y0P = [ abs( self.x[trial][gen][0][-2, SIDOTSC] - self.x[trial][gen][1][-2, SIDOTSC] ) for gen in genList ]
                p.plot( genList, yPM, label = '$\Delta E$ for $S_z = +1, -1$' )
                
                if allDifs:
                    p.plot( genList, y0M, label = '$\Delta E$ for $S_z = 0, -1$' )
                    p.plot( genList, y0P, label = '$\Delta E$ for $S_z = 0, +1$' )
                
                yl = p.get_ylim()
                p.legend()
                
                if trial in BEST_GEN:
                    p.vlines( BEST_GEN[ trial ], yl[0], yl[1] )
                    print '\tBest gen = ' + str(BEST_GEN[trial])
                
                p.set_xlabel( 'generation' )
                p.set_ylabel( '$\Delta E$' )
                p.set_title( '$(S, J_x, J_z, d) = ' + str(trial) + '$' )
                f.show()
                raw_input( str(trial) )
                f.clf()
            except KeyError:
                print '\tBusted trial: ' + str(trial)
            except EOFError:
                print '/n'
                pylab.close()
                return
        
        pylab.close()
    
    
    def CompareBestGen3( self, allDifs = False ):
        """
        Another approach -- plot the difference between the +1 and -1 sector S_z
        """
        f = pylab.figure()
        for trial in self.x:
            p = f.add_subplot( 111 )
            genList = sorted( self.x[trial].keys() )
            try:
                yPM = [ abs( self.x[trial][gen][-1][-2, SZ] + self.x[trial][gen][1][-2, SZ] ) for gen in genList ]
                y0M = [ abs( abs(self.x[trial][gen][-1][-2, SZ]) - self.x[trial][gen][0][-2, SZ] ) for gen in genList ]
                y0P = [ abs( self.x[trial][gen][0][-2, SZ] - self.x[trial][gen][1][-2, SZ] ) for gen in genList ]
                p.plot( genList, yPM, label = '$\Delta S_z$ for $S_z = +1, -1$' )
                
                if allDifs:
                    p.plot( genList, y0M, label = '$\Delta S_z$ for $S_z = 0, -1$' )
                    p.plot( genList, y0P, label = '$\Delta S_z$ for $S_z = 0, +1$' )
                
                yl = p.get_ylim()
                p.legend()
                
                if trial in BEST_GEN:
                    p.vlines( BEST_GEN[ trial ], yl[0], yl[1] )
                    print '\tBest gen = ' + str(BEST_GEN[trial])
                
                p.set_xlabel( 'generation' )
                p.set_ylabel( '$\Delta S_z$' )
                p.set_title( '$(S, J_x, J_z, d) = ' + str(trial) + '$' )
                f.show()
                raw_input( str(trial) )
                f.clf()
            except KeyError:
                print '\tBusted trial: ' + str(trial)
            except EOFError:
                print '/n'
                pylab.close()
                return
        
        pylab.close()
    
    
    def CompareBestGen4( self ):
        """
        Yet another approach -- plot the std of the S_i^z values in the S_z = 0
        sector
        """
        f = pylab.figure()
        for trial in self.x:
            p = f.add_subplot( 111 )
            genList = sorted( self.x[trial].keys() )
            try:
                y = [ scipy.sqrt( scipy.sum( (self.x[trial][gen][0][-2, SZ])**2. ) ) for gen in genList ]
                
                p.plot( genList, y, label = '$\sum_i \left\langle S_i^z \\right \\rangle$ in the $S_z = 0$ sector.' )
                
                yl = (0.0, 0.1)
                p.legend()
                
                if trial in BEST_GEN:
                    p.vlines( BEST_GEN[ trial ], yl[0], yl[1] )
                    print '\tBest gen = ' + str(BEST_GEN[trial])
                
                p.set_xlabel( 'generation' )
                p.set_ylabel( '$\sum_i \left\langle S_i^z \\right \\rangle$' )
                p.set_title( '$(S, J_x, J_z, d) = ' + str(trial) + '$' )
                p.set_ylim( yl )
                f.show()
                raw_input( str(trial) )
                f.clf()
            except KeyError:
                print '\tBusted trial: ' + str(trial)
            except EOFError:
                print '/n'
                pylab.close()
                return
        
        pylab.close()
    
    
    def TrialsSoFar( self, S ):
        """
        Make a scatter plot of all the trials simulated so far (in terms of
        Jx / Jz and d / Jz
        """
        trialList = scipy.array( [[key[1], key[3]] for key in self.x.keys() if key[0] == S] )
        fig = pylab.figure( figsize = pylab.figaspect( .5 ) )
        
        x = trialList[:,0]
        y = trialList[:,1]
        m = max( max(abs(x)), max(abs(y)) )
        
        #   All of them
        p = fig.add_subplot(121)
        p.vlines( 0, -m, m, 'k' )
        p.hlines( 0, -m, m, 'k' )
        p.plot( x, y, linestyle = '', marker = 'o', color = 'b', mec = 'k', mew = 2, ms = 7 )
        p.grid(True)
        p.set_xlim( -m, m )
        p.set_ylim( -m, m )
        p.set_xlabel( '$J_x / J_z$' )
        p.set_ylabel( '$d / J_z$' )
        p.set_title( 'All simulated trials' )
        
        #   The small values
        p1 = fig.add_subplot(122)
        p1.vlines( 0, -1.5, 1.5, 'k' )
        p1.hlines( 0, -1.5, 1.5, 'k' )
        p1.plot( x, y, linestyle = '', marker = 'o', color = 'b', mec = 'k', mew = 2, ms = 7 )
        p1.grid(True)
        p1.set_xlim( -1.5, 1.5 )
        p1.set_ylim( -1.5, 1.5 )
        p1.set_xlabel( '$J_x / J_z$' )
        p1.set_ylabel( '$d / J_z$' )
        p1.set_title( '"Small" trials' )
        
        fig.show()
        


    ############################################################################
    #                                                                          #
    #   Plottable sub-arrays                                                   #
    #                                                                          #
    ############################################################################

    def S_Slice( self, fixedVals ):
        """
        Return an array dictionary that keeps Jx, Jz, d and gen fixed but allows
        S to varry
        """
        Jx, Jz, d, gen = fixedVals
        copDic = {}
        
        #   Fill copDic with only the arrays in x which we care about
        for key in self.x:
            
            #   Figure out which generation we want to pull
            if gen == 'best' or gen == 'Best' or gen == 'BEST':
                if (key in BEST_GEN):
                    compGen = BEST_GEN[ key ]
                else:
                    compGen = 4
            else:
                compGen = gen
                
            if key[1:] == (Jx, Jz, d):
                for genKey in self.x[key].keys():
                    if (genKey == compGen) and (compGen > 4):
                        S = key[0]
                        fullKey = (S, Jx, Jz, d, genKey)
                        copDic[ fullKey ] = copy.deepcopy( self.x[key][genKey] )
        
        keyList = scipy.array( sorted( copDic.keys() ) )
        varList = keyList[:, 0]
        
        return copDic, keyList, varList
    
    
    def Jx_Slice( self, fixedVals ):
        """
        Return an array dictionary that keeps S, Jz, and d fixed but allows Jx
        to varry
        """
        S, Jz, d, gen = fixedVals
        copDic = {}
        
        #   Fill copDic with only the arrays in x which we care about
        for key in self.x:
            
            #   Figure out which generation we want to pull
            if gen == 'best' or gen == 'Best' or gen == 'BEST':
                if (key in BEST_GEN):
                    compGen = BEST_GEN[ key ]
                else:
                    compGen = 4
            else:
                compGen = gen
                
            if key[0] == S and key[2:] == (Jz, d):
                for genKey in self.x[key].keys():
                    if (genKey == compGen) and (compGen > 4):
                        Jx = key[1]
                        fullKey = (S, Jx, Jz, d, genKey)
                        copDic[ fullKey ] = copy.deepcopy( self.x[key][genKey] )
        
        keyList = scipy.array( sorted( copDic.keys() ) )
        if len( keyList.shape ) == 2:
            varList = keyList[:, 1]
        else:
            varList = []
        
        return copDic, keyList, varList
    
    
    def D_Slice( self, fixedVals ):
        """
        Return an array dictionary that keeps S, Jx, and Jz fixed but allows d
        to varry
        """
        S, Jx, Jz, gen = fixedVals
        copDic = {}
        
        #   Fill copDic with only the arrays in x which we care about
        for key in self.x:
            
            #   Figure out which generation we want to pull
            if gen == 'best' or gen == 'Best' or gen == 'BEST':
                if (key in BEST_GEN):
                    compGen = BEST_GEN[ key ]
                else:
                    compGen = 4
            else:
                compGen = gen
                
            if key[:-1] == fixedVals[:-1]:
                for genKey in self.x[key].keys():
                    if (genKey == compGen) and (compGen > 4):
                        d = key[-1]
                        fullKey = (S, Jx, Jz, d, genKey)
                        copDic[ fullKey ] = copy.deepcopy( self.x[key][genKey] )
        
        keyList = scipy.array( sorted( copDic.keys() ) )
        varList = keyList[:, 3]
        
        return copDic, keyList, varList
    
    
    def Gen_Slice( self, fixedVals ):
        """
        For a fixed trial parameter (S, Jx, Jz, d), the information at all
        generations
        """
        S, Jx, Jz, d = fixedVals
        copDic = {}
        
        #   Fill copDic with only the arrays in x which we care about
        for genKey in self.x[fixedVals]:
            fullKey = fixedVals + (genKey,)
            copDic[ fullKey ] = copy.deepcopy( self.x[fixedVals][genKey] )
        
        keyList = scipy.array( sorted( copDic.keys() ) )
        varList = keyList[:,4]
        
        return copDic, keyList, varList
            
    
    
    ############################################################################
    #                                                                          #
    #   Plotting specific measurements                                         #
    #                                                                          #
    ############################################################################
    
    def AllSliceMeasurements( self, sliceString, fixedVals, TwoToRNormalization = False, ThreeD = False, varRange = 'All', szSubset = 'All' ):
        """
        Perform SimpleSliceMeasurement for every measurement
        """
        for measurementToken in range(1, 7):
            if ThreeD:
                self.SimpleSliceMeasurement_3D( sliceString, measurementToken, fixedVals, TwoToRNormalization, varRange, szSubset )
            else:
                self.SimpleSliceMeasurement( sliceString, measurementToken, fixedVals, TwoToRNormalization, varRange, szSubset )
    
    
    def SimpleSliceMeasurement( self, sliceString, measurementToken, fixedVals, TwoToRNormalization = False, varRange = 'All', szSubset = 'All' ):
        """
        Given a sliceString option from:
            'S', 'Jx', 'd', or 'gen'
        and a measurementToken option from:
            SZ, SZ2, SIPSCM, SIMSCP, SIZSCZ, SIDOTSC
        plot the simple 1-d measurements for each spin value
        """
        if sliceString == 'S':
            plotDic, keyList, varList = self.S_Slice( fixedVals )
        elif sliceString == 'Jx':
            plotDic, keyList, varList = self.Jx_Slice( fixedVals )
        elif sliceString == 'd':
            plotDic, keyList, varList = self.D_Slice( fixedVals )
        elif sliceString == 'gen':
            plotDic, keyList, varList = self.Gen_Slice( fixedVals )
        else:
            raise ValueError, "Not an acceptable sliceString. Options are:\n\t'S'\n\t'Jx'\n\t'd'\n\t'gen'"
        
        #   We now have a dictionary of the type
        #       { trial : { gen : { sz : array, ... }, ... }, ... }
        #   pull it apart as requested.
        
        #   To deal with normalization, we want to multiply the values of
        #   all two-point correlation functions by 2^R
        twoPointCorrIndices = [SIPSCM, SIMSCP, SIZSCZ, SIDOTSC]
        if measurementToken in twoPointCorrIndices:
            labelAppendText = '$\\times 2^R$'
        else:
            labelAppendText = ''
        
        #   Let's make subplots for each Sz value represented, limited to those
        #   given in szSubset
        szList = []
        for key in plotDic:
            for sz in plotDic[key]:
                if sz not in szList:
                    szList.append( sz )
        szList = sorted( szList )
        
        if szSubset != 'All':
            i = 0
            while i < len(szList):
                if szList[i] not in szSubset:
                    tossVal = szList.pop(i)
                else:
                    i += 1
        
        #   Plotting basics
        f = pylab.figure()
        colorList = [ 'blue', 'green', 'red', 'cyan', 'magenta', 'gold', 'black' ]
        lineStyleList = [ '-', '--', '-.', ':' ]
        markerList = [ 'o', '^', '+', 'D', 'v', 'x', 's' ]
        
        for i in range( len( szList) ):
            p = f.add_subplot( len( szList ), 1, (i + 1) )
            sz = szList[i]
                        
            for j in range( len( keyList ) ):
                
                #   We saved all the keys in a sorted order in FOO_Slice()
                key = tuple(keyList[j])
                var = varList[j]
                
                if varRange != 'All':
                    varMin, varMax = sorted(varRange)
                    continueBool = ( varMin <= var ) and ( var <= varMax )
                else:
                    continueBool = True
                
                trial = key[:4]
                gen = key[4]
            
                if (sz in plotDic[key]) and continueBool:
                    
                    A = plotDic[key][sz].copy()
                    
                    try:
                        #   Formatting each trial / generation combo
                        #   distinctly (but the same across Sz values)
                        colorNow = colorList[ j % len(colorList) ]
                        markerNow = markerList[ j % len(markerList) ]
                        lineStyleNow = lineStyleList[ (j / len(colorList)) % len(lineStyleList) ]
                        
                        if TwoToRNormalization and measurementToken in twoPointCorrIndices:
                            multArray = 2**A[:,R]
                        else:
                            multArray = scipy.ones( len(A) )
                        
                        p.plot( A[:,R], multArray * A[:,measurementToken], color = colorNow, linewidth = 2, marker = markerNow, mec = colorNow, mfc = 'w', mew = 2, linestyle = lineStyleNow, label = '$J_x = ' + str(var) +'$' )
                        
                        if TwoToRNormalization and measurementToken in twoPointCorrIndices:
                            p.set_ylim( -2, 2 )
                        
                    except IndexError:
                        print LABEL_DIC[ measurementToken ] + ' measurement not made for trial ' + str(trial)
                            
            p.set_xlabel( '$R$' )
            p.set_ylabel( LABEL_DIC[ measurementToken ] + labelAppendText )
            #p.set_title( LABEL_DIC[ measurementToken ] + ' in the $S^z = ' + str(sz) + '$ sector' )
            p.legend()
    
    
    def SimpleSliceMeasurement_3D( self, sliceString, measurementToken, fixedVals, TwoToRNormalization = False, varRange = 'All', szSubset = 'All' ):
        """
        Given a sliceString option from:
            'S', 'Jx', 'd', or 'gen'
        and a measurementToken option from:
            SZ, SZ2, SIPSCM, SIMSCP, SIZSCZ, SIDOTSC
        plot the simple 1-d measurements for each spin value, as a 3D plot
        """
        if sliceString == 'S':
            plotDic, keyList, varList = self.S_Slice( fixedVals )
        elif sliceString == 'Jx':
            plotDic, keyList, varList = self.Jx_Slice( fixedVals )
        elif sliceString == 'd':
            plotDic, keyList, varList = self.D_Slice( fixedVals )
        elif sliceString == 'gen':
            plotDic, keyList, varList = self.Gen_Slice( fixedVals )
        else:
            raise ValueError, "Not an acceptable sliceString. Options are:\n\t'S'\n\t'Jx'\n\t'd'\n\t'gen'"
        
        #   To deal with normalization, we want to multiply the values of
        #   all two-point correlation functions by 2^R
        twoPointCorrIndices = [SIPSCM, SIMSCP, SIZSCZ, SIDOTSC]
        if measurementToken in twoPointCorrIndices:
            labelAppendText = '$\\times 2^R$'
        else:
            labelAppendText = ''
        
        #   We now have a dictionary of the type
        #       { trial : { gen : { sz : array, ... }, ... }, ... }
        #   pull it apart as requested.
        
        #   Let's make subplots for each Sz value represented, limited to those
        #   given in szSubset
        szList = []
        for key in plotDic:
            for sz in plotDic[key]:
                if sz not in szList:
                    szList.append( sz )
        szList = sorted( szList )
        
        if szSubset != 'All':
            i = 0
            while i < len(szList):
                if szList[i] not in szSubset:
                    tossVal = szList.pop(i)
                else:
                    i += 1
        
        #   Plotting basics
        f = pylab.figure( figsize = pylab.figaspect( len(szList) ) )
        colorList = [ 'blue', 'green', 'red', 'cyan', 'magenta', 'gold', 'black' ]
        lineStyleList = [ '-', '--', '-.', '..' ]
        markerList = [ 'o', '^', '+', 'D', 'v', 'x', 's' ]
        
        for i in range( len( szList) ):
            axNow = Axes3D( f, rect = [ 0, float(i) / len(szList), 1, 1./len(szList) ] )
            sz = szList[i]
                        
            for j in range( len( keyList ) ):
                
                #   We saved all the keys in a sorted order in FOO_Slice()
                key = tuple(keyList[j])
                var = varList[j]
                
                if varRange != 'All':
                    varMin, varMax = sorted(varRange)
                    continueBool = ( varMin <= var ) and ( var <= varMax )
                else:
                    continueBool = True
                
                trial = key[:4]
                gen = key[4]
            
                if sz in plotDic[key] and continueBool:
                    
                    A = plotDic[key][sz].copy()
                    
                    try:
                        #   Formatting each trial / generation combo
                        #   distinctly (but the same across Sz values)
                        colorNow = colorList[ j % len(colorList) ]
                        markerNow = markerList[ j % len(markerList) ]
                        lineStyleNow = lineStyleList[ (j / len(colorList)) % len(lineStyleList) ]
                        
                        if TwoToRNormalization and measurementToken in twoPointCorrIndices:
                            multArray = 2**A[:,R]
                        else:
                            multArray = scipy.ones( len(A) )
                        
                        varVal = var * scipy.ones( len(A) )
                        axNow.plot( varVal, A[:, R], multArray * A[:, measurementToken], color = colorNow, linewidth = 2, marker = markerNow, mec = colorNow, mfc = 'w', mew = 2, linestyle = lineStyleNow, label = sliceString + ' = ' + str(var) )
                        
                        if TwoToRNormalization and measurementToken in twoPointCorrIndices:
                            axNow.set_ylim( -2, 2 )
                        
                    except IndexError:
                        print LABEL_DIC[ measurementToken ] + ' measurement not made for trial ' + str(trial)
                            
            axNow.set_xlabel( sliceString )
            axNow.set_ylabel( '$R$' )
            axNow.set_zlabel( TEX_LABEL_DIC[ measurementToken ] + labelAppendText )
            axNow.set_title( TEX_LABEL_DIC[ measurementToken ] + ' in the $S^z = ' + str(sz) + '$ sector' )
            axNow.legend()


def FlipFix( keyList = 'None' ):
    """
    In case I ever need a really bootleg way of flipping around the values in
    pp.x
    
    Requires a reload.
    """
    
    with open( MEASUREMENT_INFO_FILE, 'rb' ) as f:
        x = pickle.load( f )
    
    if keyList == 'None':
        keyList = x.keys()
    
    for key in keyList:
        g = BEST_GEN[key]
        pylab.plot( x[key][g][0][:,R], x[key][g][0][:,SIZSCZ] )
        y = raw_input( str(key) )
        if y == 'y':
            for gen in x[key]:
                for sz in x[key][gen]:
                    x[key][gen][sz][:,R] = x[key][gen][sz][:,R].max() - x[key][gen][sz][:,R]
                    nodeOrder = x[key][gen][sz][:,R].argsort()
                    x[key][gen][sz] = x[key][gen][sz][nodeOrder]
                    pylab.plot( x[key][gen][sz][:,R], x[key][gen][sz][:,SIZSCZ] )
            raw_input()
        pylab.clf()
    
    with open( MEASUREMENT_INFO_FILE, 'wb' ) as f:
        pickle.dump( x, f )
