<jupyter_start><jupyter_text>[Oregon Curriculum Network](http://4dsolutions.net/ocn/)[School of Tomorrw (Home)](School_of_Tomorrow.ipynb) Calculator SandboxContinued from [Calculator of Tomorrow](arithmetic.ipynb)... Plotting CurvesIn the old days, we used graphing calculators for some of this, and paper and pencil before that.![plot](parabola.png)Those older tools still make sense to use in some contexts, but when you're going for some publication quality digital outputs, you'll want to do more homework.One way to build skills with these new tools is to revisit high schoolish content (dig up some old textbooks), perhaps already covered with a graphing calculator.  You were taught to plot some y versus some x.  You were told x would be "time" sometimes, not other times.![plot](3rd_powering.png)Then came the linear and parabolic equations, and their respective curves.  Even straight lines might be considered curves, the ones we don't see bending in the scope of our viewframe.---Lets do some review from the top, now that we've toured a large territory.Given this is a visualization course, lets talk about plotting right away.Classic opening, like pawn to King-4 in chess.  We'll get the Queen out later (pandas). By the Way... Lets Talk about Unicode! &128120; &9812; &128060;[StackOverFlow discussion](https://stackoverflow.com/questions/34538879/unicode-in-github-markdown)This way of representing Unicode characters in Markdown requires knowing the decimal equivalents.🐼🐼🐼🐼🐼🐼🐼Once you get the glyph you want, rendered, just cut and paste it back in.  Now that you've conjured the panda, the panda is yours. And now, for our opening moves...<jupyter_code>%matplotlib inline
import matplotlib.pyplot as plt
plt.style.use('seaborn-white')  # <--- good idea, looks nicer
import numpy as np<jupyter_output><empty_output><jupyter_text>In the beginning, one needs a "domain" to rule over, a turf.  We'll be using numpy to generate domains a lot, especially...<jupyter_code>np.round(np.linspace(-1, 1, 11), 2) # say how many points
np.round(np.arange(-1, 1.1, 0.2), 2) # give spread between the points<jupyter_output><empty_output><jupyter_text>Here's a Castle, an Emoji.  Do you see it? &127984;Our ability to reach a "co-domain" another turf, depends on having some domain to feed to a callable.  The callable eats domain objects (picture fish) and does whatever work necessary to reach a corresponding result.<jupyter_code>chr(127984)  # testing the chr function, see a Castle?<jupyter_output><empty_output><jupyter_text>What can they teach me about parabolas in Cyberia?  Do we find them in nature?* [Real Life Examples](https://sciencestruck.com/real-life-examples-of-parabola)* [Lots in Gravity and Area Optimizing Problems](https://www.mathsisfun.com/algebra/quadratic-equation-real-world.html)   TIME TO GET PLOTTING! A question to ask yourself, when invoking such "spells" as ```plt.plot``` or ```plt.figure``` is what do they return?  You won't necessarily need to give it a name, but it still helps to keep return types in mind.  We start learning that in the C language, one of Python's several precursors. [Docs on pyplot.plot](https://matplotlib.org/3.1.0/api/_as_gen/matplotlib.pyplot.plot.html)```plot([x], y, [fmt], *, data=None, **kwargs)plot([x], y, [fmt], [x2], y2, [fmt2], ..., **kwargs)``````>>> plot('xlabel', 'ylabel', data=obj)   for when we get to pandas``` [Docs on pyplot.figure](https://matplotlib.org/3.1.0/api/_as_gen/matplotlib.pyplot.figure.html)```pyplot.figure(num=None, figsize=None, dpi=None, facecolor=None, edgecolor=None, frameon=True, FigureClass=, clear=False, **kwargs)[source]```<jupyter_code>from functools import partial
domain = np.linspace(-10, 10, 1000)  # a thousand points, evenly spaced
parabola = lambda x, c, d: c*x*x + d

parabola1_f = partial(parabola, c=1, d=0)
parabola1_y = parabola1_f(domain)

figures = []
figures.append(plt.figure(num='2nd_powering'))  # not "squaring" necessarily

plt.plot(domain, parabola1_y, 'r')
plt.xlabel('X')
plt.ylabel('Y')
plt.title("PARABOLA");
plt.grid(True);
figures.append(plt.figure(num='PARABOLA2'))  # not "squaring" necessarily

parabola2_f = partial(parabola, c=-1, d=100)
parabola2_y = parabola1_f(domain)

plt.plot(domain, parabola2_y, 'g')
plt.xlabel('X')
plt.ylabel('Y')
plt.title("PARABOLA 2");
plt.grid(True);
figures.append(plt.figure(num='CATENARY')) 
catenary = lambda x, a: a*np.cosh(x/a)

catenary1_f = partial(catenary, a=-10)
catenary1_y = catenary1_f(domain)

plt.plot(domain, catenary1_y, 'g')
plt.xlabel('X')
plt.ylabel('Y')
plt.title("CATENARY");
plt.annotate("STL!", (-0.5,-13))
plt.grid(False);<jupyter_output><empty_output><jupyter_text>Do you see a catenary in the picture below? Look at how ```lambda``` was used to express a rule.  The object thereby created is a callable object, and we named it for later use.  [![Socratica](http://img.youtube.com/vi/25ovCm9jKfA/0.jpg)](http://www.youtube.com/watch?v=25ovCm9jKfA "Lambda Expressions")If you had wanted to show everything in some step...<jupyter_code>figures.append(plt.figure(num='3rd_powering'))              # not "cubing" necessarily
plt.plot(domain, (lambda x: x**3)(domain), '.') # thicken with markers
plt.grid(True)
plt.title("3rd Power Curve");<jupyter_output><empty_output><jupyter_text>Hey these are pretty graphics that we might want to stick in other homework, to prove we've been busy.  How do we keep the above figures as png files, for example?```savefig(fname, dpi=None, facecolor='w', edgecolor='w',        orientation='portrait', papertype=None, format=None,        transparent=False, bbox_inches=None, pad_inches=0.1,        frameon=None, metadata=None)```<jupyter_code>for figure in figures:
    figure.savefig('{0}.png'.format(figure.get_label()))<jupyter_output><empty_output><jupyter_text>Remember what it means to ```np.vectorize```?  We're making a "callable" (technical term) work with a numpy ndarray (an n-dimensional array) such that it applies to all elements in that array.lets move on to pandas and look at functions in terms of columns, x and y. 🐼🐼🐼🐼🐼🐼🐼🐼<jupyter_code>import pandas as pd
parabola = pd.DataFrame({'x': domain,
                         'y': (lambda x: x**2)(domain)})
parabola.index.name = 'samples'
parabola.head()<jupyter_output><empty_output><jupyter_text>OMG that was easy.  Might we do plotting directly from a DataFrame.  That might be too good to be true.[Yes We Can!](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.plot.html)Yet we're still free to modify and decorate the final result, having taken advantage of some streamlining.For example, we might ["annotate"](https://matplotlib.org/3.1.0/api/_as_gen/matplotlib.pyplot.annotate.html), meaning add strings to the plot in curious ways.<jupyter_code>fig, ax = plt.subplots()
parabola.plot(x='x', y='y', 
              kind='line', 
              title="PARABOLA", 
              grid=True, legend=False, ax=ax);
fig.savefig('new_parabola.png')
two_curves = pd.DataFrame({'x': domain,
                           'curve0': np.vectorize(lambda x: x**2)(domain),
                           'curve1': np.vectorize(lambda x: x**3)(domain)})
two_curves.head()<jupyter_output><empty_output><jupyter_text>We'll not use subplots at first.  Lets get both curves on the same grid.  If you don't turn subplots on, this will be the default behavior.  If you do turn subplots on, specify layout too, so that you get what you know you want.  See below.<jupyter_code>two_curves.plot(x='x', y=['curve0', 'curve1'], 
                grid=True, title="Two Curves");<jupyter_output><empty_output><jupyter_text>OK, now we're starting to get fancy.  The ```DataFrame.plot``` method will let you turn on subplots, specify their layout, and then access the subplots individually, by means of axes.Note how layout=(2,1) says "give me two rows in a single column", and don't draw the x tickmarks both times, let them share.  The returned object is a numpy array of axes, organized the same way (in the same shape) as the subplots.<jupyter_code>axes = two_curves.plot(x='x', y=['curve0', 'curve1'], layout=(2,1), 
                sharex=True, subplots=True, figsize=(4,10), grid=True)

axes[0,0].set_title('Parabola')
axes[1,0].set_title('3rd Degree');<jupyter_output><empty_output><jupyter_text>* [A Guide to Subplots (VanderPlas)](https://jakevdp.github.io/PythonDataScienceHandbook/04.08-multiple-subplots.html)* [Direct from the Docs](https://matplotlib.org/api/_as_gen/matplotlib.pyplot.subplots.html)  Different WorkoutLets essentially duplicate the work we just did, but without the benefit of the DataFrame's plot method.  We will call on plt subplots directly.```matplotlib.pyplot.subplots(nrows=1, ncols=1, sharex=False, sharey=False, squeeze=True, subplot_kw=None, gridspec_kw=None, **fig_kw)[source]```[Programmatically selecting subplots (StackOverFlow)](https://stackoverflow.com/questions/7101273/how-can-i-programmatically-select-a-specific-subplot-in-matplotlib)My recommendation:  use the ```pandas.plot``` facility, or the ```plt.subplots``` facility for pretty much all your plotting needs.<jupyter_code>import matplotlib.pyplot as plt

fig, the_axes = plt.subplots(ncols=1, nrows=2, sharex=True, figsize=(5,10))
ax0, ax1 = the_axes  # top row, only column
#======= axis0 =========
ax0.plot('x', 'curve0', data=two_curves)
ax0.set_title("Parabola")
ax0.set_xlabel("X")
ax0.set_ylabel("Y")
#======= axis1 =========
ax1.plot('x', 'curve1', data=two_curves)
ax1.set_title("3rd Power")
ax1.set_xlabel("X")
ax1.set_ylabel("Y");<jupyter_output><empty_output><jupyter_text>What Other Curves Might We Explore?<jupyter_code>three_curves = pd.merge(two_curves, 
                        pd.DataFrame({"curve2": np.exp(domain)}), 
                        right_index=True, left_index=True)
three_curves.head()
three_curves.plot(x='x', y='curve2');
μ = 0      # lets use Greek letters
σ = 1      # standard deviation
π = np.pi

rule = lambda x: (1/(σ * np.sqrt(2 * π))) * np.exp(-0.5 * ((μ - x)/σ)**2)
four_curves = pd.merge(three_curves, pd.DataFrame({"curve3": np.vectorize(rule)(domain)}), 
                                                  right_index=True, left_index=True)
four_curves.head()
four_curves.plot(x='x', y='curve3');
four_curves.to_csv("curvy_data.csv")<jupyter_output><empty_output><jupyter_text>PASCAL'S TRIANGLEThe Bell Curve above looks a lot like the Binomial Distribution, which we tend to see in a Galton Board.  Lets define a generator that gives successive rows of Pascal's Triangle, and do a bar plot of the result.<jupyter_code>def pascal():
    """
    Successive rows of Pascal's Triangle
    """
    row = np.array([1], dtype='int64')
    while True:
        yield row
        reg0 = np.append(row, np.zeros(1, dtype='int64'))
        reg1 = np.append(np.zeros(1, dtype='int64'), row)
        row = reg0 + reg1
        
gen = pascal()

for _ in range(10):
    print(next(gen))
fig, axes = plt.subplots(0,0)
data = next(gen)
pd.Series(data).plot(kind='bar', color='b');
from IPython.display import YouTubeVideo
YouTubeVideo("TQwHw61kEN4")  # https://youtu.be/TQwHw61kEN4<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13393819619116062, 'fraction_numerical': 0.017786561264822136, 'mean_word_length': 4.847163865546219, 'pattern_counts': {'":': 2, '<': 54, '<?xml version=': 0, '>': 56, 'https://': 11, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '13', 'dir': 'jupyter-structured-clean-dedup', 'id': '627707', 'license': 'MIT', 'n_tokens_mistral': 3978, 'n_tokens_neox': 3715, 'n_words': 1093, 'path': 'Sandbox_Example.ipynb', 'repo_name': '4dsolutions/School_of_Tomorrow', 'size': '11132'}