{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Images of an accretion disk around a Kerr black hole\n", "\n", "This Jupyter/SageMath notebook is relative to the lectures\n", "[Geometry and physics of black holes](https://luth.obspm.fr/~luthier/gourgoulhon/bh16/)." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'SageMath version 9.3.beta8, Release Date: 2021-03-07'" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "version()" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "%display latex" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "import matplotlib.image as mpimg\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Functions $\\ell_{\\rm c}(r_0)$ and $q_{\\rm c}(r_0)$ for critical null geodesics\n", "\n", "We use $m=1$ and denote $r_0$ simply by $r$." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "a, r = var('a r') " ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}[1]{\\mathbf{#1}}\\left( a, r \\right) \\ {\\mapsto} \\ -\\frac{a^{2} {\\left(r + 1\\right)} + {\\left(r - 3\\right)} r^{2}}{a {\\left(r - 1\\right)}}\n", "\\end{math}" ], "text/plain": [ "(a, r) |--> -(a^2*(r + 1) + (r - 3)*r^2)/(a*(r - 1))" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lsph(a, r) = (r^2*(3 - r) - a^2*(r + 1))/(a*(r -1))\n", "lsph" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}[1]{\\mathbf{#1}}\\left( a, r \\right) \\ {\\mapsto} \\ -\\frac{{\\left({\\left(r - 3\\right)}^{2} r - 4 \\, a^{2}\\right)} r^{3}}{a^{2} {\\left(r - 1\\right)}^{2}}\n", "\\end{math}" ], "text/plain": [ "(a, r) |--> -((r - 3)^2*r - 4*a^2)*r^3/(a^2*(r - 1)^2)" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "qsph(a, r) = r^3 / (a^2*(r - 1)^2) * (4*a^2 - r*(r - 3)^2)\n", "qsph" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The radii $r_+$ and $r_-$ of the two horizons:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "rp(a) = 1 + sqrt(1 - a^2)\n", "rm(a) = 1 - sqrt(1 - a^2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Critical radii $r_{\\rm ph}^{**}$, $r_{\\rm ph}^*$, $r_{\\rm ph}^+$, $r_{\\rm ph}^-$, $r_{\\rm ph}^{\\rm ms}$ and $r_{\\rm ph}^{\\rm pol}$ " ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}[1]{\\mathbf{#1}}a \\ {\\mapsto}\\ \\cos\\left(\\frac{2}{3} \\, \\pi + \\frac{2}{3} \\, \\arcsin\\left(a\\right)\\right) + \\frac{1}{2}\n", "\\end{math}" ], "text/plain": [ "a |--> cos(2/3*pi + 2/3*arcsin(a)) + 1/2" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rph_ss(a) = 1/2 + cos(2/3*asin(a) + 2*pi/3)\n", "rph_ss" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}[1]{\\mathbf{#1}}a \\ {\\mapsto}\\ 4 \\, \\cos\\left(\\frac{4}{3} \\, \\pi + \\frac{1}{3} \\, \\arccos\\left(-a\\right)\\right)^{2}\n", "\\end{math}" ], "text/plain": [ "a |--> 4*cos(4/3*pi + 1/3*arccos(-a))^2" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rph_s(a) = 4*cos(acos(-a)/3 + 4*pi/3)^2\n", "rph_s" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}[1]{\\mathbf{#1}}a \\ {\\mapsto}\\ 4 \\, \\cos\\left(\\frac{1}{3} \\, \\arccos\\left(-a\\right)\\right)^{2}\n", "\\end{math}" ], "text/plain": [ "a |--> 4*cos(1/3*arccos(-a))^2" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rph_p(a) = 4*cos(acos(-a)/3)^2\n", "rph_p" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}[1]{\\mathbf{#1}}a \\ {\\mapsto}\\ 4 \\, \\cos\\left(\\frac{1}{3} \\, \\arccos\\left(a\\right)\\right)^{2}\n", "\\end{math}" ], "text/plain": [ "a |--> 4*cos(1/3*arccos(a))^2" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rph_m(a) = 4*cos(acos(a)/3)^2\n", "rph_m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We add the radius of the marginally stable orbit:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}[1]{\\mathbf{#1}}a \\ {\\mapsto}\\ -{\\left(-a^{2} + 1\\right)}^{\\frac{1}{3}} + 1\n", "\\end{math}" ], "text/plain": [ "a |--> -(-a^2 + 1)^(1/3) + 1" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rph_ms(a) = 1 - (1 - a^2)^(1/3)\n", "rph_ms" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "as well as the radius of outer and inner polar orbits:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}[1]{\\mathbf{#1}}a \\ {\\mapsto}\\ 2 \\, \\sqrt{-\\frac{1}{3} \\, a^{2} + 1} \\cos\\left(\\frac{1}{3} \\, \\arccos\\left(-\\frac{a^{2} - 1}{{\\left(-\\frac{1}{3} \\, a^{2} + 1\\right)}^{\\frac{3}{2}}}\\right)\\right) + 1\n", "\\end{math}" ], "text/plain": [ "a |--> 2*sqrt(-1/3*a^2 + 1)*cos(1/3*arccos(-(a^2 - 1)/(-1/3*a^2 + 1)^(3/2))) + 1" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rph_pol(a) = 1 + 2*sqrt(1 - a^2/3)*cos(1/3*arccos((1 - a^2)/(1 - a^2/3)^(3/2)))\n", "rph_pol" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}[1]{\\mathbf{#1}}a \\ {\\mapsto}\\ 2 \\, \\sqrt{-\\frac{1}{3} \\, a^{2} + 1} \\cos\\left(\\frac{2}{3} \\, \\pi + \\frac{1}{3} \\, \\arccos\\left(-\\frac{a^{2}}{{\\left(-\\frac{1}{3} \\, a^{2} + 1\\right)}^{\\frac{3}{2}}} + \\frac{1}{{\\left(-\\frac{1}{3} \\, a^{2} + 1\\right)}^{\\frac{3}{2}}}\\right)\\right) + 1\n", "\\end{math}" ], "text/plain": [ "a |--> 2*sqrt(-1/3*a^2 + 1)*cos(2/3*pi + 1/3*arccos(-a^2/(-1/3*a^2 + 1)^(3/2) + 1/(-1/3*a^2 + 1)^(3/2))) + 1" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rph_pol_in(a) = 1 + 2*sqrt(1 - a^2/3)*cos(1/3*arccos((1 - a^2)/(1 - a^2/3)^(3/2)) + 2*pi/3)\n", "rph_pol_in" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}[1]{\\mathbf{#1}}r_{\\rm ph}^{**} = -0.477673658836338\n", "\\end{math}" ], "text/plain": [ "r_{\\rm ph}^{**} = -0.477673658836338" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}[1]{\\mathbf{#1}}r_{\\rm ph}^{\\rm ms} = 0.539741795874205\n", "\\end{math}" ], "text/plain": [ "r_{\\rm ph}^{\\rm ms} = 0.539741795874205" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}[1]{\\mathbf{#1}}r_{\\rm ph}^{*} = 0.658372153864346\n", "\\end{math}" ], "text/plain": [ "r_{\\rm ph}^{*} = 0.658372153864346" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}[1]{\\mathbf{#1}}r_- = 0.687750100080080\n", "\\end{math}" ], "text/plain": [ "r_- = 0.687750100080080" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}[1]{\\mathbf{#1}}r_+ = 1.31224989991992\n", "\\end{math}" ], "text/plain": [ "r_+ = 1.31224989991992" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}[1]{\\mathbf{#1}}r_{\\rm ph}^+ = 1.38628052846298\n", "\\end{math}" ], "text/plain": [ "r_{\\rm ph}^+ = 1.38628052846298" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}[1]{\\mathbf{#1}}r_{\\rm ph}^- = 3.95534731767268\n", "\\end{math}" ], "text/plain": [ "r_{\\rm ph}^- = 3.95534731767268" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}[1]{\\mathbf{#1}}r_{\\rm ph}^{\\rm pol} = 2.49269429554008\n", "\\end{math}" ], "text/plain": [ "r_{\\rm ph}^{\\rm pol} = 2.49269429554008" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}[1]{\\mathbf{#1}}r_{\\rm ph}^{\\rm pol,in} = -0.399338575773941\n", "\\end{math}" ], "text/plain": [ "r_{\\rm ph}^{\\rm pol,in} = -0.399338575773941" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "a0 = 0.95\n", "# a0 = 1\n", "show(LatexExpr(r'r_{\\rm ph}^{**} = '), n(rph_ss(a0)))\n", "show(LatexExpr(r'r_{\\rm ph}^{\\rm ms} = '), n(rph_ms(a0)))\n", "show(LatexExpr(r'r_{\\rm ph}^{*} = '), n(rph_s(a0)))\n", "show(LatexExpr(r'r_- = '), n(rm(a0)))\n", "show(LatexExpr(r'r_+ = '), n(rp(a0)))\n", "show(LatexExpr(r'r_{\\rm ph}^+ = '), n(rph_p(a0)))\n", "show(LatexExpr(r'r_{\\rm ph}^- = '), n(rph_m(a0)))\n", "show(LatexExpr(r'r_{\\rm ph}^{\\rm pol} = '), n(rph_pol(a0)))\n", "show(LatexExpr(r'r_{\\rm ph}^{\\rm pol,in} = '), n(rph_pol_in(a0)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Prograde timelike ISCO radius compared to various radii of spherical photon orbits" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "def r_isco(a, retrograde=False):\n", " eps = -1 if not retrograde else 1\n", " a2 = a^2\n", " z1 = 1 + (1 - a2)^(1/3) * ((1 + a)^(1/3) + (1 - a)^(1/3))\n", " z2 = sqrt(3*a2 + z1^2)\n", " return 3 + z2 + eps*sqrt((3 - z1)*(3 + z1 + 2*z2))" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}[1]{\\mathbf{#1}}\\left(4.23300252953083, 1.93723787813966, 1.45449793805967, 1.00000000000000\\right)\n", "\\end{math}" ], "text/plain": [ "(4.23300252953083, 1.93723787813966, 1.45449793805967, 1.00000000000000)" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "r_isco(0.5), r_isco(0.95), r_isco(0.99), r_isco(1.)" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "Graphics object consisting of 4 graphics primitives" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g = plot(r_isco(a), (a, 0, 1), color='red', thickness=2, \n", " legend_label=r'$r_{\\rm ISCO}^+$', axes_labels=[r'$a/m$', r'$r/m$'], \n", " frame=True, axes=False, gridlines=True)\n", "g += plot(rph_p(a), (a, 0, 1), color='green', thickness=2,\n", " legend_label=r'$r_{\\rm ph}^+$')\n", "g += plot(rph_m(a), (a, 0, 1), color='green', thickness=2,\n", " linestyle='--', legend_label=r'$r_{\\rm ph}^-$')\n", "g += plot(rph_pol(a), (a, 0, 1), color='green', thickness=2,\n", " linestyle=':', legend_label=r'$r_{\\rm ph}^{\\rm pol}$')\n", "g.set_legend_options(handlelength=2.5)\n", "g.save('gik_rISCO_rph.pdf')\n", "g" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}[1]{\\mathbf{#1}}0.6382847385042254\n", "\\end{math}" ], "text/plain": [ "0.6382847385042254" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fr(a) = r_isco(a) - rph_m(a)\n", "find_root(fr, 0.6, 0.7)" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}[1]{\\mathbf{#1}}0.8528351773350228\n", "\\end{math}" ], "text/plain": [ "0.8528351773350228" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fr(a) = r_isco(a) - rph_pol(a)\n", "find_root(fr, 0.8, 1)" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "def alpha(a, th_obs, r0):\n", " if a == 1:\n", " ell = - r0^2 + 2*r0 + 1\n", " else:\n", " ell = lsph(a, r0)\n", " return - ell / sin(th_obs)\n", "\n", "def Theta(a, th_obs, r0):\n", " if a == 1:\n", " ell = - r0^2 + 2*r0 + 1\n", " q = r0^3 * (4 - r0)\n", " else:\n", " ell = lsph(a, r0)\n", " q = qsph(a, r0)\n", " return q + cos(th_obs)^2 * (a^2 - ell^2/sin(th_obs)^2)\n", "\n", "def beta(a, th_obs, r0, eps_theta=1):\n", " return eps_theta * sqrt(Theta(a, th_obs, r0,))" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": [ "def r0_bounds(a, th_obs, outer=True):\n", " r\"\"\"\n", " Return (r0_min, r0_max)\n", " \"\"\"\n", " if outer:\n", " r1 = n(rph_p(a))\n", " r2 = n(rph_m(a))\n", " r3 = rph_pol(a)\n", " else:\n", " r1 = n(rph_ss(a))\n", " r2 = 0\n", " r3 = rph_pol_in(a)\n", " #\n", " # Computation of rmin:\n", " try:\n", " if a == 1:\n", " th_crit = n(asin(sqrt(3) - 1))\n", " if n(th_obs) < th_crit or n(th_obs) > n(pi) - th_crit:\n", " rmin = find_root(lambda r: Theta(a, th_obs, r), r1, r3)\n", " else:\n", " rmin = 1\n", " else:\n", " rmin = find_root(lambda r: Theta(a, th_obs, r), r1, r3)\n", " except TypeError: # special case th_obs = pi/2\n", " rmin = r1 \n", " #\n", " # Computation of rmax:\n", " try:\n", " rmax = find_root(lambda r: Theta(a, th_obs, r), r3, r2)\n", " except TypeError: # special case th_obs = pi/2\n", " rmax = r2 \n", " #\n", " return (rmin, rmax)" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": [ "def shadow_plot(a, th_obs, orientation=0, outer=True, color=None, number_colors=5, \n", " range_col=None, thickness=2, linestyle='-', plot_points=200,\n", " legend='automatic', legend_loc=(1.02, 0.36), fill=True, \n", " fillcolor='grey', draw_NHEKline=True, \n", " draw_spin=False, spin_arrow_length=7, spin_arrow_options=None,\n", " frame=True, axes=True, axes_labels='automatic', gridlines=True):\n", " if a==0:\n", " # Case a = 0:\n", " rs = 3*sqrt(3)\n", " if color is None:\n", " color = 'black'\n", " if legend == 'automatic':\n", " legend = None\n", " g = parametric_plot((rs*cos(x), rs*sin(x)), (x, 0, 2*pi), \n", " color=color, thickness=thickness,\n", " linestyle=linestyle, legend_label=legend, \n", " fill=fill, fillcolor=fillcolor, frame=frame, \n", " axes=axes, gridlines=gridlines)\n", " else:\n", " # Case a != 0\n", " rmin, rmax = r0_bounds(a, th_obs, outer=outer)\n", " if rmin > 0:\n", " rmin = 1.00000001*rmin\n", " rmax = 0.99999999*rmax\n", " else:\n", " rmin = 0.9999999*rmin\n", " rmax = 1.0000001*rmax\n", " print(\"rmin : \", rmin, \" rmax : \", rmax)\n", " co = cos(orientation)\n", " so = sin(orientation)\n", " fa = lambda r: co*alpha(a, th_obs, r) - so*beta(a, th_obs, r)\n", " fb = lambda r: so*alpha(a, th_obs, r) + co*beta(a, th_obs, r)\n", " fam = lambda r: co*alpha(a, th_obs, r) - so*beta(a, th_obs, r, eps_theta=-1)\n", " fbm = lambda r: so*alpha(a, th_obs, r) + co*beta(a, th_obs, r, eps_theta=-1)\n", " if range_col is None:\n", " range_col = r0_bounds(a, pi/2, outer=outer)\n", " rmin_col, rmax_col = range_col \n", " print(\"rmin_col : \", rmin_col, \" rmax_col : \", rmax_col)\n", " dr = (rmax_col - rmin_col) / number_colors\n", " rm = rmin_col + int((rmin - rmin_col)/dr)*dr\n", " r1s = rmin\n", " r_ranges = []\n", " while rm + dr < rmax:\n", " col = hue((rm - rmin_col)/(rmax_col - rmin_col + 0.1))\n", " r2s = rm + dr\n", " r_ranges.append((r1s, r2s, col))\n", " rm += dr\n", " r1s = r2s\n", " if color is None:\n", " col = hue((rm - rmin_col)/(rmax_col - rmin_col + 0.1))\n", " else:\n", " col = color\n", " r_ranges.append((r1s, rmax, col))\n", " g = Graphics()\n", " legend_label = None # a priori\n", " if a == 1 and draw_NHEKline:\n", " th_crit = asin(sqrt(3) - 1)\n", " if th_obs > th_crit and th_obs < pi - th_crit:\n", " # NHEK line\n", " alpha0 = -2/sin(th_obs)\n", " beta0 = sqrt(3 - cos(th_obs)**2 *(6 + cos(th_obs)**2))/sin(th_obs)\n", " alpha1 = co*alpha0 - so*beta0\n", " beta1 = so*alpha0 + co*beta0\n", " alpha2 = co*alpha0 + so*beta0\n", " beta2 = so*alpha0 - co*beta0\n", " if legend == 'automatic':\n", " legend_label = r\"$r_0 = m$\"\n", " if color is None:\n", " colNHEK = 'maroon'\n", " else:\n", " colNHEK = color\n", " g += line([(alpha1, beta1), (alpha2, beta2)], color=colNHEK, \n", " thickness=thickness, linestyle=linestyle,\n", " legend_label=legend_label)\n", " if fill:\n", " g += polygon2d([(fa(rmax), fb(rmax)), (alpha1, beta1), (alpha2, beta2)], \n", " color=fillcolor, alpha=0.5)\n", " for rg in r_ranges:\n", " r1s, r2s = rg[0], rg[1]\n", " col = rg[2]\n", " if legend:\n", " if legend == 'automatic':\n", " if draw_NHEKline and abs(r1s - 1) < 1e-5:\n", " legend_label = r\"${:.2f}\\, m < r_0 \\leq {:.2f}\\, m$\".format(\n", " float(r1s), float(r2s))\n", " else:\n", " legend_label = r\"${:.2f}\\, m \\leq r_0 \\leq {:.2f}\\, m$\".format(\n", " float(r1s), float(r2s))\n", " else:\n", " legend_label = legend\n", " g += parametric_plot((fa, fb), (r1s, r2s), plot_points=plot_points, color=col, \n", " thickness=thickness, linestyle=linestyle,\n", " legend_label=legend_label, \n", " frame=frame, axes=axes, gridlines=gridlines)\n", " g += parametric_plot((fam, fbm), (r1s, r2s), plot_points=plot_points, color=col, \n", " thickness=thickness, linestyle=linestyle)\n", " if fill:\n", " g += parametric_plot((fa, fb), (rmin, rmax), fill=True, fillcolor=fillcolor, \n", " thickness=0)\n", " g += parametric_plot((fam, fbm), (rmin, rmax), fill=True, fillcolor=fillcolor, \n", " thickness=0)\n", " if draw_spin:\n", " if not spin_arrow_options:\n", " spin_arrow_options = {}\n", " if 'color' not in spin_arrow_options:\n", " spin_arrow_options['color'] = color\n", " g += arrow2d((0,0), (-so*spin_arrow_length, co*spin_arrow_length), \n", " **spin_arrow_options)\n", " # end of case a != 0\n", " g.set_aspect_ratio(1)\n", " if axes_labels:\n", " if axes_labels == 'automatic':\n", " g.axes_labels([r\"$(r_{\\mathscr{O}}/m)\\; \\alpha$\", \n", " r\"$(r_{\\mathscr{O}}/m)\\; \\beta$\"])\n", " else:\n", " g.axes_labels(axes_labels)\n", " if legend:\n", " g.set_legend_options(handlelength=2, loc=legend_loc)\n", " return g" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "rmin : 1.00000001000000 rmax : 3.99999996000000\n", "rmin_col : 1 rmax_col : 4.0\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "Graphics object consisting of 3 graphics primitives" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "shadow_plot(1, pi/2, fill=False, color='red', number_colors=1, \n", " thickness=1.5, linestyle=':', legend=False)" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "rmin : 1.00000001000000 rmax : 3.99999996000000\n", "rmin_col : 1 rmax_col : 4.0\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "Graphics object consisting of 9 graphics primitives" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "shadow_plot(1, pi/2, orientation=pi/6, fill=True, color='red', \n", " number_colors=1, thickness=1.5, \n", " draw_spin=True, spin_arrow_options={'color': 'blue', 'width': 3},\n", " legend=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Half-width of the image in units of $m/r_{\\mathscr{O}}$:" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "fsize = 10.0963959215444 m/r_obs\n" ] } ], "source": [ "gyoto_field_of_view = 74 # Gyoto field of view for M87* (in microarcseconds)\n", "scale_M87 = 3.66467403690525 # m/r for M87* (in microarcseconds)\n", "fsize = gyoto_field_of_view / 2 / scale_M87\n", "#extent = (-fsize, fsize, -fsize, fsize)\n", "print(\"fsize =\", fsize, \"m/r_obs\")" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [], "source": [ "def empty_plot(size, frame=True, axes=False, axes_labels='automatic', \n", " gridlines=False):\n", " g = Graphics()\n", " g._extra_kwds['frame'] = frame\n", " g._extra_kwds['axes'] = axes\n", " g._extra_kwds['gridlines'] = gridlines\n", " if axes_labels:\n", " if axes_labels == 'automatic':\n", " g.axes_labels([r\"$(r_{\\mathscr{O}}/m)\\; \\alpha$\", \n", " r\"$(r_{\\mathscr{O}}/m)\\; \\beta$\"])\n", " else:\n", " g.axes_labels(axes_labels)\n", " g.set_aspect_ratio(1)\n", " g.set_axes_range(-size, size, -size, size)\n", " return g" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Default resolution of SageMath images:" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}[1]{\\mathbf{#1}}100\n", "\\end{math}" ], "text/plain": [ "100" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dpi = Graphics.SHOW_OPTIONS['dpi']\n", "dpi" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Default resolution of Matplotlib images:" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}[1]{\\mathbf{#1}}72.0\n", "\\end{math}" ], "text/plain": [ "72.0" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from matplotlib import rcParams\n", "rcParams['figure.dpi']" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [], "source": [ "gyoto_images = {'a95_th00': (0.95, 0),\n", " 'a95_th30': (0.95, pi/6),\n", " 'a95_th60': (0.95, pi/3),\n", " 'a95_th90': (0.95, pi/2)}" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": [ "#gyoto_images = {'a1_th90_rin193': (1., pi/2),\n", "# 'a1_th90_rin193-5000': (1., pi/2, 5000, 1800, 2500),\n", "# 'a99_th90_rin193': (0.99, pi/2, 2500, 900, 1250)}" ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "scrolled": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a95_th00 resolution: (500, 500, 3)\n", "figsize: (5.0, 5.0)\n", "a/m = 0.950000000000000 theta_obs = 0\n", "extent: (-10.0963959215444, 10.0963959215444, -10.0963959215444, 10.0963959215444)\n", "rmin : 2.49118715973461 rmax : 2.49420141399888\n", "rmin_col : 1.3862805284629751 rmax_col : 3.95534731767268\n" ] }, { "data": { "application/javascript": [ "/* Put everything inside the global mpl namespace */\n", "/* global mpl */\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(\n", " '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", "\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 = document.createElement('div');\n", " this.root.setAttribute('style', 'display: inline-block');\n", " this._root_extra_style(this.root);\n", "\n", " parent_element.appendChild(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", " if (fig.ratio !== 1) {\n", " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", " }\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", " fig.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 = document.createElement('div');\n", " titlebar.classList =\n", " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", " var titletext = document.createElement('div');\n", " titletext.classList = 'ui-dialog-title';\n", " titletext.setAttribute(\n", " 'style',\n", " 'width: 100%; text-align: center; padding: 3px;'\n", " );\n", " titlebar.appendChild(titletext);\n", " this.root.appendChild(titlebar);\n", " this.header = titletext;\n", "};\n", "\n", "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", "\n", "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", "\n", "mpl.figure.prototype._init_canvas = function () {\n", " var fig = this;\n", "\n", " var canvas_div = (this.canvas_div = document.createElement('div'));\n", " canvas_div.setAttribute(\n", " 'style',\n", " 'border: 1px solid #ddd;' +\n", " 'box-sizing: content-box;' +\n", " 'clear: both;' +\n", " 'min-height: 1px;' +\n", " 'min-width: 1px;' +\n", " 'outline: 0;' +\n", " 'overflow: hidden;' +\n", " 'position: relative;' +\n", " 'resize: both;'\n", " );\n", "\n", " function on_keyboard_event_closure(name) {\n", " return function (event) {\n", " return fig.key_event(event, name);\n", " };\n", " }\n", "\n", " canvas_div.addEventListener(\n", " 'keydown',\n", " on_keyboard_event_closure('key_press')\n", " );\n", " canvas_div.addEventListener(\n", " 'keyup',\n", " on_keyboard_event_closure('key_release')\n", " );\n", "\n", " this._canvas_extra_style(canvas_div);\n", " this.root.appendChild(canvas_div);\n", "\n", " var canvas = (this.canvas = document.createElement('canvas'));\n", " canvas.classList.add('mpl-canvas');\n", " canvas.setAttribute('style', 'box-sizing: content-box;');\n", "\n", " this.context = canvas.getContext('2d');\n", "\n", " var backingStore =\n", " this.context.backingStorePixelRatio ||\n", " this.context.webkitBackingStorePixelRatio ||\n", " this.context.mozBackingStorePixelRatio ||\n", " this.context.msBackingStorePixelRatio ||\n", " this.context.oBackingStorePixelRatio ||\n", " this.context.backingStorePixelRatio ||\n", " 1;\n", "\n", " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", " if (this.ratio !== 1) {\n", " fig.send_message('set_dpi_ratio', { dpi_ratio: this.ratio });\n", " }\n", "\n", " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", " 'canvas'\n", " ));\n", " rubberband_canvas.setAttribute(\n", " 'style',\n", " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", " );\n", "\n", " var resizeObserver = new ResizeObserver(function (entries) {\n", " var nentries = entries.length;\n", " for (var i = 0; i < nentries; i++) {\n", " var entry = entries[i];\n", " var width, height;\n", " if (entry.contentBoxSize) {\n", " if (entry.contentBoxSize instanceof Array) {\n", " // Chrome 84 implements new version of spec.\n", " width = entry.contentBoxSize[0].inlineSize;\n", " height = entry.contentBoxSize[0].blockSize;\n", " } else {\n", " // Firefox implements old version of spec.\n", " width = entry.contentBoxSize.inlineSize;\n", " height = entry.contentBoxSize.blockSize;\n", " }\n", " } else {\n", " // Chrome <84 implements even older version of spec.\n", " width = entry.contentRect.width;\n", " height = entry.contentRect.height;\n", " }\n", "\n", " // Keep the size of the canvas and rubber band canvas in sync with\n", " // the canvas container.\n", " if (entry.devicePixelContentBoxSize) {\n", " // Chrome 84 implements new version of spec.\n", " canvas.setAttribute(\n", " 'width',\n", " entry.devicePixelContentBoxSize[0].inlineSize\n", " );\n", " canvas.setAttribute(\n", " 'height',\n", " entry.devicePixelContentBoxSize[0].blockSize\n", " );\n", " } else {\n", " canvas.setAttribute('width', width * fig.ratio);\n", " canvas.setAttribute('height', height * fig.ratio);\n", " }\n", " canvas.setAttribute(\n", " 'style',\n", " 'width: ' + width + 'px; height: ' + height + 'px;'\n", " );\n", "\n", " rubberband_canvas.setAttribute('width', width);\n", " rubberband_canvas.setAttribute('height', height);\n", "\n", " // And update the size in Python. We ignore the initial 0/0 size\n", " // that occurs as the element is placed into the DOM, which should\n", " // otherwise not happen due to the minimum size styling.\n", " if (width != 0 && height != 0) {\n", " fig.request_resize(width, height);\n", " }\n", " }\n", " });\n", " resizeObserver.observe(canvas_div);\n", "\n", " function on_mouse_event_closure(name) {\n", " return function (event) {\n", " return fig.mouse_event(event, name);\n", " };\n", " }\n", "\n", " rubberband_canvas.addEventListener(\n", " 'mousedown',\n", " on_mouse_event_closure('button_press')\n", " );\n", " rubberband_canvas.addEventListener(\n", " 'mouseup',\n", " on_mouse_event_closure('button_release')\n", " );\n", " // Throttle sequential mouse events to 1 every 20ms.\n", " rubberband_canvas.addEventListener(\n", " 'mousemove',\n", " on_mouse_event_closure('motion_notify')\n", " );\n", "\n", " rubberband_canvas.addEventListener(\n", " 'mouseenter',\n", " on_mouse_event_closure('figure_enter')\n", " );\n", " rubberband_canvas.addEventListener(\n", " 'mouseleave',\n", " on_mouse_event_closure('figure_leave')\n", " );\n", "\n", " canvas_div.addEventListener('wheel', function (event) {\n", " if (event.deltaY < 0) {\n", " event.step = 1;\n", " } else {\n", " event.step = -1;\n", " }\n", " on_mouse_event_closure('scroll')(event);\n", " });\n", "\n", " canvas_div.appendChild(canvas);\n", " canvas_div.appendChild(rubberband_canvas);\n", "\n", " this.rubberband_context = rubberband_canvas.getContext('2d');\n", " this.rubberband_context.strokeStyle = '#000000';\n", "\n", " this._resize_canvas = function (width, height, forward) {\n", " if (forward) {\n", " canvas_div.style.width = width + 'px';\n", " canvas_div.style.height = height + 'px';\n", " }\n", " };\n", "\n", " // Disable right mouse context menu.\n", " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", " event.preventDefault();\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 toolbar = document.createElement('div');\n", " toolbar.classList = 'mpl-toolbar';\n", " this.root.appendChild(toolbar);\n", "\n", " function on_click_closure(name) {\n", " return function (_event) {\n", " return fig.toolbar_button_onclick(name);\n", " };\n", " }\n", "\n", " function on_mouseover_closure(tooltip) {\n", " return function (event) {\n", " if (!event.currentTarget.disabled) {\n", " return fig.toolbar_button_onmouseover(tooltip);\n", " }\n", " };\n", " }\n", "\n", " fig.buttons = {};\n", " var buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'mpl-button-group';\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", " /* Instead of a spacer, we start a new button group. */\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", " buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'mpl-button-group';\n", " continue;\n", " }\n", "\n", " var button = (fig.buttons[name] = document.createElement('button'));\n", " button.classList = 'mpl-widget';\n", " button.setAttribute('role', 'button');\n", " button.setAttribute('aria-disabled', 'false');\n", " button.addEventListener('click', on_click_closure(method_name));\n", " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", "\n", " var icon_img = document.createElement('img');\n", " icon_img.src = '_images/' + image + '.png';\n", " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", " icon_img.alt = tooltip;\n", " button.appendChild(icon_img);\n", "\n", " buttonGroup.appendChild(button);\n", " }\n", "\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", "\n", " var fmt_picker = document.createElement('select');\n", " fmt_picker.classList = 'mpl-widget';\n", " toolbar.appendChild(fmt_picker);\n", " this.format_dropdown = fmt_picker;\n", "\n", " for (var ind in mpl.extensions) {\n", " var fmt = mpl.extensions[ind];\n", " var option = document.createElement('option');\n", " option.selected = fmt === mpl.default_extension;\n", " option.innerHTML = fmt;\n", " fmt_picker.appendChild(option);\n", " }\n", "\n", " var status_bar = document.createElement('span');\n", " status_bar.classList = 'mpl-message';\n", " toolbar.appendChild(status_bar);\n", " this.message = status_bar;\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", "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", "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], msg['forward']);\n", " fig.send_message('refresh', {});\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", " var x0 = msg['x0'] / fig.ratio;\n", " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", " var x1 = msg['x1'] / fig.ratio;\n", " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\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,\n", " 0,\n", " fig.canvas.width / fig.ratio,\n", " fig.canvas.height / fig.ratio\n", " );\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", " 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.handle_history_buttons = function (fig, msg) {\n", " for (var key in msg) {\n", " if (!(key in fig.buttons)) {\n", " continue;\n", " }\n", " fig.buttons[key].disabled = !msg[key];\n", " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", " if (msg['mode'] === 'PAN') {\n", " fig.buttons['Pan'].classList.add('active');\n", " fig.buttons['Zoom'].classList.remove('active');\n", " } else if (msg['mode'] === 'ZOOM') {\n", " fig.buttons['Pan'].classList.remove('active');\n", " fig.buttons['Zoom'].classList.add('active');\n", " } else {\n", " fig.buttons['Pan'].classList.remove('active');\n", " fig.buttons['Zoom'].classList.remove('active');\n", " }\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", "\n", " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", " evt.data\n", " );\n", " fig.updated_canvas_event();\n", " fig.waiting = false;\n", " return;\n", " } else if (\n", " typeof evt.data === 'string' &&\n", " evt.data.slice(0, 21) === 'data:image/png;base64'\n", " ) {\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(\n", " \"No handler for the '\" + msg_type + \"' message type: \",\n", " msg\n", " );\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(\n", " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", " e,\n", " e.stack,\n", " msg\n", " );\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", " }\n", " if (e.target) {\n", " targ = e.target;\n", " } else if (e.srcElement) {\n", " targ = e.srcElement;\n", " }\n", " if (targ.nodeType === 3) {\n", " // defeat Safari bug\n", " targ = targ.parentNode;\n", " }\n", "\n", " // pageX,Y are the mouse positions relative to the document\n", " var boundingRect = targ.getBoundingClientRect();\n", " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\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", " }\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", " this.canvas.focus();\n", " this.canvas_div.focus();\n", " }\n", "\n", " var x = canvas_pos.x * this.ratio;\n", " var y = canvas_pos.y * this.ratio;\n", "\n", " this.send_message(name, {\n", " x: x,\n", " y: y,\n", " button: event.button,\n", " step: event.step,\n", " guiEvent: simpleKeys(event),\n", " });\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", " // Prevent repeat events\n", " if (name === 'key_press') {\n", " if (event.which === this._key) {\n", " return;\n", " } else {\n", " this._key = event.which;\n", " }\n", " }\n", " if (name === 'key_release') {\n", " this._key = null;\n", " }\n", "\n", " var value = '';\n", " if (event.ctrlKey && event.which !== 17) {\n", " value += 'ctrl+';\n", " }\n", " if (event.altKey && event.which !== 18) {\n", " value += 'alt+';\n", " }\n", " if (event.shiftKey && event.which !== 16) {\n", " value += 'shift+';\n", " }\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, 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\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"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\";/* global mpl */\n", "\n", "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 overridden (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 = document.getElementById(id);\n", " var ws_proxy = comm_websocket_adapter(comm);\n", "\n", " function ondownload(figure, _format) {\n", " window.open(figure.canvas.toDataURL());\n", " }\n", "\n", " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\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;\n", " fig.cell_info = mpl.find_output_cell(\"
\");\n", " if (!fig.cell_info) {\n", " console.error('Failed to find cell for figure', id, fig);\n", " return;\n", " }\n", " fig.cell_info[0].output_area.element.one(\n", " 'cleared',\n", " { fig: fig },\n", " fig._remove_fig_handler\n", " );\n", "};\n", "\n", "mpl.figure.prototype.handle_close = function (fig, msg) {\n", " var width = fig.canvas.width / fig.ratio;\n", " fig.cell_info[0].output_area.element.off(\n", " 'cleared',\n", " fig._remove_fig_handler\n", " );\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.innerHTML =\n", " '';\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 width = this.canvas.width / this.ratio;\n", " var dataURL = this.canvas.toDataURL();\n", " this.cell_info[1]['text/html'] =\n", " '';\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 () {\n", " fig.push_to_output();\n", " }, 1000);\n", "};\n", "\n", "mpl.figure.prototype._init_toolbar = function () {\n", " var fig = this;\n", "\n", " var toolbar = document.createElement('div');\n", " toolbar.classList = 'btn-toolbar';\n", " this.root.appendChild(toolbar);\n", "\n", " function on_click_closure(name) {\n", " return function (_event) {\n", " return fig.toolbar_button_onclick(name);\n", " };\n", " }\n", "\n", " function on_mouseover_closure(tooltip) {\n", " return function (event) {\n", " if (!event.currentTarget.disabled) {\n", " return fig.toolbar_button_onmouseover(tooltip);\n", " }\n", " };\n", " }\n", "\n", " fig.buttons = {};\n", " var buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'btn-group';\n", " var button;\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", " /* Instead of a spacer, we start a new button group. */\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", " buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'btn-group';\n", " continue;\n", " }\n", "\n", " button = fig.buttons[name] = document.createElement('button');\n", " button.classList = 'btn btn-default';\n", " button.href = '#';\n", " button.title = name;\n", " button.innerHTML = '';\n", " button.addEventListener('click', on_click_closure(method_name));\n", " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", " buttonGroup.appendChild(button);\n", " }\n", "\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", "\n", " // Add the status bar.\n", " var status_bar = document.createElement('span');\n", " status_bar.classList = 'mpl-message pull-right';\n", " toolbar.appendChild(status_bar);\n", " this.message = status_bar;\n", "\n", " // Add the close button to the window.\n", " var buttongrp = document.createElement('div');\n", " buttongrp.classList = 'btn-group inline pull-right';\n", " button = document.createElement('button');\n", " button.classList = 'btn btn-mini btn-primary';\n", " button.href = '#';\n", " button.title = 'Stop Interaction';\n", " button.innerHTML = '';\n", " button.addEventListener('click', function (_evt) {\n", " fig.handle_close(fig, {});\n", " });\n", " button.addEventListener(\n", " 'mouseover',\n", " on_mouseover_closure('Stop Interaction')\n", " );\n", " buttongrp.appendChild(button);\n", " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", "};\n", "\n", "mpl.figure.prototype._remove_fig_handler = function (event) {\n", " var fig = event.data.fig;\n", " fig.close_ws(fig, {});\n", "};\n", "\n", "mpl.figure.prototype._root_extra_style = function (el) {\n", " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", "};\n", "\n", "mpl.figure.prototype._canvas_extra_style = function (el) {\n", " // this is important to make the div 'focusable\n", " el.setAttribute('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", " } else {\n", " // location in version 2\n", " IPython.keyboard_manager.register_events(el);\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", "\n", " // Check for shift+enter\n", " if (event.shiftKey && event.which === 13) {\n", " this.canvas_div.blur();\n", " // select the cell after this one\n", " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", " IPython.notebook.select(index + 1);\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", " fig.ondownload(fig, null);\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(\n", " 'matplotlib',\n", " mpl.mpl_figure_comm\n", " );\n", "}\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ " \n", "a95_th30 resolution: (500, 500, 3)\n", "figsize: (5.0, 5.0)\n", "a/m = 0.950000000000000 theta_obs = 1/6*pi\n", "extent: (-10.0963959215444, 10.0963959215444, -10.0963959215444, 10.0963959215444)\n", "rmin : 1.76846188276999 rmax : 3.23697774665377\n", "rmin_col : 1.3862805284629751 rmax_col : 3.95534731767268\n" ] }, { "data": { "application/javascript": [ "/* Put everything inside the global mpl namespace */\n", "/* global mpl */\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(\n", " '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", "\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 = document.createElement('div');\n", " this.root.setAttribute('style', 'display: inline-block');\n", " this._root_extra_style(this.root);\n", "\n", " parent_element.appendChild(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", " if (fig.ratio !== 1) {\n", " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", " }\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", " fig.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 = document.createElement('div');\n", " titlebar.classList =\n", " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", " var titletext = document.createElement('div');\n", " titletext.classList = 'ui-dialog-title';\n", " titletext.setAttribute(\n", " 'style',\n", " 'width: 100%; text-align: center; padding: 3px;'\n", " );\n", " titlebar.appendChild(titletext);\n", " this.root.appendChild(titlebar);\n", " this.header = titletext;\n", "};\n", "\n", "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", "\n", "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", "\n", "mpl.figure.prototype._init_canvas = function () {\n", " var fig = this;\n", "\n", " var canvas_div = (this.canvas_div = document.createElement('div'));\n", " canvas_div.setAttribute(\n", " 'style',\n", " 'border: 1px solid #ddd;' +\n", " 'box-sizing: content-box;' +\n", " 'clear: both;' +\n", " 'min-height: 1px;' +\n", " 'min-width: 1px;' +\n", " 'outline: 0;' +\n", " 'overflow: hidden;' +\n", " 'position: relative;' +\n", " 'resize: both;'\n", " );\n", "\n", " function on_keyboard_event_closure(name) {\n", " return function (event) {\n", " return fig.key_event(event, name);\n", " };\n", " }\n", "\n", " canvas_div.addEventListener(\n", " 'keydown',\n", " on_keyboard_event_closure('key_press')\n", " );\n", " canvas_div.addEventListener(\n", " 'keyup',\n", " on_keyboard_event_closure('key_release')\n", " );\n", "\n", " this._canvas_extra_style(canvas_div);\n", " this.root.appendChild(canvas_div);\n", "\n", " var canvas = (this.canvas = document.createElement('canvas'));\n", " canvas.classList.add('mpl-canvas');\n", " canvas.setAttribute('style', 'box-sizing: content-box;');\n", "\n", " this.context = canvas.getContext('2d');\n", "\n", " var backingStore =\n", " this.context.backingStorePixelRatio ||\n", " this.context.webkitBackingStorePixelRatio ||\n", " this.context.mozBackingStorePixelRatio ||\n", " this.context.msBackingStorePixelRatio ||\n", " this.context.oBackingStorePixelRatio ||\n", " this.context.backingStorePixelRatio ||\n", " 1;\n", "\n", " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", " if (this.ratio !== 1) {\n", " fig.send_message('set_dpi_ratio', { dpi_ratio: this.ratio });\n", " }\n", "\n", " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", " 'canvas'\n", " ));\n", " rubberband_canvas.setAttribute(\n", " 'style',\n", " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", " );\n", "\n", " var resizeObserver = new ResizeObserver(function (entries) {\n", " var nentries = entries.length;\n", " for (var i = 0; i < nentries; i++) {\n", " var entry = entries[i];\n", " var width, height;\n", " if (entry.contentBoxSize) {\n", " if (entry.contentBoxSize instanceof Array) {\n", " // Chrome 84 implements new version of spec.\n", " width = entry.contentBoxSize[0].inlineSize;\n", " height = entry.contentBoxSize[0].blockSize;\n", " } else {\n", " // Firefox implements old version of spec.\n", " width = entry.contentBoxSize.inlineSize;\n", " height = entry.contentBoxSize.blockSize;\n", " }\n", " } else {\n", " // Chrome <84 implements even older version of spec.\n", " width = entry.contentRect.width;\n", " height = entry.contentRect.height;\n", " }\n", "\n", " // Keep the size of the canvas and rubber band canvas in sync with\n", " // the canvas container.\n", " if (entry.devicePixelContentBoxSize) {\n", " // Chrome 84 implements new version of spec.\n", " canvas.setAttribute(\n", " 'width',\n", " entry.devicePixelContentBoxSize[0].inlineSize\n", " );\n", " canvas.setAttribute(\n", " 'height',\n", " entry.devicePixelContentBoxSize[0].blockSize\n", " );\n", " } else {\n", " canvas.setAttribute('width', width * fig.ratio);\n", " canvas.setAttribute('height', height * fig.ratio);\n", " }\n", " canvas.setAttribute(\n", " 'style',\n", " 'width: ' + width + 'px; height: ' + height + 'px;'\n", " );\n", "\n", " rubberband_canvas.setAttribute('width', width);\n", " rubberband_canvas.setAttribute('height', height);\n", "\n", " // And update the size in Python. We ignore the initial 0/0 size\n", " // that occurs as the element is placed into the DOM, which should\n", " // otherwise not happen due to the minimum size styling.\n", " if (width != 0 && height != 0) {\n", " fig.request_resize(width, height);\n", " }\n", " }\n", " });\n", " resizeObserver.observe(canvas_div);\n", "\n", " function on_mouse_event_closure(name) {\n", " return function (event) {\n", " return fig.mouse_event(event, name);\n", " };\n", " }\n", "\n", " rubberband_canvas.addEventListener(\n", " 'mousedown',\n", " on_mouse_event_closure('button_press')\n", " );\n", " rubberband_canvas.addEventListener(\n", " 'mouseup',\n", " on_mouse_event_closure('button_release')\n", " );\n", " // Throttle sequential mouse events to 1 every 20ms.\n", " rubberband_canvas.addEventListener(\n", " 'mousemove',\n", " on_mouse_event_closure('motion_notify')\n", " );\n", "\n", " rubberband_canvas.addEventListener(\n", " 'mouseenter',\n", " on_mouse_event_closure('figure_enter')\n", " );\n", " rubberband_canvas.addEventListener(\n", " 'mouseleave',\n", " on_mouse_event_closure('figure_leave')\n", " );\n", "\n", " canvas_div.addEventListener('wheel', function (event) {\n", " if (event.deltaY < 0) {\n", " event.step = 1;\n", " } else {\n", " event.step = -1;\n", " }\n", " on_mouse_event_closure('scroll')(event);\n", " });\n", "\n", " canvas_div.appendChild(canvas);\n", " canvas_div.appendChild(rubberband_canvas);\n", "\n", " this.rubberband_context = rubberband_canvas.getContext('2d');\n", " this.rubberband_context.strokeStyle = '#000000';\n", "\n", " this._resize_canvas = function (width, height, forward) {\n", " if (forward) {\n", " canvas_div.style.width = width + 'px';\n", " canvas_div.style.height = height + 'px';\n", " }\n", " };\n", "\n", " // Disable right mouse context menu.\n", " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", " event.preventDefault();\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 toolbar = document.createElement('div');\n", " toolbar.classList = 'mpl-toolbar';\n", " this.root.appendChild(toolbar);\n", "\n", " function on_click_closure(name) {\n", " return function (_event) {\n", " return fig.toolbar_button_onclick(name);\n", " };\n", " }\n", "\n", " function on_mouseover_closure(tooltip) {\n", " return function (event) {\n", " if (!event.currentTarget.disabled) {\n", " return fig.toolbar_button_onmouseover(tooltip);\n", " }\n", " };\n", " }\n", "\n", " fig.buttons = {};\n", " var buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'mpl-button-group';\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", " /* Instead of a spacer, we start a new button group. */\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", " buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'mpl-button-group';\n", " continue;\n", " }\n", "\n", " var button = (fig.buttons[name] = document.createElement('button'));\n", " button.classList = 'mpl-widget';\n", " button.setAttribute('role', 'button');\n", " button.setAttribute('aria-disabled', 'false');\n", " button.addEventListener('click', on_click_closure(method_name));\n", " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", "\n", " var icon_img = document.createElement('img');\n", " icon_img.src = '_images/' + image + '.png';\n", " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", " icon_img.alt = tooltip;\n", " button.appendChild(icon_img);\n", "\n", " buttonGroup.appendChild(button);\n", " }\n", "\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", "\n", " var fmt_picker = document.createElement('select');\n", " fmt_picker.classList = 'mpl-widget';\n", " toolbar.appendChild(fmt_picker);\n", " this.format_dropdown = fmt_picker;\n", "\n", " for (var ind in mpl.extensions) {\n", " var fmt = mpl.extensions[ind];\n", " var option = document.createElement('option');\n", " option.selected = fmt === mpl.default_extension;\n", " option.innerHTML = fmt;\n", " fmt_picker.appendChild(option);\n", " }\n", "\n", " var status_bar = document.createElement('span');\n", " status_bar.classList = 'mpl-message';\n", " toolbar.appendChild(status_bar);\n", " this.message = status_bar;\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", "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", "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], msg['forward']);\n", " fig.send_message('refresh', {});\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", " var x0 = msg['x0'] / fig.ratio;\n", " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", " var x1 = msg['x1'] / fig.ratio;\n", " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\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,\n", " 0,\n", " fig.canvas.width / fig.ratio,\n", " fig.canvas.height / fig.ratio\n", " );\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", " 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.handle_history_buttons = function (fig, msg) {\n", " for (var key in msg) {\n", " if (!(key in fig.buttons)) {\n", " continue;\n", " }\n", " fig.buttons[key].disabled = !msg[key];\n", " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", " if (msg['mode'] === 'PAN') {\n", " fig.buttons['Pan'].classList.add('active');\n", " fig.buttons['Zoom'].classList.remove('active');\n", " } else if (msg['mode'] === 'ZOOM') {\n", " fig.buttons['Pan'].classList.remove('active');\n", " fig.buttons['Zoom'].classList.add('active');\n", " } else {\n", " fig.buttons['Pan'].classList.remove('active');\n", " fig.buttons['Zoom'].classList.remove('active');\n", " }\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", "\n", " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", " evt.data\n", " );\n", " fig.updated_canvas_event();\n", " fig.waiting = false;\n", " return;\n", " } else if (\n", " typeof evt.data === 'string' &&\n", " evt.data.slice(0, 21) === 'data:image/png;base64'\n", " ) {\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(\n", " \"No handler for the '\" + msg_type + \"' message type: \",\n", " msg\n", " );\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(\n", " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", " e,\n", " e.stack,\n", " msg\n", " );\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", " }\n", " if (e.target) {\n", " targ = e.target;\n", " } else if (e.srcElement) {\n", " targ = e.srcElement;\n", " }\n", " if (targ.nodeType === 3) {\n", " // defeat Safari bug\n", " targ = targ.parentNode;\n", " }\n", "\n", " // pageX,Y are the mouse positions relative to the document\n", " var boundingRect = targ.getBoundingClientRect();\n", " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\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", " }\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", " this.canvas.focus();\n", " this.canvas_div.focus();\n", " }\n", "\n", " var x = canvas_pos.x * this.ratio;\n", " var y = canvas_pos.y * this.ratio;\n", "\n", " this.send_message(name, {\n", " x: x,\n", " y: y,\n", " button: event.button,\n", " step: event.step,\n", " guiEvent: simpleKeys(event),\n", " });\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", " // Prevent repeat events\n", " if (name === 'key_press') {\n", " if (event.which === this._key) {\n", " return;\n", " } else {\n", " this._key = event.which;\n", " }\n", " }\n", " if (name === 'key_release') {\n", " this._key = null;\n", " }\n", "\n", " var value = '';\n", " if (event.ctrlKey && event.which !== 17) {\n", " value += 'ctrl+';\n", " }\n", " if (event.altKey && event.which !== 18) {\n", " value += 'alt+';\n", " }\n", " if (event.shiftKey && event.which !== 16) {\n", " value += 'shift+';\n", " }\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, 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\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"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\";/* global mpl */\n", "\n", "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 overridden (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 = document.getElementById(id);\n", " var ws_proxy = comm_websocket_adapter(comm);\n", "\n", " function ondownload(figure, _format) {\n", " window.open(figure.canvas.toDataURL());\n", " }\n", "\n", " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\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;\n", " fig.cell_info = mpl.find_output_cell(\"
\");\n", " if (!fig.cell_info) {\n", " console.error('Failed to find cell for figure', id, fig);\n", " return;\n", " }\n", " fig.cell_info[0].output_area.element.one(\n", " 'cleared',\n", " { fig: fig },\n", " fig._remove_fig_handler\n", " );\n", "};\n", "\n", "mpl.figure.prototype.handle_close = function (fig, msg) {\n", " var width = fig.canvas.width / fig.ratio;\n", " fig.cell_info[0].output_area.element.off(\n", " 'cleared',\n", " fig._remove_fig_handler\n", " );\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.innerHTML =\n", " '';\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 width = this.canvas.width / this.ratio;\n", " var dataURL = this.canvas.toDataURL();\n", " this.cell_info[1]['text/html'] =\n", " '';\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 () {\n", " fig.push_to_output();\n", " }, 1000);\n", "};\n", "\n", "mpl.figure.prototype._init_toolbar = function () {\n", " var fig = this;\n", "\n", " var toolbar = document.createElement('div');\n", " toolbar.classList = 'btn-toolbar';\n", " this.root.appendChild(toolbar);\n", "\n", " function on_click_closure(name) {\n", " return function (_event) {\n", " return fig.toolbar_button_onclick(name);\n", " };\n", " }\n", "\n", " function on_mouseover_closure(tooltip) {\n", " return function (event) {\n", " if (!event.currentTarget.disabled) {\n", " return fig.toolbar_button_onmouseover(tooltip);\n", " }\n", " };\n", " }\n", "\n", " fig.buttons = {};\n", " var buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'btn-group';\n", " var button;\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", " /* Instead of a spacer, we start a new button group. */\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", " buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'btn-group';\n", " continue;\n", " }\n", "\n", " button = fig.buttons[name] = document.createElement('button');\n", " button.classList = 'btn btn-default';\n", " button.href = '#';\n", " button.title = name;\n", " button.innerHTML = '';\n", " button.addEventListener('click', on_click_closure(method_name));\n", " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", " buttonGroup.appendChild(button);\n", " }\n", "\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", "\n", " // Add the status bar.\n", " var status_bar = document.createElement('span');\n", " status_bar.classList = 'mpl-message pull-right';\n", " toolbar.appendChild(status_bar);\n", " this.message = status_bar;\n", "\n", " // Add the close button to the window.\n", " var buttongrp = document.createElement('div');\n", " buttongrp.classList = 'btn-group inline pull-right';\n", " button = document.createElement('button');\n", " button.classList = 'btn btn-mini btn-primary';\n", " button.href = '#';\n", " button.title = 'Stop Interaction';\n", " button.innerHTML = '';\n", " button.addEventListener('click', function (_evt) {\n", " fig.handle_close(fig, {});\n", " });\n", " button.addEventListener(\n", " 'mouseover',\n", " on_mouseover_closure('Stop Interaction')\n", " );\n", " buttongrp.appendChild(button);\n", " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", "};\n", "\n", "mpl.figure.prototype._remove_fig_handler = function (event) {\n", " var fig = event.data.fig;\n", " fig.close_ws(fig, {});\n", "};\n", "\n", "mpl.figure.prototype._root_extra_style = function (el) {\n", " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", "};\n", "\n", "mpl.figure.prototype._canvas_extra_style = function (el) {\n", " // this is important to make the div 'focusable\n", " el.setAttribute('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", " } else {\n", " // location in version 2\n", " IPython.keyboard_manager.register_events(el);\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", "\n", " // Check for shift+enter\n", " if (event.shiftKey && event.which === 13) {\n", " this.canvas_div.blur();\n", " // select the cell after this one\n", " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", " IPython.notebook.select(index + 1);\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", " fig.ondownload(fig, null);\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(\n", " 'matplotlib',\n", " mpl.mpl_figure_comm\n", " );\n", "}\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ " \n", "a95_th60 resolution: (500, 500, 3)\n", "figsize: (5.0, 5.0)\n", "a/m = 0.950000000000000 theta_obs = 1/3*pi\n", "extent: (-10.0963959215444, 10.0963959215444, -10.0963959215444, 10.0963959215444)\n", "rmin : 1.44011965009280 rmax : 3.76536147242618\n", "rmin_col : 1.3862805284629751 rmax_col : 3.95534731767268\n" ] }, { "data": { "application/javascript": [ "/* Put everything inside the global mpl namespace */\n", "/* global mpl */\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(\n", " '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", "\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 = document.createElement('div');\n", " this.root.setAttribute('style', 'display: inline-block');\n", " this._root_extra_style(this.root);\n", "\n", " parent_element.appendChild(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", " if (fig.ratio !== 1) {\n", " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", " }\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", " fig.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 = document.createElement('div');\n", " titlebar.classList =\n", " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", " var titletext = document.createElement('div');\n", " titletext.classList = 'ui-dialog-title';\n", " titletext.setAttribute(\n", " 'style',\n", " 'width: 100%; text-align: center; padding: 3px;'\n", " );\n", " titlebar.appendChild(titletext);\n", " this.root.appendChild(titlebar);\n", " this.header = titletext;\n", "};\n", "\n", "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", "\n", "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", "\n", "mpl.figure.prototype._init_canvas = function () {\n", " var fig = this;\n", "\n", " var canvas_div = (this.canvas_div = document.createElement('div'));\n", " canvas_div.setAttribute(\n", " 'style',\n", " 'border: 1px solid #ddd;' +\n", " 'box-sizing: content-box;' +\n", " 'clear: both;' +\n", " 'min-height: 1px;' +\n", " 'min-width: 1px;' +\n", " 'outline: 0;' +\n", " 'overflow: hidden;' +\n", " 'position: relative;' +\n", " 'resize: both;'\n", " );\n", "\n", " function on_keyboard_event_closure(name) {\n", " return function (event) {\n", " return fig.key_event(event, name);\n", " };\n", " }\n", "\n", " canvas_div.addEventListener(\n", " 'keydown',\n", " on_keyboard_event_closure('key_press')\n", " );\n", " canvas_div.addEventListener(\n", " 'keyup',\n", " on_keyboard_event_closure('key_release')\n", " );\n", "\n", " this._canvas_extra_style(canvas_div);\n", " this.root.appendChild(canvas_div);\n", "\n", " var canvas = (this.canvas = document.createElement('canvas'));\n", " canvas.classList.add('mpl-canvas');\n", " canvas.setAttribute('style', 'box-sizing: content-box;');\n", "\n", " this.context = canvas.getContext('2d');\n", "\n", " var backingStore =\n", " this.context.backingStorePixelRatio ||\n", " this.context.webkitBackingStorePixelRatio ||\n", " this.context.mozBackingStorePixelRatio ||\n", " this.context.msBackingStorePixelRatio ||\n", " this.context.oBackingStorePixelRatio ||\n", " this.context.backingStorePixelRatio ||\n", " 1;\n", "\n", " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", " if (this.ratio !== 1) {\n", " fig.send_message('set_dpi_ratio', { dpi_ratio: this.ratio });\n", " }\n", "\n", " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", " 'canvas'\n", " ));\n", " rubberband_canvas.setAttribute(\n", " 'style',\n", " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", " );\n", "\n", " var resizeObserver = new ResizeObserver(function (entries) {\n", " var nentries = entries.length;\n", " for (var i = 0; i < nentries; i++) {\n", " var entry = entries[i];\n", " var width, height;\n", " if (entry.contentBoxSize) {\n", " if (entry.contentBoxSize instanceof Array) {\n", " // Chrome 84 implements new version of spec.\n", " width = entry.contentBoxSize[0].inlineSize;\n", " height = entry.contentBoxSize[0].blockSize;\n", " } else {\n", " // Firefox implements old version of spec.\n", " width = entry.contentBoxSize.inlineSize;\n", " height = entry.contentBoxSize.blockSize;\n", " }\n", " } else {\n", " // Chrome <84 implements even older version of spec.\n", " width = entry.contentRect.width;\n", " height = entry.contentRect.height;\n", " }\n", "\n", " // Keep the size of the canvas and rubber band canvas in sync with\n", " // the canvas container.\n", " if (entry.devicePixelContentBoxSize) {\n", " // Chrome 84 implements new version of spec.\n", " canvas.setAttribute(\n", " 'width',\n", " entry.devicePixelContentBoxSize[0].inlineSize\n", " );\n", " canvas.setAttribute(\n", " 'height',\n", " entry.devicePixelContentBoxSize[0].blockSize\n", " );\n", " } else {\n", " canvas.setAttribute('width', width * fig.ratio);\n", " canvas.setAttribute('height', height * fig.ratio);\n", " }\n", " canvas.setAttribute(\n", " 'style',\n", " 'width: ' + width + 'px; height: ' + height + 'px;'\n", " );\n", "\n", " rubberband_canvas.setAttribute('width', width);\n", " rubberband_canvas.setAttribute('height', height);\n", "\n", " // And update the size in Python. We ignore the initial 0/0 size\n", " // that occurs as the element is placed into the DOM, which should\n", " // otherwise not happen due to the minimum size styling.\n", " if (width != 0 && height != 0) {\n", " fig.request_resize(width, height);\n", " }\n", " }\n", " });\n", " resizeObserver.observe(canvas_div);\n", "\n", " function on_mouse_event_closure(name) {\n", " return function (event) {\n", " return fig.mouse_event(event, name);\n", " };\n", " }\n", "\n", " rubberband_canvas.addEventListener(\n", " 'mousedown',\n", " on_mouse_event_closure('button_press')\n", " );\n", " rubberband_canvas.addEventListener(\n", " 'mouseup',\n", " on_mouse_event_closure('button_release')\n", " );\n", " // Throttle sequential mouse events to 1 every 20ms.\n", " rubberband_canvas.addEventListener(\n", " 'mousemove',\n", " on_mouse_event_closure('motion_notify')\n", " );\n", "\n", " rubberband_canvas.addEventListener(\n", " 'mouseenter',\n", " on_mouse_event_closure('figure_enter')\n", " );\n", " rubberband_canvas.addEventListener(\n", " 'mouseleave',\n", " on_mouse_event_closure('figure_leave')\n", " );\n", "\n", " canvas_div.addEventListener('wheel', function (event) {\n", " if (event.deltaY < 0) {\n", " event.step = 1;\n", " } else {\n", " event.step = -1;\n", " }\n", " on_mouse_event_closure('scroll')(event);\n", " });\n", "\n", " canvas_div.appendChild(canvas);\n", " canvas_div.appendChild(rubberband_canvas);\n", "\n", " this.rubberband_context = rubberband_canvas.getContext('2d');\n", " this.rubberband_context.strokeStyle = '#000000';\n", "\n", " this._resize_canvas = function (width, height, forward) {\n", " if (forward) {\n", " canvas_div.style.width = width + 'px';\n", " canvas_div.style.height = height + 'px';\n", " }\n", " };\n", "\n", " // Disable right mouse context menu.\n", " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", " event.preventDefault();\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 toolbar = document.createElement('div');\n", " toolbar.classList = 'mpl-toolbar';\n", " this.root.appendChild(toolbar);\n", "\n", " function on_click_closure(name) {\n", " return function (_event) {\n", " return fig.toolbar_button_onclick(name);\n", " };\n", " }\n", "\n", " function on_mouseover_closure(tooltip) {\n", " return function (event) {\n", " if (!event.currentTarget.disabled) {\n", " return fig.toolbar_button_onmouseover(tooltip);\n", " }\n", " };\n", " }\n", "\n", " fig.buttons = {};\n", " var buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'mpl-button-group';\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", " /* Instead of a spacer, we start a new button group. */\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", " buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'mpl-button-group';\n", " continue;\n", " }\n", "\n", " var button = (fig.buttons[name] = document.createElement('button'));\n", " button.classList = 'mpl-widget';\n", " button.setAttribute('role', 'button');\n", " button.setAttribute('aria-disabled', 'false');\n", " button.addEventListener('click', on_click_closure(method_name));\n", " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", "\n", " var icon_img = document.createElement('img');\n", " icon_img.src = '_images/' + image + '.png';\n", " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", " icon_img.alt = tooltip;\n", " button.appendChild(icon_img);\n", "\n", " buttonGroup.appendChild(button);\n", " }\n", "\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", "\n", " var fmt_picker = document.createElement('select');\n", " fmt_picker.classList = 'mpl-widget';\n", " toolbar.appendChild(fmt_picker);\n", " this.format_dropdown = fmt_picker;\n", "\n", " for (var ind in mpl.extensions) {\n", " var fmt = mpl.extensions[ind];\n", " var option = document.createElement('option');\n", " option.selected = fmt === mpl.default_extension;\n", " option.innerHTML = fmt;\n", " fmt_picker.appendChild(option);\n", " }\n", "\n", " var status_bar = document.createElement('span');\n", " status_bar.classList = 'mpl-message';\n", " toolbar.appendChild(status_bar);\n", " this.message = status_bar;\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", "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", "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], msg['forward']);\n", " fig.send_message('refresh', {});\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", " var x0 = msg['x0'] / fig.ratio;\n", " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", " var x1 = msg['x1'] / fig.ratio;\n", " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\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,\n", " 0,\n", " fig.canvas.width / fig.ratio,\n", " fig.canvas.height / fig.ratio\n", " );\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", " 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.handle_history_buttons = function (fig, msg) {\n", " for (var key in msg) {\n", " if (!(key in fig.buttons)) {\n", " continue;\n", " }\n", " fig.buttons[key].disabled = !msg[key];\n", " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", " if (msg['mode'] === 'PAN') {\n", " fig.buttons['Pan'].classList.add('active');\n", " fig.buttons['Zoom'].classList.remove('active');\n", " } else if (msg['mode'] === 'ZOOM') {\n", " fig.buttons['Pan'].classList.remove('active');\n", " fig.buttons['Zoom'].classList.add('active');\n", " } else {\n", " fig.buttons['Pan'].classList.remove('active');\n", " fig.buttons['Zoom'].classList.remove('active');\n", " }\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", "\n", " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", " evt.data\n", " );\n", " fig.updated_canvas_event();\n", " fig.waiting = false;\n", " return;\n", " } else if (\n", " typeof evt.data === 'string' &&\n", " evt.data.slice(0, 21) === 'data:image/png;base64'\n", " ) {\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(\n", " \"No handler for the '\" + msg_type + \"' message type: \",\n", " msg\n", " );\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(\n", " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", " e,\n", " e.stack,\n", " msg\n", " );\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", " }\n", " if (e.target) {\n", " targ = e.target;\n", " } else if (e.srcElement) {\n", " targ = e.srcElement;\n", " }\n", " if (targ.nodeType === 3) {\n", " // defeat Safari bug\n", " targ = targ.parentNode;\n", " }\n", "\n", " // pageX,Y are the mouse positions relative to the document\n", " var boundingRect = targ.getBoundingClientRect();\n", " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\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", " }\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", " this.canvas.focus();\n", " this.canvas_div.focus();\n", " }\n", "\n", " var x = canvas_pos.x * this.ratio;\n", " var y = canvas_pos.y * this.ratio;\n", "\n", " this.send_message(name, {\n", " x: x,\n", " y: y,\n", " button: event.button,\n", " step: event.step,\n", " guiEvent: simpleKeys(event),\n", " });\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", " // Prevent repeat events\n", " if (name === 'key_press') {\n", " if (event.which === this._key) {\n", " return;\n", " } else {\n", " this._key = event.which;\n", " }\n", " }\n", " if (name === 'key_release') {\n", " this._key = null;\n", " }\n", "\n", " var value = '';\n", " if (event.ctrlKey && event.which !== 17) {\n", " value += 'ctrl+';\n", " }\n", " if (event.altKey && event.which !== 18) {\n", " value += 'alt+';\n", " }\n", " if (event.shiftKey && event.which !== 16) {\n", " value += 'shift+';\n", " }\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, 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\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"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\";/* global mpl */\n", "\n", "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 overridden (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 = document.getElementById(id);\n", " var ws_proxy = comm_websocket_adapter(comm);\n", "\n", " function ondownload(figure, _format) {\n", " window.open(figure.canvas.toDataURL());\n", " }\n", "\n", " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\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;\n", " fig.cell_info = mpl.find_output_cell(\"
\");\n", " if (!fig.cell_info) {\n", " console.error('Failed to find cell for figure', id, fig);\n", " return;\n", " }\n", " fig.cell_info[0].output_area.element.one(\n", " 'cleared',\n", " { fig: fig },\n", " fig._remove_fig_handler\n", " );\n", "};\n", "\n", "mpl.figure.prototype.handle_close = function (fig, msg) {\n", " var width = fig.canvas.width / fig.ratio;\n", " fig.cell_info[0].output_area.element.off(\n", " 'cleared',\n", " fig._remove_fig_handler\n", " );\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.innerHTML =\n", " '';\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 width = this.canvas.width / this.ratio;\n", " var dataURL = this.canvas.toDataURL();\n", " this.cell_info[1]['text/html'] =\n", " '';\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 () {\n", " fig.push_to_output();\n", " }, 1000);\n", "};\n", "\n", "mpl.figure.prototype._init_toolbar = function () {\n", " var fig = this;\n", "\n", " var toolbar = document.createElement('div');\n", " toolbar.classList = 'btn-toolbar';\n", " this.root.appendChild(toolbar);\n", "\n", " function on_click_closure(name) {\n", " return function (_event) {\n", " return fig.toolbar_button_onclick(name);\n", " };\n", " }\n", "\n", " function on_mouseover_closure(tooltip) {\n", " return function (event) {\n", " if (!event.currentTarget.disabled) {\n", " return fig.toolbar_button_onmouseover(tooltip);\n", " }\n", " };\n", " }\n", "\n", " fig.buttons = {};\n", " var buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'btn-group';\n", " var button;\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", " /* Instead of a spacer, we start a new button group. */\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", " buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'btn-group';\n", " continue;\n", " }\n", "\n", " button = fig.buttons[name] = document.createElement('button');\n", " button.classList = 'btn btn-default';\n", " button.href = '#';\n", " button.title = name;\n", " button.innerHTML = '';\n", " button.addEventListener('click', on_click_closure(method_name));\n", " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", " buttonGroup.appendChild(button);\n", " }\n", "\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", "\n", " // Add the status bar.\n", " var status_bar = document.createElement('span');\n", " status_bar.classList = 'mpl-message pull-right';\n", " toolbar.appendChild(status_bar);\n", " this.message = status_bar;\n", "\n", " // Add the close button to the window.\n", " var buttongrp = document.createElement('div');\n", " buttongrp.classList = 'btn-group inline pull-right';\n", " button = document.createElement('button');\n", " button.classList = 'btn btn-mini btn-primary';\n", " button.href = '#';\n", " button.title = 'Stop Interaction';\n", " button.innerHTML = '';\n", " button.addEventListener('click', function (_evt) {\n", " fig.handle_close(fig, {});\n", " });\n", " button.addEventListener(\n", " 'mouseover',\n", " on_mouseover_closure('Stop Interaction')\n", " );\n", " buttongrp.appendChild(button);\n", " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", "};\n", "\n", "mpl.figure.prototype._remove_fig_handler = function (event) {\n", " var fig = event.data.fig;\n", " fig.close_ws(fig, {});\n", "};\n", "\n", "mpl.figure.prototype._root_extra_style = function (el) {\n", " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", "};\n", "\n", "mpl.figure.prototype._canvas_extra_style = function (el) {\n", " // this is important to make the div 'focusable\n", " el.setAttribute('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", " } else {\n", " // location in version 2\n", " IPython.keyboard_manager.register_events(el);\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", "\n", " // Check for shift+enter\n", " if (event.shiftKey && event.which === 13) {\n", " this.canvas_div.blur();\n", " // select the cell after this one\n", " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", " IPython.notebook.select(index + 1);\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", " fig.ondownload(fig, null);\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(\n", " 'matplotlib',\n", " mpl.mpl_figure_comm\n", " );\n", "}\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ " \n", "a95_th90 resolution: (500, 500, 3)\n", "figsize: (5.0, 5.0)\n", "a/m = 0.950000000000000 theta_obs = 1/2*pi\n", "extent: (-10.0963959215444, 10.0963959215444, -10.0963959215444, 10.0963959215444)\n", "rmin : 1.38628054232578 rmax : 3.95534727811920\n", "rmin_col : 1.3862805284629751 rmax_col : 3.95534731767268\n" ] }, { "data": { "application/javascript": [ "/* Put everything inside the global mpl namespace */\n", "/* global mpl */\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(\n", " '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", "\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 = document.createElement('div');\n", " this.root.setAttribute('style', 'display: inline-block');\n", " this._root_extra_style(this.root);\n", "\n", " parent_element.appendChild(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", " if (fig.ratio !== 1) {\n", " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", " }\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", " fig.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 = document.createElement('div');\n", " titlebar.classList =\n", " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", " var titletext = document.createElement('div');\n", " titletext.classList = 'ui-dialog-title';\n", " titletext.setAttribute(\n", " 'style',\n", " 'width: 100%; text-align: center; padding: 3px;'\n", " );\n", " titlebar.appendChild(titletext);\n", " this.root.appendChild(titlebar);\n", " this.header = titletext;\n", "};\n", "\n", "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", "\n", "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", "\n", "mpl.figure.prototype._init_canvas = function () {\n", " var fig = this;\n", "\n", " var canvas_div = (this.canvas_div = document.createElement('div'));\n", " canvas_div.setAttribute(\n", " 'style',\n", " 'border: 1px solid #ddd;' +\n", " 'box-sizing: content-box;' +\n", " 'clear: both;' +\n", " 'min-height: 1px;' +\n", " 'min-width: 1px;' +\n", " 'outline: 0;' +\n", " 'overflow: hidden;' +\n", " 'position: relative;' +\n", " 'resize: both;'\n", " );\n", "\n", " function on_keyboard_event_closure(name) {\n", " return function (event) {\n", " return fig.key_event(event, name);\n", " };\n", " }\n", "\n", " canvas_div.addEventListener(\n", " 'keydown',\n", " on_keyboard_event_closure('key_press')\n", " );\n", " canvas_div.addEventListener(\n", " 'keyup',\n", " on_keyboard_event_closure('key_release')\n", " );\n", "\n", " this._canvas_extra_style(canvas_div);\n", " this.root.appendChild(canvas_div);\n", "\n", " var canvas = (this.canvas = document.createElement('canvas'));\n", " canvas.classList.add('mpl-canvas');\n", " canvas.setAttribute('style', 'box-sizing: content-box;');\n", "\n", " this.context = canvas.getContext('2d');\n", "\n", " var backingStore =\n", " this.context.backingStorePixelRatio ||\n", " this.context.webkitBackingStorePixelRatio ||\n", " this.context.mozBackingStorePixelRatio ||\n", " this.context.msBackingStorePixelRatio ||\n", " this.context.oBackingStorePixelRatio ||\n", " this.context.backingStorePixelRatio ||\n", " 1;\n", "\n", " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", " if (this.ratio !== 1) {\n", " fig.send_message('set_dpi_ratio', { dpi_ratio: this.ratio });\n", " }\n", "\n", " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", " 'canvas'\n", " ));\n", " rubberband_canvas.setAttribute(\n", " 'style',\n", " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", " );\n", "\n", " var resizeObserver = new ResizeObserver(function (entries) {\n", " var nentries = entries.length;\n", " for (var i = 0; i < nentries; i++) {\n", " var entry = entries[i];\n", " var width, height;\n", " if (entry.contentBoxSize) {\n", " if (entry.contentBoxSize instanceof Array) {\n", " // Chrome 84 implements new version of spec.\n", " width = entry.contentBoxSize[0].inlineSize;\n", " height = entry.contentBoxSize[0].blockSize;\n", " } else {\n", " // Firefox implements old version of spec.\n", " width = entry.contentBoxSize.inlineSize;\n", " height = entry.contentBoxSize.blockSize;\n", " }\n", " } else {\n", " // Chrome <84 implements even older version of spec.\n", " width = entry.contentRect.width;\n", " height = entry.contentRect.height;\n", " }\n", "\n", " // Keep the size of the canvas and rubber band canvas in sync with\n", " // the canvas container.\n", " if (entry.devicePixelContentBoxSize) {\n", " // Chrome 84 implements new version of spec.\n", " canvas.setAttribute(\n", " 'width',\n", " entry.devicePixelContentBoxSize[0].inlineSize\n", " );\n", " canvas.setAttribute(\n", " 'height',\n", " entry.devicePixelContentBoxSize[0].blockSize\n", " );\n", " } else {\n", " canvas.setAttribute('width', width * fig.ratio);\n", " canvas.setAttribute('height', height * fig.ratio);\n", " }\n", " canvas.setAttribute(\n", " 'style',\n", " 'width: ' + width + 'px; height: ' + height + 'px;'\n", " );\n", "\n", " rubberband_canvas.setAttribute('width', width);\n", " rubberband_canvas.setAttribute('height', height);\n", "\n", " // And update the size in Python. We ignore the initial 0/0 size\n", " // that occurs as the element is placed into the DOM, which should\n", " // otherwise not happen due to the minimum size styling.\n", " if (width != 0 && height != 0) {\n", " fig.request_resize(width, height);\n", " }\n", " }\n", " });\n", " resizeObserver.observe(canvas_div);\n", "\n", " function on_mouse_event_closure(name) {\n", " return function (event) {\n", " return fig.mouse_event(event, name);\n", " };\n", " }\n", "\n", " rubberband_canvas.addEventListener(\n", " 'mousedown',\n", " on_mouse_event_closure('button_press')\n", " );\n", " rubberband_canvas.addEventListener(\n", " 'mouseup',\n", " on_mouse_event_closure('button_release')\n", " );\n", " // Throttle sequential mouse events to 1 every 20ms.\n", " rubberband_canvas.addEventListener(\n", " 'mousemove',\n", " on_mouse_event_closure('motion_notify')\n", " );\n", "\n", " rubberband_canvas.addEventListener(\n", " 'mouseenter',\n", " on_mouse_event_closure('figure_enter')\n", " );\n", " rubberband_canvas.addEventListener(\n", " 'mouseleave',\n", " on_mouse_event_closure('figure_leave')\n", " );\n", "\n", " canvas_div.addEventListener('wheel', function (event) {\n", " if (event.deltaY < 0) {\n", " event.step = 1;\n", " } else {\n", " event.step = -1;\n", " }\n", " on_mouse_event_closure('scroll')(event);\n", " });\n", "\n", " canvas_div.appendChild(canvas);\n", " canvas_div.appendChild(rubberband_canvas);\n", "\n", " this.rubberband_context = rubberband_canvas.getContext('2d');\n", " this.rubberband_context.strokeStyle = '#000000';\n", "\n", " this._resize_canvas = function (width, height, forward) {\n", " if (forward) {\n", " canvas_div.style.width = width + 'px';\n", " canvas_div.style.height = height + 'px';\n", " }\n", " };\n", "\n", " // Disable right mouse context menu.\n", " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", " event.preventDefault();\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 toolbar = document.createElement('div');\n", " toolbar.classList = 'mpl-toolbar';\n", " this.root.appendChild(toolbar);\n", "\n", " function on_click_closure(name) {\n", " return function (_event) {\n", " return fig.toolbar_button_onclick(name);\n", " };\n", " }\n", "\n", " function on_mouseover_closure(tooltip) {\n", " return function (event) {\n", " if (!event.currentTarget.disabled) {\n", " return fig.toolbar_button_onmouseover(tooltip);\n", " }\n", " };\n", " }\n", "\n", " fig.buttons = {};\n", " var buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'mpl-button-group';\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", " /* Instead of a spacer, we start a new button group. */\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", " buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'mpl-button-group';\n", " continue;\n", " }\n", "\n", " var button = (fig.buttons[name] = document.createElement('button'));\n", " button.classList = 'mpl-widget';\n", " button.setAttribute('role', 'button');\n", " button.setAttribute('aria-disabled', 'false');\n", " button.addEventListener('click', on_click_closure(method_name));\n", " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", "\n", " var icon_img = document.createElement('img');\n", " icon_img.src = '_images/' + image + '.png';\n", " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", " icon_img.alt = tooltip;\n", " button.appendChild(icon_img);\n", "\n", " buttonGroup.appendChild(button);\n", " }\n", "\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", "\n", " var fmt_picker = document.createElement('select');\n", " fmt_picker.classList = 'mpl-widget';\n", " toolbar.appendChild(fmt_picker);\n", " this.format_dropdown = fmt_picker;\n", "\n", " for (var ind in mpl.extensions) {\n", " var fmt = mpl.extensions[ind];\n", " var option = document.createElement('option');\n", " option.selected = fmt === mpl.default_extension;\n", " option.innerHTML = fmt;\n", " fmt_picker.appendChild(option);\n", " }\n", "\n", " var status_bar = document.createElement('span');\n", " status_bar.classList = 'mpl-message';\n", " toolbar.appendChild(status_bar);\n", " this.message = status_bar;\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", "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", "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], msg['forward']);\n", " fig.send_message('refresh', {});\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", " var x0 = msg['x0'] / fig.ratio;\n", " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", " var x1 = msg['x1'] / fig.ratio;\n", " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\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,\n", " 0,\n", " fig.canvas.width / fig.ratio,\n", " fig.canvas.height / fig.ratio\n", " );\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", " 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.handle_history_buttons = function (fig, msg) {\n", " for (var key in msg) {\n", " if (!(key in fig.buttons)) {\n", " continue;\n", " }\n", " fig.buttons[key].disabled = !msg[key];\n", " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", " if (msg['mode'] === 'PAN') {\n", " fig.buttons['Pan'].classList.add('active');\n", " fig.buttons['Zoom'].classList.remove('active');\n", " } else if (msg['mode'] === 'ZOOM') {\n", " fig.buttons['Pan'].classList.remove('active');\n", " fig.buttons['Zoom'].classList.add('active');\n", " } else {\n", " fig.buttons['Pan'].classList.remove('active');\n", " fig.buttons['Zoom'].classList.remove('active');\n", " }\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", "\n", " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", " evt.data\n", " );\n", " fig.updated_canvas_event();\n", " fig.waiting = false;\n", " return;\n", " } else if (\n", " typeof evt.data === 'string' &&\n", " evt.data.slice(0, 21) === 'data:image/png;base64'\n", " ) {\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(\n", " \"No handler for the '\" + msg_type + \"' message type: \",\n", " msg\n", " );\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(\n", " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", " e,\n", " e.stack,\n", " msg\n", " );\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", " }\n", " if (e.target) {\n", " targ = e.target;\n", " } else if (e.srcElement) {\n", " targ = e.srcElement;\n", " }\n", " if (targ.nodeType === 3) {\n", " // defeat Safari bug\n", " targ = targ.parentNode;\n", " }\n", "\n", " // pageX,Y are the mouse positions relative to the document\n", " var boundingRect = targ.getBoundingClientRect();\n", " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\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", " }\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", " this.canvas.focus();\n", " this.canvas_div.focus();\n", " }\n", "\n", " var x = canvas_pos.x * this.ratio;\n", " var y = canvas_pos.y * this.ratio;\n", "\n", " this.send_message(name, {\n", " x: x,\n", " y: y,\n", " button: event.button,\n", " step: event.step,\n", " guiEvent: simpleKeys(event),\n", " });\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", " // Prevent repeat events\n", " if (name === 'key_press') {\n", " if (event.which === this._key) {\n", " return;\n", " } else {\n", " this._key = event.which;\n", " }\n", " }\n", " if (name === 'key_release') {\n", " this._key = null;\n", " }\n", "\n", " var value = '';\n", " if (event.ctrlKey && event.which !== 17) {\n", " value += 'ctrl+';\n", " }\n", " if (event.altKey && event.which !== 18) {\n", " value += 'alt+';\n", " }\n", " if (event.shiftKey && event.which !== 16) {\n", " value += 'shift+';\n", " }\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, 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\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"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\";/* global mpl */\n", "\n", "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 overridden (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 = document.getElementById(id);\n", " var ws_proxy = comm_websocket_adapter(comm);\n", "\n", " function ondownload(figure, _format) {\n", " window.open(figure.canvas.toDataURL());\n", " }\n", "\n", " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\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;\n", " fig.cell_info = mpl.find_output_cell(\"
\");\n", " if (!fig.cell_info) {\n", " console.error('Failed to find cell for figure', id, fig);\n", " return;\n", " }\n", " fig.cell_info[0].output_area.element.one(\n", " 'cleared',\n", " { fig: fig },\n", " fig._remove_fig_handler\n", " );\n", "};\n", "\n", "mpl.figure.prototype.handle_close = function (fig, msg) {\n", " var width = fig.canvas.width / fig.ratio;\n", " fig.cell_info[0].output_area.element.off(\n", " 'cleared',\n", " fig._remove_fig_handler\n", " );\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.innerHTML =\n", " '';\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 width = this.canvas.width / this.ratio;\n", " var dataURL = this.canvas.toDataURL();\n", " this.cell_info[1]['text/html'] =\n", " '';\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 () {\n", " fig.push_to_output();\n", " }, 1000);\n", "};\n", "\n", "mpl.figure.prototype._init_toolbar = function () {\n", " var fig = this;\n", "\n", " var toolbar = document.createElement('div');\n", " toolbar.classList = 'btn-toolbar';\n", " this.root.appendChild(toolbar);\n", "\n", " function on_click_closure(name) {\n", " return function (_event) {\n", " return fig.toolbar_button_onclick(name);\n", " };\n", " }\n", "\n", " function on_mouseover_closure(tooltip) {\n", " return function (event) {\n", " if (!event.currentTarget.disabled) {\n", " return fig.toolbar_button_onmouseover(tooltip);\n", " }\n", " };\n", " }\n", "\n", " fig.buttons = {};\n", " var buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'btn-group';\n", " var button;\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", " /* Instead of a spacer, we start a new button group. */\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", " buttonGroup = document.createElement('div');\n", " buttonGroup.classList = 'btn-group';\n", " continue;\n", " }\n", "\n", " button = fig.buttons[name] = document.createElement('button');\n", " button.classList = 'btn btn-default';\n", " button.href = '#';\n", " button.title = name;\n", " button.innerHTML = '';\n", " button.addEventListener('click', on_click_closure(method_name));\n", " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", " buttonGroup.appendChild(button);\n", " }\n", "\n", " if (buttonGroup.hasChildNodes()) {\n", " toolbar.appendChild(buttonGroup);\n", " }\n", "\n", " // Add the status bar.\n", " var status_bar = document.createElement('span');\n", " status_bar.classList = 'mpl-message pull-right';\n", " toolbar.appendChild(status_bar);\n", " this.message = status_bar;\n", "\n", " // Add the close button to the window.\n", " var buttongrp = document.createElement('div');\n", " buttongrp.classList = 'btn-group inline pull-right';\n", " button = document.createElement('button');\n", " button.classList = 'btn btn-mini btn-primary';\n", " button.href = '#';\n", " button.title = 'Stop Interaction';\n", " button.innerHTML = '';\n", " button.addEventListener('click', function (_evt) {\n", " fig.handle_close(fig, {});\n", " });\n", " button.addEventListener(\n", " 'mouseover',\n", " on_mouseover_closure('Stop Interaction')\n", " );\n", " buttongrp.appendChild(button);\n", " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", "};\n", "\n", "mpl.figure.prototype._remove_fig_handler = function (event) {\n", " var fig = event.data.fig;\n", " fig.close_ws(fig, {});\n", "};\n", "\n", "mpl.figure.prototype._root_extra_style = function (el) {\n", " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", "};\n", "\n", "mpl.figure.prototype._canvas_extra_style = function (el) {\n", " // this is important to make the div 'focusable\n", " el.setAttribute('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", " } else {\n", " // location in version 2\n", " IPython.keyboard_manager.register_events(el);\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", "\n", " // Check for shift+enter\n", " if (event.shiftKey && event.which === 13) {\n", " this.canvas_div.blur();\n", " // select the cell after this one\n", " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", " IPython.notebook.select(index + 1);\n", " }\n", "};\n", "\n", "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", " fig.ondownload(fig, null);\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(\n", " 'matplotlib',\n", " mpl.mpl_figure_comm\n", " );\n", "}\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ " \n" ] } ], "source": [ "%display plain\n", "%matplotlib notebook\n", "frame = True\n", "figsize_factor = 1 # default: 1\n", "axes_labels = 'automatic'\n", "#axes_labels = False\n", "test_size = False\n", "raw = False\n", "for gimage, param in gyoto_images.items():\n", " img = mpimg.imread(gimage + '.png')\n", " print(gimage, \" resolution:\", img.shape)\n", " # size of the image in inches:\n", " figsize = (float(img.shape[0])/dpi*figsize_factor, \n", " float(img.shape[1])/dpi*figsize_factor)\n", " print(\"figsize: \", figsize)\n", " a0, th_obs = param[:2]\n", " print(\"a/m =\", a0, \" theta_obs =\", th_obs)\n", " if len(param) > 2:\n", " resol = param[2]\n", " imin = param[3] - 1\n", " jmin = param[4] - 1\n", " else:\n", " resol = img.shape[0]\n", " imin = 0\n", " jmin = 0\n", " imax = imin + img.shape[1]\n", " jmax = jmin + img.shape[0]\n", " xmin = (imin - resol/2)/resol * 2*fsize\n", " xmax = (imax - resol/2)/resol * 2*fsize\n", " ymin = (jmin - resol/2)/resol * 2*fsize\n", " ymax = (jmax - resol/2)/resol * 2*fsize\n", " extent = (xmin, xmax, ymin, ymax)\n", " print(\"extent: \", extent)\n", " # Critical curve as a SageMath graphics object from shadow_plot\n", " if th_obs == 0:\n", " th_obs = 0.001\n", " if not raw:\n", " gcrit = shadow_plot(a0, th_obs, fill=False, color='red', number_colors=1, \n", " thickness=1.5, linestyle=':', frame=frame, axes=False, \n", " axes_labels=axes_labels, gridlines=False, legend=False)\n", " else:\n", " gcrit = empty_plot(fsize, axes_labels=axes_labels, frame=frame)\n", " if test_size:\n", " axes_labels_bck = gcrit.axes_labels()\n", " gcrit += point((-fsize, 0), size=60, color='red', zorder=100)\n", " gcrit += point((fsize, 0), size=60, color='red', zorder=100)\n", " gcrit += point((0, -fsize), size=60, color='red', zorder=100)\n", " gcrit += point((0, fsize), size=60, color='red', zorder=100)\n", " gcrit.axes_labels(axes_labels_bck)\n", " gcrit.set_axes_range(xmin, xmax, ymin, ymax)\n", " # Matplotlib figure corresponding to gcrit:\n", " options = gcrit.SHOW_OPTIONS.copy()\n", " options.update(gcrit._extra_kwds)\n", " options['figsize'] = figsize\n", " options['axes_pad'] = 0\n", " options.pop('dpi') # strip meaningless options for matplotlib\n", " options.pop('transparent') #\n", " options.pop('fig_tight') #\n", " fcrit = gcrit.matplotlib(**options)\n", " # Adding the Gyoto image onto it:\n", " ax = fcrit.axes[0]\n", " ax.imshow(img, extent=extent)\n", " # Save result to png and pdf\n", " ext = '_raw' if raw else '_crit'\n", " fcrit.savefig(gimage + ext + '.png', dpi=dpi, pad_inches=0, \n", " bbox_inches='tight', transparent=True)\n", " fcrit.savefig(gimage + ext + '.pdf', pad_inches=0, \n", " bbox_inches='tight')\n", " # Only for display in the current notebook:\n", " fig = plt.figure(figsize=figsize, dpi=dpi, frameon=False)\n", " imgc = mpimg.imread(gimage + '_crit.png')\n", " if axes_labels:\n", " imgcp = plt.imshow(imgc)\n", " else:\n", " imgcp = plt.imshow(imgc, extent=extent)\n", " print(\" \")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "SageMath 9.3.beta8", "language": "sage", "name": "sagemath" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.5" } }, "nbformat": 4, "nbformat_minor": 4 }