示例#1
0
文件: Task.py 项目: onetera/sp
def OnBeforeInsert(self, arg, extra):
	
	Naming.uuid( arg )
	Login.CreaterStamp( arg )
	Login.ModifyerStamp( arg )
	DefaultTypeCode( arg )	# 그냥 브레이크된 상태로 배정이 되지 않은 Unassigned가 디폴트로 지정될 것이다.
	DefaultStatCode( arg )
	
	# 디폴트로 샷의 썸네일이 그대로 등록됨
	arg["Thumb"] = Archive("Shot").getValue( arg["Parent3"], "Thumb" )
	
	# 상위 부모 정보등록
	if (arg["Parent3"] in ('null', 'underfined')):
		raise SpartaError("샷 번호(%s)가 존재 하지 않는 번호입니다." % arg["Parent3"] )
	
	shotData = Archive("Shot").getValues( arg["Parent3"], "Parent1,Parent2")
	if not shotData:
		raise SpartaError("샷 번호(%s)가 존재 하지 않는 번호입니다." % arg["Parent3"] )
	else:
		arg["Parent1"] = shotData["Parent1"]
		arg["Parent2"] = shotData["Parent2"]
		
		# Confirmer 추가
		if "Confirmer" not in arg.keys():
			projectData = Archive("Project").getValues( shotData["Parent1"], "Parent1,Parent2,Manager")
			arg["Confirmer"] = projectData["Manager"]
			del projectData
	
	return arg
示例#2
0
文件: Seq.py 项目: onetera/sp
def OnBeforeInsert(self, arg, extra):			 
	Naming.uuid( arg )
	DefaultTypeCode( arg )
	DefaultStatCode( arg )
	DefaultThumbnail( arg )
	Login.CreaterStamp( arg )
	Login.ModifyerStamp( arg )	  
	return arg
示例#3
0
文件: Project.py 项目: onetera/sp
def OnBeforeInsert( self, arg, extra ):
	if "Code" in arg: arg["Code"] = arg["Code"].upper()
	Naming.uuid( arg )
	DefaultTypeCode( arg )
	DefaultStatCode( arg )
	DefaultThumbnail( arg )
	Login.CreaterStamp( arg )
	Login.ModifyerStamp( arg )
	return arg
示例#4
0
文件: Task.py 项目: onetera/sp
def getNewName( shot_idx=None, **arg):
	
	outDic = {}    
	lastTask = Archive("Task").getValues("Task.Parent3 == %s,Task.TypeCode == %s,Task.Element == %s" % (shot_idx, arg["Task.TypeCode"], arg["Task.Element"] ) , "Name,Code",  orderString="Task.Code DESC" )	
	if lastTask:
		outDic["Name"] = Naming.increaseName( lastTask["Name"] )
	else:
		outDic["Name"] = Naming.ApplyWithQuery("Task.Name", shot_idx, baseArcv="Shot", **arg )
	
	return outDic["Name"]
示例#5
0
文件: Take.py 项目: onetera/sp
def OnBeforeInsert(self, arg, extra):

	#[TODO] 등록권한 채크
	
	task_idx = arg["Parent4"]
	taskData = Archive("Task").getValues( task_idx, "Parent1,Parent2,Parent3,Confirmer")
	if taskData:
		arg["Parent1"] = taskData["Parent1"]
		arg["Parent2"] = taskData["Parent2"]
		arg["Parent3"] = taskData["Parent3"]
		arg["Confirmer"] = taskData["Confirmer"]   # 아이디			   
		#arg["Confirmer2"] = taskData["Confirmer2"]  # 이름 
	else:
		raise SpartaError("this index %s has no task " % taskidx)
	
	arg["Code"] = arg["Name"].upper()
	
	Naming.uuid( arg )	  
	DefaultTypeCode( arg )
	DefaultStatCode( arg )
	DefaultThumbnail( arg )    
	Login.CreaterStamp(arg)
	Login.ModifyerStamp(arg)	
	return arg
