From be129a3abf3d8db7037962952f60268ab80d0b0f Mon Sep 17 00:00:00 2001 From: fdobad Date: Fri, 28 Jun 2019 14:53:19 -0400 Subject: [PATCH 1/3] Furthering examples with a quick and raw plot and changing output size question --- examples/ipympl.ipynb | 509 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 508 insertions(+), 1 deletion(-) diff --git a/examples/ipympl.ipynb b/examples/ipympl.ipynb index 4f8bb161..6dee01f9 100644 --- a/examples/ipympl.ipynb +++ b/examples/ipympl.ipynb @@ -151,6 +151,513 @@ "metadata": {}, "outputs": [], "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Multiple independent axes, same plot\n", + "This constructive tutorial aims to enhance the following example, automating the creation of new independent, but in the same plot, axes. Providing a final reusable function DisjointPlot(data,names)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Based on matplotlib example demo_parasite_axes2\n", + "https://matplotlib.org/examples/axes_grid/demo_parasite_axes2.html" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib widget\n", + "from mpl_toolkits.axes_grid1 import host_subplot\n", + "import mpl_toolkits.axisartist as AA\n", + "import matplotlib.pyplot as plt\n", + "\n", + "host = host_subplot(111, axes_class=AA.Axes)\n", + "plt.subplots_adjust(right=0.75)\n", + "\n", + "par1 = host.twinx()\n", + "par2 = host.twinx()\n", + "\n", + "new_fixed_axis = par1.get_grid_helper().new_fixed_axis\n", + "par1.axis[\"right\"] = new_fixed_axis(loc=\"right\", axes=par1,\n", + " offset=(0, 0))\n", + "par1.axis[\"right\"].toggle(all=True)\n", + "offset = 60\n", + "new_fixed_axis2 = par2.get_grid_helper().new_fixed_axis\n", + "par2.axis[\"right\"] = new_fixed_axis2(loc=\"right\", axes=par2,\n", + " offset=(offset, 0))\n", + "par2.axis[\"right\"].toggle(all=True)\n", + "\n", + "host.set_xlim(0, 2)\n", + "host.set_ylim(0, 2)\n", + "\n", + "host.set_xlabel(\"Distance\")\n", + "host.set_ylabel(\"Density\")\n", + "par1.set_ylabel(\"Temperature\")\n", + "par2.set_ylabel(\"Velocity\")\n", + "\n", + "p1, = host.plot([0, 1, 2], [0, 1, 2], label=\"Density\")\n", + "p2, = par1.plot([0, 1, 2], [0, 3, 2], label=\"Temperature\")\n", + "p3, = par2.plot([0, 1, 2], [50, 30, 15], label=\"Velocity\")\n", + "\n", + "par1.set_ylim(0, 4)\n", + "par2.set_ylim(1, 65)\n", + "\n", + "host.legend()\n", + "\n", + "host.axis[\"left\"].label.set_color(p1.get_color())\n", + "par1.axis[\"right\"].label.set_color(p2.get_color())\n", + "par2.axis[\"right\"].label.set_color(p3.get_color())\n", + "\n", + "plt.draw()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## + 1 axis" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib widget\n", + "from mpl_toolkits.axes_grid1 import host_subplot\n", + "import mpl_toolkits.axisartist as AA\n", + "import matplotlib.pyplot as plt\n", + "\n", + "host = host_subplot(111, axes_class=AA.Axes)\n", + "plt.subplots_adjust(right=0.7)\n", + "\n", + "par1 = host.twinx()\n", + "par2 = host.twinx()\n", + "par3 = host.twinx()\n", + "\n", + "new_fixed_axis1 = par1.get_grid_helper().new_fixed_axis\n", + "par1.axis[\"right\"] = new_fixed_axis1(loc=\"right\", axes=par1, offset=(0, 0))\n", + "par1.axis[\"right\"].toggle(all=True)\n", + "\n", + "offset = 45\n", + "new_fixed_axis2 = par2.get_grid_helper().new_fixed_axis\n", + "par2.axis[\"right\"] = new_fixed_axis2(loc=\"right\", axes=par2, offset=(offset, 0))\n", + "par2.axis[\"right\"].toggle(all=True)\n", + "#\n", + "new_fixed_axis3 = par3.get_grid_helper().new_fixed_axis\n", + "par3.axis[\"right\"] = new_fixed_axis3(loc=\"right\", axes=par3, offset=(2*offset, 0))\n", + "par3.axis[\"right\"].toggle(all=True)\n", + "\n", + "host.set_xlim(0, 2)\n", + "host.set_ylim(0, 2)\n", + "\n", + "host.set_xlabel(\"Distance\")\n", + "host.set_ylabel(\"Density\")\n", + "par1.set_ylabel(\"Temperature\")\n", + "par2.set_ylabel(\"Velocity\")\n", + "par3.set_ylabel(\"Luminocity\")\n", + "\n", + "p1, = host.plot([0, 1, 2], [0, 1, 2], label=\"Density\")\n", + "p2, = par1.plot([0, 1, 2], [0, 3, 2], label=\"Temperature\")\n", + "p3, = par2.plot([0, 1, 2], [50, 30, 15], label=\"Velocity\")\n", + "p4, = par3.plot([0, 1, 2], [69, 250, 600], label=\"Luminocity\")\n", + "\n", + "par1.set_ylim(0, 4)\n", + "par2.set_ylim(1, 65)\n", + "par3.set_ylim(0, 700)\n", + "\n", + "host.legend()\n", + "\n", + "host.axis[\"left\"].label.set_color(p1.get_color())\n", + "par1.axis[\"right\"].label.set_color(p2.get_color())\n", + "par2.axis[\"right\"].label.set_color(p3.get_color())\n", + "par3.axis[\"right\"].label.set_color(p4.get_color())\n", + "\n", + "#plt.draw()\n", + "plt.tight_layout()\n", + "#plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## + interact placement" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib widget\n", + "from mpl_toolkits.axes_grid1 import host_subplot\n", + "import mpl_toolkits.axisartist as AA\n", + "import matplotlib.pyplot as plt\n", + "from ipywidgets import interact, FloatSlider\n", + "\n", + "print('(Un)Commenting tight_layout (line 60) makes a big difference,\\ndoes all the adjustement automatically given you chose small enough starting parameters')\n", + "\n", + "@interact( x= FloatSlider(min=0.5,max=1,step=0.02,value=0.6),\n", + " y= FloatSlider(min=30,max=60,step=2,value=45))\n", + "def on_value_change(x,y):\n", + " plt.clf()\n", + " \n", + " host = host_subplot(111, axes_class=AA.Axes)\n", + " plt.subplots_adjust(right=x)\n", + " \n", + " par1 = host.twinx()\n", + " par2 = host.twinx()\n", + " par3 = host.twinx()\n", + " \n", + " new_fixed_axis1 = par1.get_grid_helper().new_fixed_axis\n", + " par1.axis[\"right\"] = new_fixed_axis1(loc=\"right\", axes=par1, offset=(0, 0))\n", + " par1.axis[\"right\"].toggle(all=True)\n", + " \n", + " offset = y\n", + " new_fixed_axis2 = par2.get_grid_helper().new_fixed_axis\n", + " par2.axis[\"right\"] = new_fixed_axis2(loc=\"right\", axes=par2, offset=(offset, 0))\n", + " par2.axis[\"right\"].toggle(all=True)\n", + " #\n", + " new_fixed_axis3 = par3.get_grid_helper().new_fixed_axis\n", + " par3.axis[\"right\"] = new_fixed_axis3(loc=\"right\", axes=par3, offset=(2*offset, 0))\n", + " par3.axis[\"right\"].toggle(all=True)\n", + " \n", + " host.set_xlim(0, 2)\n", + " host.set_ylim(0, 2)\n", + " \n", + " host.set_xlabel(\"Distance\")\n", + " host.set_ylabel(\"Density\")\n", + " par1.set_ylabel(\"Temperature\")\n", + " par2.set_ylabel(\"Velocity\")\n", + " par3.set_ylabel(\"Luminocity\")\n", + " \n", + " p1, = host.plot([0, 1, 2], [0, 1, 2], label=\"Density\")\n", + " p2, = par1.plot([0, 1, 2], [0, 3, 2], label=\"Temperature\")\n", + " p3, = par2.plot([0, 1, 2], [50, 30, 15], label=\"Velocity\")\n", + " p4, = par3.plot([0, 1, 2], [10, 333, 600], label=\"Luminocity\")\n", + " \n", + " par1.set_ylim(0, 4)\n", + " par2.set_ylim(1, 65)\n", + " par3.set_ylim(0, 700)\n", + " \n", + " host.legend()\n", + " \n", + " host.axis[\"left\"].label.set_color(p1.get_color())\n", + " par1.axis[\"right\"].label.set_color(p2.get_color())\n", + " par2.axis[\"right\"].label.set_color(p3.get_color())\n", + " par3.axis[\"right\"].label.set_color(p4.get_color())\n", + " \n", + " #plt.draw()\n", + " #plt.tight_layout()\n", + " #plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## + n axes test\n", + "Slight bug: By uncommenting the print at line 71, it stops printing 2 graphs on play. An alternative is just interacting with the sliders" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib widget\n", + "import matplotlib.pyplot as plt\n", + "from mpl_toolkits.axes_grid1 import host_subplot\n", + "import mpl_toolkits.axisartist as AA\n", + "from ipywidgets import interact, FloatSlider, IntSlider, Output, HTML, VBox, Layout\n", + "import numpy as np\n", + "randint = np.random.randint\n", + "randn = np.random.randn\n", + "# Two-by-four array of samples from N(3, 6.25):\n", + "# 2.5 * np.random.randn(2, 4) + 3\n", + "\n", + "out = Output()\n", + "@out.capture(clear_output=True)\n", + "@interact( w= IntSlider(description='x range',min=2,max=100,step=1,value=4,continuous_update=False),\n", + " x= FloatSlider(description='subplots_adjust(right',min=0.1,max=1,step=0.02,value=0.60,continuous_update=True,style = {'description_width': 'initial'}),\n", + " y= FloatSlider(description='offset',min=15,max=60,step=2,value=35,continuous_update=False),\n", + " z= IntSlider(description='number of lines',min=2,max=10,step=1,value=6,continuous_update=False,style = {'description_width': 'initial'}))\n", + "def on_value_change(w,x,y,z):\n", + "\n", + " data = 2.5 * np.random.randn(z, w) + 3\n", + " \n", + " plt.clf()\n", + " host = host_subplot(111, axes_class=AA.Axes)\n", + " plt.subplots_adjust(right=x)\n", + " \n", + " # parallel additional axis\n", + " par=[ host.twinx() for i in range(z-1) ]\n", + " \n", + " new_fixed_axis=[ par[i].get_grid_helper().new_fixed_axis for i in range(z-1) ]\n", + " for i in range(z-1):\n", + " par[i].axis[\"right\"] = new_fixed_axis[i](loc=\"right\", axes=par[i], offset=(i*y, 0))\n", + " par[i].axis[\"right\"].toggle(all=True)\n", + " \n", + " # horizontal lim\n", + " host.set_xlim(0, w-1)\n", + " # 0 \n", + " host.set_ylim( np.floor(data[0].min()), np.ceil(data[0].max())) #(0, 2)\n", + " \n", + " # 0\n", + " host.set_xlabel(\"x range\")\n", + " host.set_ylabel(\"label 0\")\n", + " #>0\n", + " for i in range(z-1):\n", + " par[i].set_ylabel(\"label %s\"%(i+1))\n", + "\n", + " \n", + " p=[ None for i in range(z) ]\n", + " p[0], = host.plot(range(w), data[0], label=\"label 0\")\n", + " for i in range(z-1):\n", + " p[i+1], = par[i].plot(range(w), data[i+1], label=\"label %s\"%(i+1))\n", + " \n", + " #>0\n", + " for i in range(z-1):\n", + " par[i].set_ylim( np.floor(data[i+1].min()), np.ceil(data[i+1].max()))\n", + "\n", + " host.legend(loc='best',framealpha=0.5)\n", + " \n", + " host.axis[\"left\"].label.set_color(p[0].get_color())\n", + " for i in range(z-1):\n", + " par[i].axis[\"right\"].label.set_color(p[i+1].get_color())\n", + " \n", + " #plt.draw()\n", + " plt.tight_layout()\n", + " #plt.show()\n", + " \n", + " paranoia=''\n", + " for r in range(z):\n", + " mmin=np.floor(data[r].min())\n", + " mmax=np.ceil(data[r].max())\n", + " paranoia+=str((mmin, data[r], mmax))+'
'\n", + " #print((mmin, data[r], mmax))\n", + " for c in range(w):\n", + " assert mmin <= data[r][c] and data[r][c] <= mmax, ' problem %s%s'%(row,col)\n", + " \n", + " display(VBox([plt.figure(1).canvas,HTML(paranoia)]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Final reusable form" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib widget\n", + "from mpl_toolkits.axes_grid1 import host_subplot\n", + "import mpl_toolkits.axisartist as AA\n", + "import matplotlib.pyplot as plt\n", + "from numpy import floor, ceil\n", + "\n", + "def DisjointPlot( data=[[1,2,3],[33,44,38],[6,5,8],[69,420,666]], names=['a','b','c','d'] ):\n", + " '''\n", + " A quick and raw plot of at least 2 series with a shared axis, plotting each y-axis independently\n", + " name[0] ,data[0 ] is the shared axis\n", + " name[1:],data[1:] are the series to plot\n", + " Requirements:\n", + " At least 3 lists needed: one shared axis, two series\n", + " Every list should have the same dimension\n", + " Example in the default arguments:\n", + " DisjointPlot() ~ DisjointPlot( data=[[1,2,3],[33,44,38],[6,5,8],[69,420,666]], names=['a','b','c','d'] )\n", + " '''\n", + " # check data\n", + " rows=len(data)\n", + " assert rows>2, 'At least 3 lists needed: one shared axis, two series'\n", + " cols=len(data[0])\n", + " for r in range(1,rows):\n", + " assert cols==len(data[r]), 'Serie of index %s not of the same dimension of shared axis data[0]'%r\n", + " \n", + " z=len(data)-1 #number of series\n", + " y=50 #offset\n", + " \n", + " plt.clf()\n", + " host = host_subplot(111, axes_class=AA.Axes)\n", + " plt.subplots_adjust(right=0.7)\n", + " \n", + " # parallel additional axis\n", + " par=[ host.twinx() for i in range(z-1) ]\n", + " \n", + " new_fixed_axis=[ par[i].get_grid_helper().new_fixed_axis for i in range(z-1) ]\n", + " for i in range(z-1):\n", + " par[i].axis[\"right\"] = new_fixed_axis[i](loc=\"right\", axes=par[i], offset=(i*y, 0))\n", + " par[i].axis[\"right\"].toggle(all=True)\n", + " \n", + " # horizontal lim\n", + " host.set_xlim( data[0][0], data[0][-1])\n", + " # 0 \n", + " host.set_ylim( floor(min(data[1])), ceil(max(data[1]))) #(0, 2)\n", + " \n", + " # 0\n", + " host.set_xlabel(names[0])\n", + " host.set_ylabel(names[1])\n", + " #>0\n", + " for i in range(z-1):\n", + " par[i].set_ylabel(names[i+2])\n", + "\n", + " \n", + " p=[ None for i in range(z) ]\n", + " p[0], = host.plot(data[0], data[1], label=names[1])\n", + " for i in range(z-1):\n", + " p[i+1], = par[i].plot(data[0], data[i+2], label=names[i+2])\n", + " \n", + " #>0\n", + " for i in range(z-1):\n", + " par[i].set_ylim( floor(min(data[i+2])), ceil(max(data[i+2])))\n", + "\n", + " host.legend(loc='best',framealpha=0.5)\n", + " \n", + " host.axis[\"left\"].label.set_color(p[0].get_color())\n", + " for i in range(z-1):\n", + " par[i].axis[\"right\"].label.set_color(p[i+1].get_color())\n", + " \n", + " #plt.draw()\n", + " plt.tight_layout()\n", + " #plt.show()\n", + " \n", + " return plt.figure(1).canvas\n", + "\n", + "#display(DisjointPlot())\n", + "\n", + "with plt.xkcd():\n", + " DisjointPlot()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## TODO help!\n", + "\n", + "1. Why ``display(plt.figure(1).canvas)`` outputs 2 'figures 1' instead of 1? Is this the best intended way to output the graph?\n", + "\n", + " 1.1. Why this gets solved by using ``with plt.xkcd():`` outputting just one graph?\n", + "\n", + "2. How to update the other axes on zoom ? Only the left one (host) gets updated.\n", + "\n", + "3. How to make the graph (canvas?) stretch out to the output size and have the bottom right stretch control?\n", + " \n", + " Like in the styling examples: \"A more advanced example: a reactive form\" at https://ipywidgets.readthedocs.io/en/stable/examples/Widget%20Styling.html\n", + " \n", + " 3.1. Is this a question for the ipywidgets guys instead of jupyter-matplotlib you guys?\n", + " \n", + " 3.2. Maybe is easier to try an independent frame with Tinker? Like this https://stackoverflow.com/questions/39650940/how-can-i-make-the-figurecanvas-fill-the-entire-figure-in-a-matplotlib-widget-em ?\n", + "\n", + " I've tried different combination of these things without success:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# based on \"A more advanced example: a reactive form\"\n", + "%matplotlib widget\n", + "import matplotlib.pyplot as plt\n", + "import matplotlib\n", + "matplotlib.rcParams['figure.figsize'] = [10, 5] \n", + "matplotlib.rcParams['figure.subplot.left'] = 0\n", + "matplotlib.rcParams['figure.subplot.bottom'] = 0\n", + "matplotlib.rcParams['figure.subplot.right'] = 1\n", + "matplotlib.rcParams['figure.subplot.top'] = 1\n", + "matplotlib.rcParams['figure.autolayout'] = True\n", + "\n", + "from ipywidgets import Box, VBox, Layout, Label\n", + "import numpy as np\n", + "\n", + "#plt.figure(1,figsize=(10,5))\n", + "#plt.figure(1)\n", + "plt.plot(np.sin(np.linspace(0, 20, 100)))\n", + "#plt.show()\n", + "\n", + "fig=plt.figure(1)#,figsize=(10,5))\n", + "plt.tight_layout()\n", + "\n", + "form_item_layout = Layout(flex='1 1 100%',\n", + " display='flex',\n", + " flex_flow='row',\n", + " justify_content='space-between'\n", + ")\n", + "\n", + "form_items = [\n", + " VBox([ Label(value='Need a stretching component'), fig.canvas ], layout=form_item_layout),\n", + " #Box([ fig.canvas ], layout=form_item_layout)\n", + "]\n", + "\n", + "form = Box(form_items, layout=Layout(flex='1 1 100%',\n", + " display='flex',\n", + " flex_flow='row',\n", + " border='solid 2px',\n", + " align_items='stretch',\n", + " width='50%'\n", + "))\n", + "#with plt.xkcd():\n", + "# form\n", + "display(form)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# maybe interacting gets resized: NOP\n", + "%matplotlib widget\n", + "import matplotlib.pyplot as plt\n", + "#import matplotlib\n", + "#matplotlib.rcParams['figure.figsize'] = [10, 5] # for square canvas\n", + "#matplotlib.rcParams['figure.subplot.left'] = 0\n", + "#matplotlib.rcParams['figure.subplot.bottom'] = 0\n", + "#matplotlib.rcParams['figure.subplot.right'] = 1\n", + "#matplotlib.rcParams['figure.subplot.top'] = 1\n", + "#matplotlib.rcParams['figure.autolayout'] = True\n", + "\n", + "from ipywidgets import Box, VBox, Layout, Label, interact, IntSlider\n", + "import numpy as np\n", + "\n", + "\n", + "@interact( x= IntSlider(min=1,max=10,step=1,value=7,continuous_update=False),\n", + " y= IntSlider(min=1,max=10,step=1,value=5,continuous_update=False))\n", + "def on_value_change(x,y):\n", + " plt.clf()\n", + "\n", + " plt.figure(1,figsize=(x,y))\n", + " #plt.figure(1)\n", + " plt.plot(np.sin(np.linspace(0, 20, 100)))\n", + " plt.show()\n", + " \n", + " #fig=plt.figure(1 ,figsize=(x,y))\n", + " fig=plt.figure(1)\n", + " #plt.tight_layout()\n", + " \n", + " display(fig.canvas)\n" + ] } ], "metadata": { @@ -169,7 +676,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.3" + "version": "3.7.2" } }, "nbformat": 4, From a9fc3660516df02b615bf051785f4b4a17b098e3 Mon Sep 17 00:00:00 2001 From: fdobad <29801096+fdobad@users.noreply.github.com> Date: Fri, 5 Jul 2019 11:52:50 -0400 Subject: [PATCH 2/3] moved to adva&less todo --- .gitignore | 3 + examples/advanced.ipynb | 420 +++++++++++++++++++++++++++++++++ examples/ipympl.ipynb | 507 ---------------------------------------- 3 files changed, 423 insertions(+), 507 deletions(-) create mode 100644 examples/advanced.ipynb diff --git a/.gitignore b/.gitignore index c271c172..69424a05 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +.gitignore +examples/gitignore.ipynb + *.egg-info/ .ipynb_checkpoints/ dist/ diff --git a/examples/advanced.ipynb b/examples/advanced.ipynb new file mode 100644 index 00000000..4726db12 --- /dev/null +++ b/examples/advanced.ipynb @@ -0,0 +1,420 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Multiple independent axes, same plot\n", + "This constructive tutorial aims to enhance the following example, automating the creation of new independent, but in the same plot, axes for each series. Providing a final reusable function DisjointPlot(data,names)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Based on matplotlib example demo_parasite_axes2\n", + "https://matplotlib.org/examples/axes_grid/demo_parasite_axes2.html" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib widget\n", + "from mpl_toolkits.axes_grid1 import host_subplot\n", + "import mpl_toolkits.axisartist as AA\n", + "import matplotlib.pyplot as plt\n", + "\n", + "host = host_subplot(111, axes_class=AA.Axes)\n", + "plt.subplots_adjust(right=0.75)\n", + "\n", + "par1 = host.twinx()\n", + "par2 = host.twinx()\n", + "\n", + "new_fixed_axis = par1.get_grid_helper().new_fixed_axis\n", + "par1.axis[\"right\"] = new_fixed_axis(loc=\"right\", axes=par1,\n", + " offset=(0, 0))\n", + "par1.axis[\"right\"].toggle(all=True)\n", + "offset = 60\n", + "new_fixed_axis2 = par2.get_grid_helper().new_fixed_axis\n", + "par2.axis[\"right\"] = new_fixed_axis2(loc=\"right\", axes=par2,\n", + " offset=(offset, 0))\n", + "par2.axis[\"right\"].toggle(all=True)\n", + "\n", + "host.set_xlim(0, 2)\n", + "host.set_ylim(0, 2)\n", + "\n", + "host.set_xlabel(\"Distance\")\n", + "host.set_ylabel(\"Density\")\n", + "par1.set_ylabel(\"Temperature\")\n", + "par2.set_ylabel(\"Velocity\")\n", + "\n", + "p1, = host.plot([0, 1, 2], [0, 1, 2], label=\"Density\")\n", + "p2, = par1.plot([0, 1, 2], [0, 3, 2], label=\"Temperature\")\n", + "p3, = par2.plot([0, 1, 2], [50, 30, 15], label=\"Velocity\")\n", + "\n", + "par1.set_ylim(0, 4)\n", + "par2.set_ylim(1, 65)\n", + "\n", + "host.legend()\n", + "\n", + "host.axis[\"left\"].label.set_color(p1.get_color())\n", + "par1.axis[\"right\"].label.set_color(p2.get_color())\n", + "par2.axis[\"right\"].label.set_color(p3.get_color())\n", + "\n", + "plt.draw()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## + 1 axis to get then hang of it" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib widget\n", + "from mpl_toolkits.axes_grid1 import host_subplot\n", + "import mpl_toolkits.axisartist as AA\n", + "import matplotlib.pyplot as plt\n", + "\n", + "host = host_subplot(111, axes_class=AA.Axes)\n", + "plt.subplots_adjust(right=0.7)\n", + "\n", + "par1 = host.twinx()\n", + "par2 = host.twinx()\n", + "par3 = host.twinx()\n", + "\n", + "new_fixed_axis1 = par1.get_grid_helper().new_fixed_axis\n", + "par1.axis[\"right\"] = new_fixed_axis1(loc=\"right\", axes=par1, offset=(0, 0))\n", + "par1.axis[\"right\"].toggle(all=True)\n", + "\n", + "offset = 45\n", + "new_fixed_axis2 = par2.get_grid_helper().new_fixed_axis\n", + "par2.axis[\"right\"] = new_fixed_axis2(loc=\"right\", axes=par2, offset=(offset, 0))\n", + "par2.axis[\"right\"].toggle(all=True)\n", + "#\n", + "new_fixed_axis3 = par3.get_grid_helper().new_fixed_axis\n", + "par3.axis[\"right\"] = new_fixed_axis3(loc=\"right\", axes=par3, offset=(2*offset, 0))\n", + "par3.axis[\"right\"].toggle(all=True)\n", + "\n", + "host.set_xlim(0, 2)\n", + "host.set_ylim(0, 2)\n", + "\n", + "host.set_xlabel(\"Distance\")\n", + "host.set_ylabel(\"Density\")\n", + "par1.set_ylabel(\"Temperature\")\n", + "par2.set_ylabel(\"Velocity\")\n", + "par3.set_ylabel(\"Luminocity\")\n", + "\n", + "p1, = host.plot([0, 1, 2], [0, 1, 2], label=\"Density\")\n", + "p2, = par1.plot([0, 1, 2], [0, 3, 2], label=\"Temperature\")\n", + "p3, = par2.plot([0, 1, 2], [50, 30, 15], label=\"Velocity\")\n", + "p4, = par3.plot([0, 1, 2], [69, 250, 600], label=\"Luminocity\")\n", + "\n", + "par1.set_ylim(0, 4)\n", + "par2.set_ylim(1, 65)\n", + "par3.set_ylim(0, 700)\n", + "\n", + "host.legend()\n", + "\n", + "host.axis[\"left\"].label.set_color(p1.get_color())\n", + "par1.axis[\"right\"].label.set_color(p2.get_color())\n", + "par2.axis[\"right\"].label.set_color(p3.get_color())\n", + "par3.axis[\"right\"].label.set_color(p4.get_color())\n", + "\n", + "#plt.draw()\n", + "plt.tight_layout()\n", + "#plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## + interact with placement offset & subplots_adjust" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib widget\n", + "from mpl_toolkits.axes_grid1 import host_subplot\n", + "import mpl_toolkits.axisartist as AA\n", + "import matplotlib.pyplot as plt\n", + "from ipywidgets import interact, FloatSlider\n", + "\n", + "print('(Un)Commenting tight_layout (line 60) makes a big difference,\\ndoes all the adjustement automatically given you chose small enough starting parameters')\n", + "\n", + "@interact( x= FloatSlider(min=0.5,max=1,step=0.02,value=0.6),\n", + " y= FloatSlider(min=30,max=60,step=2,value=45))\n", + "def on_value_change(x,y):\n", + " plt.clf()\n", + " \n", + " host = host_subplot(111, axes_class=AA.Axes)\n", + " plt.subplots_adjust(right=x)\n", + " \n", + " par1 = host.twinx()\n", + " par2 = host.twinx()\n", + " par3 = host.twinx()\n", + " \n", + " new_fixed_axis1 = par1.get_grid_helper().new_fixed_axis\n", + " par1.axis[\"right\"] = new_fixed_axis1(loc=\"right\", axes=par1, offset=(0, 0))\n", + " par1.axis[\"right\"].toggle(all=True)\n", + " \n", + " offset = y\n", + " new_fixed_axis2 = par2.get_grid_helper().new_fixed_axis\n", + " par2.axis[\"right\"] = new_fixed_axis2(loc=\"right\", axes=par2, offset=(offset, 0))\n", + " par2.axis[\"right\"].toggle(all=True)\n", + " #\n", + " new_fixed_axis3 = par3.get_grid_helper().new_fixed_axis\n", + " par3.axis[\"right\"] = new_fixed_axis3(loc=\"right\", axes=par3, offset=(2*offset, 0))\n", + " par3.axis[\"right\"].toggle(all=True)\n", + " \n", + " host.set_xlim(0, 2)\n", + " host.set_ylim(0, 2)\n", + " \n", + " host.set_xlabel(\"Distance\")\n", + " host.set_ylabel(\"Density\")\n", + " par1.set_ylabel(\"Temperature\")\n", + " par2.set_ylabel(\"Velocity\")\n", + " par3.set_ylabel(\"Luminocity\")\n", + " \n", + " p1, = host.plot([0, 1, 2], [0, 1, 2], label=\"Density\")\n", + " p2, = par1.plot([0, 1, 2], [0, 3, 2], label=\"Temperature\")\n", + " p3, = par2.plot([0, 1, 2], [50, 30, 15], label=\"Velocity\")\n", + " p4, = par3.plot([0, 1, 2], [10, 333, 600], label=\"Luminocity\")\n", + " \n", + " par1.set_ylim(0, 4)\n", + " par2.set_ylim(1, 65)\n", + " par3.set_ylim(0, 700)\n", + " \n", + " host.legend()\n", + " \n", + " host.axis[\"left\"].label.set_color(p1.get_color())\n", + " par1.axis[\"right\"].label.set_color(p2.get_color())\n", + " par2.axis[\"right\"].label.set_color(p3.get_color())\n", + " par3.axis[\"right\"].label.set_color(p4.get_color())\n", + " \n", + " #plt.draw()\n", + " #plt.tight_layout()\n", + " #plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## + n axes test\n", + "Slight bug: By uncommenting the print statement at line 71, it stops printing 2 graphs on play. An alternative is just interacting with the sliders" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib widget\n", + "import matplotlib.pyplot as plt\n", + "from mpl_toolkits.axes_grid1 import host_subplot\n", + "import mpl_toolkits.axisartist as AA\n", + "from ipywidgets import interact, FloatSlider, IntSlider, Output, HTML, VBox, Layout\n", + "import numpy as np\n", + "randint = np.random.randint\n", + "randn = np.random.randn\n", + "# Two-by-four array of samples from N(3, 6.25):\n", + "# 2.5 * np.random.randn(2, 4) + 3\n", + "\n", + "out = Output()\n", + "@out.capture(clear_output=True)\n", + "@interact( w= IntSlider(description='x range',min=2,max=100,step=1,value=4,continuous_update=False),\n", + " x= FloatSlider(description='subplots_adjust(right',min=0.1,max=1,step=0.02,value=0.60,continuous_update=True,style = {'description_width': 'initial'}),\n", + " y= FloatSlider(description='offset',min=15,max=60,step=2,value=35,continuous_update=False),\n", + " z= IntSlider(description='number of lines',min=2,max=10,step=1,value=6,continuous_update=False,style = {'description_width': 'initial'}))\n", + "def on_value_change(w,x,y,z):\n", + "\n", + " data = 2.5 * np.random.randn(z, w) + 3\n", + " \n", + " plt.clf()\n", + " host = host_subplot(111, axes_class=AA.Axes)\n", + " plt.subplots_adjust(right=x)\n", + " \n", + " # parallel additional axis\n", + " par=[ host.twinx() for i in range(z-1) ]\n", + " \n", + " new_fixed_axis=[ par[i].get_grid_helper().new_fixed_axis for i in range(z-1) ]\n", + " for i in range(z-1):\n", + " par[i].axis[\"right\"] = new_fixed_axis[i](loc=\"right\", axes=par[i], offset=(i*y, 0))\n", + " par[i].axis[\"right\"].toggle(all=True)\n", + " \n", + " # horizontal lim\n", + " host.set_xlim(0, w-1)\n", + " # 0 \n", + " host.set_ylim( np.floor(data[0].min()), np.ceil(data[0].max())) #(0, 2)\n", + " \n", + " # 0\n", + " host.set_xlabel(\"x range\")\n", + " host.set_ylabel(\"label 0\")\n", + " #>0\n", + " for i in range(z-1):\n", + " par[i].set_ylabel(\"label %s\"%(i+1))\n", + "\n", + " \n", + " p=[ None for i in range(z) ]\n", + " p[0], = host.plot(range(w), data[0], label=\"label 0\")\n", + " for i in range(z-1):\n", + " p[i+1], = par[i].plot(range(w), data[i+1], label=\"label %s\"%(i+1))\n", + " \n", + " #>0\n", + " for i in range(z-1):\n", + " par[i].set_ylim( np.floor(data[i+1].min()), np.ceil(data[i+1].max()))\n", + "\n", + " host.legend(loc='best',framealpha=0.5)\n", + " \n", + " host.axis[\"left\"].label.set_color(p[0].get_color())\n", + " for i in range(z-1):\n", + " par[i].axis[\"right\"].label.set_color(p[i+1].get_color())\n", + " \n", + " #plt.draw()\n", + " plt.tight_layout()\n", + " #plt.show()\n", + " \n", + " paranoia=''\n", + " for r in range(z):\n", + " mmin=np.floor(data[r].min())\n", + " mmax=np.ceil(data[r].max())\n", + " paranoia+=str((mmin, data[r], mmax))+'
'\n", + " #print((mmin, data[r], mmax))\n", + " for c in range(w):\n", + " assert mmin <= data[r][c] and data[r][c] <= mmax, ' problem %s%s'%(row,col)\n", + " \n", + " display(VBox([plt.figure(1).canvas,HTML(paranoia)]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Final reusable form" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib widget\n", + "from mpl_toolkits.axes_grid1 import host_subplot\n", + "import mpl_toolkits.axisartist as AA\n", + "import matplotlib.pyplot as plt\n", + "from numpy import floor, ceil\n", + "\n", + "def DisjointPlot( data=[[1,2,3],[33,44,38],[6,5,8],[69,420,666]], names=['a','b','c','d'] ):\n", + " '''\n", + " A quick and raw plot of at least 2 series with a shared axis, plotting each y-axis independently\n", + " name[0] ,data[0 ] is the shared axis\n", + " name[1:],data[1:] are the series to plot\n", + " Requirements:\n", + " At least 3 lists needed: one shared axis, two series\n", + " Every list should have the same dimension\n", + " Example in the default arguments:\n", + " DisjointPlot() ~ DisjointPlot( data=[[1,2,3],[33,44,38],[6,5,8],[69,420,666]], names=['a','b','c','d'] )\n", + " '''\n", + " # check data\n", + " rows=len(data)\n", + " assert rows>2, 'At least 3 lists needed: one shared axis, two series'\n", + " cols=len(data[0])\n", + " for r in range(1,rows):\n", + " assert cols==len(data[r]), 'Serie of index %s not of the same dimension of shared axis data[0]'%r\n", + " \n", + " z=len(data)-1 #number of series\n", + " y=50 #offset\n", + " \n", + " plt.clf()\n", + " host = host_subplot(111, axes_class=AA.Axes)\n", + " plt.subplots_adjust(right=0.7)\n", + " \n", + " # parallel additional axis\n", + " par=[ host.twinx() for i in range(z-1) ]\n", + " \n", + " new_fixed_axis=[ par[i].get_grid_helper().new_fixed_axis for i in range(z-1) ]\n", + " for i in range(z-1):\n", + " par[i].axis[\"right\"] = new_fixed_axis[i](loc=\"right\", axes=par[i], offset=(i*y, 0))\n", + " par[i].axis[\"right\"].toggle(all=True)\n", + " \n", + " # horizontal lim\n", + " host.set_xlim( data[0][0], data[0][-1])\n", + " # 0 \n", + " host.set_ylim( floor(min(data[1])), ceil(max(data[1]))) #(0, 2)\n", + " \n", + " # 0\n", + " host.set_xlabel(names[0])\n", + " host.set_ylabel(names[1])\n", + " #>0\n", + " for i in range(z-1):\n", + " par[i].set_ylabel(names[i+2])\n", + "\n", + " \n", + " p=[ None for i in range(z) ]\n", + " p[0], = host.plot(data[0], data[1], label=names[1])\n", + " for i in range(z-1):\n", + " p[i+1], = par[i].plot(data[0], data[i+2], label=names[i+2])\n", + " \n", + " #>0\n", + " for i in range(z-1):\n", + " par[i].set_ylim( floor(min(data[i+2])), ceil(max(data[i+2])))\n", + "\n", + " host.legend(loc='best',framealpha=0.5)\n", + " \n", + " host.axis[\"left\"].label.set_color(p[0].get_color())\n", + " for i in range(z-1):\n", + " par[i].axis[\"right\"].label.set_color(p[i+1].get_color())\n", + " \n", + " #plt.draw()\n", + " plt.tight_layout()\n", + " #plt.show()\n", + " \n", + " return plt.figure(1).canvas\n", + "\n", + "with plt.xkcd():\n", + " DisjointPlot()\n", + "# If you haven't installed the awesome xkcd styling, display it like\n", + "#display(DisjointPlot())" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "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.7.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/ipympl.ipynb b/examples/ipympl.ipynb index 6dee01f9..bcefd3ff 100644 --- a/examples/ipympl.ipynb +++ b/examples/ipympl.ipynb @@ -151,513 +151,6 @@ "metadata": {}, "outputs": [], "source": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Multiple independent axes, same plot\n", - "This constructive tutorial aims to enhance the following example, automating the creation of new independent, but in the same plot, axes. Providing a final reusable function DisjointPlot(data,names)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Based on matplotlib example demo_parasite_axes2\n", - "https://matplotlib.org/examples/axes_grid/demo_parasite_axes2.html" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib widget\n", - "from mpl_toolkits.axes_grid1 import host_subplot\n", - "import mpl_toolkits.axisartist as AA\n", - "import matplotlib.pyplot as plt\n", - "\n", - "host = host_subplot(111, axes_class=AA.Axes)\n", - "plt.subplots_adjust(right=0.75)\n", - "\n", - "par1 = host.twinx()\n", - "par2 = host.twinx()\n", - "\n", - "new_fixed_axis = par1.get_grid_helper().new_fixed_axis\n", - "par1.axis[\"right\"] = new_fixed_axis(loc=\"right\", axes=par1,\n", - " offset=(0, 0))\n", - "par1.axis[\"right\"].toggle(all=True)\n", - "offset = 60\n", - "new_fixed_axis2 = par2.get_grid_helper().new_fixed_axis\n", - "par2.axis[\"right\"] = new_fixed_axis2(loc=\"right\", axes=par2,\n", - " offset=(offset, 0))\n", - "par2.axis[\"right\"].toggle(all=True)\n", - "\n", - "host.set_xlim(0, 2)\n", - "host.set_ylim(0, 2)\n", - "\n", - "host.set_xlabel(\"Distance\")\n", - "host.set_ylabel(\"Density\")\n", - "par1.set_ylabel(\"Temperature\")\n", - "par2.set_ylabel(\"Velocity\")\n", - "\n", - "p1, = host.plot([0, 1, 2], [0, 1, 2], label=\"Density\")\n", - "p2, = par1.plot([0, 1, 2], [0, 3, 2], label=\"Temperature\")\n", - "p3, = par2.plot([0, 1, 2], [50, 30, 15], label=\"Velocity\")\n", - "\n", - "par1.set_ylim(0, 4)\n", - "par2.set_ylim(1, 65)\n", - "\n", - "host.legend()\n", - "\n", - "host.axis[\"left\"].label.set_color(p1.get_color())\n", - "par1.axis[\"right\"].label.set_color(p2.get_color())\n", - "par2.axis[\"right\"].label.set_color(p3.get_color())\n", - "\n", - "plt.draw()\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## + 1 axis" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib widget\n", - "from mpl_toolkits.axes_grid1 import host_subplot\n", - "import mpl_toolkits.axisartist as AA\n", - "import matplotlib.pyplot as plt\n", - "\n", - "host = host_subplot(111, axes_class=AA.Axes)\n", - "plt.subplots_adjust(right=0.7)\n", - "\n", - "par1 = host.twinx()\n", - "par2 = host.twinx()\n", - "par3 = host.twinx()\n", - "\n", - "new_fixed_axis1 = par1.get_grid_helper().new_fixed_axis\n", - "par1.axis[\"right\"] = new_fixed_axis1(loc=\"right\", axes=par1, offset=(0, 0))\n", - "par1.axis[\"right\"].toggle(all=True)\n", - "\n", - "offset = 45\n", - "new_fixed_axis2 = par2.get_grid_helper().new_fixed_axis\n", - "par2.axis[\"right\"] = new_fixed_axis2(loc=\"right\", axes=par2, offset=(offset, 0))\n", - "par2.axis[\"right\"].toggle(all=True)\n", - "#\n", - "new_fixed_axis3 = par3.get_grid_helper().new_fixed_axis\n", - "par3.axis[\"right\"] = new_fixed_axis3(loc=\"right\", axes=par3, offset=(2*offset, 0))\n", - "par3.axis[\"right\"].toggle(all=True)\n", - "\n", - "host.set_xlim(0, 2)\n", - "host.set_ylim(0, 2)\n", - "\n", - "host.set_xlabel(\"Distance\")\n", - "host.set_ylabel(\"Density\")\n", - "par1.set_ylabel(\"Temperature\")\n", - "par2.set_ylabel(\"Velocity\")\n", - "par3.set_ylabel(\"Luminocity\")\n", - "\n", - "p1, = host.plot([0, 1, 2], [0, 1, 2], label=\"Density\")\n", - "p2, = par1.plot([0, 1, 2], [0, 3, 2], label=\"Temperature\")\n", - "p3, = par2.plot([0, 1, 2], [50, 30, 15], label=\"Velocity\")\n", - "p4, = par3.plot([0, 1, 2], [69, 250, 600], label=\"Luminocity\")\n", - "\n", - "par1.set_ylim(0, 4)\n", - "par2.set_ylim(1, 65)\n", - "par3.set_ylim(0, 700)\n", - "\n", - "host.legend()\n", - "\n", - "host.axis[\"left\"].label.set_color(p1.get_color())\n", - "par1.axis[\"right\"].label.set_color(p2.get_color())\n", - "par2.axis[\"right\"].label.set_color(p3.get_color())\n", - "par3.axis[\"right\"].label.set_color(p4.get_color())\n", - "\n", - "#plt.draw()\n", - "plt.tight_layout()\n", - "#plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## + interact placement" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib widget\n", - "from mpl_toolkits.axes_grid1 import host_subplot\n", - "import mpl_toolkits.axisartist as AA\n", - "import matplotlib.pyplot as plt\n", - "from ipywidgets import interact, FloatSlider\n", - "\n", - "print('(Un)Commenting tight_layout (line 60) makes a big difference,\\ndoes all the adjustement automatically given you chose small enough starting parameters')\n", - "\n", - "@interact( x= FloatSlider(min=0.5,max=1,step=0.02,value=0.6),\n", - " y= FloatSlider(min=30,max=60,step=2,value=45))\n", - "def on_value_change(x,y):\n", - " plt.clf()\n", - " \n", - " host = host_subplot(111, axes_class=AA.Axes)\n", - " plt.subplots_adjust(right=x)\n", - " \n", - " par1 = host.twinx()\n", - " par2 = host.twinx()\n", - " par3 = host.twinx()\n", - " \n", - " new_fixed_axis1 = par1.get_grid_helper().new_fixed_axis\n", - " par1.axis[\"right\"] = new_fixed_axis1(loc=\"right\", axes=par1, offset=(0, 0))\n", - " par1.axis[\"right\"].toggle(all=True)\n", - " \n", - " offset = y\n", - " new_fixed_axis2 = par2.get_grid_helper().new_fixed_axis\n", - " par2.axis[\"right\"] = new_fixed_axis2(loc=\"right\", axes=par2, offset=(offset, 0))\n", - " par2.axis[\"right\"].toggle(all=True)\n", - " #\n", - " new_fixed_axis3 = par3.get_grid_helper().new_fixed_axis\n", - " par3.axis[\"right\"] = new_fixed_axis3(loc=\"right\", axes=par3, offset=(2*offset, 0))\n", - " par3.axis[\"right\"].toggle(all=True)\n", - " \n", - " host.set_xlim(0, 2)\n", - " host.set_ylim(0, 2)\n", - " \n", - " host.set_xlabel(\"Distance\")\n", - " host.set_ylabel(\"Density\")\n", - " par1.set_ylabel(\"Temperature\")\n", - " par2.set_ylabel(\"Velocity\")\n", - " par3.set_ylabel(\"Luminocity\")\n", - " \n", - " p1, = host.plot([0, 1, 2], [0, 1, 2], label=\"Density\")\n", - " p2, = par1.plot([0, 1, 2], [0, 3, 2], label=\"Temperature\")\n", - " p3, = par2.plot([0, 1, 2], [50, 30, 15], label=\"Velocity\")\n", - " p4, = par3.plot([0, 1, 2], [10, 333, 600], label=\"Luminocity\")\n", - " \n", - " par1.set_ylim(0, 4)\n", - " par2.set_ylim(1, 65)\n", - " par3.set_ylim(0, 700)\n", - " \n", - " host.legend()\n", - " \n", - " host.axis[\"left\"].label.set_color(p1.get_color())\n", - " par1.axis[\"right\"].label.set_color(p2.get_color())\n", - " par2.axis[\"right\"].label.set_color(p3.get_color())\n", - " par3.axis[\"right\"].label.set_color(p4.get_color())\n", - " \n", - " #plt.draw()\n", - " #plt.tight_layout()\n", - " #plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## + n axes test\n", - "Slight bug: By uncommenting the print at line 71, it stops printing 2 graphs on play. An alternative is just interacting with the sliders" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib widget\n", - "import matplotlib.pyplot as plt\n", - "from mpl_toolkits.axes_grid1 import host_subplot\n", - "import mpl_toolkits.axisartist as AA\n", - "from ipywidgets import interact, FloatSlider, IntSlider, Output, HTML, VBox, Layout\n", - "import numpy as np\n", - "randint = np.random.randint\n", - "randn = np.random.randn\n", - "# Two-by-four array of samples from N(3, 6.25):\n", - "# 2.5 * np.random.randn(2, 4) + 3\n", - "\n", - "out = Output()\n", - "@out.capture(clear_output=True)\n", - "@interact( w= IntSlider(description='x range',min=2,max=100,step=1,value=4,continuous_update=False),\n", - " x= FloatSlider(description='subplots_adjust(right',min=0.1,max=1,step=0.02,value=0.60,continuous_update=True,style = {'description_width': 'initial'}),\n", - " y= FloatSlider(description='offset',min=15,max=60,step=2,value=35,continuous_update=False),\n", - " z= IntSlider(description='number of lines',min=2,max=10,step=1,value=6,continuous_update=False,style = {'description_width': 'initial'}))\n", - "def on_value_change(w,x,y,z):\n", - "\n", - " data = 2.5 * np.random.randn(z, w) + 3\n", - " \n", - " plt.clf()\n", - " host = host_subplot(111, axes_class=AA.Axes)\n", - " plt.subplots_adjust(right=x)\n", - " \n", - " # parallel additional axis\n", - " par=[ host.twinx() for i in range(z-1) ]\n", - " \n", - " new_fixed_axis=[ par[i].get_grid_helper().new_fixed_axis for i in range(z-1) ]\n", - " for i in range(z-1):\n", - " par[i].axis[\"right\"] = new_fixed_axis[i](loc=\"right\", axes=par[i], offset=(i*y, 0))\n", - " par[i].axis[\"right\"].toggle(all=True)\n", - " \n", - " # horizontal lim\n", - " host.set_xlim(0, w-1)\n", - " # 0 \n", - " host.set_ylim( np.floor(data[0].min()), np.ceil(data[0].max())) #(0, 2)\n", - " \n", - " # 0\n", - " host.set_xlabel(\"x range\")\n", - " host.set_ylabel(\"label 0\")\n", - " #>0\n", - " for i in range(z-1):\n", - " par[i].set_ylabel(\"label %s\"%(i+1))\n", - "\n", - " \n", - " p=[ None for i in range(z) ]\n", - " p[0], = host.plot(range(w), data[0], label=\"label 0\")\n", - " for i in range(z-1):\n", - " p[i+1], = par[i].plot(range(w), data[i+1], label=\"label %s\"%(i+1))\n", - " \n", - " #>0\n", - " for i in range(z-1):\n", - " par[i].set_ylim( np.floor(data[i+1].min()), np.ceil(data[i+1].max()))\n", - "\n", - " host.legend(loc='best',framealpha=0.5)\n", - " \n", - " host.axis[\"left\"].label.set_color(p[0].get_color())\n", - " for i in range(z-1):\n", - " par[i].axis[\"right\"].label.set_color(p[i+1].get_color())\n", - " \n", - " #plt.draw()\n", - " plt.tight_layout()\n", - " #plt.show()\n", - " \n", - " paranoia=''\n", - " for r in range(z):\n", - " mmin=np.floor(data[r].min())\n", - " mmax=np.ceil(data[r].max())\n", - " paranoia+=str((mmin, data[r], mmax))+'
'\n", - " #print((mmin, data[r], mmax))\n", - " for c in range(w):\n", - " assert mmin <= data[r][c] and data[r][c] <= mmax, ' problem %s%s'%(row,col)\n", - " \n", - " display(VBox([plt.figure(1).canvas,HTML(paranoia)]))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Final reusable form" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib widget\n", - "from mpl_toolkits.axes_grid1 import host_subplot\n", - "import mpl_toolkits.axisartist as AA\n", - "import matplotlib.pyplot as plt\n", - "from numpy import floor, ceil\n", - "\n", - "def DisjointPlot( data=[[1,2,3],[33,44,38],[6,5,8],[69,420,666]], names=['a','b','c','d'] ):\n", - " '''\n", - " A quick and raw plot of at least 2 series with a shared axis, plotting each y-axis independently\n", - " name[0] ,data[0 ] is the shared axis\n", - " name[1:],data[1:] are the series to plot\n", - " Requirements:\n", - " At least 3 lists needed: one shared axis, two series\n", - " Every list should have the same dimension\n", - " Example in the default arguments:\n", - " DisjointPlot() ~ DisjointPlot( data=[[1,2,3],[33,44,38],[6,5,8],[69,420,666]], names=['a','b','c','d'] )\n", - " '''\n", - " # check data\n", - " rows=len(data)\n", - " assert rows>2, 'At least 3 lists needed: one shared axis, two series'\n", - " cols=len(data[0])\n", - " for r in range(1,rows):\n", - " assert cols==len(data[r]), 'Serie of index %s not of the same dimension of shared axis data[0]'%r\n", - " \n", - " z=len(data)-1 #number of series\n", - " y=50 #offset\n", - " \n", - " plt.clf()\n", - " host = host_subplot(111, axes_class=AA.Axes)\n", - " plt.subplots_adjust(right=0.7)\n", - " \n", - " # parallel additional axis\n", - " par=[ host.twinx() for i in range(z-1) ]\n", - " \n", - " new_fixed_axis=[ par[i].get_grid_helper().new_fixed_axis for i in range(z-1) ]\n", - " for i in range(z-1):\n", - " par[i].axis[\"right\"] = new_fixed_axis[i](loc=\"right\", axes=par[i], offset=(i*y, 0))\n", - " par[i].axis[\"right\"].toggle(all=True)\n", - " \n", - " # horizontal lim\n", - " host.set_xlim( data[0][0], data[0][-1])\n", - " # 0 \n", - " host.set_ylim( floor(min(data[1])), ceil(max(data[1]))) #(0, 2)\n", - " \n", - " # 0\n", - " host.set_xlabel(names[0])\n", - " host.set_ylabel(names[1])\n", - " #>0\n", - " for i in range(z-1):\n", - " par[i].set_ylabel(names[i+2])\n", - "\n", - " \n", - " p=[ None for i in range(z) ]\n", - " p[0], = host.plot(data[0], data[1], label=names[1])\n", - " for i in range(z-1):\n", - " p[i+1], = par[i].plot(data[0], data[i+2], label=names[i+2])\n", - " \n", - " #>0\n", - " for i in range(z-1):\n", - " par[i].set_ylim( floor(min(data[i+2])), ceil(max(data[i+2])))\n", - "\n", - " host.legend(loc='best',framealpha=0.5)\n", - " \n", - " host.axis[\"left\"].label.set_color(p[0].get_color())\n", - " for i in range(z-1):\n", - " par[i].axis[\"right\"].label.set_color(p[i+1].get_color())\n", - " \n", - " #plt.draw()\n", - " plt.tight_layout()\n", - " #plt.show()\n", - " \n", - " return plt.figure(1).canvas\n", - "\n", - "#display(DisjointPlot())\n", - "\n", - "with plt.xkcd():\n", - " DisjointPlot()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## TODO help!\n", - "\n", - "1. Why ``display(plt.figure(1).canvas)`` outputs 2 'figures 1' instead of 1? Is this the best intended way to output the graph?\n", - "\n", - " 1.1. Why this gets solved by using ``with plt.xkcd():`` outputting just one graph?\n", - "\n", - "2. How to update the other axes on zoom ? Only the left one (host) gets updated.\n", - "\n", - "3. How to make the graph (canvas?) stretch out to the output size and have the bottom right stretch control?\n", - " \n", - " Like in the styling examples: \"A more advanced example: a reactive form\" at https://ipywidgets.readthedocs.io/en/stable/examples/Widget%20Styling.html\n", - " \n", - " 3.1. Is this a question for the ipywidgets guys instead of jupyter-matplotlib you guys?\n", - " \n", - " 3.2. Maybe is easier to try an independent frame with Tinker? Like this https://stackoverflow.com/questions/39650940/how-can-i-make-the-figurecanvas-fill-the-entire-figure-in-a-matplotlib-widget-em ?\n", - "\n", - " I've tried different combination of these things without success:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# based on \"A more advanced example: a reactive form\"\n", - "%matplotlib widget\n", - "import matplotlib.pyplot as plt\n", - "import matplotlib\n", - "matplotlib.rcParams['figure.figsize'] = [10, 5] \n", - "matplotlib.rcParams['figure.subplot.left'] = 0\n", - "matplotlib.rcParams['figure.subplot.bottom'] = 0\n", - "matplotlib.rcParams['figure.subplot.right'] = 1\n", - "matplotlib.rcParams['figure.subplot.top'] = 1\n", - "matplotlib.rcParams['figure.autolayout'] = True\n", - "\n", - "from ipywidgets import Box, VBox, Layout, Label\n", - "import numpy as np\n", - "\n", - "#plt.figure(1,figsize=(10,5))\n", - "#plt.figure(1)\n", - "plt.plot(np.sin(np.linspace(0, 20, 100)))\n", - "#plt.show()\n", - "\n", - "fig=plt.figure(1)#,figsize=(10,5))\n", - "plt.tight_layout()\n", - "\n", - "form_item_layout = Layout(flex='1 1 100%',\n", - " display='flex',\n", - " flex_flow='row',\n", - " justify_content='space-between'\n", - ")\n", - "\n", - "form_items = [\n", - " VBox([ Label(value='Need a stretching component'), fig.canvas ], layout=form_item_layout),\n", - " #Box([ fig.canvas ], layout=form_item_layout)\n", - "]\n", - "\n", - "form = Box(form_items, layout=Layout(flex='1 1 100%',\n", - " display='flex',\n", - " flex_flow='row',\n", - " border='solid 2px',\n", - " align_items='stretch',\n", - " width='50%'\n", - "))\n", - "#with plt.xkcd():\n", - "# form\n", - "display(form)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# maybe interacting gets resized: NOP\n", - "%matplotlib widget\n", - "import matplotlib.pyplot as plt\n", - "#import matplotlib\n", - "#matplotlib.rcParams['figure.figsize'] = [10, 5] # for square canvas\n", - "#matplotlib.rcParams['figure.subplot.left'] = 0\n", - "#matplotlib.rcParams['figure.subplot.bottom'] = 0\n", - "#matplotlib.rcParams['figure.subplot.right'] = 1\n", - "#matplotlib.rcParams['figure.subplot.top'] = 1\n", - "#matplotlib.rcParams['figure.autolayout'] = True\n", - "\n", - "from ipywidgets import Box, VBox, Layout, Label, interact, IntSlider\n", - "import numpy as np\n", - "\n", - "\n", - "@interact( x= IntSlider(min=1,max=10,step=1,value=7,continuous_update=False),\n", - " y= IntSlider(min=1,max=10,step=1,value=5,continuous_update=False))\n", - "def on_value_change(x,y):\n", - " plt.clf()\n", - "\n", - " plt.figure(1,figsize=(x,y))\n", - " #plt.figure(1)\n", - " plt.plot(np.sin(np.linspace(0, 20, 100)))\n", - " plt.show()\n", - " \n", - " #fig=plt.figure(1 ,figsize=(x,y))\n", - " fig=plt.figure(1)\n", - " #plt.tight_layout()\n", - " \n", - " display(fig.canvas)\n" - ] } ], "metadata": { From 50ca83a43897944ff995cb4b538449b97fb6654d Mon Sep 17 00:00:00 2001 From: fdobad Date: Fri, 5 Jul 2019 12:00:10 -0400 Subject: [PATCH 3/3] unwanted irony --- .gitignore | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitignore b/.gitignore index 69424a05..c271c172 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,3 @@ -.gitignore -examples/gitignore.ipynb - *.egg-info/ .ipynb_checkpoints/ dist/