<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 This notebook will serve to demonstrate Retina functionality within the Jupyter notebook as it relates to Matplotlib.
Retina, Matplotlib, and the Jupyter Notebook
Retina subclasses the Matplotlib Axes hierarchy. Retina axes can be generated from a call to Pyplot's subplot function. Let's walk through how this is done.
Retina 2D Functionality
Step1:  Let's set up our plot so as to make it look more professional.
Step2:  Not too shabby. I find it annoying that the label for the y-axis is tilted sideways. Maybe someone more familiar with Matplotlib than myself could propose a solution for this.
Now that we have our axes looking respectable, let's add some data to our plot. We will organize our data via the use of Retina's Layer2D class. It provides a way of grouping Matplotlib artists so that they can be styled, displayed, hidden, etc. in tandem. Let's start by plotting some trig functions.
Step3:  As you can see, we have created two layers
Step4:  Here is another issue that I can't figure out. If all the plotting code is executed simultaneously in the notebook, the plot generates fine. If, however, the code is run in individual cells, the plots are never generated. I'm not sure if this is a Matplotlib-Jupyter issue or a Retina issue. I think it's probably the former, but maybe some of the Jupyter devs can address this. This seems to happen regardless of whether %matplotlib inline or %matplotlib notebook magics are used, with the caveat that %matplotlib notebook allows generated plots to interact effectively with calls from subsequent cells provided that the plot is generated correctly the first time. It seems that splitting the plotting code across cells causes major hiccups.
Here is an example where all the code is run simultaneously...
Step5:  Let's try adding some lines to our plot.
Step6:  And now let's try toggling the display of the sin layer.
Step7:  We can also make plots in layers "boldfaced".
Step8:  Bolding effects can be applied in succession.
Step9:  And they can be undone.
Step10:  I'm not sure if the Jupyter team has considered this, but it would be nice if the %matplotlib notebook mode generated new plots each time a cell was run. The way things currently stand, I have to scroll up to the original plot in order to watch my changes propagate. This scrolling can quickly become infeasible in lengthier notebooks.
Retina 3D Functionality
Now, let's try creating a 3D plot using Retina's 3D axes.
Step11:  We can add planes to 3D layers by specifying a point on the plane and a normal vector to the plane.
Step12:  We can bound the data contained in layers, either in a box (for 3D Layers) or in a rectangle/circle (for 2D layers).
Step13:  And we can remove the bounds.
Step14:  We can also set arbitrary properties for the plots contained in layers. For example, let's edit the alpha value of our 3D plots.
Step15:  Diagnostic Tracking
Retina also binds a diagnostic tracker class to layer instances which is linked to a "calc context". As part of the calc context, users can provide sandbox functions and see their plots updated in real-time as data within the layer changes. Let's work through an example use case.
<ASSISTANT_TASK:>
Python Code:
import retina.core.axes
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
fig = plt.figure()
ax1 = plt.subplot('111', projection='Fovea2D')
Explanation: This notebook will serve to demonstrate Retina functionality within the Jupyter notebook as it relates to Matplotlib.
Retina, Matplotlib, and the Jupyter Notebook
Retina subclasses the Matplotlib Axes hierarchy. Retina axes can be generated from a call to Pyplot's subplot function. Let's walk through how this is done.
Retina 2D Functionality
End of explanation
plt.xlabel('x')
plt.ylabel('y')
plt.title('An Introduction to Retina')
Explanation: Let's set up our plot so as to make it look more professional.
End of explanation
x = np.linspace(-2 * np.pi, 2 * np.pi)
sin_y = np.sin(x)
cos_y = np.cos(x)
sin = ax1.add_layer("sin")
cos = ax1.add_layer("cos")
sin.add_data(x, sin_y)
cos.add_data(x, cos_y)
ax1.build_layer("sin", color="green", linestyle="dashed", label="sin(x)")
ax1.build_layer("cos", color="blue", linestyle="dashed", label="cos(x)")
Explanation: Not too shabby. I find it annoying that the label for the y-axis is tilted sideways. Maybe someone more familiar with Matplotlib than myself could propose a solution for this.
Now that we have our axes looking respectable, let's add some data to our plot. We will organize our data via the use of Retina's Layer2D class. It provides a way of grouping Matplotlib artists so that they can be styled, displayed, hidden, etc. in tandem. Let's start by plotting some trig functions.
End of explanation
plt.show()
Explanation: As you can see, we have created two layers: one to hold the plot of $\sin(x)$ and the other to hold the plot of $\cos(x)$. Note that the Layer2D objects are not constructed explicitly by the user. This work is done by the add_layer function of the Fovea2D axes class. This way the layer is attached to an explicit axes and isn't left floating in a free-form void holding unvisualizable data. The add_layer function, however, returns the Layer2D instance which can then be saved to an explicit reference variable as was done here. The work of plotting is performed by the Axes' build_layer function and the keyword arguments are passed to Pyplot's default plot function. The layer-specific methods such as adding data are called from the Layer2D object directly. As a design consideration for future development, it might be useful to just attach a plot method to the layer class that works in the same way as this one. It would probably be easier to use since one could just use the layer instances to plot directly without having to pass layer names to the build_layer method.
Now, all that's left to do is show the plot.
End of explanation
import retina.core.axes
import matplotlib.pyplot as plt
import numpy as np
%matplotlib notebook
fig2 = plt.figure()
ax2 = plt.subplot('111', projection='Fovea2D')
plt.xlabel('x')
plt.ylabel('y')
plt.title('An Introduction to Retina')
ax2.set_xlim(-2 * np.pi, 2 * np.pi)
x = np.linspace(-2 * np.pi, 2 * np.pi)
sin_y = np.sin(x)
cos_y = np.cos(x)
sin = ax2.add_layer("sin")
cos = ax2.add_layer("cos")
sin.add_data(x, sin_y)
cos.add_data(x, cos_y)
ax2.build_layer("sin", color="green", linestyle="dashed", label="sin(x)")
ax2.build_layer("cos", color="blue", linestyle="dashed", label="cos(x)")
Explanation: Here is another issue that I can't figure out. If all the plotting code is executed simultaneously in the notebook, the plot generates fine. If, however, the code is run in individual cells, the plots are never generated. I'm not sure if this is a Matplotlib-Jupyter issue or a Retina issue. I think it's probably the former, but maybe some of the Jupyter devs can address this. This seems to happen regardless of whether %matplotlib inline or %matplotlib notebook magics are used, with the caveat that %matplotlib notebook allows generated plots to interact effectively with calls from subsequent cells provided that the plot is generated correctly the first time. It seems that splitting the plotting code across cells causes major hiccups.
Here is an example where all the code is run simultaneously...
End of explanation
sin.add_vline(0)
sin.add_hline(0)
Explanation: Let's try adding some lines to our plot.
End of explanation
sin.hide()
sin.show()
sin.toggle_display()
sin.toggle_display()
Explanation: And now let's try toggling the display of the sin layer.
End of explanation
cos.bold()
Explanation: We can also make plots in layers "boldfaced".
End of explanation
cos.bold()
Explanation: Bolding effects can be applied in succession.
End of explanation
cos.unbold()
cos.unbold()
Explanation: And they can be undone.
End of explanation
import retina.core.axes
import matplotlib.pyplot as plt
import numpy as np
from scipy.special import jn
%matplotlib notebook
fig = plt.figure()
ax = plt.subplot('111', projection='Fovea3D')
points = np.linspace(-10, 10, 51)
X, Y = np.meshgrid(points, points)
R = np.sqrt(X**2 + Y**2)
Z = jn(0,R)
surfing_usa = ax.add_layer('surfing_usa')
surfing_usa.add_data(X, Y, Z)
ax.build_layer('surfing_usa', plot=ax.plot_surface, rstride=1, cstride=1, cmap='jet')
surfing_usa.hide()
surfing_usa.show()
Explanation: I'm not sure if the Jupyter team has considered this, but it would be nice if the %matplotlib notebook mode generated new plots each time a cell was run. The way things currently stand, I have to scroll up to the original plot in order to watch my changes propagate. This scrolling can quickly become infeasible in lengthier notebooks.
Retina 3D Functionality
Now, let's try creating a 3D plot using Retina's 3D axes.
End of explanation
surfing_usa.add_plane([0, 3, 5], [1, 2, 1])
Explanation: We can add planes to 3D layers by specifying a point on the plane and a normal vector to the plane.
End of explanation
surfing_usa.bound()
Explanation: We can bound the data contained in layers, either in a box (for 3D Layers) or in a rectangle/circle (for 2D layers).
End of explanation
surfing_usa.unbound()
Explanation: And we can remove the bounds.
End of explanation
surfing_usa.set_prop(alpha=0.5)
Explanation: We can also set arbitrary properties for the plots contained in layers. For example, let's edit the alpha value of our 3D plots.
End of explanation
% matplotlib notebook
from IPython.display import display
from ipywidgets import widgets
textbox = widgets.Text()
display(textbox)
def handle_submit(sender):
    fn = text.value
    