示例#6
0
文件: Take.py 项目: onetera/sp
def getInitFormData( task_idx=None ):
	""" 신규 Take 작성시 양식정보 채움 """
	
	formData = {}
	
	if ( task_idx != None ):
		taskData = Archive("Task").getValues(task_idx, "Task.TypeCode,Task.Element,Task.Parent3")
		formData["TypeCode"] = taskData["TypeCode"]
		formData["Element"] = taskData["Element"]
		formData["Parent3"] = taskData["Parent3"]
		
		#Find Last Version
		lastTake = Archive("Take").getValues(
			"Take.Parent3 == %s,Take.TypeCode == %s,Take.Element == %s" %( formData["Parent3"], formData["TypeCode"], formData["Element"] ),
			"Name,Code,Version,Content,ApprovalNote",
			"Take.Version DESC")
		
		if lastTake:
			formData["Name"] = Naming.increaseName( lastTake["Name"] )
			if lastTake["Version"] == 0 or lastTake["Version"] == None:
				formData["Version"] = 1
			else:
				formData["Version"] = int(lastTake["Version"]) + 1
			formData["PrevApprNote"] = lastTake["ApprovalNote"]
			formData["PrevContent"] = lastTake["Content"]
		else:
			formData["PrevApprNote"] = "냉무"
			formData["PrevContent"] = "냉무"
			formData["Version"] = 1
			
			arg2 = { "Take.TypeCode": formData["TypeCode"],
						"Take.Element": formData["Element"],
						"Take.Version" : formData["Version"] }
			
			formData["Name"] = getNewName( task_idx, **arg2) 
			#outDic["Name"] = getNewName(taskIdx=taskIdx, shotIdx=shotIdx, taskCode=taskCode, elementName=elementName)
	
	return formData
