# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# <h3> How Does A Novel Grading Policy Affect Assigned Grade? </h3>
# <h4> <NAME> <br><br> Wed, Jan 30, 2019 </h4>

# <pre>
# Group A students (orthodox) not handing in an assignment receive 0 points.
# Group B students (novel)    not handing in an assignment receive 50 points.
#
# My question is, how does this affect the distribution of letter grades?
#
# To discover the answer run this entire python notebook, scroll to the bottom
# and interact with the sliders.
#
# Keep in mind that each run is a statistical experiment of its own.
# For best results run more than one experiment.
#
# You can set max_grade at the top to see results on a 4.0 or 100 percent scale.
# Changing max_grade requires that the entire sheet to be re-executed.
# </pre>

# <img src="images/UalrGPA.png" style="width: 50%; height: 50%" align="left">

# Sources |
# [Average UALR GPA](https://goo.gl/BmddTt) |
# [Bowen School of Law Error](https://goo.gl/Hq9k8a) | 

# <img src="images/BowenError.png" style="width: 75%; height: 75%" align="left">

import math                      # for mathematical operations (like math.h)
import matplotlib.pyplot as plt  # for plotting
import numpy as np               # for numerical operations
from ipywidgets import *         # for interactive animation
from scipy.stats import norm     # for Gaussian distribution
                                 # forces graph appearance in jupyter notebooks
# %matplotlib inline               

# <img src="images/SampleSize.png" style="width: 35%; height: 35%" align="left">

# Sources |
# [Sample Size Calculator](https://goo.gl/9A6RtW) |
# [Enrollment Data](https://goo.gl/KzAq6D) |
# [Markdown Features](https://goo.gl/4gMjPX) |
# [Markdown Table Generator](https://goo.gl/3RM5Wh) |
# [Estimated Standard Deviation](https://goo.gl/S8e16o) |
# [URL Shortener](https://goo.gl) |

sample_size = 400    # see above
ualr_μ      =   3.21 # on a 4 point scale
ualr_σ      =   0.15 # on a 4 point scale
ualr_A      =   4.0  # because an A at UALR is 4.0
max_grade   =   4    # typically either 4, or 100, but could be 5 or anything else

# Sources |
# [Scipy Statistical Functions](https://goo.gl/fBZUq2) |
# [f-string Formatting](https://goo.gl/FoDmnX) |
# [Standard Deviation](https://goo.gl/iifTH5) |
# [Numpy σ](https://goo.gl/gjEfL4) |
# [Numpy Normal](https://goo.gl/9o3UF4) |
# [Numpy Sort](https://goo.gl/L3SG2d) |
# [Numpy arange](https://goo.gl/Zp8Lvq) |

# Sources |
# [Python Plotting](https://goo.gl/iUoPeH) |
#

# Sources |
# [Plot Examples](https://goo.gl/RJ1tPG) |
# [Setting Axis Limits](https://goo.gl/LZfmfc) |
# [Plot rcParams](https://goo.gl/MD7ypV) |
# [Side by Side Plots](https://goo.gl/PKHpsV) |
# [Multiple Subplots](https://goo.gl/gXPcF9) |
# [Titling Subplots](https://goo.gl/Z9NqrW) |
# [Plotting Random Points](https://goo.gl/pXJDzQ) |

# +
μ = ualr_μ/ualr_A * max_grade
σ = ualr_σ * max_grade
x = np.linspace(μ - 20*σ, μ + 4*σ, sample_size)

plt.rcParams["figure.figsize"] = [16, 10]
fig = plt.figure()
fig.suptitle(f'Distribution of GPA, Normalized to {max_grade:.1f} scale', fontsize=16)

c = ["#dd0000", "#dd1111", "#dd3333", "#dd5555", "#dd7777", "#dd9999"]