from __future__ import division
import PyDSTool as dst
#import PyDSTool.Toolbox.phaseplane as pp
import matplotlib.pyplot as plt
import retina.core.axes
import retina.core.layer
import retina.core.calc_context as cc
import math
import numpy as np
fig = plt.figure()
ax = plt.subplot('111', projection='Fovea2D')
layer = ax.add_layer('test_layer')
tracker = layer.tracker
def make_vel_ics(speed, ang):
    rad = math.pi*(ang)/180.
    return {'vx': speed*math.cos(rad),
            'vy': speed*math.sin(rad)}
def make_shooter():
    # no friction
    # cos(atan(x)) = 1/(sqrt(1+x^2))
    Fx_str = '0' # '-speed_fn()*cos(atan2(vy,vx))'
    Fy_str = '-10'
    DSargs = dst.args()
    DSargs.varspecs = {'vx': Fx_str, 'x': 'vx',
                       'vy': Fy_str, 'y': 'vy',
                       'Fx_out': 'Fx(x,y)', 'Fy_out': 'Fy(x,y)',
                       'speed': 'speed_fn(vx, vy)',
                       'bearing': '90-180*atan2(vy,vx)/pi'}
    auxfndict = {'Fx': (['x', 'y'], Fx_str),
                 'Fy': (['x', 'y'], Fy_str),
                 'speed_fn': (['vx', 'vy'], 'sqrt(vx*vx+vy*vy)'),
                 }
    DSargs.auxvars = ['Fx_out', 'Fy_out', 'speed', 'bearing']
    DSargs.fnspecs = auxfndict
    DSargs.algparams = {'init_step':0.001,
                        'max_step': 0.1,
                        'max_pts': 20000,
                        'maxevtpts': 2,
                        'refine': 5}
    ground_event = dst.Events.makeZeroCrossEvent('y', -1,
                                                 {'name': 'ground',
                                                  'eventtol': 1e-3,
                                                  'precise': True,
                                                  'term': True},
                                                 varnames=['y'],
                                                 targetlang='python')
    peak_event = dst.Events.makeZeroCrossEvent('vy', -1,
                                                 {'name': 'peak',
                                                  'eventtol': 1e-3,
                                                  'precise': True,
                                                  'term': False},
                                                 varnames=['vy'],
                                                 targetlang='python')
    DSargs.events = [ground_event, peak_event]
    DSargs.checklevel = 2
    DSargs.ics = {'x': 0, 'y': 0,
                  'vx': 0, 'vy': 0}
    DSargs.ics.update(make_vel_ics(5,20))
    DSargs.name = 'cannon'
    DSargs.tdomain = [0, 100000]
    DSargs.tdata = [0, 10]
    return dst.embed(dst.Generator.Vode_ODEsystem(DSargs))