示例#7
0
def plot_deviation_test(file_path, output_formats=["pdf"]):
    """ Plot the (absolute) effect of the cos(theta) cut on the distributions.
  """
    # Read the input file
    log.debug("Reading file: {}".format(file_path))
    reader = IOR.Reader(file_path)

    # Output info
    output_dir = "{}/plots".format(os.path.dirname(file_path))
    base_name = os.path.basename(file_path).replace("_valdata.csv", "")
    log.debug("Output will be written to: {}".format(output_dir))

    # Get the pandas dataframe for the cut histograms
    df = reader["Data"]
    scale_factor = VMCC.TestLumi * reader["CrossSection"] / reader["NTotalMC"]

    bin_centers = reader["BinCenters"]
    n_bins = len(bin_centers)
    n_dims = len(reader["CoordName"])

    row_cut0 = df[(df["Delta-c"] == 0) & (df["Delta-w"] == 0)]
    N_cut_cut0 = np.array([row_cut0["C{}".format(b)] for b in range(n_bins)])
    N_par_cut0 = np.array([row_cut0["P{}".format(b)] for b in range(n_bins)])

    # Find the bin edges for each dimension
    bin_edges = [
        np.linspace(reader["CoordMin"][d], reader["CoordMax"][d],
                    reader["CoordNBins"][d] + 1) for d in range(n_dims)
    ]

    # Find the deltas and the minimum and maximum deviations
    deltas = IOPH.delta_pairs(df)
    delta_metrics = VMDH.delta_metric(deltas)
    colors = PHC.ColorSpectrum("turbo", -1.1 * np.amax(delta_metrics),
                               1.1 * np.amax(delta_metrics))

    for dev_dir in tqdm(dev_directions, desc="Dev. dir. loop", leave=False):
        log.debug("Looking at direction {}".format(dev_dir.name))
        dir_selection = dev_dir.func(deltas)
        dir_rows = df[dir_selection]
        dir_deltas = deltas[dir_selection]
        deltas_in_dir = delta_in_dir(dev_dir.name, dir_deltas)

        N_cut = np.array([dir_rows["C{}".format(b)] for b in range(n_bins)])
        N_par = np.array([dir_rows["P{}".format(b)] for b in range(n_bins)])

        diff_c0 = np.sqrt(scale_factor) * ratio(N_cut - N_cut_cut0,
                                                np.sqrt(N_cut_cut0))
        diff_p0 = np.sqrt(scale_factor) * ratio(N_par - N_cut_cut0,
                                                np.sqrt(N_cut_cut0))
        diff_pc = np.sqrt(scale_factor) * ratio(N_par - N_cut, np.sqrt(N_cut))

        title = "{}, ${}$ab$^{{-1}}$".format(VTN.metadata_to_process(reader),
                                             VMCC.TestLumi / 1000)
        legend_title = "Shift {}\n$\Delta {}$ $[\delta={}]$".format(
            dev_dir.name, dev_dir.coord, reader["Delta"])

        for d in tqdm(range(n_dims), desc="Dim. loop", leave=False):
            x = bin_centers[:, d]
            x_min, x_max = bin_edges[d][0], bin_edges[d][-1]
            coord_name = "${}$".format(
                VTN.name_to_coord(reader["CoordName"][d]))

            # definitions for the axes
            figsize = (12, 10)
            left, width = 0.17, 0.49
            bottom, height = 0.12, 0.49
            spacing = 0.005
            rect_scatter = [left, bottom, width, height]
            rect_histx = [
                left, bottom + height + spacing, width,
                0.93 - (bottom + height + spacing)
            ]
            rect_histy = [
                left + width + spacing, bottom,
                0.93 - (left + width + spacing), height
            ]
            leg_pos = [(width + spacing) / width, (height + spacing) / height]

            # Common plotting arguments
            common_sc_kwargs = {"color": 'none', "linewidths": 2, "s": 10**2}
            common_hist_kwargs = {"histtype": 'step', "fill": False, "lw": 2}

            #--- Plot N_cut - N_cut0 -------------------------------------------------

            # start with a rectangular Figure
            fig = plt.figure(figsize=figsize)
            fig.suptitle(title)  #, fontsize=16)

            ax_scatter = plt.axes(rect_scatter)
            ax_scatter.tick_params(direction='in', top=True, right=True)
            ax_scatter.set_xlabel(coord_name)
            ax_scatter.set_ylabel(
                r"$\left(N_{cut}^{(\Delta c,\Delta w)} - N_{cut}^{0}\right)/\sqrt{N_{cut}^{0}}$"
            )
            ax_histx = plt.axes(rect_histx)
            ax_histx.tick_params(direction='in', labelbottom=False)
            ax_histx.set_ylabel("$\sum_{bins} y^2$")
            ax_histy = plt.axes(rect_histy)
            ax_histy.tick_params(direction='in', labelleft=False)
            ax_histy.set_xlabel("#bins")

            y_bin_edges = np.linspace(np.amin(diff_c0), np.amax(diff_c0), 20)

            for row in range(len(dir_deltas)):
                y = diff_c0[:, row]
                color = colors[deltas_in_dir[row]]
                scatter = ax_scatter.scatter(
                    x,
                    y,
                    edgecolors=color,
                    marker=PHM.markers[row],
                    label=r"${}$".format(deltas_in_dir[row] / reader["Delta"]),
                    **common_sc_kwargs)

                ax_histx.hist(x,
                              bins=bin_edges[d],
                              weights=y**2,
                              ec=color,
                              **common_hist_kwargs)
                ax_histy.hist(y,
                              bins=y_bin_edges,
                              orientation='horizontal',
                              ec=color,
                              **common_hist_kwargs)

            ax_scatter.set_xlim((x_min, x_max))
            ax_histx.set_xlim(ax_scatter.get_xlim())
            ax_histy.set_ylim(ax_scatter.get_ylim())

            ax_scatter.legend(loc=leg_pos, title=legend_title, ncol=2)

            # Save the figure in all requested formats
            for format in output_formats:
                format_dir = "{}/{}/DevCutCut0".format(output_dir, format)
                IOSH.create_dir(format_dir)
                dev_dir_name = dev_dir.name.replace(" ", "_")
                fig.savefig("{}/{}_{}_DevCutCut0_{}.{}".format(
                    format_dir, base_name, reader["CoordName"][d],
                    dev_dir_name, format))

            plt.close(fig)

            #--- Only scatter plot N_cut - N_cut0 ------------------------------------

            fig = plt.figure(figsize=(9, 7), tight_layout=True)
            ax_scatter = plt.gca()
            ax_scatter.set_title(title)
            ax_scatter.set_xlabel(coord_name)
            ax_scatter.set_ylabel(
                r"$\left(N_{cut}^{(\Delta c,\Delta w)} - N_{cut}^{0}\right)/\sqrt{N_{cut}^{0}}$"
            )

            for row in range(len(dir_deltas)):
                scatter = ax_scatter.scatter(
                    x,
                    diff_c0[:, row],
                    edgecolors=colors[deltas_in_dir[row]],
                    marker=PHM.markers[row],
                    label=r"${}$".format(deltas_in_dir[row] / reader["Delta"]),
                    **common_sc_kwargs)

            ax_scatter.set_xlim((x_min, x_max))
            ax_scatter.legend(title=legend_title, ncol=3)

            # Save the figure in all requested formats
            for format in output_formats:
                format_dir = "{}/{}/DevCutCut0".format(output_dir, format)
                IOSH.create_dir(format_dir)
                dev_dir_name = dev_dir.name.replace(" ", "_")
                fig.savefig("{}/{}_{}_DevCutCut0_ScatterOnly_{}.{}".format(
                    format_dir, base_name, reader["CoordName"][d],
                    dev_dir_name, format))

            plt.close(fig)

            #--- Plot N_par - N_cut0 -------------------------------------------------

            # start with a rectangular Figure
            fig = plt.figure(figsize=figsize)
            fig.suptitle(title)  #, fontsize=16)

            ax_scatter = plt.axes(rect_scatter)
            ax_scatter.tick_params(direction='in', top=True, right=True)
            ax_scatter.set_xlabel(coord_name)
            ax_scatter.set_ylabel(
                r"$\left(N_{par}^{(\Delta c,\Delta w)} - N_{cut}^{0}\right)/\sqrt{N_{cut}^{0}}$"
            )
            ax_histx = plt.axes(rect_histx)
            ax_histx.tick_params(direction='in', labelbottom=False)
            ax_histx.set_ylabel("$\sum_{bins} y^2$")
            ax_histy = plt.axes(rect_histy)
            ax_histy.tick_params(direction='in', labelleft=False)
            ax_histy.set_xlabel("#bins")

            y_bin_edges = np.linspace(np.amin(diff_p0), np.amax(diff_p0), 20)

            for row in range(len(dir_deltas)):
                y = diff_p0[:, row]
                color = colors[deltas_in_dir[row]]
                scatter = ax_scatter.scatter(
                    x,
                    y,
                    edgecolors=color,
                    marker=PHM.markers[row],
                    label=r"${}$".format(deltas_in_dir[row] / reader["Delta"]),
                    **common_sc_kwargs)

                ax_histx.hist(x,
                              bins=bin_edges[d],
                              weights=y**2,
                              ec=color,
                              **common_hist_kwargs)
                ax_histy.hist(y,
                              bins=y_bin_edges,
                              orientation='horizontal',
                              ec=color,
                              **common_hist_kwargs)

            ax_scatter.set_xlim((x_min, x_max))
            ax_histx.set_xlim(ax_scatter.get_xlim())
            ax_histy.set_ylim(ax_scatter.get_ylim())

            ax_scatter.legend(loc=leg_pos, title=legend_title, ncol=2)

            # Save the figure in all requested formats
            for format in output_formats:
                format_dir = "{}/{}/DevParCut0".format(output_dir, format)
                IOSH.create_dir(format_dir)
                dev_dir_name = dev_dir.name.replace(" ", "_")
                fig.savefig("{}/{}_{}_DevParCut0_{}.{}".format(
                    format_dir, base_name, reader["CoordName"][d],
                    dev_dir_name, format))

            plt.close(fig)

            #--- Plot N_par - N_cut --------------------------------------------------

            # start with a rectangular Figure
            fig = plt.figure(figsize=figsize)
            fig.suptitle(title)  #, fontsize=16)

            ax_scatter = plt.axes(rect_scatter)
            ax_scatter.tick_params(direction='in', top=True, right=True)
            ax_scatter.set_xlabel(coord_name)
            ax_scatter.set_ylabel(
                r"$\left(N_{par}^{(\Delta c,\Delta w)} - N_{cut}^{(\Delta c,\Delta w)}\right)/\sqrt{N_{cut}^{(\Delta c,\Delta w)}}$"
            )
            ax_histx = plt.axes(rect_histx)
            ax_histx.tick_params(direction='in', labelbottom=False)
            ax_histx.set_ylabel("$\sum_{bins} y^2$")
            ax_histy = plt.axes(rect_histy)
            ax_histy.tick_params(direction='in', labelleft=False)
            ax_histy.set_xlabel("#bins")

            y_bin_edges = np.linspace(np.amin(diff_pc), np.amax(diff_pc), 20)

            for row in range(len(dir_deltas)):
                y = diff_pc[:, row]
                color = colors[deltas_in_dir[row]]
                scatter = ax_scatter.scatter(
                    x,
                    y,
                    edgecolors=color,
                    marker=PHM.markers[row],
                    label=r"${}$".format(deltas_in_dir[row] / reader["Delta"]),
                    **common_sc_kwargs)

                ax_histx.hist(x,
                              bins=bin_edges[d],
                              weights=y**2,
                              ec=color,
                              **common_hist_kwargs)
                ax_histy.hist(y,
                              bins=y_bin_edges,
                              orientation='horizontal',
                              ec=color,
                              **common_hist_kwargs)

            ax_scatter.set_xlim((x_min, x_max))
            ax_histx.set_xlim(ax_scatter.get_xlim())
            ax_histy.set_ylim(ax_scatter.get_ylim())

            ax_scatter.legend(loc=leg_pos, title=legend_title, ncol=2)

            # Save the figure in all requested formats
            for format in output_formats:
                format_dir = "{}/{}/DevParCut".format(output_dir, format)
                IOSH.create_dir(format_dir)
                dev_dir_name = dev_dir.name.replace(" ", "_")
                fig.savefig("{}/{}_{}_DevParCut_{}.{}".format(
                    format_dir, base_name, reader["CoordName"][d],
                    dev_dir_name, format))

            plt.close(fig)