# Percentage Annotations
plt.annotate('33.1%', xy=(μ+0.3*σ,  norm.pdf(μ+1*σ/2, loc=μ, scale=σ)/2), xycoords='data', color=c[0], fontsize=16)
plt.annotate('33.1%', xy=(μ-0.7*σ,  norm.pdf(μ-1*σ/2, loc=μ, scale=σ)/2), xycoords='data', color=c[0], fontsize=16)
plt.annotate('13.6%', xy=(μ-1.7*σ,  norm.pdf(μ-2*σ/2, loc=μ, scale=σ)/4), xycoords='data', color=c[1], fontsize=16)
plt.annotate(' 2.1%', xy=(μ-2.7*σ,  norm.pdf(μ-2*σ/2, loc=μ, scale=σ)/5), xycoords='data', color=c[2], fontsize=16)
plt.annotate(' 0.1%', xy=(μ-3.7*σ,  norm.pdf(μ-2*σ/2, loc=μ, scale=σ)/6), xycoords='data', color=c[3], fontsize=16)
plt.annotate('0.01%', xy=(μ-4.7*σ,  norm.pdf(μ-2*σ/2, loc=μ, scale=σ)/7), xycoords='data', color=c[4], fontsize=16)

# σ Annotations
plt.annotate(  '  σ', xy=(μ+1.0*σ, 1.02*norm.pdf(μ, loc=μ, scale=σ)), xycoords='data', color=c[1], fontsize=16)
plt.annotate(  '  μ', xy=(μ-0.0*σ, 1.02*norm.pdf(μ, loc=μ, scale=σ)), xycoords='data', color=c[0], fontsize=16)
plt.annotate(  ' -σ', xy=(μ-1.0*σ, 1.02*norm.pdf(μ, loc=μ, scale=σ)), xycoords='data', color=c[1], fontsize=16)
plt.annotate(  '-2σ', xy=(μ-2.0*σ, 1.02*norm.pdf(μ, loc=μ, scale=σ)), xycoords='data', color=c[2], fontsize=16)
plt.annotate(  '-3σ', xy=(μ-3.0*σ, 1.02*norm.pdf(μ, loc=μ, scale=σ)), xycoords='data', color=c[3], fontsize=16)
plt.annotate(  '-4σ', xy=(μ-4.0*σ, 1.02*norm.pdf(μ, loc=μ, scale=σ)), xycoords='data', color=c[4], fontsize=16)
plt.annotate(  '-5σ', xy=(μ-5.0*σ, 1.02*norm.pdf(μ, loc=μ, scale=σ)), xycoords='data', color=c[5], fontsize=16)

# μ & σ Vertical Lines
plt.axvline(μ+1.0*σ, color=c[1])
plt.axvline(μ+0.0*σ, color=c[0])
plt.axvline(μ-1.0*σ, color=c[1])
plt.axvline(μ-2.0*σ, color=c[2])
plt.axvline(μ-3.0*σ, color=c[3])
plt.axvline(μ-4.0*σ, color=c[4])
plt.axvline(μ-5.0*σ, color=c[5])

plt.xlim(0,max_grade)
plt.plot(x,norm.pdf(x, μ, σ), color="#222222", linewidth=3)

plt.show()

# +
plt.rcParams["figure.figsize"] = [16.1, 10]
fig = plt.figure()
fig.suptitle("Four plots to warm up this coding exercise", fontsize=16)

x = np.arange(sample_size)
y = np.random.uniform(0, max_grade, sample_size)
ys = np.sort(y)

plt1 = plt.subplot("221")
plt1.set_xlim((0, sample_size))
plt1.set_ylim((0,max_grade))
plt1.set_title(f'{sample_size:.0f} students with uniformly random scores from 0 to {max_grade:.1f}', fontsize=14)
plt1.scatter(x, y)
plt1.scatter(x, ys);

x = np.arange(sample_size)
y = np.random.uniform(max_grade/2, max_grade, sample_size)
ys = np.sort(y)