shooter = make_shooter()
# sim.model is a PyDSTool Model
sim = dst.args(tracked_objects=[],
               model=shooter,
               name='sim_cannon_traj',
               pts=None)
calc = cc.calc_context(sim, 'cannon_traj')
w = calc.workspace
shot_num = 0
def go(speed, angle, do_tracker=True):
    global shot_num, w
    shot_num += 1
    w.angle = angle
    w.speed = speed
    sim.model.set(ics=make_vel_ics(speed, angle))
    sim.model.compute('shot%i' % shot_num)
    sim.pts = sim.model.sample('shot%i' % shot_num)
    if do_tracker:
        ax.cla()
        ax.plot(sim.pts['x'], sim.pts['y'], 'b-', lw=3)
        ax.hlines(0, 0, max(sim.pts['x']))
        plt.show()
        calc()
        tracker.show()
        plt.show()
# initialize
go(30, 10, do_tracker=False)
# call tracker every loop to show all sim_stub tracked objects
# (= tracker_plotter objects)
#fig = plt.figure(1)
#ax = plt.gca()
# fig, ax = plt.subplots()
max_dist = cc.make_measure('maxdist',
                              'max(sim.pts["x"])')
max_height = cc.make_measure('maxheight',
                              'max(sim.pts["y"])')
calc.attach((max_dist, max_height))
tracker(calc, 2, ('angle', 'maxdist', 'ko'),
        clear_on_refresh=False)
tracker(calc, 2, ('angle', 'maxheight', 'ro'),
        clear_on_refresh=False)
def make_iter_angle():
    for angle in np.linspace(5, 85, 10):
        yield angle
iter_angle = make_iter_angle()
# rerun this ten times!
go(10, iter_angle.__next__())
# or call directly
go(10, 25)
Explanation: Diagnostic Tracking
Retina also binds a diagnostic tracker class to layer instances which is linked to a "calc context". As part of the calc context, users can provide sandbox functions and see their plots updated in real-time as data within the layer changes. Let's work through an example use case.
End of explanation
<END_TASK>