{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "__author__      = \"Meike Kuessner\"\n",
    "__institution__ = \"Ruhr-Univ. Bochum\"\n",
    "__description__ = \"Python Notebook to plot fit results from PAWIAN config file\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Requirement already satisfied: uproot in /opt/conda/lib/python3.7/site-packages (3.5.2)\n",
      "Requirement already satisfied: uproot-methods>=0.5.0 in /opt/conda/lib/python3.7/site-packages (from uproot) (0.5.1)\n",
      "Requirement already satisfied: awkward>=0.9.0 in /opt/conda/lib/python3.7/site-packages (from uproot) (0.9.0)\n",
      "Requirement already satisfied: numpy>=1.13.1 in /opt/conda/lib/python3.7/site-packages (from uproot) (1.15.4)\n",
      "Requirement already satisfied: cachetools in /opt/conda/lib/python3.7/site-packages (from uproot) (3.1.0)\n",
      "Note: you may need to restart the kernel to use updated packages.\n"
     ]
    }
   ],
   "source": [
    "pip install uproot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "import uproot #needed to read root files\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import math\n",
    "from mpl_toolkits.axes_grid1 import make_axes_locatable #needed for residual plot to arrange subplots"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def Get4Vecs(filename, particlename, datatype): #load four-vectors from file\n",
    "    file_Px = uproot.open(filename)[\"_\"+datatype+\"Fourvecs/\"+particlename+\"/fP/fP.fX\"]\n",
    "    file_Py = uproot.open(filename)[\"_\"+datatype+\"Fourvecs/\"+particlename+\"/fP/fP.fY\"]\n",
    "    file_Pz = uproot.open(filename)[\"_\"+datatype+\"Fourvecs/\"+particlename+\"/fP/fP.fZ\"]\n",
    "    file_E = uproot.open(filename)[\"_\"+datatype+\"Fourvecs/\"+particlename+\"/fE\"]\n",
    "    return(file_Px, file_Py, file_Pz, file_E)\n",
    "\n",
    "def GetWeight(filename, datatype): #load weights from file\n",
    "    file_weight = uproot.open(filename)[\"_\"+datatype+\"Fourvecs/weight\"]\n",
    "    return(file_weight)\n",
    "\n",
    "def Mass(vec): #Calc invariant mass of vector(s)\n",
    "    M = []\n",
    "    for i in range(0,len(vec[0][0])):\n",
    "        px=0.\n",
    "        py=0.\n",
    "        pz=0.\n",
    "        e=0.\n",
    "        for j in range(0,len(vec)):\n",
    "            px += vec[j][0][i]\n",
    "            py += vec[j][1][i]\n",
    "            pz += vec[j][2][i]\n",
    "            e  += vec[j][3][i]\n",
    "        M.append(math.sqrt(e**2-px**2-py**2-pz**2))\n",
    "    return(M)\n",
    "\n",
    "def Fill4Vecs(filename, particlename, datatype): #Fill 4Vecs from file\n",
    "    Vecs = Get4Vecs(filename, particlename, datatype)\n",
    "    array_4Vecs = [Vecs[0].array(), \n",
    "                    Vecs[1].array(), \n",
    "                    Vecs[2].array(), \n",
    "                    Vecs[3].array()]\n",
    "    return(array_4Vecs)\n",
    "\n",
    "def FillWeight(filename, datatype): #Fill Weights from file\n",
    "    Weights = GetWeight(filename, datatype)\n",
    "    array_weights = Weights.array()\n",
    "    return(array_weights)\n",
    "\n",
    "#Some standard functinos for 4 vectors... Don't hesitate to complete them...\n",
    "\n",
    "def Boost(vec, boost_vec):\n",
    "    bx = -boost_vec[0]/boost_vec[3]\n",
    "    by = -boost_vec[1]/boost_vec[3]\n",
    "    bz = -boost_vec[2]/boost_vec[3]\n",
    "    b2 = bx*bx+by*by+bz*bz\n",
    "    bp = bx*vec[0] + by*vec[1] + bz*vec[2]\n",
    "    \n",
    "    if b2<1.0:\n",
    "        gamma = 1.0 / np.sqrt(1.0 - b2)\n",
    "    else:\n",
    "        gamma=0.\n",
    "    \n",
    "    gamma2 =  (gamma - 1.0)/b2\n",
    "  \n",
    "    result = []\n",
    "    result.append(vec[0] + gamma2*bp*bx + gamma*bx*vec[3])\n",
    "    result.append(vec[1] + gamma2*bp*by + gamma*by*vec[3])\n",
    "    result.append(vec[2] + gamma2*bp*bz + gamma*bz*vec[3])\n",
    "    result.append(gamma*(bp+vec[3]))\n",
    "    return(result)\n",
    "\n",
    "def Perp(vec):\n",
    "    P = np.sqrt(vec[0]**2+vec[1]**2+vec[2]**2)\n",
    "    return(P)\n",
    "\n",
    "def Theta(vec):\n",
    "    theta = math.acos(vec[2]/Perp(vec))\n",
    "    return(theta)\n",
    "\n",
    "def CosTheta(vec):\n",
    "    cos_theta = math.cos(Theta(vec))\n",
    "    return(cos_theta)\n",
    "\n",
    "def Phi(vec):\n",
    "    phi = math.atan2(round(vec[1],5),round(vec[0],5))\n",
    "    return(phi)\n",
    "\n",
    "def RotateZ(vec, angle):\n",
    "    x = vec[0]\n",
    "    y = vec[1]\n",
    "    s = math.sin(angle)\n",
    "    c = math.cos(angle)\n",
    "    vec[0] = c*x - s*y\n",
    "    vec[1] = s*x + c*y\n",
    "    return(vec)\n",
    "\n",
    "def RotateY(vec, angle):\n",
    "    x = vec[0]\n",
    "    z = vec[2]\n",
    "    s = math.sin(angle)\n",
    "    c = math.cos(angle)\n",
    "    vec[0] = c*x + s*z\n",
    "    vec[2] = -s*x + c*z\n",
    "    return(vec)\n",
    "\n",
    "def HeliVec(motherRef, ref, mother, daughter): #Calc vector in helicity system\n",
    "    resultvec=daughter\n",
    "    refTrafovec=ref\n",
    "    refRecoilTrafovec=[motherRef[0]-ref[0], motherRef[1]-ref[1], motherRef[2]-ref[2], motherRef[3]-ref[3]]\n",
    "    pi = 3.14159265358979323846\n",
    "    \n",
    "    #boost all vectors into the mother rest frame\n",
    "    result=Boost(resultvec,mother)\n",
    "    refTrafo=Boost(refTrafovec,mother)\n",
    "    refRecoilTrafo=Boost(refRecoilTrafovec,mother)\n",
    "    \n",
    "    #rotate vectors so that refRecoilTrafo moves in the negative direction of the z-axis   \n",
    "    result=RotateZ(result,-Phi(refTrafo))\n",
    "    result=RotateY(result,pi-Theta(refTrafo))\n",
    "\n",
    "    refRecoilTrafo=RotateZ(refRecoilTrafo,-Phi(refTrafo))\n",
    "    refRecoilTrafo=RotateY(refRecoilTrafo,pi-Theta(refTrafo))\n",
    "    \n",
    "    #rotate around the z-axis so that refRecoil lies in the x-z plain\n",
    "    result=RotateZ(result,pi-Phi(refRecoilTrafo))\n",
    "    \n",
    "    return(result)\n",
    "\n",
    "def SumLV(sum_array): #sum array of LorentzVectors\n",
    "    result = []\n",
    "    for i in range(0,len(sum_array[0][0])):\n",
    "        px = 0 \n",
    "        py = 0 \n",
    "        pz = 0 \n",
    "        e = 0\n",
    "        for j in range(0,len(sum_array)):\n",
    "            px+=sum_array[j][0][i]\n",
    "            py+=sum_array[j][1][i]\n",
    "            pz+=sum_array[j][2][i]\n",
    "            e+=sum_array[j][3][i]\n",
    "        result.append([px, py, pz, e])\n",
    "    return(result)\n",
    "    \n",
    "def CalcAngles(projectile4Vec, initialP4, combinedMother4Vec, combinedDec4Vec, gamgam): #Calc angular information\n",
    "    motherRef4Vec = []\n",
    "    refVec = []\n",
    "    \n",
    "    if gamgam == True :\n",
    "        motherRef4Vec = [3., 0., 0., 10.]\n",
    "        refVec = [0., 0., Perp(projectile4Vec), projectile4Vec[3]]\n",
    "        \n",
    "    if gamgam == False:\n",
    "        motherRef4Vec = projectile4Vec\n",
    "        refVec = initialP4\n",
    "    \n",
    "    result4Vec = []\n",
    "    Costheta = []\n",
    "    Phiangle = []\n",
    "    \n",
    "    for i in range(0,len(combinedMother4Vec)):\n",
    "        combinedMother4vec=[combinedMother4Vec[i][0], combinedMother4Vec[i][1], combinedMother4Vec[i][2], combinedMother4Vec[i][3]]\n",
    "        combinedDec4vec=[combinedDec4Vec[i][0], combinedDec4Vec[i][1], combinedDec4Vec[i][2], combinedDec4Vec[i][3]]\n",
    "        \n",
    "        #result4Vec.append(Boost(combinedMother4vec, combinedDec4vec))\n",
    "        result4Vec.append(HeliVec(motherRef4Vec, refVec, combinedMother4vec, combinedDec4vec))\n",
    "        #result4Vec.append(HeliVec(projectile4Vec, motherRef4Vec, combinedMother4vec, combinedDec4vec))\n",
    "        #result4Vec.append(combinedMother4vec)\n",
    "        Costheta.append(CosTheta(result4Vec[i]))\n",
    "        Phiangle.append(Phi(result4Vec[i]))\n",
    "    return(Costheta,Phiangle,result4Vec)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "def GetParticleNames(filename): # read finalStateParticles from cfg file\n",
    "    cfg = open(filename, \"r\")\n",
    "    file = cfg.readlines()\n",
    "    particlenames = []\n",
    "    for line in file:\n",
    "        if \"finalStateParticle\" in line:\n",
    "            line = line.replace(\"finalStateParticle\", \"\")\n",
    "            line = line. replace(\"=\", \"\")\n",
    "            line = line.strip()\n",
    "            particlenames.append(line)\n",
    "    return(particlenames)\n",
    "\n",
    "def ReadCFGFile(filename): \n",
    "    # read information from cfg file. Store contribution names which provide file names \n",
    "    #and kinematic informationcfrom initial Vector and projectile vector\n",
    "    \n",
    "    path = filename.rpartition(\"/\")[0]\n",
    "    cfg = open(filename, \"r\")\n",
    "    file = cfg.readlines()\n",
    "    contrib_names = []\n",
    "    file_names = []\n",
    "    file_name_extension = \"\"\n",
    "    initial4Vec = []\n",
    "    projectile4Vec = []\n",
    "    gamgamflag = False\n",
    "    \n",
    "    for line in file:\n",
    "        if \"calcContribution\" in line and not \"#\" in line:\n",
    "            line = line.replace(\"calcContribution\", \"\")\n",
    "            line = line.replace(\"=\", \"\")\n",
    "            line = line.split('withZeroAmp')[0]\n",
    "            line = line.strip()\n",
    "            contrib_names.append(line)\n",
    "        if \"name\" in line and not \"#\" in line:\n",
    "            line = line.replace(\"name\", \"\")\n",
    "            line = line.replace(\"=\", \"\")\n",
    "            line = line.strip()\n",
    "            file_name_extension=line\n",
    "        if \"initial4Vec\" in line and not \"#\" in line:\n",
    "            line = line.replace(\"initial4Vec\",\"\")\n",
    "            line = line.replace(\"=\",\"\")\n",
    "            line = line.strip()\n",
    "            vec = line.split()\n",
    "            initial4Vec = [float(vec[1]), float(vec[2]), float(vec[3]), float(vec[0])] \n",
    "        if \"projectile4Vec\" in line and not \"#\" in line:\n",
    "            line = line.replace(\"projectile4Vec\",\"\")\n",
    "            line = line.replace(\"=\",\"\")\n",
    "            line = line.strip()\n",
    "            vec = line.split()\n",
    "            projectile4Vec = [float(vec[1]), float(vec[2]), float(vec[3]), float(vec[0])]\n",
    "        if \"productionFormalism\" in line and \"FormationGamGam\" in line and not \"#\" in line:\n",
    "            gamgamflag = True\n",
    "    \n",
    "    file_names.append(str(path+\"/pawianHists\"+file_name_extension+\".root\"))\n",
    "    for i in range(0,len(contrib_names)): file_names.append(str(path+\"/pawianHists\"+file_name_extension+contrib_names[i]+\".root\"))\n",
    "    \n",
    "    return(file_names, contrib_names, file_name_extension, initial4Vec, projectile4Vec, gamgamflag)\n",
    "\n",
    "def ConvertToLatex(phrase): #Convert particle names to Latex code which can be used for plot labels etc.\n",
    "    latex_phrase = []\n",
    "    for i in range(0,len(phrase)):\n",
    "        dummy = phrase[i]\n",
    "        if \"+\" in dummy:\n",
    "            dummy=dummy.replace(\"+\",\"^{+}\")\n",
    "        if \"-\" in dummy:\n",
    "            dummy=dummy.replace(\"-\",\"^{-}\")\n",
    "        if \"0\" in dummy:\n",
    "            dummy=dummy.replace(\"0\",\"^{0}\")\n",
    "        if \"pion\" in dummy:\n",
    "            dummy = dummy.replace(\"pion\",\"\\pi\")\n",
    "        if \"etaprime\" in dummy:\n",
    "            dummy = dummy.replace(\"etaprime\",\"\\eta'\")\n",
    "        if \"eta\" in dummy:\n",
    "            dummy = dummy.replace(\"eta\",\"\\eta\")\n",
    "        if \"phi\" in dummy:\n",
    "            dummy = dummy.replace(\"phi\",\"\\phi\")\n",
    "        if \"rho\" in dummy:\n",
    "            dummy = dummy.replace(\"rho\",\"\\rho\")\n",
    "        if \"pbar\" in dummy:\n",
    "            dummy = dummy.replace(\"pbar\",\"\\bar{p}\")\n",
    "        if \"nbar\" in dummy:\n",
    "            dummy = dummy.replace(\"nbar\",\"\\bar{n}\")\n",
    "        latex_phrase.append(dummy)\n",
    "    return(latex_phrase)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "def DrawContribData(Data, Weight, Color, Name, plot_range, N_bins): #Draw Data Contribution with error bars\n",
    "    histo = plt.hist(Data, bins = N_bins, range=plot_range, weights=Weight, histtype='step', label = Name, color = Color, linewidth=2.0)\n",
    "    edges = histo[1]\n",
    "    entries = histo[0] \n",
    "    bin_centers= []\n",
    "    for i in range(0,len(edges)-1):\n",
    "        bin_centers.append(0.5 * (edges[i+1] + edges[i]))\n",
    "    graph = plt.errorbar(bin_centers, entries, yerr=np.sqrt(entries), color = Color, fmt = '.', linewidth=2.0)\n",
    "    return(N_bins, histo)\n",
    "\n",
    "def DrawContrib(Data, Weight, Color, Name, plot_range, N_bins): #Draw Fitted Contribution as simple histogram \n",
    "    histo = plt.hist(Data, N_bins, range=plot_range, weights=Weight, label = Name, histtype='step', color = Color, linewidth=2.0)\n",
    "    return(histo)\n",
    "\n",
    "\n",
    "def DrawAllContribs(vals_data, vals_fit, weights, labels, xlabels, nbins, resid, hist_type): #Draw them all together...\n",
    "    \n",
    "    #calc senseful range of x-Axis\n",
    "    \n",
    "    if hist_type==1: x_range=[-1., 1.]\n",
    "    if hist_type==2: x_range=[-3.2, 3.2]\n",
    "\n",
    "    \n",
    "    if hist_type==0:\n",
    "        \n",
    "        bla = DrawContribData(vals_data, weights[0], \"black\", labels[0], (0., 4.), nbins)\n",
    "        bin_width = 4./nbins\n",
    "    \n",
    "        dummy = 0.\n",
    "        x_min_opti=0.\n",
    "        x_max_opti=0.\n",
    "    \n",
    "        for i in range(0,len(bla[1][0])):\n",
    "            dummy+=bla[1][0][i]\n",
    "            if dummy==0.: \n",
    "                x_min_opti=bin_width*(i)\n",
    "          \n",
    "        dummy = 0.\n",
    "    \n",
    "        for i in reversed(range(0,len(bla[1][0]))):\n",
    "            dummy+=bla[1][0][i]\n",
    "            if dummy==0.: \n",
    "                x_max_opti=bin_width*(i)\n",
    "        \n",
    "        # clear figure before plotting with right ranges\n",
    "        plt.clf()\n",
    "        \n",
    "        x_range = [x_min_opti, x_max_opti]\n",
    "\n",
    "    bla = plt.hist(vals_data, bins = \"auto\")\n",
    "    \n",
    "    nbins=2*len(bla[0])\n",
    "    plt.clf()\n",
    "    \n",
    "    fig = plt.figure(figsize=(10,10))\n",
    "\n",
    "    frame1=fig.add_axes((.1,.1,.8,0.6))\n",
    "    \n",
    "    #Draw data\n",
    "    hist_data = DrawContribData(vals_data, weights[0], \"black\", labels[0], (x_range[0],x_range[1]), nbins)\n",
    "    \n",
    "    #Draw Total Fit result\n",
    "    hist_fit = DrawContrib(vals_fit, weights[1], \"red\", labels[1], (x_range[0],x_range[1]), nbins)\n",
    "    \n",
    "    #Set \"nice\" plot colors, change if necessesary...\n",
    "    col = [\"darkorange\", \"deepskyblue\", \"dodgerblue\", \"forestgreen\", \"yellowgreen\", \"greenyellow\", \"m\", \"deeppink\", \"violet\", \"gold\"]\n",
    "    #col = [\n",
    "    #\"#1f77b4\", \"#aec7e8\", \"#ff7f0e\", \"#ffbb78\", \"#2ca02c\", \"#98df8a\",\n",
    "    #\"#d62728\", \"#ff9896\", \"#9467bd\", \"#c5b0d5\", \"#8c564b\", \"#c49c94\",\n",
    "    #\"#e377c2\", \"#f7b6d2\", \"#7f7f7f\", \"#c7c7c7\", \"#bcbd22\", \"#dbdb8d\",\n",
    "    #\"#17becf\", \"#9edae5\"]\n",
    "    \n",
    "    #Draw contribs\n",
    "    for i in range(2,len(labels)):\n",
    "        DrawContrib(vals_fit, weights[i], col[i-2], labels[i], (x_range[0],x_range[1]), nbins)\n",
    "\n",
    "    plt.legend()\n",
    "\n",
    "    x_min, x_max = plt.xlim()\n",
    "\n",
    "    #Set labels if mass- or angular plot\n",
    "    if hist_type==0:\n",
    "        plt.xlabel(\"$\\mathrm{M(\"+xlabels+\")\\,\\,\\,[GeV/c^{2}]}$\", fontsize=18)\n",
    "        plt.ylabel(\"Events\" + \" / (\" + str(round((x_max-x_min)/nbins-(x_max-x_min)/(10*nbins),3)) + \" $\\mathrm{GeV/c^{2}})$\", fontsize=18)\n",
    "    if hist_type==1 : \n",
    "        plt.xlabel(\"$\\mathrm{\\cos(\"+xlabels+\"}$\", fontsize=18)\n",
    "        plt.ylabel(\"Events\" + \" / (\" + str(round((x_max-x_min)/nbins-(x_max-x_min)/(10*nbins),3)) + \")\", fontsize=18)\n",
    "    if hist_type==2 : \n",
    "        plt.xlabel(\"$\\mathrm{\\phi(\"+xlabels+\"}$\", fontsize=18)\n",
    "        plt.ylabel(\"Events\" + \" / (\" + str(round((x_max-x_min)/nbins-(x_max-x_min)/(10*nbins),3)) + \")\", fontsize=18)\n",
    "    \n",
    "    #Draw Residuals if enabled\n",
    "    if resid == True:\n",
    "        residx = []\n",
    "        residy = []\n",
    "    \n",
    "        for i in range(0, len(hist_fit[0])):\n",
    "            if hist_data[1][0][i]!=0: \n",
    "                residy.append((hist_data[1][0][i]-hist_fit[0][i])/np.sqrt(hist_data[1][0][i]))\n",
    "                residx.append(0.5*(hist_data[1][1][i]+hist_data[1][1][i+1]))\n",
    "    \n",
    "        frame2=fig.add_axes((.1,.7,0.8,0.2))\n",
    "        frame2.set_xticklabels([])\n",
    "\n",
    "        x_min = 1.\n",
    "        x_max = 2.\n",
    "        x_line=[x_min,x_max]\n",
    "        y_line=[3.,3.]\n",
    "\n",
    "        graph = plt.errorbar(x=residx, y=residy, color = \"black\", fmt = 'o', linewidth=2.0, alpha=0.75)\n",
    "        plt.axhline(y=3., color='gray', linestyle='--', alpha=1.)\n",
    "        plt.axhline(y=-3., color='gray', linestyle='--', alpha=1.)\n",
    "        plt.axhline(y=0., color='gray', linestyle='-', alpha=1.)\n",
    "        plt.ylabel(\"Residuals\")\n",
    "        plt.ylim(-3.5,3.5)\n",
    "    \n",
    "    plt.show()\n",
    "\n",
    "    \n",
    "def CalcMassHistos(filename, array_data, array_fit): \n",
    "    #Read mass histos from cfg file, remember involved partilces, prepare vectors for all specified plots and build labels\n",
    "    \n",
    "    cfg=open(filename, \"r\")\n",
    "    file =cfg.readlines()\n",
    "    mass_histos_data = []\n",
    "    mass_histos_fit = []\n",
    "    particles = GetParticleNames(filename)\n",
    "    latex_particles = ConvertToLatex(particles)\n",
    "    xlabels = []\n",
    "    \n",
    "    for line in file:\n",
    "        \n",
    "        if \"histMass\" in line and not \"#\" in line:\n",
    "            line = line.replace(\"histMass\", \"\")\n",
    "            line = line.replace(\"=\", \"\")\n",
    "            line = line.strip()\n",
    "            particles_in_histo_data = []\n",
    "            particles_in_histo_fit = []\n",
    "            particle_names = \"\"\n",
    "\n",
    "            for i in range(0,len(particles)):\n",
    "                if particles[i] in line:\n",
    "                    print(array_data[i])\n",
    "                    particles_in_histo_data.append(array_data[i])\n",
    "                    particles_in_histo_fit.append(array_fit[i])\n",
    "                    particle_names+=latex_particles[i]\n",
    "            \n",
    "            mass_histos_data.append(Mass(particles_in_histo_data))\n",
    "            mass_histos_fit.append(Mass(particles_in_histo_fit))\n",
    "            xlabels.append(particle_names)\n",
    "            \n",
    "    return(mass_histos_data, mass_histos_fit, xlabels)\n",
    "\n",
    "\n",
    "def CalcAngleHistos(filename, array_data, array_fit):\n",
    "    #Read angle histos from cfg file, remember involved partilces, prepare vectors for all specified plots and build labels\n",
    "\n",
    "    cfg = open(filename, \"r\")\n",
    "    file = cfg.readlines()\n",
    "    \n",
    "    angles_fit = []\n",
    "    angles_data = []\n",
    "    particles = GetParticleNames(filename)\n",
    "    latex_particles = ConvertToLatex(particles)\n",
    "    \n",
    "    #print(particles)\n",
    "    #print(latex_particles)\n",
    "    \n",
    "    #get infos from cfg file\n",
    "    cfg_info = ReadCFGFile(filename)\n",
    "    initial4Vec = cfg_info[3]\n",
    "    projectile4Vec = cfg_info[4]\n",
    "    formation_gamgam = cfg_info[5]\n",
    "    \n",
    "    xlabels = []\n",
    "    \n",
    "    for line in file:\n",
    "        #Go through all lines search for histAngles (if not commented....) and just tatke everything after \"=\" sign\n",
    "        #Separate  mother and daughter particles by \"from\" index in partticle list is the same as in four vector array \n",
    "        #therefore add all involved particles up and plug them into CalcAngles\n",
    "        if \"histAngles\" in line and not \"#\" in line:\n",
    "            line = line.replace(\"histAngles\", \"\")\n",
    "            line = line.replace(\"=\", \"\")\n",
    "            line = line.strip()\n",
    "            daughter, mother = line.split(\"from\")\n",
    "    \n",
    "            #print(daughter, mother)\n",
    "        \n",
    "            daughter_in_histo_data = []\n",
    "            daughter_in_histo_fit = []\n",
    "\n",
    "            mother_in_histo_data = []\n",
    "            mother_in_histo_fit = []\n",
    "            angle_histos_daughter_data = []\n",
    "            angle_histos_daughter_fit = []\n",
    "\n",
    "            angle_histos_mother_data = []\n",
    "            angle_histos_mother_fit = []\n",
    "            particle_names_daughter = \"\"\n",
    "            particle_names_mother = \"\"\n",
    "                \n",
    "            for i in range(0,len(particles)):\n",
    "                if particles[i] in daughter: \n",
    "                    daughter_in_histo_data.append(array_data[i])\n",
    "                    daughter_in_histo_fit.append(array_fit[i])\n",
    "                    particle_names_daughter+=latex_particles[i]\n",
    "                    #print(\"daughter: \", i, particles[i])\n",
    "      \n",
    "                if particles[i] in mother: \n",
    "                    mother_in_histo_data.append(array_data[i])\n",
    "                    mother_in_histo_fit.append(array_fit[i])\n",
    "                    particle_names_mother+=latex_particles[i]\n",
    "                    #print(\"mother: \", i, particles[i])\n",
    "                    \n",
    "            angle_histos_daughter_data=SumLV(daughter_in_histo_data)\n",
    "            angle_histos_daughter_fit=SumLV(daughter_in_histo_fit)\n",
    "        \n",
    "            angle_histos_mother_data=SumLV(mother_in_histo_data)\n",
    "            angle_histos_mother_fit=SumLV(mother_in_histo_fit)\n",
    "            \n",
    "            angles_data.append(CalcAngles(projectile4Vec, initial4Vec, angle_histos_mother_data, angle_histos_daughter_data, formation_gamgam))\n",
    "            angles_fit.append(CalcAngles(projectile4Vec, initial4Vec, angle_histos_mother_fit, angle_histos_daughter_fit, formation_gamgam))\n",
    "\n",
    "            xlabels.append(particle_names_daughter+\")_{\"+particle_names_mother+\"}\")\n",
    "        #print(xlabels)\n",
    "    return(angles_data, angles_fit, xlabels)\n",
    "\n",
    "def DataFitCompare(filename):\n",
    "\n",
    "    cfg_info = ReadCFGFile(filename)\n",
    "    file_array = cfg_info[0]\n",
    "    contrib_names = cfg_info[1]\n",
    "    \n",
    "    initial4Vec = cfg_info[3]\n",
    "    projectile4Vec = cfg_info[4]\n",
    "\n",
    "    particles=GetParticleNames(filename)\n",
    "    \n",
    "    Labels=[\"Data\",\"Fit\"]\n",
    "    for i in range(0,len(contrib_names)): Labels.append(\"$\\mathrm{\"+contrib_names[i]+\"}$\")\n",
    "\n",
    "    array_data = []\n",
    "    array_fit= []\n",
    "        \n",
    "    for i in range(0,len(particles)):\n",
    "        array_data.append(Fill4Vecs(filename = file_array[0], particlename=particles[i], datatype=\"data\"))\n",
    "        array_weight_data = FillWeight(filename = file_array[0], datatype=\"data\")\n",
    "    \n",
    "        array_fit.append(Fill4Vecs(filename = file_array[0], particlename=particles[i], datatype=\"fitted\"))\n",
    "        array_weight_fit = FillWeight(filename = file_array[0], datatype=\"fitted\")\n",
    "\n",
    "    array_weight_fit_contrib = []\n",
    "\n",
    "\n",
    "    for i in range(1,len(file_array)):\n",
    "\n",
    "        weight = FillWeight(filename = file_array[i], datatype=\"fitted\")\n",
    "        array_weight_fit_contrib.append(weight)\n",
    "    \n",
    "    #weight has to be scaled to number of data events\n",
    "\n",
    "    for i in range(0,len(array_weight_fit)):\n",
    "        array_weight_fit[i] = array_weight_fit[i]*(len(array_weight_data)/len(array_weight_fit))\n",
    "        for j in range(0,len(array_weight_fit_contrib)):\n",
    "            array_weight_fit_contrib[j][i] = array_weight_fit_contrib[j][i]*(len(array_weight_data)/len(array_weight_fit))\n",
    "\n",
    "    Weights = [array_weight_data, array_weight_fit] \n",
    "\n",
    "    for i in range(0,len(array_weight_fit_contrib)): Weights.append(array_weight_fit_contrib[i])\n",
    "\n",
    "    mass_histos = CalcMassHistos(filename, array_data, array_fit)\n",
    "    mass_histos_data = mass_histos[0]\n",
    "    mass_histos_fit = mass_histos[1]\n",
    "    mass_xlabels = mass_histos[2]\n",
    "\n",
    "    angle_histos = CalcAngleHistos(filename, array_data, array_fit)\n",
    "    angle_histos_data = angle_histos[0]\n",
    "    angle_histos_fit = angle_histos[1]\n",
    "    angle_xlabels = angle_histos[2]\n",
    "\n",
    "\n",
    "    for i in range(0,len(mass_histos_data)):\n",
    "        DrawAllContribs(mass_histos_data[i], mass_histos_fit[i], weights=Weights, labels=Labels, xlabels=mass_xlabels[i], nbins=100, resid=True, hist_type=0)\n",
    "    \n",
    "    #rows = math.ceil(len(angle_histos_data)/2.)\n",
    "    #fig, axs = plt.subplots(nrows=rows, ncols=2, constrained_layout=True)\n",
    "    for i in range(0,len(angle_histos_data)):\n",
    "    \n",
    "        DrawAllContribs(angle_histos_data[i][0], angle_histos_fit[i][0], weights=Weights, labels=Labels, xlabels=angle_xlabels[i], nbins=50, resid=True, hist_type=1)\n",
    "        DrawAllContribs(angle_histos_data[i][1], angle_histos_fit[i][1], weights=Weights, labels=Labels, xlabels=angle_xlabels[i], nbins=50, resid=True, hist_type=2)\n",
    "            \n",
    "#DataFitCompare(\"work/notebooks/gamgamToKpKm.cfg\")\n",
    "#DataFitCompare(\"work/notebooks/gamgamToPiPi.cfg\")\n",
    "#DataFitCompare(\"work/notebooks/gamgamToPiEta.cfg\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h1 style=\"color:red;\">Hier Config File angeben! </h1>\n",
    "<h1 style=\"color:red;\">Mit Shift + return Zelle ausführen! </h1>\n",
    "<h1 style=\"color:red;\">  &#8595; </h1>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[array([-0.14315829,  0.32363623,  0.24919981, ...,  0.31879199,\n",
      "       -0.05554278, -0.35699686]), array([ 0.31108049, -0.14174055,  0.08356895, ..., -0.66165715,\n",
      "        0.42708772,  0.24288993]), array([ 0.48183188, -0.52449453, -0.0743541 , ...,  0.53555232,\n",
      "       -0.20083331,  0.03695475]), array([0.77015865, 0.80227321, 0.56420726, ..., 1.03438485, 0.68522984,\n",
      "       0.65690553])]\n",
      "[array([ 0.15555391, -0.31354654, -0.24040399, ..., -0.29747751,\n",
      "        0.07234567,  0.36732161]), array([-0.31488803,  0.13087773, -0.08565993, ...,  0.64843708,\n",
      "       -0.42404261, -0.24543616]), array([ 0.49711576, -0.01161289, -0.40197691, ...,  0.45678344,\n",
      "        0.36669087,  0.097618  ]), array([0.7837044 , 0.59940994, 0.68588203, ..., 0.98047519, 0.75048333,\n",
      "       0.66963446])]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 432x288 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 41304 characters]\n",
      "text/plain": [
       "<Figure size 720x720 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 432x288 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 39408 characters]\n",
      "text/plain": [
       "<Figure size 720x720 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 432x288 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 33472 characters]\n",
      "text/plain": [
       "<Figure size 720x720 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "DataFitCompare(\"/data/jollyj/mkuessner/pwa/coupled_KK_PiEta_PiPi_Scatter/V2_4180_ptfit/qaKK/gamgamToKpKm.cfg\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[array([ 0.08701415, -0.18051487,  0.14957982, ..., -0.24390289,\n",
      "        0.81115645, -0.76107383]), array([-0.15064873,  0.02720066,  0.09696195, ..., -0.75077325,\n",
      "        0.04613239,  0.12793149]), array([ 0.10056948,  0.14994252, -0.08001667, ..., -0.64653009,\n",
      "       -0.35265854, -0.8949396 ]), array([0.24320398, 0.2694729 , 0.23742744, ..., 1.02881885, 0.8946228 ,\n",
      "       1.18998528])]\n",
      "[array([-0.06759977,  0.17651421, -0.14947739, ...,  0.25990972,\n",
      "       -0.78893614,  0.76363564]), array([ 0.15401419, -0.010195  , -0.09198552, ...,  0.75453895,\n",
      "       -0.04817993, -0.13815258]), array([ 1.40905104e-04,  1.14547811e-01, -6.86994866e-02, ...,\n",
      "        4.88685668e-01,  8.40710163e-01,  3.34449500e-01]), array([0.21824704, 0.2425352 , 0.22053307, ..., 0.94504374, 1.16243923,\n",
      "       0.85441542])]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 432x288 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 46456 characters]\n",
      "text/plain": [
       "<Figure size 720x720 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 432x288 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 37584 characters]\n",
      "text/plain": [
       "<Figure size 720x720 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 432x288 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 29704 characters]\n",
      "text/plain": [
       "<Figure size 720x720 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "DataFitCompare(\"work/notebooks/qaPiPi_4180/gamgamToPiPi.cfg\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[array([-0.02547574,  0.06912413,  0.08497836, ...,  0.06535703,\n",
      "        0.90747565,  0.46422556]), array([ 0.0510571 ,  0.02558937, -0.03077922, ..., -0.89117134,\n",
      "        0.02503978, -0.72017324]), array([ 0.28659117,  0.31157529, -0.22558844, ..., -0.05729357,\n",
      "       -0.21771196, -0.81005758]), array([0.3182531 , 0.34923548, 0.27392986, ..., 0.90481704, 0.94088709,\n",
      "       1.18516695])]\n",
      "[array([ 0.03882256, -0.07688417, -0.09492538, ..., -0.0459692 ,\n",
      "       -0.90885234, -0.45010287]), array([-0.06510972, -0.02735111,  0.01158894, ...,  0.88413632,\n",
      "       -0.05046833,  0.74610251]), array([ 0.15203504,  0.11642899, -0.23303194, ...,  0.75137591,\n",
      "        0.56995136,  0.15631956]), array([0.2245198 , 0.1897838 , 0.28221929, ..., 1.16930711, 1.08239281,\n",
      "       0.89538449])]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 432x288 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 35716 characters]\n",
      "text/plain": [
       "<Figure size 720x720 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 432x288 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 31700 characters]\n",
      "text/plain": [
       "<Figure size 720x720 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 432x288 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 28112 characters]\n",
      "text/plain": [
       "<Figure size 720x720 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "DataFitCompare(\"work/notebooks/qaPiPi/gamgamToPiPi.cfg\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[array([-0.37809569,  0.01578744,  0.06944999, ..., -0.17304711,\n",
      "       -0.11967529, -0.42186007]), array([ 0.19861966,  0.3917653 , -0.30622399, ...,  0.31263259,\n",
      "        0.27353317, -0.03355177]), array([-0.20003013,  0.10878587, -0.24113791, ..., -0.44859827,\n",
      "       -0.19285816, -0.43695033]), array([0.49054751, 0.42869845, 0.41828534, ..., 0.58918875, 0.38020495,\n",
      "       0.62308574])]\n",
      "[array([ 0.42276418,  0.00528423, -0.05348444, ...,  0.13510601,\n",
      "        0.1348726 ,  0.45582226]), array([-0.2102544 , -0.44589275,  0.31397161, ..., -0.24363372,\n",
      "       -0.2561506 ,  0.03273025]), array([ 0.03851523, -0.1684939 , -0.29506364, ...,  0.30988386,\n",
      "       -0.20663238,  0.01320917]), array([0.72427386, 0.72621703, 0.69903797, ..., 0.68832535, 0.65318716,\n",
      "       0.7135632 ])]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 432x288 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 33088 characters]\n",
      "text/plain": [
       "<Figure size 720x720 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 432x288 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 30292 characters]\n",
      "text/plain": [
       "<Figure size 720x720 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 432x288 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 26104 characters]\n",
      "text/plain": [
       "<Figure size 720x720 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "DataFitCompare(\"work/notebooks/qaPiEta/gamgamToPiEta.cfg\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Jetzt kommt nur ein Test die Sheets zu plotten für eins meiner files..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [],
   "source": [
    "from matplotlib import cm\n",
    "from mpl_toolkits.mplot3d import Axes3D\n",
    "#%matplotlib notebook\n",
    "# aka import ipympl\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "\n",
    "file = uproot.open(\"work/notebooks/TMatrixGeneral.root\")\n",
    "hist = file[\"sheet_----;1\"]\n",
    "\n",
    "arr=hist.allvalues\n",
    "nbinsx=len(arr)\n",
    "nbinsy=len(arr[0])\n",
    "x_low, y_low = hist.low\n",
    "x_max, y_max = hist.high\n",
    "binning_x = (x_max-x_low)/nbinsx\n",
    "binning_y = (y_max-y_low)/nbinsy\n",
    "\n",
    "X=[]\n",
    "Y=[]\n",
    "\n",
    "bla_x = []\n",
    "\n",
    "for i in range(0,nbinsx):\n",
    "    bla_x.append(i*(binning_x)+x_low)\n",
    "\n",
    "for j in range(0,nbinsy):\n",
    "    X.append(bla_x)\n",
    "\n",
    "\n",
    "\n",
    "for i in range(0,nbinsx):\n",
    "    bla=i*(binning_y)+y_low\n",
    "    #print(bla)\n",
    "    bla_y = []\n",
    "    for j in range(0,nbinsy):\n",
    "        bla_y.append(bla)\n",
    "    Y.append(bla_y)\n",
    "    #print(Y[i][0])\n",
    "\n",
    "#fig = plt.figure(figsize=(10,5))\n",
    "#ax = Axes3D(fig)\n",
    "\n",
    "#ax.plot_surface(X, Y, arr, cmap=cm.viridis, rstride=2, cstride=2)\n",
    "\n",
    "#plt.show()\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [],
   "source": [
    "import ipyvolume as ipv"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 12876 characters]\n",
      "text/plain": [
       "<Figure size 468x360 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 20956 characters]\n",
      "text/plain": [
       "<Figure size 468x360 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "ee4019fa4efa4a40b88d017bdb8c6a3d",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "VBox(children=(Figure(camera=PerspectiveCamera(fov=46.0, position=(0.0, 0.0, 2.0), quaternion=(0.0, 0.0, 0.0, …"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "arr=hist.allvalues \n",
    "#print(X[0])\n",
    "Z=arr\n",
    "\n",
    "#for i in range(0,len(arr)):\n",
    "#    for j in range(0,len(arr[0])):\n",
    "#        if arr[i][j] != 0.:\n",
    "#            Z[i][j]=np.log(arr[i][j])\n",
    "\n",
    "\n",
    "#bla=Z\n",
    "\n",
    "\n",
    "Z=Z.transpose()\n",
    "\n",
    "Norm = cm.colors.Normalize(vmax=60., vmin=5.)\n",
    "\n",
    "fig, ax = plt.subplots(figsize=(6.5,5))\n",
    "ax.set_title(\"Sheet ----\")\n",
    "ax.set_xlim(1., 2.2)\n",
    "ax.set_xlabel(\"Re(Z)\")\n",
    "ax.set_ylabel(\"Im(Z)\")\n",
    "\n",
    "ax.set_ylim(-0.3, -0.005)\n",
    "surf_plotf = ax.contourf(X, Y, Z, 20, norm=Norm, cmap=cm.jet)\n",
    "surf_plot = ax.contour(X, Y, Z, 20, colors='black', linewidths=(1.))\n",
    "\n",
    "cbar = fig.colorbar(surf_plotf)\n",
    "cbar.ax.set_ylabel(\"log\")\n",
    "\n",
    "plt.show()\n",
    "\n",
    "\n",
    "Norm = cm.colors.Normalize(vmax=20., vmin=-1.)\n",
    "\n",
    "fig, ax = plt.subplots(figsize=(6.5,5))\n",
    "ax.set_xlim(1., 2.2)\n",
    "ax.set_xlabel(\"Re(Z)\")\n",
    "ax.set_ylabel(\"Im(Z)\")\n",
    "\n",
    "ax.set_ylim(-0.3, -0.01)\n",
    "surf_plot = ax.contour(X, Y, Z, 50, cmap=cm.jet)\n",
    "\n",
    "cbar = fig.colorbar(surf_plot)\n",
    "cbar.ax.set_ylabel(\"log\")\n",
    "\n",
    "plt.show()\n",
    "\n",
    "\n",
    "blaX = np.array(X)\n",
    "blaY = np.array(Y)\n",
    "blaZ = np.array(Z)\n",
    "\n",
    "colormap = cm.jet\n",
    "znorm = blaZ - blaZ.min()+10.\n",
    "znorm /= znorm.ptp()\n",
    "znorm.min(), znorm.max()\n",
    "color = colormap(znorm)\n",
    "\n",
    "ipv.figure()\n",
    "surf = ipv.plot_surface(blaX, blaY, blaZ, color=color[...,:3])\n",
    "\n",
    "ipv.style.box_off()\n",
    "ipv.pylab.xlim(1.,2.)\n",
    "ipv.pylab.ylim(-0.4,-0.01)\n",
    "\n",
    "\n",
    "ipv.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
