%matplotlib notebook
import matplotlib.pyplot as plt
import numpy as np
import polo
import demo

"""
Explanation: Note: This notebook works with IPython 4.2.0, matplotlib 1.5.1, and ipywidgets 5.1.3
End of explanation
"""


data = demo.generate_data()
print data.head()

"""
Explanation: Let's generate some demonstration data from a set of PyClaw runs:
End of explanation
"""


facets = {'subplot' : 'nx',
          'line' : 'solver_type',
          'slider' : 'time'}

# Select only rows for WENO5 and TVD runs
tvd_weno5 = data[(data['weno_order']==5) | np.isnan(data['weno_order'])]
fig = plt.figure(figsize=(8,6))
polo.comparison_plot(tvd_weno5,fig,facets);

"""
Explanation: Here data is a Pandas DataFrame; each row corresponds to one output time from a PyClaw simulation.  The simulations have been run with a variety of algorithms and grid sizes.
Let's examine the data from the 5th-order WENO and the 2nd-order TVD runs.  We'll use different plots for each value of nx (the number of grid cells)
End of explanation
"""


facets = {'subplot' : None,
        'line' : 'solver_type',
        'slider' : ['time','nx']}

fig = plt.figure(figsize=(10,6))
polo.comparison_plot(tvd_weno5,fig,facets)

facets = {'subplot' : None,
        'line' : None,
        'slider' : ['time','nx','solver_type']}

fig = plt.figure(figsize=(10,6))
polo.comparison_plot(tvd_weno5,fig,facets);

"""
Explanation: Play with the slider above to see the difference between the two method solutions at various times.
Multiple sliders
We can include sliders to adjust two or more parameters separately.
End of explanation
"""


facets = {'subplot' : 'nx',
          'line' : ('solver_type',('classic',)),
          'slider' : 'time'}

fig = plt.figure(figsize=(10,6))
polo.comparison_plot(data,fig,facets);

"""
Explanation: Restrict to a subset of the data
In the examples above, the facets dictionary values correspond to column headings in the dataframe.  We can further filter by setting one of the facets dictionary values to a tuple, whose first value is the column heading and whose second value is a tuple containing all the values for the rows we want to include.  So we can get just the solutions computed with the Classic algorithm, for example:
End of explanation
"""


facets = {'subplot' : 'nx',
          'line' : 'time',
          'slider' : 'solver_type'}

fig = plt.figure(figsize=(10,6))
polo.comparison_plot(tvd_weno5,fig,facets);

facets = {'subplot' : 'solver_type',
          'line' : 'time',
          'slider' : 'nx'}

fig = plt.figure(figsize=(10,6))
polo.comparison_plot(tvd_weno5,fig,facets);

facets = {'subplot' : 'time',
          'line' : 'solver_type',
          'slider' : 'nx'}

fig = plt.figure(figsize=(10,6))
polo.comparison_plot(tvd_weno5,fig,facets);

facets = {'subplot' : 'time',
          'line' : 'nx',
          'slider' : 'solver_type'}

fig = plt.figure(figsize=(10,6))
polo.comparison_plot(tvd_weno5,fig,facets);

facets = {'subplot' : 'nx',
          'line' : 'time',
          'slider' : 'solver_type'}

fig = plt.figure(figsize=(10,6))
polo.comparison_plot(tvd_weno5,fig,facets);

"""
Explanation: Mixing it up
Any property can be varied over subplots, line plots within a subplot, or via a slider.  Here are some combinations for the current dataset.
End of explanation
"""


t05 = tvd_weno5[tvd_weno5['time']==0.5]
t05.head()

facets = {'subplot' : 'nx',
          'line' : 'solver_type'}

fig = plt.figure(figsize=(10,6))
polo.comparison_plot(t05,fig,facets);

facets = {'line' : 'solver_type',
          'slider' : 'nx'}

fig = plt.figure(figsize=(10,6))
polo.comparison_plot(t05,fig,facets);

facets = {'subplot' : 'solver_type',
          'slider' : 'nx'}

fig = plt.figure(figsize=(10,6))

polo.comparison_plot(t05,fig,facets);

"""
Explanation: Comparing over fewer dimensions
We can filter to get solutions only at time $t=0.5$:
End of explanation
"""


facets = {'subplot' : 'solver_type',
          'line' : ('time',(0.5,)),
          'slider' : 'nx'}

fig = plt.figure(figsize=(10,6))

polo.comparison_plot(tvd_weno5,fig,facets);

"""
Explanation: The same can be achieved via:
End of explanation
"""


def q_minus_one(row):
    r"""Subtract 1 from q."""
    sol = row.data[row.index[0]]
    xc = sol.state.grid.p_centers[0] + 0
    q = sol.state.q[0,:] - 1
    return xc, q

facets = {'subplot' : 'nx',
          'line' : 'solver_type',
          'slider' : 'time'}

fig = plt.figure(figsize=(8,6))

polo.comparison_plot(tvd_weno5,fig,facets,data_fun = q_minus_one,ylim=(-1.1,0.1));

"""
Explanation: Manipulating the data
What if we want to plot some function of the data, instead of the data itself?  We just define the function we want; as a simple example let's subtract 1 from the solution values:
End of explanation
"""


def total_mass(row):
    r"""Get data for 1D PyClaw results."""
    sol = row.data[row.index[0]]
    time = row['time']
    xc = sol.state.grid.p_centers[0] + 0
    q = sol.state.q[0,:]
    dx = sol.state.grid.delta[0]
    mass = np.sum(q)*dx
    return time, mass

facets = {'subplot' : 'nx',
          'line' : 'solver_type',
          'slider' : 'time'}

fig = plt.figure(figsize=(8,6))

polo.comparison_plot(tvd_weno5,fig,facets,data_fun = total_mass);

"""
Explanation: Plotting scalar functionals
Sometimes we are interested in a functional of the data, such as the total mass, the total energy, or the average of some quantity.  This should work similarly, but is not implemented correctly yet.
End of explanation
"""