plt2 = plt.subplot("222")
plt2.set_xlim((0,sample_size))
plt2.set_ylim((0,max_grade))
plt2.set_title(f'{sample_size:.0f} students with uniformly random scores from {max_grade/2:.1f} to {max_grade:.1f}', fontsize=14)
plt2.scatter(x, y);
plt2.scatter(x, ys);

x = np.arange(sample_size)
y = np.random.normal(0, max_grade, sample_size)
ys = np.sort(y)

plt1 = plt.subplot("223")
plt1.set_xlim((0, sample_size))
plt1.set_ylim((0,max_grade))
plt1.set_title(f'{sample_size:.0f} students with Gaussian random scores from {0:.1f} to {max_grade:.1f}', fontsize=14)
plt1.scatter(x, y)
plt1.scatter(x, ys);

x = np.arange(sample_size)
y = np.random.normal(max_grade/2, max_grade, sample_size)
ys = np.sort(y)

plt2 = plt.subplot("224")
plt2.set_xlim((0,sample_size))
plt2.set_ylim((0,max_grade))
plt2.set_title(f'{sample_size:.0f} students with Gaussian random scores from {max_grade/2:.1f} to {max_grade:.1f}', fontsize=14)
plt2.scatter(x, y);
plt2.scatter(x, ys);


# -

# Sources |
# [Histogramics](https://goo.gl/tRKkYX) |
# [Numpy Float to Int Array](https://goo.gl/asLn5x) |
# [Numpy Rounding](https://goo.gl/Z5NiFW) |
# [Numpy Where](https://goo.gl/KhD8LM) |
# [Python Predicates](https://goo.gl/YxE453) |
# [Python Iteration](https://goo.gl/zFDwbt) |
# [Python Multivalue Return](https://goo.gl/CpLc6C) |

# +
def gen_grades(μ, σ, size, missed, policy):

    grades = norm.rvs(μ, σ, size=size)
    
    if policy.lower() == 'orthodox':
        for g in range(missed):
            grades[g]=0
    elif policy.lower() == 'novel':
        for g in range(missed):
            grades[g]=max_grade/2
    else:
        print('unknown policy')

    mu, std = norm.fit(grades)
    
    # Generate a equally spaced set of x values from 0 to max_grade
    x = np.linspace(0, max_grade, sample_size)

    # Generate the probability density function - the Gaussian in this case
    y = norm.pdf(x, mu, std)

    # Fit a normal distribution to the data:
    return mu, std, grades, x, y

def dual_plot(foo, grades, x, y, μ, σ, mu, std, annotation):
    
    # Plot the histogram.
    foo.hist(grades, bins=20, range=(0,max_grade), density=True, alpha=0.6, color='g')

    # Plot the PDF.
    foo.plot(x, y, 'k', linewidth=2)

    t1 = " Policy:  μ = %.2f,    σ = %.2f " % (μ, σ)
    t2 = " Output: mu = %.2f,  std = %.2f" % (mu, std)
    foo.set_title(annotation + t1 + t2)



# -

def dual_panel(pcnt_missed, assignments):
    missed = int(round(pcnt_missed/100.0 * assignments))
    fig = plt.figure()
    fig.suptitle(f' One Trial Comparison of Policy Effect for {missed} missed assignments out of {assignments}',
                 fontsize=16)
    mu, std, grades, x, y = gen_grades(μ, σ, assignments, missed, 'Orthodox')
    dual_plot(plt.subplot("221"), grades, x, y, μ, σ, mu, std, 'Orthodox')

    mu, std, grades, x, y = gen_grades(μ, σ, assignments, missed, 'Novel')
    dual_plot(plt.subplot("222"), grades, x, y, μ, σ, mu, std, 'Novel')


interact(dual_panel, pcnt_missed=(0,100,5), assignments=(10,400,10));



StarcoderdataJupyterScriptsDedupFiltered