def plot_cut_effect(file_path, output_formats=["pdf"]):
    """ Plot the (absolute) effect of the cos(theta) cut on the distributions.
  """
    # Read the input file
    log.debug("Reading file: {}".format(file_path))
    reader = IOR.Reader(file_path)

    # Output info
    output_dir = "{}/plots".format(os.path.dirname(file_path))
    base_name = os.path.basename(file_path).replace("_valdata.csv", "")
    log.debug("Output will be written to: {}".format(output_dir))

    # Get the pandas dataframe for the cut histograms
    df = reader["Data"]
    row_cut0 = df[(df["Delta-c"] == 0) & (df["Delta-w"] == 0)]

    bin_centers = reader["BinCenters"]
    n_bins = len(bin_centers)
    n_dims = len(reader["CoordName"])

    # Find the MC event histograms
    y_nocut = reader["NoCutData"]
    y_cut = []
    # y_par = []
    for b in range(n_bins):
        y_cut.append(row_cut0["C{}".format(b)])
        # y_par.append(row_cut0["P{}".format(b)])
    y_cut = np.array(y_cut)
    # y_par = np.array(y_par)

    # Correctly normalise the MC event histograms
    scale_factor = VMCC.TestLumi * reader["CrossSection"] / reader["NTotalMC"]
    y_nocut *= scale_factor
    y_cut *= scale_factor
    # y_par *= scale_factor

    # Create the test histograms
    for d in tqdm(range(n_dims), desc="Dim.", leave=False):
        # Find the binning x range and the relevant x bin center of each bin
        x_edges = np.linspace(reader["CoordMin"][d], reader["CoordMax"][d],
                              reader["CoordNBins"][d] + 1)
        x_vals = bin_centers[:, d]
        coord_name = "${}$".format(VTN.name_to_coord(reader["CoordName"][d]))

        # Create the figure
        fig, ax = plt.subplots(figsize=(8.5, 6))  #, tight_layout=True)
        # title = "{} : {}{}".format(reader["Name"],VTN.eM_chirality(reader["e-Chirality"]),VTN.eP_chirality(reader["e+Chirality"]))
        title = "{}, ${}$ab$^{{-1}}$".format(VTN.metadata_to_process(reader),
                                             VMCC.TestLumi / 1000)
        ax.set_title(title)

        # Create the plots (no cut, actual cut, parametrised cut)
        colors = plt.rcParams['axes.prop_cycle'].by_key()['color']
        h_kwargs = {"bins": x_edges, "fill": False, "lw": 2}
        hist_nocut = plt.hist(x_vals,
                              weights=y_nocut,
                              label="Before cut",
                              ec=colors[0],
                              hatch="//",
                              **h_kwargs)  #, ec='black', fill=False)
        hist_cut = plt.hist(
            x_vals,
            weights=y_cut,
            label="After cut",
            ec=colors[1],
            hatch="\\\\",
            **h_kwargs)  #, ec='#CC3311', fill=False, hatch="//")
        # hist_par = plt.hist(x_vals, bins=x_edges, weights=y_par, label="Param. cut", ec='#009988', fill=False, hatch="\\\\")

        # Some nicer plotting
        ax.set_xlabel(coord_name)
        ax.set_ylabel("#Events")
        ax.set_xlim((x_edges[0], x_edges[-1]))
        # ax.set_ylim([0,1.1*np.amax(hist_nocut[0])])
        ax.legend(title=r"$\cos\theta_{{\mu}}^{{cut}}={}$".format(
            reader["Coef|MuonAcc_CutValue"]))
        fig.tight_layout(rect=[0, 0, 0.95, 1.0])

        # Save the figure in all requested formats
        for format in output_formats:
            format_dir = "{}/{}/CutEffect".format(output_dir, format)
            IOSH.create_dir(format_dir)
            fig.savefig("{}/{}_{}_CutEffect.{}".format(format_dir, base_name,
                                                       reader["CoordName"][d],
                                                       format))

        plt.close(fig)
