3157 lines
255 KiB
Text
3157 lines
255 KiB
Text
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Twin Premixed Counter-Flow Flame Example"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"This example documents how to simulate two identical, axisymmetric, premixed jets of reactants shooting into each other. An illustration of this configuration is shown in the figure below"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
""
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Import modules"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 1,
|
|
"metadata": {
|
|
"collapsed": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Running Cantera Version: 2.3.0a3\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"from __future__ import print_function\n",
|
|
"from __future__ import division\n",
|
|
"\n",
|
|
"import cantera as ct\n",
|
|
"import numpy as np\n",
|
|
"\n",
|
|
"print(\"Running Cantera Version: \" + str(ct.__version__))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Define the reactant conditions, gas mixture and kinetic mechanism associated with the gas"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 2,
|
|
"metadata": {
|
|
"collapsed": false
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"#Inlet Temperature in Kelvin and Inlet Pressure in Pascals\n",
|
|
"#In this case we are setting the inlet T and P to room temperature conditions\n",
|
|
"To = 300\n",
|
|
"Po = 101325\n",
|
|
"\n",
|
|
"#Define the gas-mixutre and kinetics\n",
|
|
"#In this case, we are choosing a GRI3.0 gas\n",
|
|
"gas = ct.Solution('gri30.cti')\n",
|
|
"\n",
|
|
"# Create a CH4/Air premixed mixture with equivalence ratio=0.75\n",
|
|
"gas.set_equivalence_ratio(0.75, 'CH4', {'O2':1.0, 'N2':3.76})\n",
|
|
"gas.TP = To, Po\n",
|
|
"\n",
|
|
"# Set the velocity of the reactants\n",
|
|
"# This is what determines the strain-rate\n",
|
|
"axial_velocity = 2.0 # in m/s\n",
|
|
"\n",
|
|
"# Done with initial conditions\n",
|
|
"# Compute the mass flux, as this is what the Flame object requires\n",
|
|
"massFlux = gas.density * axial_velocity # units kg/m2/s\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Define functions"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 3,
|
|
"metadata": {
|
|
"collapsed": true
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Differentiation function for data that has variable grid spacing Used here to\n",
|
|
"# compute normal strain-rate\n",
|
|
"def derivative(x, y):\n",
|
|
" dydx = np.zeros(y.shape, y.dtype.type)\n",
|
|
"\n",
|
|
" dx = np.diff(x)\n",
|
|
" dy = np.diff(y)\n",
|
|
" dydx[0:-1] = dy/dx\n",
|
|
"\n",
|
|
" dydx[-1] = (y[-1] - y[-2])/(x[-1] - x[-2])\n",
|
|
"\n",
|
|
" return dydx\n",
|
|
"\n",
|
|
"def computeStrainRates(oppFlame):\n",
|
|
" # Compute the derivative of axial velocity to obtain normal strain rate\n",
|
|
" strainRates = derivative(oppFlame.grid, oppFlame.u)\n",
|
|
"\n",
|
|
" # Obtain the location of the max. strain rate upstream of the pre-heat zone.\n",
|
|
" # This is the characteristic strain rate\n",
|
|
" maxStrLocation = abs(strainRates).argmax()\n",
|
|
" minVelocityPoint = oppFlame.u[:maxStrLocation].argmin()\n",
|
|
"\n",
|
|
" # Characteristic Strain Rate = K\n",
|
|
" strainRatePoint = abs(strainRates[:minVelocityPoint]).argmax()\n",
|
|
" K = abs(strainRates[strainRatePoint])\n",
|
|
"\n",
|
|
" return strainRates, strainRatePoint, K\n",
|
|
"\n",
|
|
"def computeConsumptionSpeed(oppFlame):\n",
|
|
"\n",
|
|
" Tb = max(oppFlame.T)\n",
|
|
" Tu = min(oppFlame.T)\n",
|
|
" rho_u = max(oppFlame.density)\n",
|
|
"\n",
|
|
" integrand = oppFlame.heat_release_rate/oppFlame.cp\n",
|
|
"\n",
|
|
" I = np.trapz(integrand, oppFlame.grid)\n",
|
|
" Sc = I/(Tb - Tu)/rho_u\n",
|
|
"\n",
|
|
" return Sc\n",
|
|
"\n",
|
|
"# This function is called to run the solver\n",
|
|
"def solveOpposedFlame(oppFlame, massFlux=0.12, loglevel=0,\n",
|
|
" ratio=2, slope=0.3, curve=0.3, prune=0.05):\n",
|
|
" \"\"\"\n",
|
|
" Execute this function to run the Oppposed Flow Simulation This function\n",
|
|
" takes a CounterFlowTwinPremixedFlame object as the first argument\n",
|
|
" \"\"\"\n",
|
|
"\n",
|
|
" oppFlame.reactants.mdot = massFlux\n",
|
|
" oppFlame.set_refine_criteria(ratio=ratio, slope=slope, curve=curve, prune=prune)\n",
|
|
"\n",
|
|
" oppFlame.show_solution()\n",
|
|
" oppFlame.solve(loglevel, auto=True)\n",
|
|
"\n",
|
|
" # Compute the strain rate, just before the flame. This is not necessarily\n",
|
|
" # the maximum We use the max. strain rate just upstream of the pre-heat zone\n",
|
|
" # as this is the strain rate that computations comprare against, like when\n",
|
|
" # plotting Su vs. K\n",
|
|
" strainRates, strainRatePoint, K = computeStrainRates(oppFlame)\n",
|
|
"\n",
|
|
" return np.max(oppFlame.T), K, strainRatePoint"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Define a flame object, domain width and tranport model"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 4,
|
|
"metadata": {
|
|
"collapsed": true
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Define a domain half-width of 2.5 cm, meaning the whole domain is 5 cm wide\n",
|
|
"width = 0.025\n",
|
|
"\n",
|
|
"# Create the flame object\n",
|
|
"oppFlame = ct.CounterflowTwinPremixedFlame(gas, width=width)\n",
|
|
"\n",
|
|
"# Uncomment the following line to use a Multi-component formulation. Default is\n",
|
|
"# mixture-averaged\n",
|
|
"#oppFlame.transport_model = 'Multi'"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Run the Solver"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 5,
|
|
"metadata": {
|
|
"collapsed": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"\n",
|
|
"\n",
|
|
">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> reactants <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n",
|
|
"\n",
|
|
" Mass Flux: 2.268 kg/m^2/s \n",
|
|
" Temperature: 300 K \n",
|
|
" Mass Fractions: \n",
|
|
" O2 0.2232 \n",
|
|
" CH4 0.04197 \n",
|
|
" N2 0.7348 \n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> flame <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n",
|
|
"\n",
|
|
" Pressure: 1.013e+05 Pa\n",
|
|
"\n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" z u V T lambda H2 \n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" 0 2 0 300 0 0 \n",
|
|
" 0.005 1.6 32 300 0 0 \n",
|
|
" 0.01 1.2 64 300 0 2.06e-21 \n",
|
|
" 0.0125 1 80 1110 0 3.711e-06 \n",
|
|
" 0.015 0.8 96 1920 0 7.422e-06 \n",
|
|
" 0.02 0.4 128 1920 0 7.422e-06 \n",
|
|
" 0.025 0 160 1920 0 7.422e-06 \n",
|
|
"\n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" z H O O2 OH H2O \n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" 0 0 0 0.2232 0 0 \n",
|
|
" 0.005 0 0 0.2232 0 0 \n",
|
|
" 0.01 9.354e-23 1.216e-20 0.2232 1.907e-19 2.604e-17 \n",
|
|
" 0.0125 1.685e-07 2.191e-05 0.1386 0.0003435 0.04691 \n",
|
|
" 0.015 3.37e-07 4.382e-05 0.05403 0.0006871 0.09382 \n",
|
|
" 0.02 3.37e-07 4.382e-05 0.05403 0.0006871 0.09382 \n",
|
|
" 0.025 3.37e-07 4.382e-05 0.05403 0.0006871 0.09382 \n",
|
|
"\n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" z HO2 H2O2 C CH CH2 \n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" 0 0 0 0 0 0 \n",
|
|
" 0.005 0 0 0 0 0 \n",
|
|
" 0.01 2.619e-22 1.513e-23 1.528e-38 1.236e-39 4.048e-39 \n",
|
|
" 0.0125 4.718e-07 2.725e-08 2.753e-23 2.226e-24 7.292e-24 \n",
|
|
" 0.015 9.435e-07 5.45e-08 5.506e-23 4.452e-24 1.458e-23 \n",
|
|
" 0.02 9.435e-07 5.45e-08 5.506e-23 4.452e-24 1.458e-23 \n",
|
|
" 0.025 9.435e-07 5.45e-08 5.506e-23 4.452e-24 1.458e-23 \n",
|
|
"\n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" z CH2(S) CH3 CH4 CO CO2 \n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" 0 0 0 0.04197 0 0 \n",
|
|
" 0.005 0 0 0.04197 0 0 \n",
|
|
" 0.01 1.788e-40 3.885e-38 0.04197 6.135e-20 3.186e-17 \n",
|
|
" 0.0125 3.22e-25 6.999e-23 0.02098 0.0001105 0.05739 \n",
|
|
" 0.015 6.441e-25 1.4e-22 0 0.0002211 0.1148 \n",
|
|
" 0.02 6.441e-25 1.4e-22 8.264e-23 0.0002211 0.1148 \n",
|
|
" 0.025 6.441e-25 1.4e-22 8.264e-23 0.0002211 0.1148 \n",
|
|
"\n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" z HCO CH2O CH2OH CH3O CH3OH \n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" 0 0 0 0 0 0 \n",
|
|
" 0.005 0 0 0 0 0 \n",
|
|
" 0.01 2.588e-28 2.804e-30 6.75e-37 8.315e-39 5.227e-38 \n",
|
|
" 0.0125 4.662e-13 5.052e-15 1.216e-21 1.498e-23 9.416e-23 \n",
|
|
" 0.015 9.324e-13 1.01e-14 2.432e-21 2.996e-23 1.883e-22 \n",
|
|
" 0.02 9.324e-13 1.01e-14 2.432e-21 2.996e-23 1.883e-22 \n",
|
|
" 0.025 9.324e-13 1.01e-14 2.432e-21 2.996e-23 1.883e-22 \n",
|
|
"\n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" z C2H C2H2 C2H3 C2H4 C2H5 \n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" 0 0 0 0 0 0 \n",
|
|
" 0.005 0 0 0 0 0 \n",
|
|
" 0.01 9.354e-48 7.624e-45 5.836e-51 9.138e-51 1.002e-56 \n",
|
|
" 0.0125 1.685e-32 1.373e-29 1.051e-35 1.646e-35 1.805e-41 \n",
|
|
" 0.015 3.37e-32 2.747e-29 2.103e-35 3.292e-35 3.61e-41 \n",
|
|
" 0.02 3.37e-32 2.747e-29 2.103e-35 3.292e-35 3.61e-41 \n",
|
|
" 0.025 3.37e-32 2.747e-29 2.103e-35 3.292e-35 3.61e-41 \n",
|
|
"\n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" z C2H6 HCCO CH2CO HCCOH N \n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" 0 0 0 0 0 0 \n",
|
|
" 0.005 0 0 0 0 0 \n",
|
|
" 0.01 7.332e-58 2.1e-41 3.353e-41 1.05e-44 3.232e-26 \n",
|
|
" 0.0125 1.321e-42 3.783e-26 6.04e-26 1.892e-29 5.822e-11 \n",
|
|
" 0.015 2.641e-42 7.567e-26 1.208e-25 3.785e-29 1.164e-10 \n",
|
|
" 0.02 2.641e-42 7.567e-26 1.208e-25 3.785e-29 1.164e-10 \n",
|
|
" 0.025 2.641e-42 7.567e-26 1.208e-25 3.785e-29 1.164e-10 \n",
|
|
"\n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" z NH NH2 NH3 NNH NO \n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" 0 0 0 0 0 0 \n",
|
|
" 0.005 0 0 0 0 0 \n",
|
|
" 0.01 2.797e-27 8.651e-28 3.559e-27 4.476e-27 8.318e-19 \n",
|
|
" 0.0125 5.038e-12 1.559e-12 6.411e-12 8.062e-12 0.001498 \n",
|
|
" 0.015 1.008e-11 3.117e-12 1.282e-11 1.612e-11 0.002997 \n",
|
|
" 0.02 1.008e-11 3.117e-12 1.282e-11 1.612e-11 0.002997 \n",
|
|
" 0.025 1.008e-11 3.117e-12 1.282e-11 1.612e-11 0.002997 \n",
|
|
"\n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" z NO2 N2O HNO CN HCN \n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" 0 0 0 0 0 0 \n",
|
|
" 0.005 0 0 0 0 0 \n",
|
|
" 0.01 1.205e-21 6.697e-23 2.279e-24 1.185e-33 8.215e-31 \n",
|
|
" 0.0125 2.17e-06 1.206e-07 4.106e-09 2.135e-18 1.48e-15 \n",
|
|
" 0.015 4.341e-06 2.413e-07 8.212e-09 4.269e-18 2.96e-15 \n",
|
|
" 0.02 4.341e-06 2.413e-07 8.212e-09 4.269e-18 2.96e-15 \n",
|
|
" 0.025 4.341e-06 2.413e-07 8.212e-09 4.269e-18 2.96e-15 \n",
|
|
"\n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" z H2CN HCNN HCNO HOCN HNCO \n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" 0 0 0 0 0 0 \n",
|
|
" 0.005 0 0 0 0 0 \n",
|
|
" 0.01 1.546e-38 4.735e-42 1.504e-35 8.599e-31 7.04e-28 \n",
|
|
" 0.0125 2.785e-23 8.53e-27 2.71e-20 1.549e-15 1.268e-12 \n",
|
|
" 0.015 5.57e-23 1.706e-26 5.42e-20 3.098e-15 2.536e-12 \n",
|
|
" 0.02 5.57e-23 1.706e-26 5.42e-20 3.098e-15 2.536e-12 \n",
|
|
" 0.025 5.57e-23 1.706e-26 5.42e-20 3.098e-15 2.536e-12 \n",
|
|
"\n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" z NCO N2 AR C3H7 C3H8 \n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" 0 0 0.7348 0 0 0 \n",
|
|
" 0.005 0 0.7348 0 0 0 \n",
|
|
" 0.01 1.842e-29 0.7348 0 6.242e-76 4.325e-77 \n",
|
|
" 0.0125 3.319e-14 0.7341 0 1.125e-60 7.791e-62 \n",
|
|
" 0.015 6.638e-14 0.7334 0 2.249e-60 1.558e-61 \n",
|
|
" 0.02 6.638e-14 0.7334 0 2.249e-60 1.558e-61 \n",
|
|
" 0.025 6.638e-14 0.7334 0 2.249e-60 1.558e-61 \n",
|
|
"\n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" z CH2CHO CH3CHO \n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" 0 0 0 \n",
|
|
" 0.005 0 0 \n",
|
|
" 0.01 1.343e-47 2.414e-48 \n",
|
|
" 0.0125 2.42e-32 4.349e-33 \n",
|
|
" 0.015 4.84e-32 8.698e-33 \n",
|
|
" 0.02 4.84e-32 8.698e-33 \n",
|
|
" 0.025 4.84e-32 8.698e-33 \n",
|
|
"\n",
|
|
"\n",
|
|
">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> products <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n",
|
|
"\n",
|
|
"\n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" z dummy \n",
|
|
"-------------------------------------------------------------------------------\n",
|
|
" 0 0 \n",
|
|
"\n",
|
|
"************ Solving on 7 point grid with energy equation enabled ************\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 2.848e-05 5.886\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 0.0004865 5.142\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 0.008313 2.22\n",
|
|
"Attempt Newton solution of steady-state problem... success.\n",
|
|
"\n",
|
|
"Problem solved on [7] point grid(s).\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"grid refinement disabled.\n",
|
|
"\n",
|
|
"******************** Solving with grid refinement enabled ********************\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"Attempt Newton solution of steady-state problem... success.\n",
|
|
"\n",
|
|
"Problem solved on [7] point grid(s).\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"##############################################################################\n",
|
|
"Refining grid in flame.\n",
|
|
" New points inserted after grid points 1 2 3 4 5 \n",
|
|
" to resolve C2H2 C2H4 C2H6 CH CH2 CH2(S) CH2CO CH2O CH2OH CH3 CH3CHO CH3O CH3OH CH4 CO CO2 H H2 H2O H2O2 HCCO HCN HCO HNCO HO2 N2 N2O NO NO2 O O2 OH T V point 1 point 4 u \n",
|
|
"##############################################################################\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 0.0001139 5.734\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 0.002919 3.555\n",
|
|
"Attempt Newton solution of steady-state problem... success.\n",
|
|
"\n",
|
|
"Problem solved on [12] point grid(s).\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"##############################################################################\n",
|
|
"Refining grid in flame.\n",
|
|
" New points inserted after grid points 2 4 5 6 7 8 9 10 \n",
|
|
" to resolve C C2H2 C2H3 C2H4 C2H5 C2H6 C3H8 CH CH2 CH2(S) CH2CO CH2O CH2OH CH3 CH3CHO CH3O CH3OH CH4 CO CO2 H H2 H2O H2O2 HCCO HCN HCO HNCO HO2 N2 N2O NO NO2 O O2 OH T V point 2 point 7 u \n",
|
|
"##############################################################################\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 0.0001139 5.653\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 0.0001442 5.86\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 0.002463 3.926\n",
|
|
"Attempt Newton solution of steady-state problem... success.\n",
|
|
"\n",
|
|
"Problem solved on [20] point grid(s).\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"##############################################################################\n",
|
|
"Refining grid in flame.\n",
|
|
" New points inserted after grid points 1 4 9 10 11 12 13 17 18 \n",
|
|
" to resolve C C2H2 C2H3 C2H4 C2H6 CH CH2 CH2(S) CH2CO CH2O CH2OH CH3 CH3CHO CH3O CH3OH CH4 CO CO2 H H2 H2O H2O2 HCCO HCN HCO HNCO HO2 N2 N2O NO NO2 O O2 OH T V point 1 point 4 u \n",
|
|
"##############################################################################\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 0.0001139 5.647\n",
|
|
"Attempt Newton solution of steady-state problem... success.\n",
|
|
"\n",
|
|
"Problem solved on [29] point grid(s).\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"##############################################################################\n",
|
|
"Refining grid in flame.\n",
|
|
" New points inserted after grid points 0 10 14 15 16 17 18 23 26 27 \n",
|
|
" to resolve C C2H2 C2H3 C2H4 C2H5 C2H6 C3H8 CH CH2 CH2(S) CH2CHO CH2CO CH2O CH2OH CH3 CH3CHO CH3O CH3OH CH4 CO CO2 H H2 H2O H2O2 HCCO HCN HCO HNCO HO2 N2 N2O NO NO2 O O2 OH T V point 0 point 10 point 23 u \n",
|
|
"##############################################################################\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 7.594e-05 6.151\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 0.0001442 6.013\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 4.561e-05 5.695\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 0.0001155 5.755\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 0.001973 4.03\n",
|
|
"Attempt Newton solution of steady-state problem... success.\n",
|
|
"\n",
|
|
"Problem solved on [39] point grid(s).\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"##############################################################################\n",
|
|
"Refining grid in flame.\n",
|
|
" New points inserted after grid points 24 25 26 27 28 36 37 \n",
|
|
" to resolve C C2H2 C2H3 C2H4 C2H5 C2H6 C3H8 CH CH2 CH2(S) CH2CO CH2O CH2OH CH3 CH3CHO CH3O CH3OH CH4 CO CO2 H H2 H2O H2O2 HCCO HCN HCO HNCO HO2 N2 N2O NO NO2 O O2 OH T V u \n",
|
|
"##############################################################################\n",
|
|
"refine: discarding point at 0.0148437\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 5.695e-05 5.862\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 7.208e-05 6.072\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 0.0005474 4.974\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 7.306e-05 6.124\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 0.001248 4.287\n",
|
|
"Attempt Newton solution of steady-state problem... success.\n",
|
|
"\n",
|
|
"Problem solved on [45] point grid(s).\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"##############################################################################\n",
|
|
"Refining grid in flame.\n",
|
|
" New points inserted after grid points 28 29 30 31 32 33 \n",
|
|
" to resolve C C2H2 C2H3 C2H4 C2H5 C2H6 C3H8 CH CH2 CH2(S) CH2CHO CH2CO CH2O CH2OH CH3 CH3CHO CH3O CH3OH CH4 CO CO2 H H2 H2O H2O2 HCCO HCN HCO HNCO HO2 N2 N2O NO NO2 O O2 OH T V u \n",
|
|
"##############################################################################\n",
|
|
"refine: discarding point at 0.0170313\n",
|
|
"refine: discarding point at 0.0173438\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 0.0001709 5.41\n",
|
|
"Attempt Newton solution of steady-state problem... success.\n",
|
|
"\n",
|
|
"Problem solved on [49] point grid(s).\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"##############################################################################\n",
|
|
"Refining grid in flame.\n",
|
|
" New points inserted after grid points 30 31 32 33 34 35 36 \n",
|
|
" to resolve C C2H2 C2H3 C2H4 C2H5 C2H6 C3H7 C3H8 CH CH2 CH2(S) CH2CHO CH2CO CH2O CH2OH CH3 CH3CHO CH3O CH3OH CH4 CO CO2 H H2 H2O H2O2 HCCO HCCOH HCN HCO HNCO HO2 N2 N2O NO NO2 O O2 OH T V u \n",
|
|
"##############################################################################\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 0.0001139 5.784\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 0.0005767 5.383\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 0.0003079 5.314\n",
|
|
"Attempt Newton solution of steady-state problem... success.\n",
|
|
"\n",
|
|
"Problem solved on [56] point grid(s).\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"##############################################################################\n",
|
|
"Refining grid in flame.\n",
|
|
" New points inserted after grid points 29 34 39 40 41 42 43 44 \n",
|
|
" to resolve C C2H2 C2H3 C2H4 C2H5 C2H6 C3H7 C3H8 CH CH2 CH2(S) CH2CHO CH2CO CH2O CH2OH CH3 CH3CHO CH3O CH3OH CH4 CO CO2 H H2 H2O H2O2 HCCO HCCOH HCN HCNO HCO HNCO HO2 N2 N2O NO NO2 O O2 OH T point 29 point 34 u \n",
|
|
"##############################################################################\n",
|
|
"refine: discarding point at 0.0179688\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 0.0001709 5.61\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 0.001297 4.393\n",
|
|
"Attempt Newton solution of steady-state problem... success.\n",
|
|
"\n",
|
|
"Problem solved on [63] point grid(s).\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"##############################################################################\n",
|
|
"Refining grid in flame.\n",
|
|
" New points inserted after grid points 45 46 47 48 49 50 51 52 \n",
|
|
" to resolve C2H2 C2H3 C2H4 C2H5 C2H6 C3H7 C3H8 CH CH2 CH2(S) CH2CHO CH2CO CH2O CH2OH CH3 CH3CHO CH3O CH3OH CH4 CO CO2 H H2 H2O H2O2 HCCO HCCOH HCN HCO HNCO HO2 N2 NO NO2 O O2 OH T point 46 u \n",
|
|
"##############################################################################\n",
|
|
"refine: discarding point at 0.0184375\n",
|
|
"refine: discarding point at 0.01875\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 0.0002563 5.356\n",
|
|
"Attempt Newton solution of steady-state problem... failure. \n",
|
|
"Take 10 timesteps 0.001297 4.473\n",
|
|
"Attempt Newton solution of steady-state problem... success.\n",
|
|
"\n",
|
|
"Problem solved on [69] point grid(s).\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"##############################################################################\n",
|
|
"Refining grid in flame.\n",
|
|
" New points inserted after grid points 42 50 51 52 53 54 55 56 57 \n",
|
|
" to resolve C2H2 C2H3 C2H4 C2H5 C2H6 C3H7 C3H8 CH CH2 CH2(S) CH2CHO CH2CO CH2O CH2OH CH3 CH3CHO CH3O CH3OH CH4 CO CO2 H H2 H2O H2O2 HCCO HCCOH HCN HCO HNCO HO2 N2 NO2 O O2 OH T point 42 point 53 u \n",
|
|
"##############################################################################\n",
|
|
"refine: discarding point at 0.0182813\n",
|
|
"refine: discarding point at 0.0185938\n",
|
|
"refine: discarding point at 0.0189063\n",
|
|
"refine: discarding point at 0.0192188\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"Attempt Newton solution of steady-state problem... success.\n",
|
|
"\n",
|
|
"Problem solved on [74] point grid(s).\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"##############################################################################\n",
|
|
"Refining grid in flame.\n",
|
|
" New points inserted after grid points 52 53 54 55 56 57 58 59 60 61 \n",
|
|
" to resolve C2H2 C2H3 C2H4 C2H5 C2H6 C3H7 C3H8 CH CH2 CH2(S) CH2CHO CH2CO CH2O CH2OH CH3 CH3CHO CH3O CH3OH CH4 CO H H2 H2O H2O2 HCCO HCCOH HCN HCO HO2 N2 NO2 O O2 OH T point 61 \n",
|
|
"##############################################################################\n",
|
|
"refine: discarding point at 0.0196875\n",
|
|
"refine: discarding point at 0.0199219\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"Attempt Newton solution of steady-state problem... success.\n",
|
|
"\n",
|
|
"Problem solved on [82] point grid(s).\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"##############################################################################\n",
|
|
"Refining grid in flame.\n",
|
|
" New points inserted after grid points 51 52 55 56 57 58 59 60 61 62 \n",
|
|
" to resolve C2H2 C2H3 C2H4 C2H5 C2H6 C3H8 CH CH2 CH2(S) CH2CO CH2OH CH3 CH3CHO CH3O HCCO HCO \n",
|
|
"##############################################################################\n",
|
|
"refine: discarding point at 0.0195313\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"Attempt Newton solution of steady-state problem... success.\n",
|
|
"\n",
|
|
"Problem solved on [91] point grid(s).\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"##############################################################################\n",
|
|
"Refining grid in flame.\n",
|
|
" New points inserted after grid points 46 47 48 52 54 55 72 \n",
|
|
" to resolve C2H6 C3H8 CH3O point 52 point 72 \n",
|
|
"##############################################################################\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"Attempt Newton solution of steady-state problem... success.\n",
|
|
"\n",
|
|
"Problem solved on [98] point grid(s).\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"##############################################################################\n",
|
|
"Refining grid in flame.\n",
|
|
" New points inserted after grid points 45 80 \n",
|
|
" to resolve point 45 point 80 \n",
|
|
"##############################################################################\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"Attempt Newton solution of steady-state problem... success.\n",
|
|
"\n",
|
|
"Problem solved on [100] point grid(s).\n",
|
|
"\n",
|
|
"..............................................................................\n",
|
|
"no new points needed in flame\n",
|
|
"Solution saved to 'premixed_twin_flame.csv'.\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"# The solver returns the peak temperature, strain rate and\n",
|
|
"# the point which we ascribe to the characteristic strain rate.\n",
|
|
"\n",
|
|
"(T, K, strainRatePoint) = solveOpposedFlame(oppFlame, massFlux, loglevel=1)\n",
|
|
"\n",
|
|
"# You can plot/see all state space variables by calling oppFlame.foo where foo\n",
|
|
"# is T, Y[i], etc. The spatial variable (distance in meters) is in oppFlame.grid\n",
|
|
"# Thus to plot temperature vs distance, use oppFlame.grid and oppFlame.T\n",
|
|
"\n",
|
|
"#This is to save output\n",
|
|
"oppFlame.write_csv(\"premixed_twin_flame.csv\", quiet=False)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 6,
|
|
"metadata": {
|
|
"collapsed": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Peak temperature: 1920.5 K\n",
|
|
"Strain Rate: 163.6 1/s\n",
|
|
"Consumption Speed: 20.80 cm/s\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"Sc = computeConsumptionSpeed(oppFlame)\n",
|
|
"\n",
|
|
"print(\"Peak temperature: {0:.1f} K\".format(T))\n",
|
|
"print(\"Strain Rate: {0:.1f} 1/s\".format(K))\n",
|
|
"print(\"Consumption Speed: {0:.2f} cm/s\".format(Sc*100))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Plot figures\n",
|
|
"\n",
|
|
"Note that the graphs only represent one-half of the domain, because the solution is symmetric"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 7,
|
|
"metadata": {
|
|
"collapsed": true
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Import plotting modules and define plotting preference\n",
|
|
"import matplotlib.pyplot as plt\n",
|
|
"%matplotlib notebook\n",
|
|
"\n",
|
|
"plt.rcParams['figure.autolayout'] = True\n",
|
|
"\n",
|
|
"plt.rcParams['axes.labelsize'] = 14\n",
|
|
"plt.rcParams['xtick.labelsize'] = 12\n",
|
|
"plt.rcParams['ytick.labelsize'] = 12\n",
|
|
"plt.rcParams['legend.fontsize'] = 10\n",
|
|
"plt.rcParams['figure.facecolor'] = 'white'\n",
|
|
"plt.rcParams['figure.figsize'] = (8,6)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### Axial velocity plot"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 8,
|
|
"metadata": {
|
|
"collapsed": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"application/javascript": [
|
|
"/* Put everything inside the global mpl namespace */\n",
|
|
"window.mpl = {};\n",
|
|
"\n",
|
|
"mpl.get_websocket_type = function() {\n",
|
|
" if (typeof(WebSocket) !== 'undefined') {\n",
|
|
" return WebSocket;\n",
|
|
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
|
|
" return MozWebSocket;\n",
|
|
" } else {\n",
|
|
" alert('Your browser does not have WebSocket support.' +\n",
|
|
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
|
|
" 'Firefox 4 and 5 are also supported but you ' +\n",
|
|
" 'have to enable WebSockets in about:config.');\n",
|
|
" };\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
|
|
" this.id = figure_id;\n",
|
|
"\n",
|
|
" this.ws = websocket;\n",
|
|
"\n",
|
|
" this.supports_binary = (this.ws.binaryType != undefined);\n",
|
|
"\n",
|
|
" if (!this.supports_binary) {\n",
|
|
" var warnings = document.getElementById(\"mpl-warnings\");\n",
|
|
" if (warnings) {\n",
|
|
" warnings.style.display = 'block';\n",
|
|
" warnings.textContent = (\n",
|
|
" \"This browser does not support binary websocket messages. \" +\n",
|
|
" \"Performance may be slow.\");\n",
|
|
" }\n",
|
|
" }\n",
|
|
"\n",
|
|
" this.imageObj = new Image();\n",
|
|
"\n",
|
|
" this.context = undefined;\n",
|
|
" this.message = undefined;\n",
|
|
" this.canvas = undefined;\n",
|
|
" this.rubberband_canvas = undefined;\n",
|
|
" this.rubberband_context = undefined;\n",
|
|
" this.format_dropdown = undefined;\n",
|
|
"\n",
|
|
" this.image_mode = 'full';\n",
|
|
"\n",
|
|
" this.root = $('<div/>');\n",
|
|
" this._root_extra_style(this.root)\n",
|
|
" this.root.attr('style', 'display: inline-block');\n",
|
|
"\n",
|
|
" $(parent_element).append(this.root);\n",
|
|
"\n",
|
|
" this._init_header(this);\n",
|
|
" this._init_canvas(this);\n",
|
|
" this._init_toolbar(this);\n",
|
|
"\n",
|
|
" var fig = this;\n",
|
|
"\n",
|
|
" this.waiting = false;\n",
|
|
"\n",
|
|
" this.ws.onopen = function () {\n",
|
|
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
|
|
" fig.send_message(\"send_image_mode\", {});\n",
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
" }\n",
|
|
"\n",
|
|
" this.imageObj.onload = function() {\n",
|
|
" if (fig.image_mode == 'full') {\n",
|
|
" // Full images could contain transparency (where diff images\n",
|
|
" // almost always do), so we need to clear the canvas so that\n",
|
|
" // there is no ghosting.\n",
|
|
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
" }\n",
|
|
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
|
|
" };\n",
|
|
"\n",
|
|
" this.imageObj.onunload = function() {\n",
|
|
" this.ws.close();\n",
|
|
" }\n",
|
|
"\n",
|
|
" this.ws.onmessage = this._make_on_message_function(this);\n",
|
|
"\n",
|
|
" this.ondownload = ondownload;\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype._init_header = function() {\n",
|
|
" var titlebar = $(\n",
|
|
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
|
|
" 'ui-helper-clearfix\"/>');\n",
|
|
" var titletext = $(\n",
|
|
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
|
|
" 'text-align: center; padding: 3px;\"/>');\n",
|
|
" titlebar.append(titletext)\n",
|
|
" this.root.append(titlebar);\n",
|
|
" this.header = titletext[0];\n",
|
|
"}\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
|
|
"\n",
|
|
"}\n",
|
|
"\n",
|
|
"\n",
|
|
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
|
|
"\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype._init_canvas = function() {\n",
|
|
" var fig = this;\n",
|
|
"\n",
|
|
" var canvas_div = $('<div/>');\n",
|
|
"\n",
|
|
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
|
|
"\n",
|
|
" function canvas_keyboard_event(event) {\n",
|
|
" return fig.key_event(event, event['data']);\n",
|
|
" }\n",
|
|
"\n",
|
|
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
|
|
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
|
|
" this.canvas_div = canvas_div\n",
|
|
" this._canvas_extra_style(canvas_div)\n",
|
|
" this.root.append(canvas_div);\n",
|
|
"\n",
|
|
" var canvas = $('<canvas/>');\n",
|
|
" canvas.addClass('mpl-canvas');\n",
|
|
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
|
|
"\n",
|
|
" this.canvas = canvas[0];\n",
|
|
" this.context = canvas[0].getContext(\"2d\");\n",
|
|
"\n",
|
|
" var rubberband = $('<canvas/>');\n",
|
|
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
|
|
"\n",
|
|
" var pass_mouse_events = true;\n",
|
|
"\n",
|
|
" canvas_div.resizable({\n",
|
|
" start: function(event, ui) {\n",
|
|
" pass_mouse_events = false;\n",
|
|
" },\n",
|
|
" resize: function(event, ui) {\n",
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
" },\n",
|
|
" stop: function(event, ui) {\n",
|
|
" pass_mouse_events = true;\n",
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
" },\n",
|
|
" });\n",
|
|
"\n",
|
|
" function mouse_event_fn(event) {\n",
|
|
" if (pass_mouse_events)\n",
|
|
" return fig.mouse_event(event, event['data']);\n",
|
|
" }\n",
|
|
"\n",
|
|
" rubberband.mousedown('button_press', mouse_event_fn);\n",
|
|
" rubberband.mouseup('button_release', mouse_event_fn);\n",
|
|
" // Throttle sequential mouse events to 1 every 20ms.\n",
|
|
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
|
|
"\n",
|
|
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
|
|
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
|
|
"\n",
|
|
" canvas_div.on(\"wheel\", function (event) {\n",
|
|
" event = event.originalEvent;\n",
|
|
" event['data'] = 'scroll'\n",
|
|
" if (event.deltaY < 0) {\n",
|
|
" event.step = 1;\n",
|
|
" } else {\n",
|
|
" event.step = -1;\n",
|
|
" }\n",
|
|
" mouse_event_fn(event);\n",
|
|
" });\n",
|
|
"\n",
|
|
" canvas_div.append(canvas);\n",
|
|
" canvas_div.append(rubberband);\n",
|
|
"\n",
|
|
" this.rubberband = rubberband;\n",
|
|
" this.rubberband_canvas = rubberband[0];\n",
|
|
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
|
|
" this.rubberband_context.strokeStyle = \"#000000\";\n",
|
|
"\n",
|
|
" this._resize_canvas = function(width, height) {\n",
|
|
" // Keep the size of the canvas, canvas container, and rubber band\n",
|
|
" // canvas in synch.\n",
|
|
" canvas_div.css('width', width)\n",
|
|
" canvas_div.css('height', height)\n",
|
|
"\n",
|
|
" canvas.attr('width', width);\n",
|
|
" canvas.attr('height', height);\n",
|
|
"\n",
|
|
" rubberband.attr('width', width);\n",
|
|
" rubberband.attr('height', height);\n",
|
|
" }\n",
|
|
"\n",
|
|
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
|
|
" // upon first draw.\n",
|
|
" this._resize_canvas(600, 600);\n",
|
|
"\n",
|
|
" // Disable right mouse context menu.\n",
|
|
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
|
|
" return false;\n",
|
|
" });\n",
|
|
"\n",
|
|
" function set_focus () {\n",
|
|
" canvas.focus();\n",
|
|
" canvas_div.focus();\n",
|
|
" }\n",
|
|
"\n",
|
|
" window.setTimeout(set_focus, 100);\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
" var fig = this;\n",
|
|
"\n",
|
|
" var nav_element = $('<div/>')\n",
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
" this.root.append(nav_element);\n",
|
|
"\n",
|
|
" // Define a callback function for later on.\n",
|
|
" function toolbar_event(event) {\n",
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
" }\n",
|
|
" function toolbar_mouse_event(event) {\n",
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
" }\n",
|
|
"\n",
|
|
" for(var toolbar_ind in mpl.toolbar_items) {\n",
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
"\n",
|
|
" if (!name) {\n",
|
|
" // put a spacer in here.\n",
|
|
" continue;\n",
|
|
" }\n",
|
|
" var button = $('<button/>');\n",
|
|
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
|
|
" 'ui-button-icon-only');\n",
|
|
" button.attr('role', 'button');\n",
|
|
" button.attr('aria-disabled', 'false');\n",
|
|
" button.click(method_name, toolbar_event);\n",
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
"\n",
|
|
" var icon_img = $('<span/>');\n",
|
|
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
|
|
" icon_img.addClass(image);\n",
|
|
" icon_img.addClass('ui-corner-all');\n",
|
|
"\n",
|
|
" var tooltip_span = $('<span/>');\n",
|
|
" tooltip_span.addClass('ui-button-text');\n",
|
|
" tooltip_span.html(tooltip);\n",
|
|
"\n",
|
|
" button.append(icon_img);\n",
|
|
" button.append(tooltip_span);\n",
|
|
"\n",
|
|
" nav_element.append(button);\n",
|
|
" }\n",
|
|
"\n",
|
|
" var fmt_picker_span = $('<span/>');\n",
|
|
"\n",
|
|
" var fmt_picker = $('<select/>');\n",
|
|
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
|
|
" fmt_picker_span.append(fmt_picker);\n",
|
|
" nav_element.append(fmt_picker_span);\n",
|
|
" this.format_dropdown = fmt_picker[0];\n",
|
|
"\n",
|
|
" for (var ind in mpl.extensions) {\n",
|
|
" var fmt = mpl.extensions[ind];\n",
|
|
" var option = $(\n",
|
|
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
|
|
" fmt_picker.append(option)\n",
|
|
" }\n",
|
|
"\n",
|
|
" // Add hover states to the ui-buttons\n",
|
|
" $( \".ui-button\" ).hover(\n",
|
|
" function() { $(this).addClass(\"ui-state-hover\");},\n",
|
|
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
|
|
" );\n",
|
|
"\n",
|
|
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
|
|
" nav_element.append(status_bar);\n",
|
|
" this.message = status_bar[0];\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
|
|
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
|
|
" // which will in turn request a refresh of the image.\n",
|
|
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.send_message = function(type, properties) {\n",
|
|
" properties['type'] = type;\n",
|
|
" properties['figure_id'] = this.id;\n",
|
|
" this.ws.send(JSON.stringify(properties));\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.send_draw_message = function() {\n",
|
|
" if (!this.waiting) {\n",
|
|
" this.waiting = true;\n",
|
|
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
|
|
" }\n",
|
|
"}\n",
|
|
"\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
" var format_dropdown = fig.format_dropdown;\n",
|
|
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
|
|
" fig.ondownload(fig, format);\n",
|
|
"}\n",
|
|
"\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
|
|
" var size = msg['size'];\n",
|
|
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
|
|
" fig._resize_canvas(size[0], size[1]);\n",
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
" };\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
|
|
" var x0 = msg['x0'];\n",
|
|
" var y0 = fig.canvas.height - msg['y0'];\n",
|
|
" var x1 = msg['x1'];\n",
|
|
" var y1 = fig.canvas.height - msg['y1'];\n",
|
|
" x0 = Math.floor(x0) + 0.5;\n",
|
|
" y0 = Math.floor(y0) + 0.5;\n",
|
|
" x1 = Math.floor(x1) + 0.5;\n",
|
|
" y1 = Math.floor(y1) + 0.5;\n",
|
|
" var min_x = Math.min(x0, x1);\n",
|
|
" var min_y = Math.min(y0, y1);\n",
|
|
" var width = Math.abs(x1 - x0);\n",
|
|
" var height = Math.abs(y1 - y0);\n",
|
|
"\n",
|
|
" fig.rubberband_context.clearRect(\n",
|
|
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
"\n",
|
|
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
|
|
" // Updates the figure title.\n",
|
|
" fig.header.textContent = msg['label'];\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
|
|
" var cursor = msg['cursor'];\n",
|
|
" switch(cursor)\n",
|
|
" {\n",
|
|
" case 0:\n",
|
|
" cursor = 'pointer';\n",
|
|
" break;\n",
|
|
" case 1:\n",
|
|
" cursor = 'default';\n",
|
|
" break;\n",
|
|
" case 2:\n",
|
|
" cursor = 'crosshair';\n",
|
|
" break;\n",
|
|
" case 3:\n",
|
|
" cursor = 'move';\n",
|
|
" break;\n",
|
|
" }\n",
|
|
" fig.rubberband_canvas.style.cursor = cursor;\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
|
|
" fig.message.textContent = msg['message'];\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
|
|
" // Request the server to send over a new figure.\n",
|
|
" fig.send_draw_message();\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
|
|
" fig.image_mode = msg['mode'];\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
" // Called whenever the canvas gets updated.\n",
|
|
" this.send_message(\"ack\", {});\n",
|
|
"}\n",
|
|
"\n",
|
|
"// A function to construct a web socket function for onmessage handling.\n",
|
|
"// Called in the figure constructor.\n",
|
|
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
|
|
" return function socket_on_message(evt) {\n",
|
|
" if (evt.data instanceof Blob) {\n",
|
|
" /* FIXME: We get \"Resource interpreted as Image but\n",
|
|
" * transferred with MIME type text/plain:\" errors on\n",
|
|
" * Chrome. But how to set the MIME type? It doesn't seem\n",
|
|
" * to be part of the websocket stream */\n",
|
|
" evt.data.type = \"image/png\";\n",
|
|
"\n",
|
|
" /* Free the memory for the previous frames */\n",
|
|
" if (fig.imageObj.src) {\n",
|
|
" (window.URL || window.webkitURL).revokeObjectURL(\n",
|
|
" fig.imageObj.src);\n",
|
|
" }\n",
|
|
"\n",
|
|
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
|
|
" evt.data);\n",
|
|
" fig.updated_canvas_event();\n",
|
|
" fig.waiting = false;\n",
|
|
" return;\n",
|
|
" }\n",
|
|
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
|
|
" fig.imageObj.src = evt.data;\n",
|
|
" fig.updated_canvas_event();\n",
|
|
" fig.waiting = false;\n",
|
|
" return;\n",
|
|
" }\n",
|
|
"\n",
|
|
" var msg = JSON.parse(evt.data);\n",
|
|
" var msg_type = msg['type'];\n",
|
|
"\n",
|
|
" // Call the \"handle_{type}\" callback, which takes\n",
|
|
" // the figure and JSON message as its only arguments.\n",
|
|
" try {\n",
|
|
" var callback = fig[\"handle_\" + msg_type];\n",
|
|
" } catch (e) {\n",
|
|
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
|
|
" return;\n",
|
|
" }\n",
|
|
"\n",
|
|
" if (callback) {\n",
|
|
" try {\n",
|
|
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
|
|
" callback(fig, msg);\n",
|
|
" } catch (e) {\n",
|
|
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
|
|
" }\n",
|
|
" }\n",
|
|
" };\n",
|
|
"}\n",
|
|
"\n",
|
|
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
|
|
"mpl.findpos = function(e) {\n",
|
|
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
|
|
" var targ;\n",
|
|
" if (!e)\n",
|
|
" e = window.event;\n",
|
|
" if (e.target)\n",
|
|
" targ = e.target;\n",
|
|
" else if (e.srcElement)\n",
|
|
" targ = e.srcElement;\n",
|
|
" if (targ.nodeType == 3) // defeat Safari bug\n",
|
|
" targ = targ.parentNode;\n",
|
|
"\n",
|
|
" // jQuery normalizes the pageX and pageY\n",
|
|
" // pageX,Y are the mouse positions relative to the document\n",
|
|
" // offset() returns the position of the element relative to the document\n",
|
|
" var x = e.pageX - $(targ).offset().left;\n",
|
|
" var y = e.pageY - $(targ).offset().top;\n",
|
|
"\n",
|
|
" return {\"x\": x, \"y\": y};\n",
|
|
"};\n",
|
|
"\n",
|
|
"/*\n",
|
|
" * return a copy of an object with only non-object keys\n",
|
|
" * we need this to avoid circular references\n",
|
|
" * http://stackoverflow.com/a/24161582/3208463\n",
|
|
" */\n",
|
|
"function simpleKeys (original) {\n",
|
|
" return Object.keys(original).reduce(function (obj, key) {\n",
|
|
" if (typeof original[key] !== 'object')\n",
|
|
" obj[key] = original[key]\n",
|
|
" return obj;\n",
|
|
" }, {});\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
|
|
" var canvas_pos = mpl.findpos(event)\n",
|
|
"\n",
|
|
" if (name === 'button_press')\n",
|
|
" {\n",
|
|
" this.canvas.focus();\n",
|
|
" this.canvas_div.focus();\n",
|
|
" }\n",
|
|
"\n",
|
|
" var x = canvas_pos.x;\n",
|
|
" var y = canvas_pos.y;\n",
|
|
"\n",
|
|
" this.send_message(name, {x: x, y: y, button: event.button,\n",
|
|
" step: event.step,\n",
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
"\n",
|
|
" /* This prevents the web browser from automatically changing to\n",
|
|
" * the text insertion cursor when the button is pressed. We want\n",
|
|
" * to control all of the cursor setting manually through the\n",
|
|
" * 'cursor' event from matplotlib */\n",
|
|
" event.preventDefault();\n",
|
|
" return false;\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
" // Handle any extra behaviour associated with a key event\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.key_event = function(event, name) {\n",
|
|
"\n",
|
|
" // Prevent repeat events\n",
|
|
" if (name == 'key_press')\n",
|
|
" {\n",
|
|
" if (event.which === this._key)\n",
|
|
" return;\n",
|
|
" else\n",
|
|
" this._key = event.which;\n",
|
|
" }\n",
|
|
" if (name == 'key_release')\n",
|
|
" this._key = null;\n",
|
|
"\n",
|
|
" var value = '';\n",
|
|
" if (event.ctrlKey && event.which != 17)\n",
|
|
" value += \"ctrl+\";\n",
|
|
" if (event.altKey && event.which != 18)\n",
|
|
" value += \"alt+\";\n",
|
|
" if (event.shiftKey && event.which != 16)\n",
|
|
" value += \"shift+\";\n",
|
|
"\n",
|
|
" value += 'k';\n",
|
|
" value += event.which.toString();\n",
|
|
"\n",
|
|
" this._key_event_extra(event, name);\n",
|
|
"\n",
|
|
" this.send_message(name, {key: value,\n",
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
" return false;\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
|
|
" if (name == 'download') {\n",
|
|
" this.handle_save(this, null);\n",
|
|
" } else {\n",
|
|
" this.send_message(\"toolbar_button\", {name: name});\n",
|
|
" }\n",
|
|
"};\n",
|
|
"\n",
|
|
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
|
|
" this.message.textContent = tooltip;\n",
|
|
"};\n",
|
|
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
|
|
"\n",
|
|
"mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
|
|
"\n",
|
|
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
|
|
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
|
|
" // object with the appropriate methods. Currently this is a non binary\n",
|
|
" // socket, so there is still some room for performance tuning.\n",
|
|
" var ws = {};\n",
|
|
"\n",
|
|
" ws.close = function() {\n",
|
|
" comm.close()\n",
|
|
" };\n",
|
|
" ws.send = function(m) {\n",
|
|
" //console.log('sending', m);\n",
|
|
" comm.send(m);\n",
|
|
" };\n",
|
|
" // Register the callback with on_msg.\n",
|
|
" comm.on_msg(function(msg) {\n",
|
|
" //console.log('receiving', msg['content']['data'], msg);\n",
|
|
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
|
|
" ws.onmessage(msg['content']['data'])\n",
|
|
" });\n",
|
|
" return ws;\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.mpl_figure_comm = function(comm, msg) {\n",
|
|
" // This is the function which gets called when the mpl process\n",
|
|
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
|
|
"\n",
|
|
" var id = msg.content.data.id;\n",
|
|
" // Get hold of the div created by the display call when the Comm\n",
|
|
" // socket was opened in Python.\n",
|
|
" var element = $(\"#\" + id);\n",
|
|
" var ws_proxy = comm_websocket_adapter(comm)\n",
|
|
"\n",
|
|
" function ondownload(figure, format) {\n",
|
|
" window.open(figure.imageObj.src);\n",
|
|
" }\n",
|
|
"\n",
|
|
" var fig = new mpl.figure(id, ws_proxy,\n",
|
|
" ondownload,\n",
|
|
" element.get(0));\n",
|
|
"\n",
|
|
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
|
|
" // web socket which is closed, not our websocket->open comm proxy.\n",
|
|
" ws_proxy.onopen();\n",
|
|
"\n",
|
|
" fig.parent_element = element.get(0);\n",
|
|
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
|
|
" if (!fig.cell_info) {\n",
|
|
" console.error(\"Failed to find cell for figure\", id, fig);\n",
|
|
" return;\n",
|
|
" }\n",
|
|
"\n",
|
|
" var output_index = fig.cell_info[2]\n",
|
|
" var cell = fig.cell_info[0];\n",
|
|
"\n",
|
|
"};\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
|
|
" fig.root.unbind('remove')\n",
|
|
"\n",
|
|
" // Update the output cell to use the data from the current canvas.\n",
|
|
" fig.push_to_output();\n",
|
|
" var dataURL = fig.canvas.toDataURL();\n",
|
|
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
|
|
" // the notebook keyboard shortcuts fail.\n",
|
|
" IPython.keyboard_manager.enable()\n",
|
|
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
|
|
" fig.close_ws(fig, msg);\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
|
|
" fig.send_message('closing', msg);\n",
|
|
" // fig.ws.close()\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
|
|
" // Turn the data on the canvas into data in the output cell.\n",
|
|
" var dataURL = this.canvas.toDataURL();\n",
|
|
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
" // Tell IPython that the notebook contents must change.\n",
|
|
" IPython.notebook.set_dirty(true);\n",
|
|
" this.send_message(\"ack\", {});\n",
|
|
" var fig = this;\n",
|
|
" // Wait a second, then push the new image to the DOM so\n",
|
|
" // that it is saved nicely (might be nice to debounce this).\n",
|
|
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
" var fig = this;\n",
|
|
"\n",
|
|
" var nav_element = $('<div/>')\n",
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
" this.root.append(nav_element);\n",
|
|
"\n",
|
|
" // Define a callback function for later on.\n",
|
|
" function toolbar_event(event) {\n",
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
" }\n",
|
|
" function toolbar_mouse_event(event) {\n",
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
" }\n",
|
|
"\n",
|
|
" for(var toolbar_ind in mpl.toolbar_items){\n",
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
"\n",
|
|
" if (!name) { continue; };\n",
|
|
"\n",
|
|
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
|
|
" button.click(method_name, toolbar_event);\n",
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
" nav_element.append(button);\n",
|
|
" }\n",
|
|
"\n",
|
|
" // Add the status bar.\n",
|
|
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
|
|
" nav_element.append(status_bar);\n",
|
|
" this.message = status_bar[0];\n",
|
|
"\n",
|
|
" // Add the close button to the window.\n",
|
|
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
|
|
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
|
|
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
|
|
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
|
|
" buttongrp.append(button);\n",
|
|
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
|
|
" titlebar.prepend(buttongrp);\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype._root_extra_style = function(el){\n",
|
|
" var fig = this\n",
|
|
" el.on(\"remove\", function(){\n",
|
|
"\tfig.close_ws(fig, {});\n",
|
|
" });\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
|
|
" // this is important to make the div 'focusable\n",
|
|
" el.attr('tabindex', 0)\n",
|
|
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
|
|
" // off when our div gets focus\n",
|
|
"\n",
|
|
" // location in version 3\n",
|
|
" if (IPython.notebook.keyboard_manager) {\n",
|
|
" IPython.notebook.keyboard_manager.register_events(el);\n",
|
|
" }\n",
|
|
" else {\n",
|
|
" // location in version 2\n",
|
|
" IPython.keyboard_manager.register_events(el);\n",
|
|
" }\n",
|
|
"\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
" var manager = IPython.notebook.keyboard_manager;\n",
|
|
" if (!manager)\n",
|
|
" manager = IPython.keyboard_manager;\n",
|
|
"\n",
|
|
" // Check for shift+enter\n",
|
|
" if (event.shiftKey && event.which == 13) {\n",
|
|
" this.canvas_div.blur();\n",
|
|
" event.shiftKey = false;\n",
|
|
" // Send a \"J\" for go to next cell\n",
|
|
" event.which = 74;\n",
|
|
" event.keyCode = 74;\n",
|
|
" manager.command_mode();\n",
|
|
" manager.handle_keydown(event);\n",
|
|
" }\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
" fig.ondownload(fig, null);\n",
|
|
"}\n",
|
|
"\n",
|
|
"\n",
|
|
"mpl.find_output_cell = function(html_output) {\n",
|
|
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
|
|
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
|
|
" // IPython event is triggered only after the cells have been serialised, which for\n",
|
|
" // our purposes (turning an active figure into a static one), is too late.\n",
|
|
" var cells = IPython.notebook.get_cells();\n",
|
|
" var ncells = cells.length;\n",
|
|
" for (var i=0; i<ncells; i++) {\n",
|
|
" var cell = cells[i];\n",
|
|
" if (cell.cell_type === 'code'){\n",
|
|
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
|
|
" var data = cell.output_area.outputs[j];\n",
|
|
" if (data.data) {\n",
|
|
" // IPython >= 3 moved mimebundle to data attribute of output\n",
|
|
" data = data.data;\n",
|
|
" }\n",
|
|
" if (data['text/html'] == html_output) {\n",
|
|
" return [cell, data, j];\n",
|
|
" }\n",
|
|
" }\n",
|
|
" }\n",
|
|
" }\n",
|
|
"}\n",
|
|
"\n",
|
|
"// Register the function which deals with the matplotlib target/channel.\n",
|
|
"// The kernel may be null if the page has been refreshed.\n",
|
|
"if (IPython.notebook.kernel != null) {\n",
|
|
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
|
|
"}\n"
|
|
],
|
|
"text/plain": [
|
|
"<IPython.core.display.Javascript object>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
},
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAAXNSR0IArs4c6QAAQABJREFUeAHsnQecFeXV/38CLipFXEAB2UVRLFEsxFVjiWshqIi9xBY0USMKKS5YMDFqLCAuGrFrYq/xffNGRcXGmtj+YolgCza2IChFmpQFlv/vzGUus5d7l927c+fOzP2dz+cw7d6Z5/k+o3vueZ5zDiARAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQAREQARHIE4Hr+dyp1IXUmdRHqb2pTUkXXnyEuoA6n/oQdXOqRAREQAREQAREQAREIIVAm5TjMBw2sBFDqV2pO1PXUJ+hNiVm/HWnbkvdntqD+gBVIgIiIAIiIAIiIAIiEEECu7PNq6mZPHqlvGZG465UV3bjjp3bkOfQ/by2IiACIiACIiACIlAwBMLoAUyFP4gnqqk2JZxO9uDJ5dSPPBdtCrmeatckIiACIiACIiACIiACHgLtPPth3D2Mjfoj9fgmGteZ19IZh7Ye0K5JREAEREAEREAEREAEPATCbAAexXZaMMfp1Jc8bU7dXcQT6aaHu/C8XUuVjXiiF3Vx6gUdi4AIiIAIiIAIiEAICHRiG76hWhxETiSsBqAZfbdST6K+vIGe/4fX21NtDaA7DWzrBjem2rVUMeOvLvWkjkVABERABERABEQgRAQsjsGyoeREzBsWNhnOBl1NHUJ9o5mNsyhhM/jMcLQ+PUZdQj2OmirOlHEtz9rOqO7dce2vfoWiuXOB2bMT+t13iW29LSNsoXRl8HIPBiGbbrVVQt192265ZeJahw4tvPGGP17P9s6fPx/FxcUoKira8Bci+InRo0fjuuuui2DLC7vJGrfojr/GTmMXXQLRbPmiRYtQUlJijbfZzXQzmb50LIwewFvYs5XU59f20Aw6c4EeQTWD0Kh8Qj18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\">"
|
|
],
|
|
"text/plain": [
|
|
"<IPython.core.display.HTML object>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"plt.figure()\n",
|
|
"\n",
|
|
"plt.plot(oppFlame.grid*100, oppFlame.u, 'r-o', lw=2)\n",
|
|
"plt.xlim(oppFlame.grid[0], oppFlame.grid[-1]*100)\n",
|
|
"plt.xlabel('Distance (cm)')\n",
|
|
"plt.ylabel('Axial Velocity (m/s)')\n",
|
|
"\n",
|
|
"# Identify the point where the strain rate is calculated\n",
|
|
"plt.plot(oppFlame.grid[strainRatePoint]*100, oppFlame.u[strainRatePoint],'gs')\n",
|
|
"plt.annotate('Strain-Rate point',\n",
|
|
" xy=(oppFlame.grid[strainRatePoint]*100, oppFlame.u[strainRatePoint]),\n",
|
|
" xytext=(0.001, 0.1),\n",
|
|
" arrowprops={'arrowstyle':'->'});"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### Temperature Plot"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 9,
|
|
"metadata": {
|
|
"collapsed": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"application/javascript": [
|
|
"/* Put everything inside the global mpl namespace */\n",
|
|
"window.mpl = {};\n",
|
|
"\n",
|
|
"mpl.get_websocket_type = function() {\n",
|
|
" if (typeof(WebSocket) !== 'undefined') {\n",
|
|
" return WebSocket;\n",
|
|
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
|
|
" return MozWebSocket;\n",
|
|
" } else {\n",
|
|
" alert('Your browser does not have WebSocket support.' +\n",
|
|
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
|
|
" 'Firefox 4 and 5 are also supported but you ' +\n",
|
|
" 'have to enable WebSockets in about:config.');\n",
|
|
" };\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
|
|
" this.id = figure_id;\n",
|
|
"\n",
|
|
" this.ws = websocket;\n",
|
|
"\n",
|
|
" this.supports_binary = (this.ws.binaryType != undefined);\n",
|
|
"\n",
|
|
" if (!this.supports_binary) {\n",
|
|
" var warnings = document.getElementById(\"mpl-warnings\");\n",
|
|
" if (warnings) {\n",
|
|
" warnings.style.display = 'block';\n",
|
|
" warnings.textContent = (\n",
|
|
" \"This browser does not support binary websocket messages. \" +\n",
|
|
" \"Performance may be slow.\");\n",
|
|
" }\n",
|
|
" }\n",
|
|
"\n",
|
|
" this.imageObj = new Image();\n",
|
|
"\n",
|
|
" this.context = undefined;\n",
|
|
" this.message = undefined;\n",
|
|
" this.canvas = undefined;\n",
|
|
" this.rubberband_canvas = undefined;\n",
|
|
" this.rubberband_context = undefined;\n",
|
|
" this.format_dropdown = undefined;\n",
|
|
"\n",
|
|
" this.image_mode = 'full';\n",
|
|
"\n",
|
|
" this.root = $('<div/>');\n",
|
|
" this._root_extra_style(this.root)\n",
|
|
" this.root.attr('style', 'display: inline-block');\n",
|
|
"\n",
|
|
" $(parent_element).append(this.root);\n",
|
|
"\n",
|
|
" this._init_header(this);\n",
|
|
" this._init_canvas(this);\n",
|
|
" this._init_toolbar(this);\n",
|
|
"\n",
|
|
" var fig = this;\n",
|
|
"\n",
|
|
" this.waiting = false;\n",
|
|
"\n",
|
|
" this.ws.onopen = function () {\n",
|
|
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
|
|
" fig.send_message(\"send_image_mode\", {});\n",
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
" }\n",
|
|
"\n",
|
|
" this.imageObj.onload = function() {\n",
|
|
" if (fig.image_mode == 'full') {\n",
|
|
" // Full images could contain transparency (where diff images\n",
|
|
" // almost always do), so we need to clear the canvas so that\n",
|
|
" // there is no ghosting.\n",
|
|
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
" }\n",
|
|
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
|
|
" };\n",
|
|
"\n",
|
|
" this.imageObj.onunload = function() {\n",
|
|
" this.ws.close();\n",
|
|
" }\n",
|
|
"\n",
|
|
" this.ws.onmessage = this._make_on_message_function(this);\n",
|
|
"\n",
|
|
" this.ondownload = ondownload;\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype._init_header = function() {\n",
|
|
" var titlebar = $(\n",
|
|
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
|
|
" 'ui-helper-clearfix\"/>');\n",
|
|
" var titletext = $(\n",
|
|
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
|
|
" 'text-align: center; padding: 3px;\"/>');\n",
|
|
" titlebar.append(titletext)\n",
|
|
" this.root.append(titlebar);\n",
|
|
" this.header = titletext[0];\n",
|
|
"}\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
|
|
"\n",
|
|
"}\n",
|
|
"\n",
|
|
"\n",
|
|
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
|
|
"\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype._init_canvas = function() {\n",
|
|
" var fig = this;\n",
|
|
"\n",
|
|
" var canvas_div = $('<div/>');\n",
|
|
"\n",
|
|
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
|
|
"\n",
|
|
" function canvas_keyboard_event(event) {\n",
|
|
" return fig.key_event(event, event['data']);\n",
|
|
" }\n",
|
|
"\n",
|
|
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
|
|
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
|
|
" this.canvas_div = canvas_div\n",
|
|
" this._canvas_extra_style(canvas_div)\n",
|
|
" this.root.append(canvas_div);\n",
|
|
"\n",
|
|
" var canvas = $('<canvas/>');\n",
|
|
" canvas.addClass('mpl-canvas');\n",
|
|
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
|
|
"\n",
|
|
" this.canvas = canvas[0];\n",
|
|
" this.context = canvas[0].getContext(\"2d\");\n",
|
|
"\n",
|
|
" var rubberband = $('<canvas/>');\n",
|
|
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
|
|
"\n",
|
|
" var pass_mouse_events = true;\n",
|
|
"\n",
|
|
" canvas_div.resizable({\n",
|
|
" start: function(event, ui) {\n",
|
|
" pass_mouse_events = false;\n",
|
|
" },\n",
|
|
" resize: function(event, ui) {\n",
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
" },\n",
|
|
" stop: function(event, ui) {\n",
|
|
" pass_mouse_events = true;\n",
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
" },\n",
|
|
" });\n",
|
|
"\n",
|
|
" function mouse_event_fn(event) {\n",
|
|
" if (pass_mouse_events)\n",
|
|
" return fig.mouse_event(event, event['data']);\n",
|
|
" }\n",
|
|
"\n",
|
|
" rubberband.mousedown('button_press', mouse_event_fn);\n",
|
|
" rubberband.mouseup('button_release', mouse_event_fn);\n",
|
|
" // Throttle sequential mouse events to 1 every 20ms.\n",
|
|
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
|
|
"\n",
|
|
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
|
|
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
|
|
"\n",
|
|
" canvas_div.on(\"wheel\", function (event) {\n",
|
|
" event = event.originalEvent;\n",
|
|
" event['data'] = 'scroll'\n",
|
|
" if (event.deltaY < 0) {\n",
|
|
" event.step = 1;\n",
|
|
" } else {\n",
|
|
" event.step = -1;\n",
|
|
" }\n",
|
|
" mouse_event_fn(event);\n",
|
|
" });\n",
|
|
"\n",
|
|
" canvas_div.append(canvas);\n",
|
|
" canvas_div.append(rubberband);\n",
|
|
"\n",
|
|
" this.rubberband = rubberband;\n",
|
|
" this.rubberband_canvas = rubberband[0];\n",
|
|
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
|
|
" this.rubberband_context.strokeStyle = \"#000000\";\n",
|
|
"\n",
|
|
" this._resize_canvas = function(width, height) {\n",
|
|
" // Keep the size of the canvas, canvas container, and rubber band\n",
|
|
" // canvas in synch.\n",
|
|
" canvas_div.css('width', width)\n",
|
|
" canvas_div.css('height', height)\n",
|
|
"\n",
|
|
" canvas.attr('width', width);\n",
|
|
" canvas.attr('height', height);\n",
|
|
"\n",
|
|
" rubberband.attr('width', width);\n",
|
|
" rubberband.attr('height', height);\n",
|
|
" }\n",
|
|
"\n",
|
|
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
|
|
" // upon first draw.\n",
|
|
" this._resize_canvas(600, 600);\n",
|
|
"\n",
|
|
" // Disable right mouse context menu.\n",
|
|
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
|
|
" return false;\n",
|
|
" });\n",
|
|
"\n",
|
|
" function set_focus () {\n",
|
|
" canvas.focus();\n",
|
|
" canvas_div.focus();\n",
|
|
" }\n",
|
|
"\n",
|
|
" window.setTimeout(set_focus, 100);\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
" var fig = this;\n",
|
|
"\n",
|
|
" var nav_element = $('<div/>')\n",
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
" this.root.append(nav_element);\n",
|
|
"\n",
|
|
" // Define a callback function for later on.\n",
|
|
" function toolbar_event(event) {\n",
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
" }\n",
|
|
" function toolbar_mouse_event(event) {\n",
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
" }\n",
|
|
"\n",
|
|
" for(var toolbar_ind in mpl.toolbar_items) {\n",
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
"\n",
|
|
" if (!name) {\n",
|
|
" // put a spacer in here.\n",
|
|
" continue;\n",
|
|
" }\n",
|
|
" var button = $('<button/>');\n",
|
|
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
|
|
" 'ui-button-icon-only');\n",
|
|
" button.attr('role', 'button');\n",
|
|
" button.attr('aria-disabled', 'false');\n",
|
|
" button.click(method_name, toolbar_event);\n",
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
"\n",
|
|
" var icon_img = $('<span/>');\n",
|
|
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
|
|
" icon_img.addClass(image);\n",
|
|
" icon_img.addClass('ui-corner-all');\n",
|
|
"\n",
|
|
" var tooltip_span = $('<span/>');\n",
|
|
" tooltip_span.addClass('ui-button-text');\n",
|
|
" tooltip_span.html(tooltip);\n",
|
|
"\n",
|
|
" button.append(icon_img);\n",
|
|
" button.append(tooltip_span);\n",
|
|
"\n",
|
|
" nav_element.append(button);\n",
|
|
" }\n",
|
|
"\n",
|
|
" var fmt_picker_span = $('<span/>');\n",
|
|
"\n",
|
|
" var fmt_picker = $('<select/>');\n",
|
|
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
|
|
" fmt_picker_span.append(fmt_picker);\n",
|
|
" nav_element.append(fmt_picker_span);\n",
|
|
" this.format_dropdown = fmt_picker[0];\n",
|
|
"\n",
|
|
" for (var ind in mpl.extensions) {\n",
|
|
" var fmt = mpl.extensions[ind];\n",
|
|
" var option = $(\n",
|
|
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
|
|
" fmt_picker.append(option)\n",
|
|
" }\n",
|
|
"\n",
|
|
" // Add hover states to the ui-buttons\n",
|
|
" $( \".ui-button\" ).hover(\n",
|
|
" function() { $(this).addClass(\"ui-state-hover\");},\n",
|
|
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
|
|
" );\n",
|
|
"\n",
|
|
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
|
|
" nav_element.append(status_bar);\n",
|
|
" this.message = status_bar[0];\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
|
|
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
|
|
" // which will in turn request a refresh of the image.\n",
|
|
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.send_message = function(type, properties) {\n",
|
|
" properties['type'] = type;\n",
|
|
" properties['figure_id'] = this.id;\n",
|
|
" this.ws.send(JSON.stringify(properties));\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.send_draw_message = function() {\n",
|
|
" if (!this.waiting) {\n",
|
|
" this.waiting = true;\n",
|
|
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
|
|
" }\n",
|
|
"}\n",
|
|
"\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
" var format_dropdown = fig.format_dropdown;\n",
|
|
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
|
|
" fig.ondownload(fig, format);\n",
|
|
"}\n",
|
|
"\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
|
|
" var size = msg['size'];\n",
|
|
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
|
|
" fig._resize_canvas(size[0], size[1]);\n",
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
" };\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
|
|
" var x0 = msg['x0'];\n",
|
|
" var y0 = fig.canvas.height - msg['y0'];\n",
|
|
" var x1 = msg['x1'];\n",
|
|
" var y1 = fig.canvas.height - msg['y1'];\n",
|
|
" x0 = Math.floor(x0) + 0.5;\n",
|
|
" y0 = Math.floor(y0) + 0.5;\n",
|
|
" x1 = Math.floor(x1) + 0.5;\n",
|
|
" y1 = Math.floor(y1) + 0.5;\n",
|
|
" var min_x = Math.min(x0, x1);\n",
|
|
" var min_y = Math.min(y0, y1);\n",
|
|
" var width = Math.abs(x1 - x0);\n",
|
|
" var height = Math.abs(y1 - y0);\n",
|
|
"\n",
|
|
" fig.rubberband_context.clearRect(\n",
|
|
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
"\n",
|
|
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
|
|
" // Updates the figure title.\n",
|
|
" fig.header.textContent = msg['label'];\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
|
|
" var cursor = msg['cursor'];\n",
|
|
" switch(cursor)\n",
|
|
" {\n",
|
|
" case 0:\n",
|
|
" cursor = 'pointer';\n",
|
|
" break;\n",
|
|
" case 1:\n",
|
|
" cursor = 'default';\n",
|
|
" break;\n",
|
|
" case 2:\n",
|
|
" cursor = 'crosshair';\n",
|
|
" break;\n",
|
|
" case 3:\n",
|
|
" cursor = 'move';\n",
|
|
" break;\n",
|
|
" }\n",
|
|
" fig.rubberband_canvas.style.cursor = cursor;\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
|
|
" fig.message.textContent = msg['message'];\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
|
|
" // Request the server to send over a new figure.\n",
|
|
" fig.send_draw_message();\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
|
|
" fig.image_mode = msg['mode'];\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
" // Called whenever the canvas gets updated.\n",
|
|
" this.send_message(\"ack\", {});\n",
|
|
"}\n",
|
|
"\n",
|
|
"// A function to construct a web socket function for onmessage handling.\n",
|
|
"// Called in the figure constructor.\n",
|
|
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
|
|
" return function socket_on_message(evt) {\n",
|
|
" if (evt.data instanceof Blob) {\n",
|
|
" /* FIXME: We get \"Resource interpreted as Image but\n",
|
|
" * transferred with MIME type text/plain:\" errors on\n",
|
|
" * Chrome. But how to set the MIME type? It doesn't seem\n",
|
|
" * to be part of the websocket stream */\n",
|
|
" evt.data.type = \"image/png\";\n",
|
|
"\n",
|
|
" /* Free the memory for the previous frames */\n",
|
|
" if (fig.imageObj.src) {\n",
|
|
" (window.URL || window.webkitURL).revokeObjectURL(\n",
|
|
" fig.imageObj.src);\n",
|
|
" }\n",
|
|
"\n",
|
|
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
|
|
" evt.data);\n",
|
|
" fig.updated_canvas_event();\n",
|
|
" fig.waiting = false;\n",
|
|
" return;\n",
|
|
" }\n",
|
|
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
|
|
" fig.imageObj.src = evt.data;\n",
|
|
" fig.updated_canvas_event();\n",
|
|
" fig.waiting = false;\n",
|
|
" return;\n",
|
|
" }\n",
|
|
"\n",
|
|
" var msg = JSON.parse(evt.data);\n",
|
|
" var msg_type = msg['type'];\n",
|
|
"\n",
|
|
" // Call the \"handle_{type}\" callback, which takes\n",
|
|
" // the figure and JSON message as its only arguments.\n",
|
|
" try {\n",
|
|
" var callback = fig[\"handle_\" + msg_type];\n",
|
|
" } catch (e) {\n",
|
|
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
|
|
" return;\n",
|
|
" }\n",
|
|
"\n",
|
|
" if (callback) {\n",
|
|
" try {\n",
|
|
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
|
|
" callback(fig, msg);\n",
|
|
" } catch (e) {\n",
|
|
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
|
|
" }\n",
|
|
" }\n",
|
|
" };\n",
|
|
"}\n",
|
|
"\n",
|
|
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
|
|
"mpl.findpos = function(e) {\n",
|
|
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
|
|
" var targ;\n",
|
|
" if (!e)\n",
|
|
" e = window.event;\n",
|
|
" if (e.target)\n",
|
|
" targ = e.target;\n",
|
|
" else if (e.srcElement)\n",
|
|
" targ = e.srcElement;\n",
|
|
" if (targ.nodeType == 3) // defeat Safari bug\n",
|
|
" targ = targ.parentNode;\n",
|
|
"\n",
|
|
" // jQuery normalizes the pageX and pageY\n",
|
|
" // pageX,Y are the mouse positions relative to the document\n",
|
|
" // offset() returns the position of the element relative to the document\n",
|
|
" var x = e.pageX - $(targ).offset().left;\n",
|
|
" var y = e.pageY - $(targ).offset().top;\n",
|
|
"\n",
|
|
" return {\"x\": x, \"y\": y};\n",
|
|
"};\n",
|
|
"\n",
|
|
"/*\n",
|
|
" * return a copy of an object with only non-object keys\n",
|
|
" * we need this to avoid circular references\n",
|
|
" * http://stackoverflow.com/a/24161582/3208463\n",
|
|
" */\n",
|
|
"function simpleKeys (original) {\n",
|
|
" return Object.keys(original).reduce(function (obj, key) {\n",
|
|
" if (typeof original[key] !== 'object')\n",
|
|
" obj[key] = original[key]\n",
|
|
" return obj;\n",
|
|
" }, {});\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
|
|
" var canvas_pos = mpl.findpos(event)\n",
|
|
"\n",
|
|
" if (name === 'button_press')\n",
|
|
" {\n",
|
|
" this.canvas.focus();\n",
|
|
" this.canvas_div.focus();\n",
|
|
" }\n",
|
|
"\n",
|
|
" var x = canvas_pos.x;\n",
|
|
" var y = canvas_pos.y;\n",
|
|
"\n",
|
|
" this.send_message(name, {x: x, y: y, button: event.button,\n",
|
|
" step: event.step,\n",
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
"\n",
|
|
" /* This prevents the web browser from automatically changing to\n",
|
|
" * the text insertion cursor when the button is pressed. We want\n",
|
|
" * to control all of the cursor setting manually through the\n",
|
|
" * 'cursor' event from matplotlib */\n",
|
|
" event.preventDefault();\n",
|
|
" return false;\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
" // Handle any extra behaviour associated with a key event\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.key_event = function(event, name) {\n",
|
|
"\n",
|
|
" // Prevent repeat events\n",
|
|
" if (name == 'key_press')\n",
|
|
" {\n",
|
|
" if (event.which === this._key)\n",
|
|
" return;\n",
|
|
" else\n",
|
|
" this._key = event.which;\n",
|
|
" }\n",
|
|
" if (name == 'key_release')\n",
|
|
" this._key = null;\n",
|
|
"\n",
|
|
" var value = '';\n",
|
|
" if (event.ctrlKey && event.which != 17)\n",
|
|
" value += \"ctrl+\";\n",
|
|
" if (event.altKey && event.which != 18)\n",
|
|
" value += \"alt+\";\n",
|
|
" if (event.shiftKey && event.which != 16)\n",
|
|
" value += \"shift+\";\n",
|
|
"\n",
|
|
" value += 'k';\n",
|
|
" value += event.which.toString();\n",
|
|
"\n",
|
|
" this._key_event_extra(event, name);\n",
|
|
"\n",
|
|
" this.send_message(name, {key: value,\n",
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
" return false;\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
|
|
" if (name == 'download') {\n",
|
|
" this.handle_save(this, null);\n",
|
|
" } else {\n",
|
|
" this.send_message(\"toolbar_button\", {name: name});\n",
|
|
" }\n",
|
|
"};\n",
|
|
"\n",
|
|
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
|
|
" this.message.textContent = tooltip;\n",
|
|
"};\n",
|
|
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
|
|
"\n",
|
|
"mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
|
|
"\n",
|
|
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
|
|
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
|
|
" // object with the appropriate methods. Currently this is a non binary\n",
|
|
" // socket, so there is still some room for performance tuning.\n",
|
|
" var ws = {};\n",
|
|
"\n",
|
|
" ws.close = function() {\n",
|
|
" comm.close()\n",
|
|
" };\n",
|
|
" ws.send = function(m) {\n",
|
|
" //console.log('sending', m);\n",
|
|
" comm.send(m);\n",
|
|
" };\n",
|
|
" // Register the callback with on_msg.\n",
|
|
" comm.on_msg(function(msg) {\n",
|
|
" //console.log('receiving', msg['content']['data'], msg);\n",
|
|
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
|
|
" ws.onmessage(msg['content']['data'])\n",
|
|
" });\n",
|
|
" return ws;\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.mpl_figure_comm = function(comm, msg) {\n",
|
|
" // This is the function which gets called when the mpl process\n",
|
|
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
|
|
"\n",
|
|
" var id = msg.content.data.id;\n",
|
|
" // Get hold of the div created by the display call when the Comm\n",
|
|
" // socket was opened in Python.\n",
|
|
" var element = $(\"#\" + id);\n",
|
|
" var ws_proxy = comm_websocket_adapter(comm)\n",
|
|
"\n",
|
|
" function ondownload(figure, format) {\n",
|
|
" window.open(figure.imageObj.src);\n",
|
|
" }\n",
|
|
"\n",
|
|
" var fig = new mpl.figure(id, ws_proxy,\n",
|
|
" ondownload,\n",
|
|
" element.get(0));\n",
|
|
"\n",
|
|
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
|
|
" // web socket which is closed, not our websocket->open comm proxy.\n",
|
|
" ws_proxy.onopen();\n",
|
|
"\n",
|
|
" fig.parent_element = element.get(0);\n",
|
|
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
|
|
" if (!fig.cell_info) {\n",
|
|
" console.error(\"Failed to find cell for figure\", id, fig);\n",
|
|
" return;\n",
|
|
" }\n",
|
|
"\n",
|
|
" var output_index = fig.cell_info[2]\n",
|
|
" var cell = fig.cell_info[0];\n",
|
|
"\n",
|
|
"};\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
|
|
" fig.root.unbind('remove')\n",
|
|
"\n",
|
|
" // Update the output cell to use the data from the current canvas.\n",
|
|
" fig.push_to_output();\n",
|
|
" var dataURL = fig.canvas.toDataURL();\n",
|
|
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
|
|
" // the notebook keyboard shortcuts fail.\n",
|
|
" IPython.keyboard_manager.enable()\n",
|
|
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
|
|
" fig.close_ws(fig, msg);\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
|
|
" fig.send_message('closing', msg);\n",
|
|
" // fig.ws.close()\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
|
|
" // Turn the data on the canvas into data in the output cell.\n",
|
|
" var dataURL = this.canvas.toDataURL();\n",
|
|
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
" // Tell IPython that the notebook contents must change.\n",
|
|
" IPython.notebook.set_dirty(true);\n",
|
|
" this.send_message(\"ack\", {});\n",
|
|
" var fig = this;\n",
|
|
" // Wait a second, then push the new image to the DOM so\n",
|
|
" // that it is saved nicely (might be nice to debounce this).\n",
|
|
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
" var fig = this;\n",
|
|
"\n",
|
|
" var nav_element = $('<div/>')\n",
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
" this.root.append(nav_element);\n",
|
|
"\n",
|
|
" // Define a callback function for later on.\n",
|
|
" function toolbar_event(event) {\n",
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
" }\n",
|
|
" function toolbar_mouse_event(event) {\n",
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
" }\n",
|
|
"\n",
|
|
" for(var toolbar_ind in mpl.toolbar_items){\n",
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
"\n",
|
|
" if (!name) { continue; };\n",
|
|
"\n",
|
|
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
|
|
" button.click(method_name, toolbar_event);\n",
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
" nav_element.append(button);\n",
|
|
" }\n",
|
|
"\n",
|
|
" // Add the status bar.\n",
|
|
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
|
|
" nav_element.append(status_bar);\n",
|
|
" this.message = status_bar[0];\n",
|
|
"\n",
|
|
" // Add the close button to the window.\n",
|
|
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
|
|
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
|
|
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
|
|
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
|
|
" buttongrp.append(button);\n",
|
|
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
|
|
" titlebar.prepend(buttongrp);\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype._root_extra_style = function(el){\n",
|
|
" var fig = this\n",
|
|
" el.on(\"remove\", function(){\n",
|
|
"\tfig.close_ws(fig, {});\n",
|
|
" });\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
|
|
" // this is important to make the div 'focusable\n",
|
|
" el.attr('tabindex', 0)\n",
|
|
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
|
|
" // off when our div gets focus\n",
|
|
"\n",
|
|
" // location in version 3\n",
|
|
" if (IPython.notebook.keyboard_manager) {\n",
|
|
" IPython.notebook.keyboard_manager.register_events(el);\n",
|
|
" }\n",
|
|
" else {\n",
|
|
" // location in version 2\n",
|
|
" IPython.keyboard_manager.register_events(el);\n",
|
|
" }\n",
|
|
"\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
" var manager = IPython.notebook.keyboard_manager;\n",
|
|
" if (!manager)\n",
|
|
" manager = IPython.keyboard_manager;\n",
|
|
"\n",
|
|
" // Check for shift+enter\n",
|
|
" if (event.shiftKey && event.which == 13) {\n",
|
|
" this.canvas_div.blur();\n",
|
|
" event.shiftKey = false;\n",
|
|
" // Send a \"J\" for go to next cell\n",
|
|
" event.which = 74;\n",
|
|
" event.keyCode = 74;\n",
|
|
" manager.command_mode();\n",
|
|
" manager.handle_keydown(event);\n",
|
|
" }\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
" fig.ondownload(fig, null);\n",
|
|
"}\n",
|
|
"\n",
|
|
"\n",
|
|
"mpl.find_output_cell = function(html_output) {\n",
|
|
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
|
|
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
|
|
" // IPython event is triggered only after the cells have been serialised, which for\n",
|
|
" // our purposes (turning an active figure into a static one), is too late.\n",
|
|
" var cells = IPython.notebook.get_cells();\n",
|
|
" var ncells = cells.length;\n",
|
|
" for (var i=0; i<ncells; i++) {\n",
|
|
" var cell = cells[i];\n",
|
|
" if (cell.cell_type === 'code'){\n",
|
|
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
|
|
" var data = cell.output_area.outputs[j];\n",
|
|
" if (data.data) {\n",
|
|
" // IPython >= 3 moved mimebundle to data attribute of output\n",
|
|
" data = data.data;\n",
|
|
" }\n",
|
|
" if (data['text/html'] == html_output) {\n",
|
|
" return [cell, data, j];\n",
|
|
" }\n",
|
|
" }\n",
|
|
" }\n",
|
|
" }\n",
|
|
"}\n",
|
|
"\n",
|
|
"// Register the function which deals with the matplotlib target/channel.\n",
|
|
"// The kernel may be null if the page has been refreshed.\n",
|
|
"if (IPython.notebook.kernel != null) {\n",
|
|
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
|
|
"}\n"
|
|
],
|
|
"text/plain": [
|
|
"<IPython.core.display.Javascript object>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
},
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<img src=\"data:image/png;base64,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\">"
|
|
],
|
|
"text/plain": [
|
|
"<IPython.core.display.HTML object>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"plt.figure()\n",
|
|
"\n",
|
|
"plt.plot(oppFlame.grid*100, oppFlame.T, 'b-s', lw=2)\n",
|
|
"plt.xlim(oppFlame.grid[0], oppFlame.grid[-1]*100)\n",
|
|
"plt.xlabel('Distance (cm)')\n",
|
|
"plt.ylabel('Temperature (K)');"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### Major Species' Plot"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 10,
|
|
"metadata": {
|
|
"collapsed": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"application/javascript": [
|
|
"/* Put everything inside the global mpl namespace */\n",
|
|
"window.mpl = {};\n",
|
|
"\n",
|
|
"mpl.get_websocket_type = function() {\n",
|
|
" if (typeof(WebSocket) !== 'undefined') {\n",
|
|
" return WebSocket;\n",
|
|
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
|
|
" return MozWebSocket;\n",
|
|
" } else {\n",
|
|
" alert('Your browser does not have WebSocket support.' +\n",
|
|
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
|
|
" 'Firefox 4 and 5 are also supported but you ' +\n",
|
|
" 'have to enable WebSockets in about:config.');\n",
|
|
" };\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
|
|
" this.id = figure_id;\n",
|
|
"\n",
|
|
" this.ws = websocket;\n",
|
|
"\n",
|
|
" this.supports_binary = (this.ws.binaryType != undefined);\n",
|
|
"\n",
|
|
" if (!this.supports_binary) {\n",
|
|
" var warnings = document.getElementById(\"mpl-warnings\");\n",
|
|
" if (warnings) {\n",
|
|
" warnings.style.display = 'block';\n",
|
|
" warnings.textContent = (\n",
|
|
" \"This browser does not support binary websocket messages. \" +\n",
|
|
" \"Performance may be slow.\");\n",
|
|
" }\n",
|
|
" }\n",
|
|
"\n",
|
|
" this.imageObj = new Image();\n",
|
|
"\n",
|
|
" this.context = undefined;\n",
|
|
" this.message = undefined;\n",
|
|
" this.canvas = undefined;\n",
|
|
" this.rubberband_canvas = undefined;\n",
|
|
" this.rubberband_context = undefined;\n",
|
|
" this.format_dropdown = undefined;\n",
|
|
"\n",
|
|
" this.image_mode = 'full';\n",
|
|
"\n",
|
|
" this.root = $('<div/>');\n",
|
|
" this._root_extra_style(this.root)\n",
|
|
" this.root.attr('style', 'display: inline-block');\n",
|
|
"\n",
|
|
" $(parent_element).append(this.root);\n",
|
|
"\n",
|
|
" this._init_header(this);\n",
|
|
" this._init_canvas(this);\n",
|
|
" this._init_toolbar(this);\n",
|
|
"\n",
|
|
" var fig = this;\n",
|
|
"\n",
|
|
" this.waiting = false;\n",
|
|
"\n",
|
|
" this.ws.onopen = function () {\n",
|
|
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
|
|
" fig.send_message(\"send_image_mode\", {});\n",
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
" }\n",
|
|
"\n",
|
|
" this.imageObj.onload = function() {\n",
|
|
" if (fig.image_mode == 'full') {\n",
|
|
" // Full images could contain transparency (where diff images\n",
|
|
" // almost always do), so we need to clear the canvas so that\n",
|
|
" // there is no ghosting.\n",
|
|
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
" }\n",
|
|
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
|
|
" };\n",
|
|
"\n",
|
|
" this.imageObj.onunload = function() {\n",
|
|
" this.ws.close();\n",
|
|
" }\n",
|
|
"\n",
|
|
" this.ws.onmessage = this._make_on_message_function(this);\n",
|
|
"\n",
|
|
" this.ondownload = ondownload;\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype._init_header = function() {\n",
|
|
" var titlebar = $(\n",
|
|
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
|
|
" 'ui-helper-clearfix\"/>');\n",
|
|
" var titletext = $(\n",
|
|
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
|
|
" 'text-align: center; padding: 3px;\"/>');\n",
|
|
" titlebar.append(titletext)\n",
|
|
" this.root.append(titlebar);\n",
|
|
" this.header = titletext[0];\n",
|
|
"}\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
|
|
"\n",
|
|
"}\n",
|
|
"\n",
|
|
"\n",
|
|
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
|
|
"\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype._init_canvas = function() {\n",
|
|
" var fig = this;\n",
|
|
"\n",
|
|
" var canvas_div = $('<div/>');\n",
|
|
"\n",
|
|
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
|
|
"\n",
|
|
" function canvas_keyboard_event(event) {\n",
|
|
" return fig.key_event(event, event['data']);\n",
|
|
" }\n",
|
|
"\n",
|
|
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
|
|
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
|
|
" this.canvas_div = canvas_div\n",
|
|
" this._canvas_extra_style(canvas_div)\n",
|
|
" this.root.append(canvas_div);\n",
|
|
"\n",
|
|
" var canvas = $('<canvas/>');\n",
|
|
" canvas.addClass('mpl-canvas');\n",
|
|
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
|
|
"\n",
|
|
" this.canvas = canvas[0];\n",
|
|
" this.context = canvas[0].getContext(\"2d\");\n",
|
|
"\n",
|
|
" var rubberband = $('<canvas/>');\n",
|
|
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
|
|
"\n",
|
|
" var pass_mouse_events = true;\n",
|
|
"\n",
|
|
" canvas_div.resizable({\n",
|
|
" start: function(event, ui) {\n",
|
|
" pass_mouse_events = false;\n",
|
|
" },\n",
|
|
" resize: function(event, ui) {\n",
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
" },\n",
|
|
" stop: function(event, ui) {\n",
|
|
" pass_mouse_events = true;\n",
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
" },\n",
|
|
" });\n",
|
|
"\n",
|
|
" function mouse_event_fn(event) {\n",
|
|
" if (pass_mouse_events)\n",
|
|
" return fig.mouse_event(event, event['data']);\n",
|
|
" }\n",
|
|
"\n",
|
|
" rubberband.mousedown('button_press', mouse_event_fn);\n",
|
|
" rubberband.mouseup('button_release', mouse_event_fn);\n",
|
|
" // Throttle sequential mouse events to 1 every 20ms.\n",
|
|
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
|
|
"\n",
|
|
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
|
|
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
|
|
"\n",
|
|
" canvas_div.on(\"wheel\", function (event) {\n",
|
|
" event = event.originalEvent;\n",
|
|
" event['data'] = 'scroll'\n",
|
|
" if (event.deltaY < 0) {\n",
|
|
" event.step = 1;\n",
|
|
" } else {\n",
|
|
" event.step = -1;\n",
|
|
" }\n",
|
|
" mouse_event_fn(event);\n",
|
|
" });\n",
|
|
"\n",
|
|
" canvas_div.append(canvas);\n",
|
|
" canvas_div.append(rubberband);\n",
|
|
"\n",
|
|
" this.rubberband = rubberband;\n",
|
|
" this.rubberband_canvas = rubberband[0];\n",
|
|
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
|
|
" this.rubberband_context.strokeStyle = \"#000000\";\n",
|
|
"\n",
|
|
" this._resize_canvas = function(width, height) {\n",
|
|
" // Keep the size of the canvas, canvas container, and rubber band\n",
|
|
" // canvas in synch.\n",
|
|
" canvas_div.css('width', width)\n",
|
|
" canvas_div.css('height', height)\n",
|
|
"\n",
|
|
" canvas.attr('width', width);\n",
|
|
" canvas.attr('height', height);\n",
|
|
"\n",
|
|
" rubberband.attr('width', width);\n",
|
|
" rubberband.attr('height', height);\n",
|
|
" }\n",
|
|
"\n",
|
|
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
|
|
" // upon first draw.\n",
|
|
" this._resize_canvas(600, 600);\n",
|
|
"\n",
|
|
" // Disable right mouse context menu.\n",
|
|
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
|
|
" return false;\n",
|
|
" });\n",
|
|
"\n",
|
|
" function set_focus () {\n",
|
|
" canvas.focus();\n",
|
|
" canvas_div.focus();\n",
|
|
" }\n",
|
|
"\n",
|
|
" window.setTimeout(set_focus, 100);\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
" var fig = this;\n",
|
|
"\n",
|
|
" var nav_element = $('<div/>')\n",
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
" this.root.append(nav_element);\n",
|
|
"\n",
|
|
" // Define a callback function for later on.\n",
|
|
" function toolbar_event(event) {\n",
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
" }\n",
|
|
" function toolbar_mouse_event(event) {\n",
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
" }\n",
|
|
"\n",
|
|
" for(var toolbar_ind in mpl.toolbar_items) {\n",
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
"\n",
|
|
" if (!name) {\n",
|
|
" // put a spacer in here.\n",
|
|
" continue;\n",
|
|
" }\n",
|
|
" var button = $('<button/>');\n",
|
|
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
|
|
" 'ui-button-icon-only');\n",
|
|
" button.attr('role', 'button');\n",
|
|
" button.attr('aria-disabled', 'false');\n",
|
|
" button.click(method_name, toolbar_event);\n",
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
"\n",
|
|
" var icon_img = $('<span/>');\n",
|
|
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
|
|
" icon_img.addClass(image);\n",
|
|
" icon_img.addClass('ui-corner-all');\n",
|
|
"\n",
|
|
" var tooltip_span = $('<span/>');\n",
|
|
" tooltip_span.addClass('ui-button-text');\n",
|
|
" tooltip_span.html(tooltip);\n",
|
|
"\n",
|
|
" button.append(icon_img);\n",
|
|
" button.append(tooltip_span);\n",
|
|
"\n",
|
|
" nav_element.append(button);\n",
|
|
" }\n",
|
|
"\n",
|
|
" var fmt_picker_span = $('<span/>');\n",
|
|
"\n",
|
|
" var fmt_picker = $('<select/>');\n",
|
|
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
|
|
" fmt_picker_span.append(fmt_picker);\n",
|
|
" nav_element.append(fmt_picker_span);\n",
|
|
" this.format_dropdown = fmt_picker[0];\n",
|
|
"\n",
|
|
" for (var ind in mpl.extensions) {\n",
|
|
" var fmt = mpl.extensions[ind];\n",
|
|
" var option = $(\n",
|
|
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
|
|
" fmt_picker.append(option)\n",
|
|
" }\n",
|
|
"\n",
|
|
" // Add hover states to the ui-buttons\n",
|
|
" $( \".ui-button\" ).hover(\n",
|
|
" function() { $(this).addClass(\"ui-state-hover\");},\n",
|
|
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
|
|
" );\n",
|
|
"\n",
|
|
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
|
|
" nav_element.append(status_bar);\n",
|
|
" this.message = status_bar[0];\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
|
|
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
|
|
" // which will in turn request a refresh of the image.\n",
|
|
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.send_message = function(type, properties) {\n",
|
|
" properties['type'] = type;\n",
|
|
" properties['figure_id'] = this.id;\n",
|
|
" this.ws.send(JSON.stringify(properties));\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.send_draw_message = function() {\n",
|
|
" if (!this.waiting) {\n",
|
|
" this.waiting = true;\n",
|
|
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
|
|
" }\n",
|
|
"}\n",
|
|
"\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
" var format_dropdown = fig.format_dropdown;\n",
|
|
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
|
|
" fig.ondownload(fig, format);\n",
|
|
"}\n",
|
|
"\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
|
|
" var size = msg['size'];\n",
|
|
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
|
|
" fig._resize_canvas(size[0], size[1]);\n",
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
" };\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
|
|
" var x0 = msg['x0'];\n",
|
|
" var y0 = fig.canvas.height - msg['y0'];\n",
|
|
" var x1 = msg['x1'];\n",
|
|
" var y1 = fig.canvas.height - msg['y1'];\n",
|
|
" x0 = Math.floor(x0) + 0.5;\n",
|
|
" y0 = Math.floor(y0) + 0.5;\n",
|
|
" x1 = Math.floor(x1) + 0.5;\n",
|
|
" y1 = Math.floor(y1) + 0.5;\n",
|
|
" var min_x = Math.min(x0, x1);\n",
|
|
" var min_y = Math.min(y0, y1);\n",
|
|
" var width = Math.abs(x1 - x0);\n",
|
|
" var height = Math.abs(y1 - y0);\n",
|
|
"\n",
|
|
" fig.rubberband_context.clearRect(\n",
|
|
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
"\n",
|
|
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
|
|
" // Updates the figure title.\n",
|
|
" fig.header.textContent = msg['label'];\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
|
|
" var cursor = msg['cursor'];\n",
|
|
" switch(cursor)\n",
|
|
" {\n",
|
|
" case 0:\n",
|
|
" cursor = 'pointer';\n",
|
|
" break;\n",
|
|
" case 1:\n",
|
|
" cursor = 'default';\n",
|
|
" break;\n",
|
|
" case 2:\n",
|
|
" cursor = 'crosshair';\n",
|
|
" break;\n",
|
|
" case 3:\n",
|
|
" cursor = 'move';\n",
|
|
" break;\n",
|
|
" }\n",
|
|
" fig.rubberband_canvas.style.cursor = cursor;\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
|
|
" fig.message.textContent = msg['message'];\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
|
|
" // Request the server to send over a new figure.\n",
|
|
" fig.send_draw_message();\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
|
|
" fig.image_mode = msg['mode'];\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
" // Called whenever the canvas gets updated.\n",
|
|
" this.send_message(\"ack\", {});\n",
|
|
"}\n",
|
|
"\n",
|
|
"// A function to construct a web socket function for onmessage handling.\n",
|
|
"// Called in the figure constructor.\n",
|
|
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
|
|
" return function socket_on_message(evt) {\n",
|
|
" if (evt.data instanceof Blob) {\n",
|
|
" /* FIXME: We get \"Resource interpreted as Image but\n",
|
|
" * transferred with MIME type text/plain:\" errors on\n",
|
|
" * Chrome. But how to set the MIME type? It doesn't seem\n",
|
|
" * to be part of the websocket stream */\n",
|
|
" evt.data.type = \"image/png\";\n",
|
|
"\n",
|
|
" /* Free the memory for the previous frames */\n",
|
|
" if (fig.imageObj.src) {\n",
|
|
" (window.URL || window.webkitURL).revokeObjectURL(\n",
|
|
" fig.imageObj.src);\n",
|
|
" }\n",
|
|
"\n",
|
|
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
|
|
" evt.data);\n",
|
|
" fig.updated_canvas_event();\n",
|
|
" fig.waiting = false;\n",
|
|
" return;\n",
|
|
" }\n",
|
|
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
|
|
" fig.imageObj.src = evt.data;\n",
|
|
" fig.updated_canvas_event();\n",
|
|
" fig.waiting = false;\n",
|
|
" return;\n",
|
|
" }\n",
|
|
"\n",
|
|
" var msg = JSON.parse(evt.data);\n",
|
|
" var msg_type = msg['type'];\n",
|
|
"\n",
|
|
" // Call the \"handle_{type}\" callback, which takes\n",
|
|
" // the figure and JSON message as its only arguments.\n",
|
|
" try {\n",
|
|
" var callback = fig[\"handle_\" + msg_type];\n",
|
|
" } catch (e) {\n",
|
|
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
|
|
" return;\n",
|
|
" }\n",
|
|
"\n",
|
|
" if (callback) {\n",
|
|
" try {\n",
|
|
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
|
|
" callback(fig, msg);\n",
|
|
" } catch (e) {\n",
|
|
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
|
|
" }\n",
|
|
" }\n",
|
|
" };\n",
|
|
"}\n",
|
|
"\n",
|
|
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
|
|
"mpl.findpos = function(e) {\n",
|
|
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
|
|
" var targ;\n",
|
|
" if (!e)\n",
|
|
" e = window.event;\n",
|
|
" if (e.target)\n",
|
|
" targ = e.target;\n",
|
|
" else if (e.srcElement)\n",
|
|
" targ = e.srcElement;\n",
|
|
" if (targ.nodeType == 3) // defeat Safari bug\n",
|
|
" targ = targ.parentNode;\n",
|
|
"\n",
|
|
" // jQuery normalizes the pageX and pageY\n",
|
|
" // pageX,Y are the mouse positions relative to the document\n",
|
|
" // offset() returns the position of the element relative to the document\n",
|
|
" var x = e.pageX - $(targ).offset().left;\n",
|
|
" var y = e.pageY - $(targ).offset().top;\n",
|
|
"\n",
|
|
" return {\"x\": x, \"y\": y};\n",
|
|
"};\n",
|
|
"\n",
|
|
"/*\n",
|
|
" * return a copy of an object with only non-object keys\n",
|
|
" * we need this to avoid circular references\n",
|
|
" * http://stackoverflow.com/a/24161582/3208463\n",
|
|
" */\n",
|
|
"function simpleKeys (original) {\n",
|
|
" return Object.keys(original).reduce(function (obj, key) {\n",
|
|
" if (typeof original[key] !== 'object')\n",
|
|
" obj[key] = original[key]\n",
|
|
" return obj;\n",
|
|
" }, {});\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
|
|
" var canvas_pos = mpl.findpos(event)\n",
|
|
"\n",
|
|
" if (name === 'button_press')\n",
|
|
" {\n",
|
|
" this.canvas.focus();\n",
|
|
" this.canvas_div.focus();\n",
|
|
" }\n",
|
|
"\n",
|
|
" var x = canvas_pos.x;\n",
|
|
" var y = canvas_pos.y;\n",
|
|
"\n",
|
|
" this.send_message(name, {x: x, y: y, button: event.button,\n",
|
|
" step: event.step,\n",
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
"\n",
|
|
" /* This prevents the web browser from automatically changing to\n",
|
|
" * the text insertion cursor when the button is pressed. We want\n",
|
|
" * to control all of the cursor setting manually through the\n",
|
|
" * 'cursor' event from matplotlib */\n",
|
|
" event.preventDefault();\n",
|
|
" return false;\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
" // Handle any extra behaviour associated with a key event\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.key_event = function(event, name) {\n",
|
|
"\n",
|
|
" // Prevent repeat events\n",
|
|
" if (name == 'key_press')\n",
|
|
" {\n",
|
|
" if (event.which === this._key)\n",
|
|
" return;\n",
|
|
" else\n",
|
|
" this._key = event.which;\n",
|
|
" }\n",
|
|
" if (name == 'key_release')\n",
|
|
" this._key = null;\n",
|
|
"\n",
|
|
" var value = '';\n",
|
|
" if (event.ctrlKey && event.which != 17)\n",
|
|
" value += \"ctrl+\";\n",
|
|
" if (event.altKey && event.which != 18)\n",
|
|
" value += \"alt+\";\n",
|
|
" if (event.shiftKey && event.which != 16)\n",
|
|
" value += \"shift+\";\n",
|
|
"\n",
|
|
" value += 'k';\n",
|
|
" value += event.which.toString();\n",
|
|
"\n",
|
|
" this._key_event_extra(event, name);\n",
|
|
"\n",
|
|
" this.send_message(name, {key: value,\n",
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
" return false;\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
|
|
" if (name == 'download') {\n",
|
|
" this.handle_save(this, null);\n",
|
|
" } else {\n",
|
|
" this.send_message(\"toolbar_button\", {name: name});\n",
|
|
" }\n",
|
|
"};\n",
|
|
"\n",
|
|
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
|
|
" this.message.textContent = tooltip;\n",
|
|
"};\n",
|
|
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
|
|
"\n",
|
|
"mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
|
|
"\n",
|
|
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
|
|
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
|
|
" // object with the appropriate methods. Currently this is a non binary\n",
|
|
" // socket, so there is still some room for performance tuning.\n",
|
|
" var ws = {};\n",
|
|
"\n",
|
|
" ws.close = function() {\n",
|
|
" comm.close()\n",
|
|
" };\n",
|
|
" ws.send = function(m) {\n",
|
|
" //console.log('sending', m);\n",
|
|
" comm.send(m);\n",
|
|
" };\n",
|
|
" // Register the callback with on_msg.\n",
|
|
" comm.on_msg(function(msg) {\n",
|
|
" //console.log('receiving', msg['content']['data'], msg);\n",
|
|
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
|
|
" ws.onmessage(msg['content']['data'])\n",
|
|
" });\n",
|
|
" return ws;\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.mpl_figure_comm = function(comm, msg) {\n",
|
|
" // This is the function which gets called when the mpl process\n",
|
|
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
|
|
"\n",
|
|
" var id = msg.content.data.id;\n",
|
|
" // Get hold of the div created by the display call when the Comm\n",
|
|
" // socket was opened in Python.\n",
|
|
" var element = $(\"#\" + id);\n",
|
|
" var ws_proxy = comm_websocket_adapter(comm)\n",
|
|
"\n",
|
|
" function ondownload(figure, format) {\n",
|
|
" window.open(figure.imageObj.src);\n",
|
|
" }\n",
|
|
"\n",
|
|
" var fig = new mpl.figure(id, ws_proxy,\n",
|
|
" ondownload,\n",
|
|
" element.get(0));\n",
|
|
"\n",
|
|
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
|
|
" // web socket which is closed, not our websocket->open comm proxy.\n",
|
|
" ws_proxy.onopen();\n",
|
|
"\n",
|
|
" fig.parent_element = element.get(0);\n",
|
|
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
|
|
" if (!fig.cell_info) {\n",
|
|
" console.error(\"Failed to find cell for figure\", id, fig);\n",
|
|
" return;\n",
|
|
" }\n",
|
|
"\n",
|
|
" var output_index = fig.cell_info[2]\n",
|
|
" var cell = fig.cell_info[0];\n",
|
|
"\n",
|
|
"};\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
|
|
" fig.root.unbind('remove')\n",
|
|
"\n",
|
|
" // Update the output cell to use the data from the current canvas.\n",
|
|
" fig.push_to_output();\n",
|
|
" var dataURL = fig.canvas.toDataURL();\n",
|
|
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
|
|
" // the notebook keyboard shortcuts fail.\n",
|
|
" IPython.keyboard_manager.enable()\n",
|
|
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
|
|
" fig.close_ws(fig, msg);\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
|
|
" fig.send_message('closing', msg);\n",
|
|
" // fig.ws.close()\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
|
|
" // Turn the data on the canvas into data in the output cell.\n",
|
|
" var dataURL = this.canvas.toDataURL();\n",
|
|
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
" // Tell IPython that the notebook contents must change.\n",
|
|
" IPython.notebook.set_dirty(true);\n",
|
|
" this.send_message(\"ack\", {});\n",
|
|
" var fig = this;\n",
|
|
" // Wait a second, then push the new image to the DOM so\n",
|
|
" // that it is saved nicely (might be nice to debounce this).\n",
|
|
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
" var fig = this;\n",
|
|
"\n",
|
|
" var nav_element = $('<div/>')\n",
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
" this.root.append(nav_element);\n",
|
|
"\n",
|
|
" // Define a callback function for later on.\n",
|
|
" function toolbar_event(event) {\n",
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
" }\n",
|
|
" function toolbar_mouse_event(event) {\n",
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
" }\n",
|
|
"\n",
|
|
" for(var toolbar_ind in mpl.toolbar_items){\n",
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
"\n",
|
|
" if (!name) { continue; };\n",
|
|
"\n",
|
|
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
|
|
" button.click(method_name, toolbar_event);\n",
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
" nav_element.append(button);\n",
|
|
" }\n",
|
|
"\n",
|
|
" // Add the status bar.\n",
|
|
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
|
|
" nav_element.append(status_bar);\n",
|
|
" this.message = status_bar[0];\n",
|
|
"\n",
|
|
" // Add the close button to the window.\n",
|
|
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
|
|
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
|
|
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
|
|
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
|
|
" buttongrp.append(button);\n",
|
|
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
|
|
" titlebar.prepend(buttongrp);\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype._root_extra_style = function(el){\n",
|
|
" var fig = this\n",
|
|
" el.on(\"remove\", function(){\n",
|
|
"\tfig.close_ws(fig, {});\n",
|
|
" });\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
|
|
" // this is important to make the div 'focusable\n",
|
|
" el.attr('tabindex', 0)\n",
|
|
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
|
|
" // off when our div gets focus\n",
|
|
"\n",
|
|
" // location in version 3\n",
|
|
" if (IPython.notebook.keyboard_manager) {\n",
|
|
" IPython.notebook.keyboard_manager.register_events(el);\n",
|
|
" }\n",
|
|
" else {\n",
|
|
" // location in version 2\n",
|
|
" IPython.keyboard_manager.register_events(el);\n",
|
|
" }\n",
|
|
"\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
" var manager = IPython.notebook.keyboard_manager;\n",
|
|
" if (!manager)\n",
|
|
" manager = IPython.keyboard_manager;\n",
|
|
"\n",
|
|
" // Check for shift+enter\n",
|
|
" if (event.shiftKey && event.which == 13) {\n",
|
|
" this.canvas_div.blur();\n",
|
|
" event.shiftKey = false;\n",
|
|
" // Send a \"J\" for go to next cell\n",
|
|
" event.which = 74;\n",
|
|
" event.keyCode = 74;\n",
|
|
" manager.command_mode();\n",
|
|
" manager.handle_keydown(event);\n",
|
|
" }\n",
|
|
"}\n",
|
|
"\n",
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
" fig.ondownload(fig, null);\n",
|
|
"}\n",
|
|
"\n",
|
|
"\n",
|
|
"mpl.find_output_cell = function(html_output) {\n",
|
|
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
|
|
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
|
|
" // IPython event is triggered only after the cells have been serialised, which for\n",
|
|
" // our purposes (turning an active figure into a static one), is too late.\n",
|
|
" var cells = IPython.notebook.get_cells();\n",
|
|
" var ncells = cells.length;\n",
|
|
" for (var i=0; i<ncells; i++) {\n",
|
|
" var cell = cells[i];\n",
|
|
" if (cell.cell_type === 'code'){\n",
|
|
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
|
|
" var data = cell.output_area.outputs[j];\n",
|
|
" if (data.data) {\n",
|
|
" // IPython >= 3 moved mimebundle to data attribute of output\n",
|
|
" data = data.data;\n",
|
|
" }\n",
|
|
" if (data['text/html'] == html_output) {\n",
|
|
" return [cell, data, j];\n",
|
|
" }\n",
|
|
" }\n",
|
|
" }\n",
|
|
" }\n",
|
|
"}\n",
|
|
"\n",
|
|
"// Register the function which deals with the matplotlib target/channel.\n",
|
|
"// The kernel may be null if the page has been refreshed.\n",
|
|
"if (IPython.notebook.kernel != null) {\n",
|
|
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
|
|
"}\n"
|
|
],
|
|
"text/plain": [
|
|
"<IPython.core.display.Javascript object>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
},
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAAXNSR0IArs4c6QAAQABJREFUeAHsnQdgVFX2xk8qIYFQg4BUQ0ekW1jFdcVFRcG+rij2gvrX3RVdZNVF10UUsewKKKCrtBVQERUURBFBhUXpvVfpaZDe/t95M294mcyEZDIzmTf5Tvzy3ruv3fu7g3Nyy7kiNBIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARsReB55PQidhL6DOkPe7B84sQrKhb73ctHZSJ8GHYcyoPXQuRCNBEiABEiABEiABEggBAg8iTzshTpBNaBR0AEoHvJkdyJxAPRvyJMDWA/pu6FXoLqQWjLU0NjjLxIgARIgARIgARIggSonsAs5eNSSiyjsH4EGW9I87f4diZ4cQG0h/J+nG5hGAiRAAiRAAiRAAuFAINLmhUhE/ltBKy3lKMT+Gqi7Ja0iu/1wsTqVn0AnoM3QM5DdWaEINBIgARIgARIgARIQibY5BHUA1dIcG9fvVOyZ51yJ5dzRrt7e0B3QzZCOJ/wC0jGDYyAaCZAACZAACZAACdiagN0dQJ2goWaO1XMcieg4Ph0H6IvpM7VF8b/Om9dhOx66AXJ3ACOQ1hTSySc0EiABEiABEiABEvAHgdp4yK9QsT8e5ukZ4eAA7kHBtMVuhbOAOgZQu3+nOI8rulmFG7TVrzymzp+vjmZ5ns9rSIAESIAESIAEqieBZii2RjgJiNndAVQo2jo3DFoM6di95yDtrp0DeTItsyoG0hY8nTmspveoTYB+hG6BPoI6Qg9Bb0DuZrT87d+/XxITfe1xdn8kjwNFYMSIETJqlE4Sp4U6AdZVqNfQ6fyxrk6zCPU91lWo15AjfxkZGdK8eXM9CGjvYjg4gK8CUi1oEaRNpj9DV0JZkBLc5Dz+AVu1SdCdkNmsmu3c15ZDNW0BvBF6CXoXOgyNgzw5gEjGYEM4f3QADRQh/Ss2Npb1FNI1dDpzrKvTLEJ9j3UV6jV0On+sq9MsuGf/SSBmHY7Ejsrd9iNBnUKr3Y0DVVk2DydVNBIgARIgARIgARIIOwLh0AIYkpWSk5MjeXl5IZm3YGRK/9KMi4sLxqvK/Y7+/fuX+1peWLUEWFdVy78ib2ddVYRW1V7Luqpa/qH2dh0DR/OdgA78S4eV6FpU569169Zy+LD2HldPa9y4sezevTvknMDqWRssNQmQAAmQgF0I6BjAOnXqaHb1lxntxO/ZZwug35GK0fKnzl91nRxiDmDVFtBQawUMQHXzkSRAAiRAAiRgOwJ0AANYZZwcEkC4fDQJkAAJkAAJkIDPBLi8mc/oeCMJkAAJkAAJkAAJ2JMAHUB71htzTQIkQAIkQAIkQAI+E6AD6DM63kgCJEACJEACJEAC9iRAB9Ce9cZckwAJkAAJkAAJkIDPBOgA+oyON5IACZAACZAACZCAPQlwFnAV1JuGRzlx4oQ0aNBANGByRawy95rvKSoqksmTJ7vykJ+fb8Qt1HiGtWvXlkcffVQGDRok9913n0RGRsrTTz8taWlpMmzYMBk4cKD5GG5JgARIgARIgARsSoAOYBArTh2vYaNGybzNmyWjfn1JTEmRAR07yqsjRhiOVllZqcy91ueqs3frrbfK0KFD5YEHHnCdOv/882XatGnStm1bI33MmDEu5zQhIUFuv/12On8uWtwhARIgARIgAXsToAMYxPpT528CWthy7r/feKuuE7J37Vo5+cIL8vfhw8vMyfOjR8vUevUk13LvPtwreOZrzzxT5r3Wk0899ZR0795d+vXrZ02Wa665Rtq1ayfr16+XTp06uZy/4uJiWbx4sYwdO7bE9TwgARIgARIgARKwLwE6gEGqO+261ZY/0/kzX5vbtatMfvNNmbx0qUhMjJlccotWO1m3TuSxx0qk5+DeeRMnymg8uzxdyceOHTNa+XSJNnfT7l21pchHPTiaU6ZMEXX+Dhw4INoC2LRp0xK3qCP5yiuvlEjjAQmQAAmQAAmQgD0I0AEMUj3pmD/t9vVojRqJnDwp4u081gWUpCSPt57EPSnoSta1d89kP/zwg/Tu3Vtq1apV6tL4+HgjTR3Ahx9+WC677DLj+O2335ZLLrmkxPWb4chu3769RBoPSIAESIAESIAE7EOADmCQ6konfOiYP+32dbdz4Px9jS5Zb6142nrY7+OPpXS7nUjt1FT4jV4cS7cX6YQOT9cuX75cWrRoYbTyqZM4adIk150rVqwo5QCqM6uthDQSIAESIAESIAF7EmAYmCDVmzp3OuEjTsftWUyPB2HM3TmJidIsLs6j9Nx1uMbTvfpMb46j5TXGrrbqacvdqVOnXKcOHjwo+/fvN5w/7RrW9YutLYTqHF588cWu6/VYJ4xo9zCNBEiABEiABEjAngTYAhjEetPZvjppQ8ftadettt6Zs4DPlI3K3Gs+W0O8TMS7h2PCSefOnY2xfXXr1pWbb75ZVq5cKW+99ZYxG3nJkiXSEY7l+++/Lzt27JDvv/9e2rdvbzxm3759cuTIEdHt6tWrjQkl5vO5JQESIAESIAESsAeBCHtkM2RzmYicIXxeutFyZuYyA2P26tSpoydKpJvntUtXx+1pd2x5W+/8ca/5jMpudQzgkCFDZPz48caYQvfnnan87tfzmARIgARIgARIwEHA/A7FUR0IkwACY2wBDAzXMp+qTl95Jm14ekhl7vX0PF/StHVQWwxpJEACJEACJEAC9iTAMYD2rDfmmgRIgARIgARIgAR8JkAH0Gd0vJEESIAESIAESIAE7EmADqA96425JgESIAESIAESIAGfCdAB9BkdbyQBEiABEiABEiABexKgA2jPemOuSYAESIAESIAESMBnAnQAfUbHG0mABEiABEiABEjAngToANqz3phrEiABEiABEiABEvCZAB1An9HxRhIgARIgARIgARKwJwE6gPasN+aaBEiABEiABEiABHwmQAfQZ3S8kQRIgARIgARIgATsSYBLwdmz3iqV66KiIpk8ebKcOHFCGjRoIPn5+dK6dWvR9QcHDRokEyZMMJaqi4+PlzVr1shDDz3k89J1lcoobyYBEiABEiABmxAoLi6WGbNnyLKVy2TCmAklcm09N/6V8a7rrPt6j14385OZJe4N1AEdwECR9fDcJ25/QtJ2ppU6Uze5roydNrZUujWhMvdan6PO3q233ipDhw6VBx54wHXq/PPPl3/961+GA/jWW29Ju3btjHPdu3eXIUOGyMKFC13XcocESIAESIAEqiMBqyNnOnlm2qv/eVW2JW2TTpmdZE/aHknNTjX0xedfyCeffiK/Nv1VErckytxL58rR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iIAIiIAIuAjQASzjG1YyvAsY67UyERABERABERABERCBXCIgBzCXZltjFQEREAEREAEREAEQkAOor4EIiIAIiIAIiIAI5BgBOYA5NuEargiIgAiIgAiIgAjIAdR3QAREQAREQAREQARyjIAcwBybcA1XBERABERABERABOQA6jsgAiIgAiIgAiIgAjlGQA5gjk24hisCIiACIiACIiACcgD1HRABERABERABERCBHCMgBzDHJlzDFQEREAEREAEREAE5gPoOiIAIiIAIiIAIiECOEZADmGMTruGKgAiIgAiIgAiIgBxAfQdEQAREQAREQAREIMcIyAHMsQnXcEVABERABERABERADqC+AyIgAiIgAiIgAiKQYwTkAObYhGu4IiACIiACIiACIiAHUN8BERABERABERABEcgxAnIAc2zCNVwREAEREAEREAERkAOo74AIiIAIiIAIiIAI5BgBOYA5NuEargiIgAiIgAiIgAjIAdR3QAREQAREQAREQARyjIAcwBybcA1XBERABERABERABOQA6jsgAiIgAiIgAiIgAjlGQA5gjk24hisCIiACIiACIiACcgD1HRABERABERABERCBHCMgBzDHJlzDFQEREAEREAEREAE5gPoOiIAIiIAIiIAIiECOEZADmGMTruGKgAiIgAiIgAiIgBxAfQdEQAREQAREQAREIMcIyAHMsQnXcEVABERABERABERADqC+AyIgAiIgAiIgAiKQYwTkAObYhGu4IiACIiACIiACIiAHUN8BERABERABERABEcgxAnIAc2zCNVwREAEREAEREAERCLsD+C1M4UKoDvoQOgXakd2EDKuhWmgONAZy7BAEZkNroSroXWgyJBMBERABERABERCBnYZAmB3ACZiFGdA1UF/oemgmdCCUzK5AwmToGGgANB96AeoF0fpD/wuNhcqhS6C7oBMhmQiIgAiIgAiIgAjsFATC7AD+EDPwHPQUtBX6M/Q8dAGUzJj2C6gSaoLoNBZCzsrhXxB+GNoA0eZA/4C+BslCTuCFF+jry8JAQHMVhlmK9lFzpbkKDwH11E0gzA7geAzkdfdgEH4DOsAT5xxylXA4xDyO0XF8B0pVhiuNbzkF9BleAvqPKjxzp7nSXIWHQHh6qvMqPHMVRE+z0QF8EANvg+ic8dMrrsjR6NBVRULb/tkci98Wsy3E/LTOluHK4OMQVwt5aVkmAiIgAiIgAiIgAjsFgR5ZOIoL0aefpuhXSyytBp/lnny74JjxicyJT1RmladATxzPgsjnRIhOaFKrqXGqTppFCVlAoLm52TRXWTARneiC5qoTkLIki+YqSyaiE93QXHUCUhZkCer/qbwsGGtXu/AACnJVjzuBHfszAhuh850Iz+dSHN8J3R2LL8And/xeCjmrfHQQn4V4HyDrdhxOBLezLyHG6zxul0kRIiACIiACIiACIpAmgcHIvzrNMp3Ono0rgJ3t/L3I+BJ0EkSHjZ+ToCOgZPZbJFwOsRydwRsgbgbhah9tV+hvEB8pcxbEy9CpbA0SOUF8pIxMBERABERABERABPwg0AeV0MeQJSFwKuIXQvUQ79U7GXLbBzi42h2B8BSIq35boDnQGMgxOoR0+ujQUby2S9HBlImACIiACIiACIiACIiACIiACIiACIiACIiACIiACIiACIiACIiACIiACOwUBFK9Ps47QG4i4YaSKmgTxLeVlEGyYAikM1dz0CXeA8rL/M4l/x8hLMssgdNR/TyoGuItFzt6HJXOKUD6gizduZqDfuqcCn6ybkWT70E8p7hp4BGI96enMp1XqehkLq0rczUH3dF5lbk5SVrzFUhZDu0LFUNTIe78dV4fh2AH4/2Cf4X4SJp+EDeVPAXJMk8g3bniZiA6jLJgCRyD5uhYfB/qjAOocyrY+XG3lu5c6Zxy0wsufAuaOgDixk4+HWMm9DaUynRepaKTubSuzJXOq8zNR8qauVv4IlcOPjrmc+hMV5wTHIpAG7SfE4HP/WNxO/przFVEwS4SSGeu2ARPqp91sS0V6z6BI1HFjhxAnVPd5+xHDZ2ZK7ajc8oP2t2vYxyq4LmV7OqTzqvuM/arhh3NFdvJyHm1o0svfg0wrPXwL6nhUGdfHzceeRsh7j52jMvyzRDTZJkjkO5cOT3h+6H57EjuIufSfCkkyx4COqeyZy462xOdU50llbl8k1A1r1zxknAi03mViMoXE7ejuXJ65ft5FebnADpQMvlJp4JWFf2I/7sZISctHhmLS3TCsXyi/O6yCnePgMO3s3PF1q6BFkEsMxZ6CBoOfQeSZQcBzqvOqeyYi870QudUZyhlNs/RqP566D9SNKPzKgWcAJM6M1fsjs6rACfFaYonCS/pTnAiYp8v4PMOTxwPT4T4TEKvcVXwBG+kjn0lkO5cJWr8q4jkai3v9ZRlnkBnLivqnMr8PHSmhc7MVaJ6dE4lopK5OP4/wwUKnjepTOdVKjrBpHV2rhL1xpfzSpeAE6HdFleD4DLo4G1RxnsAebPt2644J/gOAnQe9nMi8Mnr+4UQ02SZI5DuXKXqSV6qRKUFSkDnVKC4M9aYzqmMoY1XzPvS+dSJ06DZ8djEAZ1XibkEFZvOXKXqk86rVHR8SOOr45ZBfGNIT+hWaCWUbBfwM0h7HuoPDYC4C3gWJMs8gXTmahC6Mwly5pHzy3s9n4RkmSXAPzz5h9I3IN6ozjngcbJfZjqnAOcLsnTmSufUFzRJaPYiaBP0lTS6oPMqDVg+Zk13rnRe+Qi/K1VNQaG10BZoDkRngTYEqoXcJ105jv8IVUFcin8Y6gvJgiEwBc10Zq6GIt9rEOeIq4cfQ7dCpZAsswTOQfVtEJ0/ygnzsobOKUDIIktnrnROfXETx3OoCeLvMor/L/HT+b9J5xVgZImlO1c6r7Jk4tQNERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABERABEQg9gRsxAj41n+IbQ6qhD6B7ofGQ1x5ERKU3MsXxMKSxjd1T5AlDUg908hPo9IA6uwfaqYf4hgKZCIiACIiACIiACPhKgM5ZA3QwdAj0NehC6E2oFboEctsIHIx1R+wgfCTS6Vyy7jDbf6HzH0HJ3qWcibHNRKV/yETFqlMEREAEREAERCC3CdAB5EqT1+jo0AGhEzjBm5jG8VHIy5XFsDuAdP6ugIK0f0NjfPfswCAbVVsiIAIiIAIiIAI7P4FkDiBH3g/i6uAMHsTsD/hc6Bzgsy/0O2gl1AitgZ6GyiBn9Y8OoPsyMw6tBLoLqoTqIJanw7kb5LaXcPAX6ESIl6a3QPOhcZDXzkYEVy7p0G6Anof2ghyrQOAP0OcQx/U6xBXPHdlXkIFjGJYg43GImwexX1Wx8ER80pzxH4swx1YDrYZ+CNHOg5ZALPcY1BtyWz4O2NdL3ZEKi4AIhIcAT2KZCIiACISNwCZ0mA7VYa6OtyNMOfYrBOicXQsdDV0ErYXo4C2AeDmZ9gPoUMhxjnoizDw3QnSQ6OSMhOZCBZDbeMn5eugG6AyoHJoFufNdieOHoPehb0HnQO9BjkNJh5SOI1ci2Rb7vBSik7gPlMqOQSLHtNyT6XQc/x+0GToL+jb0IjQEcts0HHwMnQL9A7oHuh1i/h9DP4W+Cf0Mchud5n9BbF8mAiIgAiIgAiIgAr4RoANWn6K2R5DGFTrHHkSg0jnAJx2uO1zH3uCRiODq2SHeBM8x/1AeDNHpoUPo2EsIsP1BTgQ+J0Gs03Em6dxxBW46lMw4zmpoV0+Gt3DMMaayvyDxOU+GPByvgOjwJTOOneNx8ynFcQNEh7IYcuw+BFif16YgYqM3UsciIALhIMBfbDIREAERCCMBOjrtKTrOFcLJ0JXQOCgd+w4yvwHRMWuF6ACxLfdlWxxGVvLWMRCzSnyyX85KG1cWuaJ4P5TMuIo2F9oAceWQ4s5eOnCHQKmMq4gs5zb2cTA03R2ZJPw3Vzyd2TUQV/aaXPFcIWQ7HJfb2C5XPIvckQqLgAiEgwB/ychEQAREIIwE6GR9lqLjFyHrYAZ5AAADs0lEQVSN96n9CLo1Fv4tPm+GUtlJSJwJPQjdCNHRofP3GlQCuY2XWN3WHDtw8vWPHa92Z/KEB+F4ItTiiedhojh3NrbjdtaYxjbZXzpzqYx5EvWf9/25jWPiYkEh5IyP6Y38B0YH1x0fidQ/IiAC2U1ADmB2z496JwIikJgAnZyDoMcTJ0diuaJ1dUyj8DkZ+hnE1byHoWR2GhLeh851ZRjuCqcTdFbnvoRCbDeR8X7GTyH21bvKlii/O45ly9wRCLNN1sM2M2m7oHJe7uYqqUwERCBkBPJD1l91VwREQAT4e+s3EFek7u4kjiXIdz3EFa99Y2W4akVHyVmti0VbLwS8K2/nII4rZukaL6fWQ25n0lvHXxHBPi2GeN+fV4hKah8hZbgn9WMc09n8gSfe78MRqPATvytVfSIgAsEQ0ApgMJzVigiIQNcI0EGbECtKx4yO0vehcdBl0JtQMnsFCU9BH0C8XHkSxNUyOlw0OkpcwWJ9zRCdvgXQCxAvFd8CcWfsV6EzoK5YLQrdAN0B0XH9E8TNF6yTGzjmQXdCp0P/hO6ClkJ8zM2BEMdPxzWZvYwE9o2/y1tdmX6KMFdHn4YehLgaegjEMT8J0Vh3d+xgFGafZSIgAiIgAiIgAiLgG4EbURMdNEe81Ehn7nfQeMhrdHQ+dEXehvDbEO9po16FToXcdj4OuPJGB5Dt0OioTYVWQzXQs9BIiOlXQI69hADT3LYrDpjve+5IhM+CuLLXAK2HnoP2hBzrj8A0aAVEZ3UlROdtEpTKBiCR9wAemyAT416B6qBN0BxoAkQ7EmI/6RS6rRIH97sjEL4EYl73Zg+Okw7n1yGZCIiACIiACIiACIhAwAQeQ3szAm6TTuGSgNtUcyIgAiIgAiIgAiIgAjECY/DJVb4hAREpQDt0/s4OqD01IwIikAECPJFlIiACIiAC4SXAS8q8XM1LsisDGMZQtMFL5r8NoC01IQIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAI+E/h/jlcmxjRopIEAAAAASUVORK5CYII=\">"
|
|
],
|
|
"text/plain": [
|
|
"<IPython.core.display.HTML object>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"\"\"\"\n",
|
|
"# To plot species, we first have to identify the index of the species in the array\n",
|
|
"# For this, cut & paste the following lines and run in a new cell to get the index\n",
|
|
"for i, specie in enumerate(gas.species()):\n",
|
|
" print(str(i) + '. ' + str(specie))\n",
|
|
"\"\"\"\n",
|
|
"\n",
|
|
"# Extract concentration data\n",
|
|
"X_CH4 = oppFlame.X[13]\n",
|
|
"X_CO2 = oppFlame.X[15]\n",
|
|
"X_H2O = oppFlame.X[5]\n",
|
|
"\n",
|
|
"plt.figure()\n",
|
|
"\n",
|
|
"plt.plot(oppFlame.grid*100, X_CH4, 'c-o', lw=2, label=r'$CH_{4}$')\n",
|
|
"plt.plot(oppFlame.grid*100, X_CO2, 'm-s', lw=2, label=r'$CO_{2}$')\n",
|
|
"plt.plot(oppFlame.grid*100, X_H2O, 'g-<', lw=2, label=r'$H_{2}O$')\n",
|
|
"\n",
|
|
"plt.xlim(oppFlame.grid[0], oppFlame.grid[-1]*100)\n",
|
|
"plt.xlabel('Distance (cm)')\n",
|
|
"plt.ylabel('Mole Fractions')\n",
|
|
"\n",
|
|
"plt.legend(loc=2);"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"collapsed": true
|
|
},
|
|
"outputs": [],
|
|
"source": []
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 2",
|
|
"language": "python",
|
|
"name": "python2"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 2
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython2",
|
|
"version": "2.7.11"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 0
|
|
}
|