{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The Process Macro by Andrew F. Hayes has helped thousands of researchers\n",
    "in their analysis of moderation, mediation, and conditional processes.\n",
    "Unfortunately, Process was only available for proprietary softwares\n",
    "(SAS and SPSS), which means that students and researchers had to\n",
    "purchase a license of those softwares to make use of the Macro.\n",
    "\n",
    "Because of the growing popularity of Python in the scientific community,\n",
    "I decided to implement the features of the Process Macro into an\n",
    "open-source library, that researchers will be able to use without\n",
    "relying on proprietary softwares. pyprocessmacro is open-source, and\n",
    "released under a MIT license."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1. Features"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## A. Current Implementation"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the current version, pyprocessmacro replicates the following features\n",
    "from the original Process Macro v2.16:\n",
    "\n",
    "* All models (1 to 76), with the exception of Model 6 (serial mediation)\n",
    "are supported, and have been numerically tested for accuracy against the\n",
    "output of the original Process macro (see the `test_models_accuracy.py`)\n",
    "* Estimation of binary/continuous outcome variables. The binary outcomes\n",
    "are estimated in Logit using the Newton-Raphson convergence algorithm,\n",
    "the continuous variables are estimated using OLS.\n",
    "* Estimation of (conditional) direct and indirect effects\n",
    "* Indices for Partial/Conditional/Moderated Moderated Mediation\n",
    "* Automatic generation of spotlight values for continuous/discrete\n",
    "moderators.\n",
    "* Rich set of options to tweak the estimation and display of the\n",
    "different models: (almost) all the options from Process exist in\n",
    "pyprocessmacro. See the documentation for more details"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## B. Changes and Improvements"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "The following changes and improvements have been made from the original Process Macro:\n",
    "\n",
    "* Variable names can be of any length, and even include spaces and\n",
    "special characters.\n",
    "* All mediation models support an infinite number of mediators\n",
    "(versus a maximum of 10 in Process).\n",
    "* Normal theory tests for the indirect effect(s) are not reported, as\n",
    "the bias-corrected bootstrapping approach is now widely accepted and in\n",
    "most cases more robust.\n",
    "* Plotting capabilities: pyprocessmacro can generate the plot of direct\n",
    "and indirect effects at various levels of the moderators.\n",
    "* Fast estimation process: pyprocessmacro leverages the capabilities of\n",
    "NumPy to efficiently compute a large number of bootstrap estimates,\n",
    "which dramatically speeds up the estimation of complex models.\n",
    "* Transparent bootstrapping: pyprocessmacro automatically store the\n",
    "bootstrap estimates for convenient inspection, and explicitely reports\n",
    "the samples that have been discarded because of numerical instability."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## C. Missing Features"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the current version, the following features have not yet been ported to pyprocessmacro:\n",
    "\n",
    "* Support for categorical independent variables.\n",
    "* Generation of individual fixed effects for repeated measures.\n",
    "* R² improvement from moderators in moderation models (1, 2, 3).\n",
    "* Estimation of serial mediation (Model 6)\n",
    "* Some options (`normal`, `varorder`, ...). pyprocessmacro will issue a\n",
    "warning if you are trying to use an option that has not been implemented."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2. Installation and Usage "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## A. Installation "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can install pyprocessmacro with pip:\n",
    "\n",
    "    pip install pyprocessmacro"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## B. Minimal Example"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Process successfully initialized.\n",
      "Based on the Process Macro by Andrew F. Hayes, Ph.D. (www.afhayes.com)\n",
      "\n",
      "\n",
      "****************************** SPECIFICATION ****************************\n",
      "\n",
      "Model = 4\n",
      "\n",
      "Variables:\n",
      "    Cons = Cons\n",
      "    x = Effort\n",
      "    y = Success\n",
      "    m1 = MediationSkills\n",
      "\n",
      "Sample size:\n",
      "1000\n",
      "\n",
      "Bootstrapping information for indirect effects:\n",
      "Final number of bootstrap samples: 5000\n",
      "Number of samples discarded due to convergence issues: 0\n",
      "\n",
      "***************************** OUTCOME MODELS ****************************\n",
      "\n",
      "Outcome = Success \n",
      "OLS Regression Summary\n",
      "\n",
      "     R²  Adj. R²    MSE          F  df1  df2  p-value\n",
      " 0.9699   0.9698 2.0003 16083.2644    2  997   0.0000\n",
      "\n",
      "Coefficients\n",
      "\n",
      "                 coeff     se        t      p    LLCI   ULCI\n",
      "Cons            1.8755 0.0664  28.2317 0.0000  1.7453 2.0057\n",
      "Effort          0.0653 0.0500   1.3060 0.1919 -0.0327 0.1632\n",
      "MediationSkills 1.0053 0.0066 153.1107 0.0000  0.9925 1.0182\n",
      "\n",
      "-------------------------------------------------------------------------\n",
      "\n",
      "Outcome = MediationSkills \n",
      "OLS Regression Summary\n",
      "\n",
      "     R²  Adj. R²     MSE        F  df1  df2  p-value\n",
      " 0.2648   0.2633 46.4881 359.3661    1  998   0.0000\n",
      "\n",
      "Coefficients\n",
      "\n",
      "        coeff     se       t      p   LLCI   ULCI\n",
      "Cons   4.1472 0.2921 14.1967 0.0000 3.5746 4.7197\n",
      "Effort 3.9167 0.2066 18.9570 0.0000 3.5118 4.3216\n",
      "\n",
      "-------------------------------------------------------------------------\n",
      "\n",
      "\n",
      "********************** DIRECT AND INDIRECT EFFECTS **********************\n",
      "\n",
      "Direct effect of Effort on Success:\n",
      "\n",
      "  Effect     SE      t      p    LLCI   ULCI\n",
      "  0.0653 0.0500 1.3060 0.1919 -0.0327 0.1632\n",
      "\n",
      "Indirect effect of Effort on Success:\n",
      "\n",
      "                   Effect  Boot SE  BootLLCI  BootULCI\n",
      "  MediationSkills  3.9377   0.2362    3.4967    4.4323\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import pandas as pd\n",
    "from pyprocessmacro import Process\n",
    "\n",
    "df = pd.read_csv(\"files/data.csv\")\n",
    "p = Process(data=df, model=4, x=\"Effort\", y=\"Success\", m=[\"MediationSkills\"])\n",
    "p.summary()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Two important notes:\n",
    "* There is no argument `varlist` in pyprocessmacro: this list is automatically inferred from the variable names given to x, y, m, etc...\n",
    "* The argument supplied to `m` is a list, even if you have a single mediator.\n",
    "\n",
    "Other than this, the syntax for pyprocessmacro is (almost) identical to that of Process. Unless this documentation\n",
    "mentions otherwise, you can assume that all the options/keywords from Process exist in pyprocessmacro.\n",
    "\n",
    "Once the object is initialized, its `summary()` method is used to\n",
    "display the estimation results."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## C. Suppress the Initialization Message"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "When the Process object is initialized by Python, it displays various\n",
    "information about the model (model number, list of variables,\n",
    "sample size, number of bootstrap samples, etc...). If you wish not to\n",
    "display this information, just add the argument `suppr_init=True` when\n",
    "initializing the model.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "p = Process(\n",
    "    data=df,\n",
    "    model=4,\n",
    "    x=\"Effort\",\n",
    "    y=\"Success\",\n",
    "    m=[\"MediationSkills\"],\n",
    "    controls=[\"ModerationSkills\"],\n",
    "    controls_in=\"all\",\n",
    "    suppr_init=True,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## D. Adding Statistical Controls"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In Process, the controls are defined as \"any argument in the varlist\n",
    "that is not the IV, the DV, a moderator, or  a mediator.\" \n",
    "\n",
    "In\n",
    "pyprocessmacro, the list of variables to include as controls have to\n",
    "be explicitely specified in the \"controls\" argument."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "p = Process(\n",
    "    data=df,\n",
    "    model=4,\n",
    "    x=\"Effort\",\n",
    "    y=\"Success\",\n",
    "    m=[\"MediationSkills\"],\n",
    "    controls=[\"ModerationSkills\"],\n",
    "    controls_in=\"all\",\n",
    "    suppr_init=True,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "The equation(s) to which the controls are added is specified through\n",
    "a `controls_in` argument:\n",
    "\n",
    "  * `x_to_m` means that the controls will only be added in the path\n",
    "  from the IV to the mediator(s) only.\n",
    "  * `all_to_y` means that the controls will only be added in the path\n",
    "  from the IV and the mediators to the DV.\n",
    "  * `all` means that the controls will be added in all equations.\n",
    "  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## E. Logistic Regressions for Binary Outcomes\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The original Process Macro automatically uses a Logistic (instead of OLS)\n",
    "regression when it detects a binary outcome.\n",
    " \n",
    "pyprocessmacro favors a more explicit approach, and requires you to set\n",
    "the parameter `logit` to `True` if your DV should be estimated using a\n",
    "Logistic regression. It goes without saying that this will return an error if your DV is not\n",
    "dichotomous.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "p = Process(\n",
    "    data=df,\n",
    "    model=4,\n",
    "    x=\"Effort\",\n",
    "    y=\"SuccessBinary\",\n",
    "    m=[\"MediationSkills\"],\n",
    "    controls=[\"ModerationSkills\"],\n",
    "    logit=True,\n",
    "    suppr_init=True,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## F. Spotlight Values for Moderators"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In Process as in pyprocessmacro, the spotlight values of the moderators\n",
    " are defined as follow:\n",
    "\n",
    "* By default, the spotlight values are equal to M - 1SD, M and M + 1SD,\n",
    "where M and SD are the mean and standard deviation of that variable.\n",
    "* If the option `quantile=True` is specified, then the spotlight values\n",
    "for each moderator are the 10th, 25th, 50th, 75th and 90th percentile of\n",
    "that variable.\n",
    "* If a moderator is a discrete variable, the spotlight values are those\n",
    "discrete values.\n",
    "\n",
    "In Process, custom spotlight values can be applied to each moderator\n",
    "q, v, z, ... through the arguments qmodval, vmodval, zmodval...\n",
    "\n",
    "In pyprocessmacro, the user must instead supply custom values for each\n",
    "moderator in a dictionary passed to the `modval` parameter:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "p = Process(\n",
    "    data=df,\n",
    "    model=13,\n",
    "    x=\"Effort\",\n",
    "    y=\"Success\",\n",
    "    w=\"Motivation\",\n",
    "    z=\"SkillRelevance\",\n",
    "    m=[\"MediationSkills\"],\n",
    "    modval={\n",
    "        \"Motivation\": [-5, 0, 5],\n",
    "        # Moderator 'Motivation' at values -5, 0 and 5\n",
    "        \"SkillRelevance\": [-1, 1]\n",
    "        # Moderator 'SkillRelevance' at values -1 and 1\n",
    "    },\n",
    "    suppr_init=True,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 3. Accessing the Results"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## A. `summary()`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This method replicates the output that you would see in Process, and\n",
    "displays the following information:\n",
    "\n",
    "* Model summaries and parameters estimates for all outcomes (i.e. the independent variable, and the mediator(s)).\n",
    "* If the model has a moderation, conditional effects at the spotlight values of the moderator(s).\n",
    "* If the model has a mediation, direct and indirect effects.\n",
    "* If the model has a moderation and a mediation, conditional direct and indirect effects at values of the moderator(s).\n",
    "* If those statistics are relevant, indices for partial, conditional, and moderated moderated mediation will be \n",
    "reported."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "***************************** OUTCOME MODELS ****************************\n",
      "\n",
      "Outcome = Success \n",
      "OLS Regression Summary\n",
      "\n",
      "     R²  Adj. R²    MSE          F  df1  df2  p-value\n",
      " 0.9699   0.9698 2.0003 16083.2644    2  997   0.0000\n",
      "\n",
      "Coefficients\n",
      "\n",
      "                 coeff     se        t      p    LLCI   ULCI\n",
      "Cons            1.8755 0.0664  28.2317 0.0000  1.7453 2.0057\n",
      "Effort          0.0653 0.0500   1.3060 0.1919 -0.0327 0.1632\n",
      "MediationSkills 1.0053 0.0066 153.1107 0.0000  0.9925 1.0182\n",
      "\n",
      "-------------------------------------------------------------------------\n",
      "\n",
      "Outcome = MediationSkills \n",
      "OLS Regression Summary\n",
      "\n",
      "     R²  Adj. R²     MSE        F  df1  df2  p-value\n",
      " 0.2648   0.2633 46.4881 359.3661    1  998   0.0000\n",
      "\n",
      "Coefficients\n",
      "\n",
      "        coeff     se       t      p   LLCI   ULCI\n",
      "Cons   4.1472 0.2921 14.1967 0.0000 3.5746 4.7197\n",
      "Effort 3.9167 0.2066 18.9570 0.0000 3.5118 4.3216\n",
      "\n",
      "-------------------------------------------------------------------------\n",
      "\n",
      "\n",
      "********************** DIRECT AND INDIRECT EFFECTS **********************\n",
      "\n",
      "Direct effect of Effort on Success:\n",
      "\n",
      "  Effect     SE      t      p    LLCI   ULCI\n",
      "  0.0653 0.0500 1.3060 0.1919 -0.0327 0.1632\n",
      "\n",
      "Indirect effect of Effort on Success:\n",
      "\n",
      "                   Effect  Boot SE  BootLLCI  BootULCI\n",
      "  MediationSkills  3.9377   0.2362    3.4967    4.4323\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "p = Process(\n",
    "    data=df, model=4, x=\"Effort\", y=\"Success\", m=[\"MediationSkills\"], \n",
    "    suppr_init=True\n",
    ")\n",
    "p.summary()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## B. `outcome_models`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This command gives you individual access to each of the outcome models\n",
    "through a dictionary. This allows you to recover the model and\n",
    "parameters estimates for each outcome.\n",
    "\n",
    "Each OutcomeModel object has the following methods:\n",
    "\n",
    "* `summary()` prints the full summary of the model (as Process does).\n",
    "* `model_summary()` returns a DataFrame of goodness-of-fit statistics\n",
    "for the model.\n",
    "* `coeff_summary()`  returns a DataFrame of estimate, standard error,\n",
    "corresponding z/t, p-value, and confidence interval for each of the\n",
    "parameters in the model.\n",
    "* `estimation_results` gives you access to a dictionary containing all\n",
    "the statistical information of the model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Outcome = MediationSkills \n",
      "OLS Regression Summary\n",
      "\n",
      "     R²  Adj. R²     MSE        F  df1  df2  p-value\n",
      " 0.2648   0.2633 46.4881 359.3661    1  998   0.0000\n",
      "\n",
      "Coefficients\n",
      "\n",
      "        coeff     se       t      p   LLCI   ULCI\n",
      "Cons   4.1472 0.2921 14.1967 0.0000 3.5746 4.7197\n",
      "Effort 3.9167 0.2066 18.9570 0.0000 3.5118 4.3216\n"
     ]
    }
   ],
   "source": [
    "# The model for the outcome \"MediationSkills\"\n",
    "model_medskills = p.outcome_models[\"MediationSkills\"]\n",
    "\n",
    "# Print the summary for this model\n",
    "print(model_medskills.summary())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>coeff</th>\n",
       "      <th>se</th>\n",
       "      <th>t</th>\n",
       "      <th>p</th>\n",
       "      <th>LLCI</th>\n",
       "      <th>ULCI</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>Cons</th>\n",
       "      <td>4.147182</td>\n",
       "      <td>0.292122</td>\n",
       "      <td>14.196744</td>\n",
       "      <td>8.392403e-42</td>\n",
       "      <td>3.574633</td>\n",
       "      <td>4.719730</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Effort</th>\n",
       "      <td>3.916699</td>\n",
       "      <td>0.206610</td>\n",
       "      <td>18.956953</td>\n",
       "      <td>1.096456e-68</td>\n",
       "      <td>3.511751</td>\n",
       "      <td>4.321648</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "           coeff        se          t             p      LLCI      ULCI\n",
       "Cons    4.147182  0.292122  14.196744  8.392403e-42  3.574633  4.719730\n",
       "Effort  3.916699  0.206610  18.956953  1.096456e-68  3.511751  4.321648"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Acccess the DataFrame of estimates\n",
    "model_medskills.coeff_summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.2647525050214642"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Access the R² of the model\n",
    "model_medskills.estimation_results[\"R2\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that the methods are called from the `model_medskills` object!\n",
    "If you call `p.coeff_summary()`, you will get an error."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## C. `direct_model`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When the Process model includes a mediation, the direct effect model\n",
    "can be accessed. It implements the following methods:\n",
    "* `summary()` prints the full summary of the direct effects, as printed\n",
    "when calling Process.summary().\n",
    "* `coeff_summary()` returns a DataFrame of estimate, standard error,\n",
    "t-value, p-value, and confidence interval for each of the (conditional)\n",
    "direct effect(s).\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Direct effect of Effort on Success:\n",
      "\n",
      "  Effect     SE      t      p    LLCI   ULCI\n",
      "  0.0653 0.0500 1.3060 0.1919 -0.0327 0.1632\n",
      "\n"
     ]
    }
   ],
   "source": [
    "direct_effect_model = p.direct_model\n",
    "\n",
    "# Store the DataFrame of estimates into a variable.\n",
    "df_params_direct = direct_effect_model.coeff_summary()\n",
    "\n",
    "# Print the summary for this model\n",
    "print(direct_effect_model.summary())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "Note that the methods are called from the `direct_effect_model` object!\n",
    "If you call `p.coeff_summary()`, you will get an error."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## D. `indirect_model`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "When the Process model includes a parallel mediation, the indirect\n",
    "effect model can be accessed as well. It implements the following\n",
    "methods:\n",
    "\n",
    "* `summary()` prints the full summary of the indirect effects, and other\n",
    "related indices, as printed by Process.summary().\n",
    "* `coeff_summary()` returns a DataFrame of indirect effect(s) and their\n",
    "SE/CI for each of the mediation paths\n",
    "* `PMM_index_summary()` returns a DataFrame of indices for Partial\n",
    "Moderated Mediation, and their SE/CI, for each of the moderators and\n",
    "mediation paths. If the model does not compute a PMM, this will return\n",
    "an error.\n",
    "* `CMM_index_summary()` returns a DataFrame of indices for Conditional\n",
    "Moderated Mediation, and their SE/CI, for each of the moderators and\n",
    "mediation paths. If the model does not compute a CMM, this will return\n",
    "an error.\n",
    "* `CMM_index_summary()` returns a DataFrame of indices for Moderated\n",
    "Moderated Mediation, and their SE/CI, for each of the mediation paths.\n",
    "If the model does not compute a MMM, this will return an error."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "# The model for the direct effect\n",
    "indirect_effect_model = p.indirect_model\n",
    "\n",
    "# Store the DataFrame of estimates into a variable.\n",
    "df_params_direct = indirect_effect_model.coeff_summary()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that the methods are called from the `indirect_effect_model` object!\n",
    "If you call `p.coeff_summary()`, you will get an error."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4. Recover the Bootstrap Estimates"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The original Process macro allows you to save the parameter estimates\n",
    "for each bootstrap sample by specifying the `save` keyword. The Macro\n",
    "then returns a new dataset of bootstrap estimates.\n",
    "\n",
    "In pyprocessmacro, this is done by calling the method\n",
    "`get_bootstrap_estimates()`, which returns a DataFrame containing\n",
    "the parameters estimates. Each row represents a bootstrap repetition,\n",
    "and the columns are explicitely labeled to identity the variables and\n",
    "the model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>BootSample</th>\n",
       "      <th>OutcomeName</th>\n",
       "      <th>Cons</th>\n",
       "      <th>Effort</th>\n",
       "      <th>MediationSkills</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0</td>\n",
       "      <td>Success</td>\n",
       "      <td>1.891449</td>\n",
       "      <td>0.019013</td>\n",
       "      <td>1.010788</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1</td>\n",
       "      <td>Success</td>\n",
       "      <td>1.999370</td>\n",
       "      <td>0.047046</td>\n",
       "      <td>0.991365</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>2</td>\n",
       "      <td>Success</td>\n",
       "      <td>1.879890</td>\n",
       "      <td>-0.013556</td>\n",
       "      <td>1.017109</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>3</td>\n",
       "      <td>Success</td>\n",
       "      <td>1.889204</td>\n",
       "      <td>0.018213</td>\n",
       "      <td>1.007163</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>4</td>\n",
       "      <td>Success</td>\n",
       "      <td>1.781783</td>\n",
       "      <td>0.085147</td>\n",
       "      <td>1.010819</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5000</th>\n",
       "      <td>0</td>\n",
       "      <td>MediationSkills</td>\n",
       "      <td>4.008258</td>\n",
       "      <td>4.035267</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5001</th>\n",
       "      <td>1</td>\n",
       "      <td>MediationSkills</td>\n",
       "      <td>4.097921</td>\n",
       "      <td>3.992029</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5002</th>\n",
       "      <td>2</td>\n",
       "      <td>MediationSkills</td>\n",
       "      <td>3.842924</td>\n",
       "      <td>3.913002</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5003</th>\n",
       "      <td>3</td>\n",
       "      <td>MediationSkills</td>\n",
       "      <td>4.206325</td>\n",
       "      <td>3.959671</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5004</th>\n",
       "      <td>4</td>\n",
       "      <td>MediationSkills</td>\n",
       "      <td>4.140622</td>\n",
       "      <td>3.867696</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      BootSample      OutcomeName      Cons    Effort  MediationSkills\n",
       "0              0          Success  1.891449  0.019013         1.010788\n",
       "1              1          Success  1.999370  0.047046         0.991365\n",
       "2              2          Success  1.879890 -0.013556         1.017109\n",
       "3              3          Success  1.889204  0.018213         1.007163\n",
       "4              4          Success  1.781783  0.085147         1.010819\n",
       "5000           0  MediationSkills  4.008258  4.035267              NaN\n",
       "5001           1  MediationSkills  4.097921  3.992029              NaN\n",
       "5002           2  MediationSkills  3.842924  3.913002              NaN\n",
       "5003           3  MediationSkills  4.206325  3.959671              NaN\n",
       "5004           4  MediationSkills  4.140622  3.867696              NaN"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "boot_estimates = p.get_bootstrap_estimates()  # Called from the Process object directly.\n",
    "boot_estimates.groupby(\"OutcomeName\").head(\n",
    "    5\n",
    ")  # Estimates in the first 5 bootstrap samples"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 5. Spotlight and Floodlight Analysis"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "pyprocessmacro offers four convenience functions for spotlight and floodlight analysis: \n",
    "* `floodlight_direct_effect()` runs a floodlight analysis on the direct effect\n",
    "* `floodlight_indirect_effect()` runs a floodlight analysis on the indirect effect\n",
    "* `spotlight_direct_effect()` runs a spotlight analysis on the direct effect\n",
    "* `spotlight_indirect_effect()` runs a spotlight analysis on the indirect effect\n",
    "\n",
    "Let's consider a new model, in which the direct and indirect paths are moderated by two moderators (Process Model 12)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "ename": "FileNotFoundError",
     "evalue": "[Errno 2] File SampleData.csv does not exist: 'SampleData.csv'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mFileNotFoundError\u001b[0m                         Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-13-2a109d525810>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mdf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpd\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread_csv\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"SampleData.csv\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      2\u001b[0m p = Process(\n\u001b[1;32m      3\u001b[0m     \u001b[0mdata\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdf\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      4\u001b[0m     \u001b[0mmodel\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m12\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m     \u001b[0mx\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"Effort\"\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.7/site-packages/pandas/io/parsers.py\u001b[0m in \u001b[0;36mparser_f\u001b[0;34m(filepath_or_buffer, sep, delimiter, header, names, index_col, usecols, squeeze, prefix, mangle_dupe_cols, dtype, engine, converters, true_values, false_values, skipinitialspace, skiprows, skipfooter, nrows, na_values, keep_default_na, na_filter, verbose, skip_blank_lines, parse_dates, infer_datetime_format, keep_date_col, date_parser, dayfirst, cache_dates, iterator, chunksize, compression, thousands, decimal, lineterminator, quotechar, quoting, doublequote, escapechar, comment, encoding, dialect, error_bad_lines, warn_bad_lines, delim_whitespace, low_memory, memory_map, float_precision)\u001b[0m\n\u001b[1;32m    674\u001b[0m         )\n\u001b[1;32m    675\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 676\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0m_read\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfilepath_or_buffer\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkwds\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    677\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    678\u001b[0m     \u001b[0mparser_f\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__name__\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.7/site-packages/pandas/io/parsers.py\u001b[0m in \u001b[0;36m_read\u001b[0;34m(filepath_or_buffer, kwds)\u001b[0m\n\u001b[1;32m    446\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    447\u001b[0m     \u001b[0;31m# Create the parser.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 448\u001b[0;31m     \u001b[0mparser\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mTextFileReader\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfp_or_buf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwds\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    449\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    450\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0mchunksize\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0miterator\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.7/site-packages/pandas/io/parsers.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, f, engine, **kwds)\u001b[0m\n\u001b[1;32m    878\u001b[0m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0moptions\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"has_index_names\"\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mkwds\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"has_index_names\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    879\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 880\u001b[0;31m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_make_engine\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mengine\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    881\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    882\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0mclose\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.7/site-packages/pandas/io/parsers.py\u001b[0m in \u001b[0;36m_make_engine\u001b[0;34m(self, engine)\u001b[0m\n\u001b[1;32m   1112\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0m_make_engine\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mengine\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"c\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1113\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0mengine\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"c\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1114\u001b[0;31m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_engine\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCParserWrapper\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0moptions\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   1115\u001b[0m         \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1116\u001b[0m             \u001b[0;32mif\u001b[0m \u001b[0mengine\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"python\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.7/site-packages/pandas/io/parsers.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, src, **kwds)\u001b[0m\n\u001b[1;32m   1889\u001b[0m         \u001b[0mkwds\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"usecols\"\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0musecols\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1890\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1891\u001b[0;31m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_reader\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mparsers\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mTextReader\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msrc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwds\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   1892\u001b[0m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0munnamed_cols\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_reader\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0munnamed_cols\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1893\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32mpandas/_libs/parsers.pyx\u001b[0m in \u001b[0;36mpandas._libs.parsers.TextReader.__cinit__\u001b[0;34m()\u001b[0m\n",
      "\u001b[0;32mpandas/_libs/parsers.pyx\u001b[0m in \u001b[0;36mpandas._libs.parsers.TextReader._setup_parser_source\u001b[0;34m()\u001b[0m\n",
      "\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] File SampleData.csv does not exist: 'SampleData.csv'"
     ]
    }
   ],
   "source": [
    "df = pd.read_csv(\"SampleData.csv\")\n",
    "p = Process(\n",
    "    data=df,\n",
    "    model=12,\n",
    "    x=\"Effort\",\n",
    "    y=\"Success\",\n",
    "    w=\"Motivation\",\n",
    "    z=\"SkillRelevance\",\n",
    "    m=[\"MediationSkills\", \"ModerationSkills\"],\n",
    "    suppr_init=True,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## A. Spotlight Analysis"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The two functions `spotlight_direct_effect()` and `spotlight_indirect_effect()` return the conditional direct/indirect effects at various levels of the moderator(s).\n",
    "\n",
    "`spotlight_direct_effect()` can be called without any argument, but `spotlight_indirect_effect()` requires you to specify the name of the mediator for which you want to compute the indirect effects, \n",
    "\n",
    "By default, the spotlight values are the ones provided at initialization, but you can change them through the `spotval` argument:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "p.spotlight_indirect_effect(\"MediationSkills\", spotval={\"SkillRelevance\": [0, 1]})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## B. Floodlight Analysis"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`floodlight_direct_effect()` and `floodlight_indirect_effect()` use an iteration procedure to find the Johnson-Neyman region(s) of significance for the direct/indirect effect.\n",
    "\n",
    "You must specify:\n",
    "* The name of the moderator on which to run the Johnson-Neyman procedure\n",
    "* The name of the mediation path (only for `floodlight_indirect_effect()`)\n",
    "\n",
    "If there are multiple moderators, the analysis is run assuming that all the other moderators are at 0. You can change this behavior through the `other_modval` argument."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "jn_region = p.floodlight_indirect_effect(\"MediationSkills\", \"SkillRelevance\", other_modval={\"Motivation\": 1})\n",
    "print(jn_region)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 6. Plotting Capabilities"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "pyprocessmacro allows you to plot the conditional direct and indirect\n",
    "effect(s), at different values of the moderators.\n",
    "\n",
    "The methods `plot_conditional_indirect_effects()` and `plot_direct_effects()` are\n",
    "identical in syntax, with one small exception: you must specify the name\n",
    "of the mediator for `plot_indirect_effects` as a first argument.\n",
    "\n",
    "They return a `seaborn.FacetGrid` object that can be used to further\n",
    "tweak the appearance of the plot."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## A. Basic Usage"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When plotting conditional direct (and indirect) effects, the effect is\n",
    "always represented on the y-axis. The various spotlight values of the\n",
    "moderator(s) can be represented on several dimensions:\n",
    "\n",
    "* On the x-axis (moderator passed to `x`).\n",
    "* As a color-code, in which case several lines are displayed on the same\n",
    "plot (moderator passed to `hue`).\n",
    "* On different plots, displayed side-by-side (moderator passed to `col`).\n",
    "* On different plots, displayed one below the other (moderator passed\n",
    "to `row`)\n",
    "\n",
    "At the minimum, the `x` argument is required, while the `hue`, `col`\n",
    "and `row` are optional.\n",
    "The examples below are showing what the plots could look like for a\n",
    "model with two moderators.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Conditional direct effects of Effort, at values of Motivation (x-axis)\n",
    "g = p.plot_conditional_direct_effects(x=\"Motivation\", hue=\"SkillRelevance\")\n",
    "\n",
    "# Display figure\n",
    "g.add_legend(title=\"\")\n",
    "fig = plt.gcf()\n",
    "plt.close()\n",
    "display(fig, metadata=dict(filename=\"Fig1\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## B. Different Spotlight Values"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "By default, the spotlight values used to plot the effects are the same\n",
    "as the ones passed when initializing Process.\n",
    "\n",
    "However, you can pass custom values for some, or all, the moderators\n",
    "through the `mods_at` argument. The library will automatically compute\n",
    "the conditional effects at those new spotlight values, and plot them.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "g = p.plot_conditional_indirect_effects(\n",
    "    med_name=\"MediationSkills\",\n",
    "    x=\"Motivation\",\n",
    "    hue=\"SkillRelevance\",\n",
    "    # Change the spotlight values for SkillRelevance\n",
    "    modval={\"SkillRelevance\": [-5, 5]},\n",
    ")\n",
    "\n",
    "# Display figure\n",
    "g.add_legend(title=\"\")\n",
    "fig = plt.gcf()\n",
    "plt.close()\n",
    "display(fig, metadata=dict(filename=\"Fig2\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## C. Different Visualizations of Uncertainty"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The display of confidence intervals for the direct/indirect effects can\n",
    "be customized through the `errstyle` argument:\n",
    "* `errstyle=\"band\"` (default) plots a continuous error band between the\n",
    "lower and higher confidence interval. This representation works well\n",
    "when the moderator displayed on the x-axis is continuous (e.g. age),\n",
    "as it allows you to visualize the error at all levels of the moderator.\n",
    "* `errstyle=\"ci\"` plots an error bar at each value of the moderator on\n",
    "x-axis. It works well when the moderator displayed on the x-axis is\n",
    "dichotomous or has few values (e.g. gender), as it reduces clutter.\n",
    "* `errstyle=\"none\"` does not show the error on the plot."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "g = p.plot_conditional_indirect_effects(\n",
    "    med_name=\"MediationSkills\",\n",
    "    x=\"Motivation\",\n",
    "    hue=\"SkillRelevance\",\n",
    "    # Dichotomous values for moderators...\n",
    "    modval={\"SkillRelevance\": [0, 1], \"Motivation\": [0, 1]},\n",
    "    # Call for error bars rather than error bands\n",
    "    errstyle=\"ci\"\n",
    ")\n",
    "\n",
    "# Display figure\n",
    "g.add_legend(title=\"\")\n",
    "fig = plt.gcf()\n",
    "plt.close()\n",
    "display(fig, metadata=dict(filename=\"Fig3\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## D. Customizing Plots"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Under the hood, the plotting functions relies on a `seaborn.FacetGrid`\n",
    "object, on which the following functions are called:\n",
    "\n",
    " * `plt.plot` when `errstyle=\"none\"`\n",
    " * `plt.plot` and `plt.fill_between` when `errstyle=\"band\"`\n",
    " * `plt.plot` and `plt.errorbar` when `errstyle=\"ci\"`\n",
    " \n",
    "You can pass custom arguments to each of those objects to customize the appearance of the plot:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Plot: Make the lines bolder\n",
    "plot_kws = {\"lw\": 3}\n",
    "# Errors: Make the CI bolder, red, and remove the 'caps'\n",
    "err_kws = {\"ecolor\": \"red\", \"elinewidth\": 3, \"capsize\": 0}\n",
    "# Grid: Change the aspect ratio of the plot\n",
    "facet_kws = {\"aspect\": 2}\n",
    "\n",
    "g = p.plot_conditional_indirect_effects(\n",
    "    med_name=\"MediationSkills\",\n",
    "    x=\"Motivation\",\n",
    "    errstyle=\"ci\",\n",
    "    hue=\"SkillRelevance\",\n",
    "    modval={\"Motivation\":[-2, -1, 0, 1, 2]},\n",
    "    plot_kws=plot_kws,\n",
    "    err_kws=err_kws,\n",
    "    facet_kws=facet_kws,\n",
    ")\n",
    "\n",
    "# Display figure\n",
    "g.add_legend(title=\"\")\n",
    "fig = plt.gcf()\n",
    "plt.close()\n",
    "display(fig, metadata=dict(filename=\"Fig4\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 7. About"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "pyprocessmacro was developed by Quentin André during his Ph.D. in\n",
    "Marketing at INSEAD Business School, France.\n",
    "\n",
    "His work on this library was made possible by Andrew F. Hayes' \n",
    "[book](http:/afhayes.com/introduction-to-mediation-moderation-and-conditional-process-analysis.html), \n",
    "by the financial support of INSEAD and by the ADLPartner Ph.D. award."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 8. Copyright Notice"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The original Process Macro for SAS and SPSS, and its associated files,\n",
    "are copyrighted by Andrew F. Hayes.\n",
    "\n",
    "The original code must not be edited or modified, and must not be distributed outside of\n",
    "[http://www.processmacro.org](http://www.processmacro.org).\n",
    " \n",
    "Because pyprocessmacro is a complete reimplementation of the Process\n",
    "Macro, and was not based on the original code, pyprocessmacro is released under a MIT\n",
    "license.\n",
    " \n",
    "Andrew F. Hayes does not endorse pyprocessmacro: All potential\n",
    "errors, bugs and inaccuracies are my own, and Andrew F. Hayes was not\n",
    "involved in writing, reviewing, or debugging the code."
   ]
  }
 ],
 "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.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}