示例#9
0
def plot_chi_squared_test(file_path, output_formats=["pdf"]):
    # TODO TODO TODO DESCRIPTION

    # Read the input file
    log.debug("Reading file: {}".format(file_path))
    reader = IOR.Reader(file_path)

    # Output info
    output_dir = "{}/plots".format(os.path.dirname(file_path))
    base_name = os.path.basename(file_path).replace("_valdata.csv", "")
    log.debug("Output will be written to: {}".format(output_dir))

    # Get the pandas dataframe for the cut histograms
    df = reader["Data"]
    n_bins = len(reader["BinCenters"])

    row_cut0 = df[(df["Delta-c"] == 0) & (df["Delta-w"] == 0)]
    N_cut_cut0 = np.array(
        [row_cut0["C{}".format(b)].values[0] for b in range(n_bins)])

    # Get scale factor to normalise distribution to the (roughly) number of events
    # expected during the fit
    scale_factor = VMCC.TestLumi * reader["CrossSection"] / reader["NTotalMC"]
    N_cut_cut0 *= scale_factor

    # Find the deltas
    deltas = IOPH.delta_pairs(df)
    delta_metrics = VMDH.delta_metric(deltas)

    # Maximum sqrt(dc**2 + dw**2) that should be included in chi-squared calc.
    # -> Don't use outermost test values, not bad if not exact fit there
    d_max = 2.0 * reader["Delta"]

    # Chi squared arrays for each dev dir
    chi_sq_pc = []
    chi_sq_c0 = []

    for dev_dir in dev_directions:
        log.debug("Looking at direction {}".format(dev_dir.name))

        # Get the rows for this direction which fulfill the d_max criterium
        dir_selection = dev_dir.func(deltas)
        d_max_selection = delta_metrics <= d_max
        selection = np.logical_and(dir_selection, d_max_selection)
        dir_rows = df[selection]
        dir_deltas = deltas[selection]
        n_dev_points = len(dir_deltas)

        N_cut = np.array([dir_rows["C{}".format(b)]
                          for b in range(n_bins)]) * scale_factor
        N_par = np.array([dir_rows["P{}".format(b)]
                          for b in range(n_bins)]) * scale_factor

        diff_pc_sq = (N_par - N_cut)**2
        diff_c0_sq = ((N_cut.transpose() - N_cut_cut0)**2).transpose()

        dir_chi_sq_pc = []
        dir_chi_sq_c0 = []

        # Calculate the chi-squared for each bin
        for d in range(n_dev_points):
            dev_chi_sq_pc = 0
            dev_chi_sq_c0 = 0
            diff_pc_sq_d = diff_pc_sq[:, d]
            diff_c0_sq_d = diff_c0_sq[:, d]
            N_cut_d = N_cut[:, d]

            for b in range(n_bins):
                if not N_cut_d[b] > 0:
                    if abs(diff_pc_sq_d[b]) > 0:
                        log.warning(
                            "Bin {} at deviation ({}) has 0 for cut and non-0 for parametrisation"
                            .format(b, dir_deltas[d]))
                elif np.all(N_cut[b] == N_cut_cut0[b]):
                    # Skip bins that aren't affected by the cut
                    # Their contribution to each chi^2 is zero anyway
                    continue
                else:
                    dev_chi_sq_pc += diff_pc_sq_d[b] / N_cut_d[b]
                    dev_chi_sq_c0 += diff_c0_sq_d[b] / N_cut_cut0[b]

            dir_chi_sq_pc.append(dev_chi_sq_pc)
            dir_chi_sq_c0.append(dev_chi_sq_c0)

        chi_sq_pc.append(dir_chi_sq_pc)
        chi_sq_c0.append(dir_chi_sq_c0)

    # --- Plotting ---------------------------------------------------------------

    # start with a rectangular Figure
    fig = plt.figure(figsize=(7.5, 6), tight_layout=True)

    ax_scatter = plt.gca()
    title = "{}, ${}$ab$^{{-1}}$".format(VTN.metadata_to_process(reader),
                                         VMCC.TestLumi / 1000)
    ax_scatter.set_title(title)
    ax_scatter.set_xlabel(r"$\chi_{shift}^{2}$", fontsize=26)
    ax_scatter.set_ylabel(r"$\chi_{mismodel}^{2}$", fontsize=26)
    # ax_scatter.set_xlabel(r"$\chi_{shift}^{2} = \sum_{bins} \left(\frac{N_{cut}^{(\Delta c, \Delta w)} - N_{cut}^{0}}{\sqrt{N_{cut}^{0}}}\right)^2$")
    # ax_scatter.set_ylabel(r"$\chi_{par}^{2} = \sum_{bins} \left(\frac{N_{par}^{(\Delta c, \Delta w)} - N_{cut}^{(\Delta c, \Delta w)}}{\sqrt{N_{cut}^{(\Delta c, \Delta w)}}}\right)^2$")

    # Set logarithmic axes
    x_min = min([min(c) for c in chi_sq_c0])
    x_max = max([max(c) for c in chi_sq_c0])
    y_min = min([min(c) for c in chi_sq_pc])
    y_max = max([max(c) for c in chi_sq_pc])
    edge_min = 0.5 * y_min
    edge_max = 1.5 * max(x_max, y_max)
    log_edge_min = np.log10(edge_min)
    log_edge_max = np.log10(edge_max)
    edges = np.logspace(log_edge_min, log_edge_max, 16)
    ax_scatter.set_yscale('log')
    ax_scatter.set_xscale('log')
    ax_scatter.set_ylim(edge_min, edge_max)
    ax_scatter.set_xlim(edge_min, edge_max)

    # Draw diagonal axis line, everything below that line is fine
    ax_scatter.fill_between(edges,
                            edges,
                            edge_max * np.ones(16),
                            color='red',
                            alpha=0.5)
    ax_scatter.axline((edge_min, edge_min), (edge_max, edge_max),
                      ls='--',
                      color='black')

    colors = plt.rcParams['axes.prop_cycle'].by_key()['color']

    for i_dir in range(len(dev_directions)):
        scatter = ax_scatter.scatter(chi_sq_c0[i_dir],
                                     chi_sq_pc[i_dir],
                                     color='none',
                                     ec=colors[i_dir],
                                     lw=2,
                                     s=10**2,
                                     marker=PHM.markers[i_dir],
                                     label=dev_directions[i_dir].name)

    legend_title = r"$\cos\theta_{{\mu}}^{{cut}}={}$,".format(
        reader["Coef|MuonAcc_CutValue"]
    ) + "\n" + r"$\sqrt{{\Delta c^2 + \Delta w^2}} \leq {}\delta$".format(
        d_max / reader["Delta"])
    ax_scatter.legend(title=legend_title, loc="upper left")

    # Save the figure in all requested formats
    for format in output_formats:
        format_dir = "{}/{}/ChiSquared".format(output_dir, format)
        IOSH.create_dir(format_dir)
        fig.savefig("{}/{}_ChiSquared.{}".format(format_dir, base_name,
                                                 format))

    plt.close(fig)