From 66308a9afe8fd9f9d236d4f739a634a01dd43d1b Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sun, 3 Jun 2018 21:32:12 -0500 Subject: [PATCH 01/22] DOC: edits to Part 1 - changes to the backend discussion - formatting changes - add color mapping to scatter up front --- ...b-Part1-Figures_Subplots_and_layouts.ipynb | 158 +++++++----------- 1 file changed, 65 insertions(+), 93 deletions(-) diff --git a/AnatomyOfMatplotlib-Part1-Figures_Subplots_and_layouts.ipynb b/AnatomyOfMatplotlib-Part1-Figures_Subplots_and_layouts.ipynb index 94e0cc2..f06de9e 100644 --- a/AnatomyOfMatplotlib-Part1-Figures_Subplots_and_layouts.ipynb +++ b/AnatomyOfMatplotlib-Part1-Figures_Subplots_and_layouts.ipynb @@ -1,20 +1,5 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false, - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "# Let printing work the same in Python 2 and 3\n", - "from __future__ import print_function" - ] - }, { "cell_type": "markdown", "metadata": { @@ -25,7 +10,13 @@ "source": [ "# Matplotlib\n", "## Introduction\n", - "Matplotlib is a library for producing publication-quality figures. mpl (for short) was designed from the beginning to serve two purposes. First, allow for interactive, cross-platform control of figures and plots, and second, to make it very easy to produce static raster or vector graphics files without the need for any GUIs. Furthermore, mpl -- much like Python itself -- gives the developer complete control over the appearance of their plots, while still being very usable through a powerful defaults system." + "\n", + "Matplotlib is a library for producing publication-quality figures. mpl (for short) was designed from the beginning to serve two purposes: \n", + "\n", + " 1. allow for interactive, cross-platform control of figures and plots\n", + " 2. make it easy to produce static raster or vector graphics files without the need for any GUIs. \n", + " \n", + "Furthermore, mpl -- much like Python itself -- gives the developer complete control over the appearance of their plots, while still being very usable through a powerful defaults system." ] }, { @@ -33,17 +24,19 @@ "metadata": {}, "source": [ "## Online Documentation\n", - "The [matplotlib.org](http://matplotlib.org) project website is the primary online resource for the library's documentation. It contains [examples](http://matplotlib.org/examples/index.html), [FAQs](http://matplotlib.org/faq/index.html), [API documentation](http://matplotlib.org/api/index.html), and, most importantly, the [gallery](http://matplotlib.org/gallery.html).\n", + "The [matplotlib.org](http://matplotlib.org) project website is the primary online resource for the library's documentation. It contains the [example galleries](https://matplotlib.org/gallery/index.html), [FAQs](http://matplotlib.org/faq/index.html), [API documentation](http://matplotlib.org/api/index.html), and [tutorials](https://matplotlib.org/tutorials/index.html).\n", "\n", "## Gallery\n", - "Many users of Matplotlib are often faced with the question, \"I want to make a figure that has X with Y in the same figure, but it needs to look like Z\". Good luck getting an answer from a web search with that query! This is why the [gallery](http://matplotlib.org/gallery.html) is so useful, because it showcases the variety of ways one can make figures. Browse through the gallery, click on any figure that has pieces of what you want to see and the code that generated it. Soon enough, you will be like a chef, mixing and matching components to produce your masterpiece!\n", + "Many users of Matplotlib are often faced with the question, \"I want to make a figure that has X with Y in the same figure, but it needs to look like Z\". Good luck getting an answer from a web search with that query! This is why the [gallery](https://matplotlib.org/gallery/index.html) is so useful, because it showcases the variety of ways one can make figures. Browse through the gallery, click on any figure that has pieces of what you want to see and the code that generated it. Soon enough, you will be like a chef, mixing and matching components to produce your masterpiece!\n", "\n", "As always, if you have a new and interesting plot that demonstrates a feature of Matplotlib, feel free to submit a concise, well-commented version of the code for inclusion in the gallery.\n", "\n", - "## Mailing Lists and StackOverflow\n", - "When you are just simply stuck, and cannot figure out how to get something to work, or just need some hints on how to get started, you will find much of the community at the matplotlib-users [mailing list](https://mail.python.org/mailman/listinfo/matplotlib-users). This mailing list is an excellent resource of information with many friendly members who just love to help out newcomers. The number one rule to remember with this list is to be persistant. While many questions do get answered fairly quickly, some do fall through the cracks, or the one person who knows the answer isn't available. Therefore, try again with your questions rephrased, or with a plot showing your attempts so far. We love plots, so an image showing what is wrong often gets the quickest responses.\n", + "## Mailing Lists, StackOverflow, and gitter\n", + "When you are just simply stuck, and cannot figure out how to get something to work, or just need some hints on how to get started, you will find much of the community at the matplotlib-users [mailing list](https://mail.python.org/mailman/listinfo/matplotlib-users). This mailing list is an excellent resource of information with many friendly members who just love to help out newcomers. We love plots, so an image showing what is wrong often gets the quickest responses.\n", + "\n", + "Another community resource is [StackOverflow](http://stackoverflow.com/questions/tagged/matplotlib), so if you need to build up karma points, submit your questions here, and help others out too! \n", "\n", - "Another community resource is [StackOverflow](http://stackoverflow.com/questions/tagged/matplotlib), so if you need to build up karma points, submit your questions here, and help others out too! We are also on [Gitter](https://gitter.im/matplotlib/matplotlib).\n", + "We are also on [Gitter](https://gitter.im/matplotlib/matplotlib).\n", "\n", "## Github repository\n", "### Location\n", @@ -58,15 +51,16 @@ "metadata": {}, "source": [ "# Quick note on \"backends\" and Jupyter notebooks\n", - "Matplotlib has multiple backends. The backends allow mpl to be used on a variety of platforms with a variety of GUI toolkits (GTK, Qt, Wx, etc.), all of them written so that most of the time, you will not need to care which backend you are using. " + "\n", + "Matplotlib has multiple \"backends\" that handle converting Matplotlib's in-memory representation of your plot into the colorful output you can look at. This is either by writing files (ex png, svg, pdf) thaht ou can use an external tool to look at or by embedding into your GUI toolkit of choice (Qt, Tk, Wx, etc).\n", + "\n", + "To check what backend Matplotlib is currently using:" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "import matplotlib\n", @@ -78,32 +72,32 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Normally we wouldn't need to think about this too much, but IPython/Jupyter notebooks behave a touch differently than \"normal\" python.\n", - "\n", - "Inside of IPython, it's often easiest to use the Jupyter ``nbagg`` or ``notebook`` backend. This allows plots to be displayed and interacted with in the browser in a Jupyter notebook. Otherwise, figures will pop up in a separate GUI window.\n", - "\n", - "We can do this in two ways:\n", - "\n", - "1. The IPython ``%matplotlib backend_name`` \"magic\" command (or ``plt.ion()``, which behaves similarly)\n", - " - Figures will be shown automatically by IPython, even if you don't call ``plt.show()``.\n", - " \n", - "2. ``matplotlib.use(\"backend_name\")``\n", - " - Figures will only be shown when you call ``plt.show()``.\n", - "\n", - "Here, we'll use the second method for one simple reason: it allows our code to behave the same way regardless of whether we run it inside of an Jupyter notebook or from a python script at the command line. Feel free to use the ``%matplotlib`` magic command if you'd prefer.\n", + "If you are working interactively at an (I)python prompt, the GUI framework is not critical (mostly aesthetic) however when working in Jupyter we need to pick a backend that integrates with Jupyter (javascript) framework.\n", "\n", - "One final note: You will always need to do this before you ``import matplotlib.pyplot as plt``." + "To select the backend use ``matplotlib.use(\"backend_name\")``, in this case we want ``'nbagg'``\n" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ - "matplotlib.use('nbagg')" + "matplotlib.use('nbagg')\n", + "print(matplotlib.get_backend())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "which must be done *before* you `import matplotlib.pyplot as plt`.\n", + "\n", + "You can also set the backend via a 'magic ``%matplotlib backend_name``. In addition to setting the backend, the magic also calls `plt.ion()`, which puts Matplotlib in 'interacitve mode' (the inverse is `plt.ioff()`). In 'interactive mode' figures are shown (injected into the web page in the notebook) as soon as they are created. Otherwise, figures are not shown until you explicitly call `plt.show()`.\n", + "\n", + "\n", + "In these tutorials we will mostly work in non-interactive mode for better control of when\n", + "figures are shown in the notebooks." ] }, { @@ -138,9 +132,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", @@ -159,12 +151,10 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ - "fig = plt.figure()" + "fig = plt.figure(facecolor=(1, 0, 0, .1)) # red background to see where the figure is" ] }, { @@ -179,9 +169,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "plt.show()" @@ -193,6 +181,7 @@ "source": [ "Great, a blank figure! Not terribly useful yet.\n", "\n", + "\n", "However, while we're on the topic, you can control the size of the figure through the ``figsize`` argument, which expects a tuple of ``(width, height)`` in inches. \n", "\n", "A really useful utility function is [`figaspect`](http://matplotlib.org/api/figure_api.html?highlight=figaspect#matplotlib.figure.figaspect)" @@ -201,13 +190,11 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "# Twice as tall as it is wide:\n", - "fig = plt.figure(figsize=plt.figaspect(2.0))\n", + "fig = plt.figure(figsize=plt.figaspect(2.0), facecolor=(1, 0, 0, .1))\n", "plt.show()" ] }, @@ -227,9 +214,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "fig = plt.figure()\n", @@ -254,16 +239,15 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "ax.set_xlim([0.5, 4.5])\n", "ax.set_ylim([-2, 8])\n", - "ax.set_title('An Example Axes')\n", - "ax.set_ylabel('Y-Axis')\n", - "ax.set_xlabel('X-Axis')" + "ax.set_title('An Diferent Example Axes Tile')\n", + "ax.set_ylabel('Y-Axis (changed)')\n", + "ax.set_xlabel('X-Axis (changed)')\n", + "fig.canvas.draw_idle()" ] }, { @@ -295,15 +279,13 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "fig = plt.figure()\n", "ax = fig.add_subplot(111)\n", "ax.plot([1, 2, 3, 4], [10, 20, 25, 30], color='lightblue', linewidth=3)\n", - "ax.scatter([0.3, 3.8, 1.2, 2.5], [11, 25, 9, 26], color='darkgreen', marker='^')\n", + "ax.scatter([0.3, 3.8, 1.2, 2.5], [11, 25, 9, 26], c=[1 ,2, 3, 5], marker='^')\n", "ax.set_xlim(0.5, 4.5)\n", "plt.show()" ] @@ -320,13 +302,11 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "plt.plot([1, 2, 3, 4], [10, 20, 25, 30], color='lightblue', linewidth=3)\n", - "plt.scatter([0.3, 3.8, 1.2, 2.5], [11, 25, 9, 26], color='darkgreen', marker='^')\n", + "plt.scatter([0.3, 3.8, 1.2, 2.5], [11, 25, 9, 26], c=[1, 2, 3, 5], marker='^')\n", "plt.xlim(0.5, 4.5)\n", "plt.show()" ] @@ -335,7 +315,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Much cleaner, and much clearer! So, why will most of my examples not follow the pyplot approach? Because [PEP20](http://www.python.org/dev/peps/pep-0020/) \"The Zen of Python\" says:\n", + "That is a bit terser and has fewer local varialbes, so, why will most of my examples not follow the pyplot approach? Because [PEP20](http://www.python.org/dev/peps/pep-0020/) \"The Zen of Python\" says:\n", "\n", "\"Explicit is better than implicit\"\n", "\n", @@ -358,9 +338,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "fig, axes = plt.subplots(nrows=2, ncols=2)\n", @@ -381,9 +359,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "fig, axes = plt.subplots(nrows=2, ncols=2)\n", @@ -441,9 +417,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "%load exercises/1.1-subplots_and_basic_plotting.py" @@ -452,9 +426,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", @@ -473,23 +445,23 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 2", + "display_name": "Python 3", "language": "python", - "name": "python2" + "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", - "version": 2 + "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.12" + "pygments_lexer": "ipython3", + "version": "3.6.5" } }, "nbformat": 4, - "nbformat_minor": 0 + "nbformat_minor": 1 } From dba20c6357cf470b2e8c83601d18f0b65f9c12c1 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sun, 3 Jun 2018 22:17:48 -0500 Subject: [PATCH 02/22] ENH: switch problem 2.2 away from classic style --- .../2.2-vmin_vmax_imshow_and_colorbars.py | 2 -- ...ise_2.2-vmin_vmax_imshow_and_colorbars.png | Bin 13142 -> 53155 bytes .../2.2-vmin_vmax_imshow_and_colorbars.py | 1 - 3 files changed, 3 deletions(-) diff --git a/exercises/2.2-vmin_vmax_imshow_and_colorbars.py b/exercises/2.2-vmin_vmax_imshow_and_colorbars.py index 0b504f2..4922fb3 100644 --- a/exercises/2.2-vmin_vmax_imshow_and_colorbars.py +++ b/exercises/2.2-vmin_vmax_imshow_and_colorbars.py @@ -2,8 +2,6 @@ import matplotlib.pyplot as plt np.random.seed(1) -plt.style.use('classic') - # Generate random data with different ranges... data1 = np.random.random((10, 10)) data2 = 2 * np.random.random((10, 10)) diff --git a/images/exercise_2.2-vmin_vmax_imshow_and_colorbars.png b/images/exercise_2.2-vmin_vmax_imshow_and_colorbars.png index 66aaa3e81c511ba8d34181bb792fea87b70df5a9..45db4d946dd07594e8cabf4d74ccf51a64230ee6 100644 GIT binary patch literal 53155 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�r z7|g~;^`%so{nQ~rVn<7$n$X8Hv!t*^k0iKia_X=jNsXgbaS z!;90poB7Nplo7|vZVo|2lhRFXCh!dwEie1j| zY+1=c&k(DotaF>A&EShNyyVj_52=cpwl#qwcBLHzmUaV8O}nD7IbVUzY2pQ@SEV#R zDG}?}%>sMH!8cFEM)h^KMTrxzvIe!ozhn1;T}fImd}VmSRUd~uFbq6a9(mQ=+GTIs z|7$;DZG9<5)SzF^qeZ?pzalNt{U8Y>H{!RQSMmen=o{en!?LcS&Uk%m`(p8i?Sl1j zxiyx)ZyZMeLl1uQWClpIHX)I8v73q(G(;}jCrIw~%`PP-12ZDp-Kg3i9S`un-R8Yt zzC zriwXw%lmFSm)>SLcKdxVF#hO@y9nC!eOzdW8_FNjW_9_;~6x~(WB_Nj0w}NN; zdsftfi5#N6aZ}aV7M_vmj(_s?6do7|j_I}MU*rc)=nhupM61|T#PVOv7<1R&_3^&k zq6&F~MM8%O2ew!=H;onEmty&zgE=9X^YEG{WDj9N2nb0FW{}DLAfA}&d9@qBtB%6=y}Yg`FFoYSyh6eFN(PMa-6R7bCrhMV2=?fgB9pj?7oTa|$TA=1Y^>08tvvNOuZ4AZS|)LET+(vKjP68UdhOJ%ZDG_;eBL?lAQed+MR%O{Vvliz@WyTr9`CpI+X0 zn6rLbS2@M@*x7u3SVYp= z$Diu^osB zE4_NOoPKs>_{q>N>=Ip*5l)5-8y}VZ#Q`bgpf<>DJLLfI1{UzEn5QJP^tbQPsi&bJoMVgGuc{L(7CbPA?yZrjR^tUj$|_&dL+dF4stH;!Gk z$Iclni_jQ&;u@|oaByI$5TYXuQ`m2;N=m1+Sfx43kC(MDXWNYE&EQ9;o)4@^Ua6{< z0%lyz$xyJwj`xA#rIx1>MI~ei<1IeMeD?I~wN5YxTHnxxcIW<~zK^RPXSSVzMUS}q zU#&QJcBI$8uVU{Vy;oDAT3@{U^}MB;sA*nT!wzWHstpWLGIH#}mTFxNsKk7*SZg<` zs=C5(Q`uPbmBzka=24s2A_wb1h~RwVt%|AE|JZPDA_Uqxj|^8Gq(*xhew8gOI}H=! zF0QTaw6&g66vOPfJpXthSb(f!%_-|t)uOcLrop?BQDZ#+umMtNed572>YlfB`LZ@u zu5NAh)KB1=3>bqU;)|=|?_1B9UMt9Jskx|f{4yXZqrZi1iC0_vIoz``a9DqFZMO?m z(?$m~kkU|2{a1|)JNI}@+r`%I6Posq*A#GD2o2VeYgCJ7yn$g2?Wk4e_?6%8oudxs z{hlAv{}p||7v7=xNbzEu@D=VMpUm3Sc&e?-n%&pliCTmic=SNxVw&Di#D9`gZ-4mr zPMaUgm#^o|;AVU+c%soUqjnQ4$cJBSXR`8cFznBbVq(o%mE()SmLHojvS?3fO38A* ztKQFo<=%!ra&4cWN>RB-Rr5MA+i z_ZMAti8eaWv<-RD5Pic=gS)R_1uICuJN~3{{00C?ipd*}{f8;Ayjv?s*2er$QABjH zogW*czxq?Vcy<1%uZO3WJ(l7WDJo>fdEbfWJnMakT8b`fk5s$=~e9g=yRX@_dXwgfF~#W?6db? zG5Q(Jz<6^$@4g-?M}Vp*!VWubN{_Qsm?t8nu1>>=X zS5vlVhs!pb%Ptsc+=72ypD5Q!mY4?g5v(`M>fL+gLME-&ZqMin?2B@Ed#4*tU`9pQ zvhJRSpFlaAAIg9tHz@r0;`o*^ez*;~!Y(b_qM5(Tf6`8+mEX!`C(icUppUDK@g-~* zKlG9M#@PNR&<#HBzNh6#E-8=G>Q+l#Fk>&>)98`;Fn zdH+l%&B;?qqyVES@1y3|sy2e6^nKKR7?g3xn(_5D9lzwdHofNWTFvgzi{PFKXmeB4 z^fxj$!3W&vB_yO4CDobRqF)_JOLcgn?Btx^6jOB!OhNp+9DOygoOV?>dFK$BdIE|} zdg#+EY_>sbQm;4|NieFd^_)YT$)rTw(}!tc+%tJ8np90jbrU8NO#3Uy37BKjpDU<7 zII%*w;zBmrqZ?nMJk%98WJxC7EiLdLU=!~9p3XU4q8vBW(3Tp{&209}KF=mt=cseb zrJEu^V3fG$;v}V;62qvf%^jC9KBZ(SM)iX*E{)G3c(2y@hQ+59_3~+2@LS6`%vc3< zI+pyK-kQa5VKEaT);VVOYf@34x$}$Jj#*GN(-%%QU0aMnKfBJ%*f`7%6*>4X5X!|N zKZa#R|*6l<+bv;O^yhccH3yc6f{o)w3aOd5CkJ;&p?gfu9+gp?C*IS zPn(XadO{{a=DWnk|IJC+v>K$!RC(gp16?|5@9*bJHXDqU`wV4g#UV&KQ8Yi5wQrM0 zF(e5sJ1N*_T$6RDy|fhv_$+>=PU9)9TghIPB`JV+00DuG6IcJz+~+6Rjg5eFSOWbZ zKBijEAkX7*htrG73aqJ3g`(jom&P@r#1*^kQJHNet)#4m(!S|NsKK>5U%_vqO-s&= zmU-bjJ9{hvkd1bs+No^bNtBVl56h+A>VY_vrWpd+Ud^pnmeh#4tnRt^`oVA%*V zud3}?Hu9K=V?y@!)Cd&j2_5l(dfV)z3MXmW7J*L{8fw?$3}=`~@u|;;4rlbc$CQOH zuJZ`ig4O-G(5kQ~&6{Tu%}L_D!G*7<&eXEgMS^rjg8iYe53{XI|MLcg7wph>DsOY9 zeY?b^tI$)C)-UE%)Ejbkvx}+oo_a{b#VDN~-I?BZUpc271x%;RQVrH@-El9es5!#; zY-{J;^F|LnA9vjA0wx6;dL<55csaRNssNl9azwk`o;YbCnz9hrmgdgmgI#LR$xEO% zffU>b(}wI~)maotB_t3(c8O^qT~9Adw5)W<#t%F_-7^_SGgwzS5#^=vIGHvkdY&#k zDCio%S}hDlFWeVa?-QE*0$nzxs0$G~<(a}U(LB{mVe>wyYkTxI{(Cqbx)f3@)3~js zVU9Dr$=^R5fYV^2mumV+157s14SS~VbsGlwtxZijH~VbUvBUX-{RP{M zF9i=)4@HH_6)}hm(gfwl^bhSq_pB^K_IHkVqO=vu)d|(Bb*83C*d47g1GkZba18GL3HnRg*D~_fCSVedB0kP#)aQtnexOI)5RR^y5skoS z{kIOtrS+DRDF{}<)}r7KA&o>EsiHY5W%m?P0xB913DaL*H<)1&)dDR8Y}I!)b7?v^ zi*j4XM%;*Z7^D!2`^c~xMT&whdRO?+mS@NUQk~zf4i2d~(#Y*Ox7s7meMI9GBAfYB z!yXJ_?zP69WqFST8uGB!g=D9n?c3n={et_Rr)HeNKp|+eZI6(n6Tcj7_#g#df9c-D zSH}q&SOO0^Nm{$b?KH!R*W!)5B6Stkx_^EwRHSGk;&?6G6AD12Sb_9DqaeP8eF~#` zT<0d8-&+3aE?%b#u=hb4|Ft2mi!m(odgTGQd2ySklg%YKGA?%v${co<4*o%tx~|oN z_e_)OF8?q$S3OL2W+Y}IJ3@Xp-?LB%U3FQvg6L%#$;-Nf0<)2aPwZHe0A44-&hjmO zt*Upr^xpJiqF!`pAnn^O;j1UW3@9`NKnybgno)nC-Edm)=kJFVO$RxNExDmuD(BjQ z!cJG^O_0@X}oa>(mL0D+F1k8?KhDxJ(Sv~>x=3HhKUI^QBodAhe_ zBO^%n3@_8~BhjFI@L*uDb&ShBsXvh!C)$l_Z4-r~gY3u8^wS3p?xmFo#t<->$cU&_ z9%BqQajRdJDyOUt$AV`YY`4jGi?Kath27j+Mw~_P&~Y|pVTjTI?4LBP<}AEMeYNt3 z2Q*QVMZO(_QJBWhLv*>^hv}@)*(~=}p303Aq|g}>QKY33Fqj*P>MK`HDs&H#pSbR9 z=rF!|KkvqXI;Grad_x?E^skG+k6}rDi6Oj*oRvDWU-k>}c9`-0$f-~+$7;~InR>Zm z(t)rso5NE@-u(G8D6Zx#&Q9e^g`{pKr35Z(8YNIXIW15K-^c(1bt%+6D>Yy{aC<^= z07_;R=^v$_^AlD<;IIm8=?3|c%OKCPGS@YAXJy|FI2(c2VzP0ih^;=!{fxWkmtkP8}VWmH#FKpFr z=AN-tq?e^9qwkiEmU0`SL#FN^47nC;PfE)7p59Zl5B6eiitqHYOgZFl>;QU2KT$9hw5g^DP3{H6qNXN`AgqtQvOW8n-K&LE7%5v_|#F*Q&-= z868((Q9M`F2{L`L=koFiq4l77t%o&|FFsF2(8IjKX2qZ_@7%Q|#j@UE&Gd^aVpN~4 zpO}4+aD*Bnn&nb3K%BBDLD+4%xcQ;Ui=opO9Xkpf^VQyiK7C`pYM5Z85pWyXx*^e+ zPRrF0;6d3zH~EXJde&5sF%2PcrQvfy?zaap+C7bzjL?;WZ0AJof6OWj@5 zrpsp;pCEtGS#cMEyTvsmAzF)wj_m}UB_(=vo=*Y7(z$UV)2R#kf^?ZhlWYPZFm4+LuuMez(<#zeqSRO*_h&X0JZu^PiQ z3Kkl`Vu{{1$p8A?5TA9y1|6B2fo$rmXii0gTC)(W|-Ul7eEoq0*Wyrg*FbV~_M2q%Hmgw-_A_0@fK!4^$dW9nSU!IS34t$53$pvSu-`=uFX2lDoa z1_VCWJCW9X+)e{gj@?E1iTDx3f!tq)>lF815fjc*{a&&rl;CJuHEv7xC}=)N2p(i8 z-tg514N#7~?&~<39Gr@@+o)6W(x6L8lYuKbefSUj0uS-~UK(0DfC1hPG`a;QP3c4u z9N204DZT9yz(?D=?N)|0aiRAkiEXLpMlD zRLEaq9GZ)~Mu}JsX+}$9==bUfNe4-NX`sODAYRl=_kJovtasjfYeugH->hn= z75!$z!YM0zw>qup4wt$hgk&i~yvNBZDXjN6-BlqUVb91FK6?L1vhIS>UX@*e;2+2O zwisO;Z;$2d#vICUNt+h_W>tQ6JnG!swJ&e2wct>Hsd+>?ca(p|6=x(q@WWp6A2El literal 13142 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 T+FLmM2gA-;oF$yOa_7GRGuw)! diff --git a/solutions/2.2-vmin_vmax_imshow_and_colorbars.py b/solutions/2.2-vmin_vmax_imshow_and_colorbars.py index da67e7b..2bc76a8 100644 --- a/solutions/2.2-vmin_vmax_imshow_and_colorbars.py +++ b/solutions/2.2-vmin_vmax_imshow_and_colorbars.py @@ -2,7 +2,6 @@ import matplotlib.pyplot as plt np.random.seed(1) -plt.style.use('classic') # Generate random data with different ranges... data1 = np.random.random((10, 10)) From dd049413394af0f2884e66ae015edea2c041028b Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sun, 3 Jun 2018 22:36:46 -0500 Subject: [PATCH 03/22] DOC: minor edits do data kwarg discussion + code style + links --- ...tlib-Part2-Plotting_Methods_Overview.ipynb | 80 +++++++------------ 1 file changed, 28 insertions(+), 52 deletions(-) diff --git a/AnatomyOfMatplotlib-Part2-Plotting_Methods_Overview.ipynb b/AnatomyOfMatplotlib-Part2-Plotting_Methods_Overview.ipynb index b354ba0..6ab58e8 100644 --- a/AnatomyOfMatplotlib-Part2-Plotting_Methods_Overview.ipynb +++ b/AnatomyOfMatplotlib-Part2-Plotting_Methods_Overview.ipynb @@ -47,9 +47,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "# Let's get our standard imports out of the way\n", @@ -77,9 +75,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "np.random.seed(1)\n", @@ -111,9 +107,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "fig, ax = plt.subplots()\n", @@ -147,9 +141,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "np.random.seed(1)\n", @@ -171,9 +163,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "x = np.linspace(0, 10, 200)\n", @@ -197,7 +187,8 @@ "metadata": {}, "source": [ "## `data` keyword argument\n", - "When using specialized data structures such as Pandas DataFrame and XArray, the input data to be plotted are accessed like dictionary elements. This can get very repetitive and tedious as one types out a plotting command accessing those elements. So, the `data` keyword argument was added to many of the plotting functions in v1.5. With this feature, one can pass in a single dictionary-like object as `data`, and use the string key names in the place of the usual input data arguments.\n", + "\n", + "When using nested data structures such as h5py objects, Pandas DataFrames, or XArrays, the data can be accessed via `[]` like dictionary elements. This can get very repetitive and tedious as one types out a plotting command accessing those elements. So, the `data` keyword argument was added to almost all of the plotting functions in v1.5. With this feature, one can pass in a single dictionary-like object as `data`, and use the string key names in the place of the usual input data arguments.\n", "\n", "Let's revisit the above example:" ] @@ -205,9 +196,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "x = np.linspace(0, 10, 200)\n", @@ -242,9 +231,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "%load exercises/2.1-bar_and_fill_between.py" @@ -253,9 +240,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", @@ -316,9 +301,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "from matplotlib.cbook import get_sample_data\n", @@ -342,9 +325,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "fig, ax = plt.subplots()\n", @@ -377,22 +358,22 @@ " \n", "`vmin` and `vmax` are particularly useful. Quite often, you'll want the colors to be mapped to a set range of data values, which aren't the min/max of your input data. For example, you might want a symmetric ranges of values around 0.\n", "\n", - "As an example of that, let's use a divergent colormap with the data we showed earlier. We'll also use `interpolation=\"nearest\"` to \"turn off\" interpolation of the cells in the input dataset:" + "See the documentation for longer discussions of [colormaps](https://matplotlib.org/tutorials/colors/colormaps.html) and [norms](https://matplotlib.org/tutorials/colors/colormapnorms.html).\n", + "\n", + "As an example of that, let's use a divergent colormap with the data we showed earlier. " ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "from matplotlib.cbook import get_sample_data\n", "data = np.load(get_sample_data('axes_grid/bivariate_normal.npy'))\n", "\n", "fig, ax = plt.subplots()\n", - "im = ax.imshow(data, cmap='seismic', interpolation='nearest')\n", + "im = ax.imshow(data, cmap='seismic')\n", "fig.colorbar(im)\n", "plt.show()" ] @@ -407,13 +388,12 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "fig, ax = plt.subplots()\n", - "im = ax.imshow(data, cmap='seismic', interpolation='nearest',\n", + "im = ax.imshow(data, \n", + " cmap='seismic',\n", " vmin=-2, vmax=2)\n", "fig.colorbar(im)\n", "plt.show()" @@ -434,9 +414,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "%load exercises/2.2-vmin_vmax_imshow_and_colorbars.py" @@ -445,9 +423,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", @@ -472,23 +448,23 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 2", + "display_name": "Python 3", "language": "python", - "name": "python2" + "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", - "version": 2 + "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.12" + "pygments_lexer": "ipython3", + "version": "3.6.5" } }, "nbformat": 4, - "nbformat_minor": 0 + "nbformat_minor": 1 } From 7ced77a0a6654a8c474f363813eb9c50a4da2d2e Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sun, 3 Jun 2018 23:11:22 -0500 Subject: [PATCH 04/22] DOC: tweak comments about color --- AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb | 105 ++++++------------ 1 file changed, 36 insertions(+), 69 deletions(-) diff --git a/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb b/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb index 8afa98f..5c572bf 100644 --- a/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb +++ b/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb @@ -3,14 +3,12 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "# Let printing work the same in Python 2 and 3\n", "from __future__ import print_function\n", - "# Turning on inline plots -- just for use in jupyter notebooks.\n", + "# Turning on notebook plots -- just for use in jupyter notebooks.\n", "import matplotlib\n", "matplotlib.use('nbagg')\n", "import numpy as np\n", @@ -45,23 +43,26 @@ "- k: black\n", "- w: white\n", "\n", - "Other colornames that are allowed are the HTML/CSS colornames such as \"burlywood\" and \"chartreuse\". See the [full list](http://www.w3schools.com/html/html_colornames.asp) of the 147 colornames. For the British speaking and poor spellers among us (I am not implying that British speakers are poor spellers!), we allow \"grey\" where-ever \"gray\" appears in that list of colornames. All of these colornames are case-insensitive.\n", + "Other colornames that are allowed are the HTML/CSS colornames such as \"burlywood\" and \"chartreuse\". See the [full list](http://www.w3schools.com/html/html_colornames.asp) of the 147 colornames. \n", + "\n", + "Matplotlib supports the [xkcd color names](https://xkcd.com/color/rgb/) prefxed by `'xkcd:'`.\n", + "\n", + "Matplotlib also understands `{'tab:blue', 'tab:orange', 'tab:green', 'tab:red', 'tab:purple', 'tab:brown', 'tab:pink', 'tab:gray', 'tab:olive', 'tab:cyan'}` which are the Tableau Colors from the ‘T10’ categorical palette (and the default color cycle);\n", "\n", "### Hex values\n", "Colors can also be specified by supplying a HTML/CSS hex string, such as `'#0000FF'` for blue. Support for an optional alpha channel was added for v2.0.\n", "\n", - "### 256 Shades of Gray\n", - "A gray level can be given instead of a color by passing a string representation of a number between 0 and 1, inclusive. `'0.0'` is black, while `'1.0'` is white. `'0.75'` would be a light shade of gray.\n", + "### Cycle references\n", + "With the advent of fancier color cycles coming from the many available styles, users needed a way to reference those colors in the style without explicitly knowing what they are. So, in v2.0, the ability to reference the first 10 iterations of the color cycle was added. Whereever one could specify a color, you can supply a 2 character string of 'C#'. So, 'C0' would be the first color, 'C1' would be the second, and so on and so forth up to 'C9'.\n", + "\n", "\n", "### RGB[A] tuples\n", - "You may come upon instances where the previous ways of specifying colors do not work. This can sometimes happen in some of the deeper, stranger levels of the library. When all else fails, the universal language of colors for matplotlib is the RGB[A] tuple. This is the \"Red\", \"Green\", \"Blue\", and sometimes \"Alpha\" tuple of floats in the range of [0, 1]. One means full saturation of that channel, so a red RGBA tuple would be `(1.0, 0.0, 0.0, 1.0)`, whereas a partly transparent green RGBA tuple would be `(0.0, 1.0, 0.0, 0.75)`. The documentation will usually specify whether it accepts RGB or RGBA tuples. Sometimes, a list of tuples would be required for multiple colors, and you can even supply a Nx3 or Nx4 numpy array in such cases.\n", + "You may come upon instances where the previous ways of specifying colors do not work. When all else fails, the universal language of colors for matplotlib is the RGB[A] tuple. This is the \"Red\", \"Green\", \"Blue\", and sometimes \"Alpha\" tuple of floats in the range of [0, 1]. One means full saturation of that channel, so a red RGBA tuple would be `(1.0, 0.0, 0.0, 1.0)`, whereas a partly transparent green RGBA tuple would be `(0.0, 1.0, 0.0, 0.75)`. The documentation will usually specify whether it accepts RGB or RGBA tuples. Sometimes, a list of tuples would be required for multiple colors, and you can even supply a Nx3 or Nx4 numpy array in such cases.\n", "\n", "In functions such as `plot()` and `scatter()`, while it may appear that they can take a color specification, what they really need is a \"format specification\", which includes color as part of the format. Unfortunately, such specifications are string only and so RGB[A] tuples are not supported for such arguments (but you can still pass an RGB[A] tuple for a \"color\" argument).\n", "\n", "Oftentimes there is a separate argument for \"alpha\" where-ever you can specify a color. The value for \"alpha\" will usually take precedence over the alpha value in the RGBA tuple. There is no easy way around this inconsistency.\n", - "\n", - "### Cycle references\n", - "With the advent of fancier color cycles coming from the many available styles, users needed a way to reference those colors in the style without explicitly knowing what they are. So, in v2.0, the ability to reference the first 10 iterations of the color cycle was added. Whereever one could specify a color, you can supply a 2 character string of 'C#'. So, 'C0' would be the first color, 'C1' would be the second, and so on and so forth up to 'C9'." + "\n" ] }, { @@ -75,20 +76,16 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ - "%load exercises/3.1-colors.py" + "%load exercises/3.1-colors.py\n" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "t = np.arange(0.0, 5.0, 0.2)\n", @@ -119,9 +116,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "xs, ys = np.mgrid[:4, 9:0:-1]\n", @@ -151,9 +146,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "%load exercises/3.2-markers.py" @@ -162,9 +155,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "t = np.arange(0.0, 5.0, 0.2)\n", @@ -195,9 +186,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "t = np.arange(0.0, 5.0, 0.2)\n", @@ -215,9 +204,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "fig, ax = plt.subplots(1, 1)\n", @@ -236,9 +223,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "t = np.arange(0., 5., 0.2)\n", @@ -284,9 +269,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "%load exercises/3.3-properties.py" @@ -295,9 +278,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "t = np.arange(0.0, 5.0, 0.1)\n", @@ -323,9 +304,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "# %load http://matplotlib.org/mpl_examples/color/colormaps_reference.py\n", @@ -434,9 +413,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "fig, (ax1, ax2) = plt.subplots(1, 2)\n", @@ -457,9 +434,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "plt.scatter([1, 2, 3, 4], [4, 3, 2, 1])\n", @@ -505,9 +480,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "import matplotlib as mpl\n", @@ -532,9 +505,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "mpl.rc('axes', prop_cycle=cycler('color', ['r', 'orange', 'c', 'y']) +\n", @@ -575,9 +546,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "import matplotlib\n", @@ -594,9 +563,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "import matplotlib as mpl\n", @@ -624,23 +591,23 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 2", + "display_name": "Python 3", "language": "python", - "name": "python2" + "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", - "version": 2 + "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.12" + "pygments_lexer": "ipython3", + "version": "3.6.5" } }, "nbformat": 4, - "nbformat_minor": 0 + "nbformat_minor": 1 } From 206a25bd64a76e21238082c8115cca8d25d04c2a Mon Sep 17 00:00:00 2001 From: Benjamin Root Date: Wed, 13 Jun 2018 20:55:56 -0400 Subject: [PATCH 05/22] Adding notes on testing the tutorial install --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ee93428..9493e3f 100644 --- a/README.md +++ b/README.md @@ -26,4 +26,5 @@ git clone https://github.com/WeatherGod/AnatomyOfMatplotlib.git cd AnatomyOfMatplotlib jupyter notebook ``` +A browser window should appear and you can verify that everything works as expected by clicking on the `Test Install.ipynb` notebook. There, you will see a "code cell" that you can execute. Run it, and you should see a very simple line plot, indicating that all is well. From 7128e50033c9ca47d8506deb8f5e3a5cc31b6cf9 Mon Sep 17 00:00:00 2001 From: Benjamin Root Date: Wed, 13 Jun 2018 20:58:55 -0400 Subject: [PATCH 06/22] Update links in readme.md --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 9493e3f..3cb647b 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,13 @@ Please fork and contribute back improvements! Feel free to use this tutorial for conferences and other opportunities for training. The tutorial can be viewed on [nbviewer](http://nbviewer.jupyter.org): -* [Part 0: Introduction To NumPy](http://nbviewer.jupyter.org/github/WeatherGod/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part0-Intro2NumPy.ipynb) -* [Part 1: Overview of Matplotlib](http://nbviewer.jupyter.org/github/WeatherGod/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part1-Figures_Subplots_and_layouts.ipynb) -* [Part 2: Plotting Methods](http://nbviewer.jupyter.org/github/WeatherGod/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part2-Plotting_Methods_Overview.ipynb) -* [Part 3: How To Speak MPL](http://nbviewer.jupyter.org/github/WeatherGod/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb) -* [Part 4: Limits, Legends, and Layouts](http://nbviewer.jupyter.org/github/WeatherGod/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part4-Limits_Legends_and_Layouts.ipynb) -* [Part 5: Artists](http://nbviewer.jupyter.org/github/WeatherGod/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part5-Artists.ipynb) -* [Part 6: mpl_toolkits](http://nbviewer.jupyter.org/github/WeatherGod/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part6-mpl_toolkits.ipynb) +* [Part 0: Introduction To NumPy](http://nbviewer.jupyter.org/github/matplotlib/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part0-Intro2NumPy.ipynb) +* [Part 1: Overview of Matplotlib](http://nbviewer.jupyter.org/github/matplotlib/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part1-Figures_Subplots_and_layouts.ipynb) +* [Part 2: Plotting Methods](http://nbviewer.jupyter.org/github/matplotlib/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part2-Plotting_Methods_Overview.ipynb) +* [Part 3: How To Speak MPL](http://nbviewer.jupyter.org/github/matplotlib/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb) +* [Part 4: Limits, Legends, and Layouts](http://nbviewer.jupyter.org/github/matplotlib/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part4-Limits_Legends_and_Layouts.ipynb) +* [Part 5: Artists](http://nbviewer.jupyter.org/github/matplotlib/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part5-Artists.ipynb) +* [Part 6: mpl_toolkits](http://nbviewer.jupyter.org/github/matplotlib/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part6-mpl_toolkits.ipynb) # Installation All you need is matplotlib (v1.5 or greater) and jupyter installed. From 8c0fa6f65c50271300c317bb9fa9981bb5b20da5 Mon Sep 17 00:00:00 2001 From: Benjamin Root Date: Wed, 13 Jun 2018 21:01:29 -0400 Subject: [PATCH 07/22] Update README.md I swear, this is the last remnant of the WeatherGod repo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3cb647b..726412c 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ You can use your favorite Python package installer for this: ```bash conda install matplotlib jupyter -git clone https://github.com/WeatherGod/AnatomyOfMatplotlib.git +git clone https://github.com/matplotlib/AnatomyOfMatplotlib.git cd AnatomyOfMatplotlib jupyter notebook ``` From 5d4d1ee485572c650f30ac40c1929ccf74e2c87e Mon Sep 17 00:00:00 2001 From: Benjamin Root Date: Wed, 27 Jun 2018 21:06:17 -0400 Subject: [PATCH 08/22] Some copy-editing, and putting backa from __future__ that was taken out --- ...b-Part1-Figures_Subplots_and_layouts.ipynb | 28 +++++++++++++++---- AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb | 4 ++- exercises/1.1-subplots_and_basic_plotting.py | 2 -- solutions/1.1-subplots_and_basic_plotting.py | 2 -- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/AnatomyOfMatplotlib-Part1-Figures_Subplots_and_layouts.ipynb b/AnatomyOfMatplotlib-Part1-Figures_Subplots_and_layouts.ipynb index f06de9e..efa6b8a 100644 --- a/AnatomyOfMatplotlib-Part1-Figures_Subplots_and_layouts.ipynb +++ b/AnatomyOfMatplotlib-Part1-Figures_Subplots_and_layouts.ipynb @@ -1,5 +1,20 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false, + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "# Let printing work the same in Python 2 and 3\n", + "from __future__ import print_function" + ] + }, { "cell_type": "markdown", "metadata": { @@ -52,7 +67,7 @@ "source": [ "# Quick note on \"backends\" and Jupyter notebooks\n", "\n", - "Matplotlib has multiple \"backends\" that handle converting Matplotlib's in-memory representation of your plot into the colorful output you can look at. This is either by writing files (ex png, svg, pdf) thaht ou can use an external tool to look at or by embedding into your GUI toolkit of choice (Qt, Tk, Wx, etc).\n", + "Matplotlib has multiple \"backends\" that handle converting Matplotlib's in-memory representation of your plot into the colorful output you can look at. This is done either by writing files (e.g., png, svg, pdf) that you can use an external tool to look at or by embedding into your GUI toolkit of choice (Qt, Tk, Wx, etc).\n", "\n", "To check what backend Matplotlib is currently using:" ] @@ -93,11 +108,12 @@ "source": [ "which must be done *before* you `import matplotlib.pyplot as plt`.\n", "\n", - "You can also set the backend via a 'magic ``%matplotlib backend_name``. In addition to setting the backend, the magic also calls `plt.ion()`, which puts Matplotlib in 'interacitve mode' (the inverse is `plt.ioff()`). In 'interactive mode' figures are shown (injected into the web page in the notebook) as soon as they are created. Otherwise, figures are not shown until you explicitly call `plt.show()`.\n", + "You can also set the backend via an 'ipython magic' ``%matplotlib backend_name``. In addition to setting the backend, the magic also calls `plt.ion()`, which puts Matplotlib in 'interacitve mode' (the inverse is `plt.ioff()`). In 'interactive mode' figures are shown (injected into the web page in the notebook) as soon as they are created. Otherwise, figures are not shown until you explicitly call `plt.show()`.\n", "\n", "\n", "In these tutorials we will mostly work in non-interactive mode for better control of when\n", - "figures are shown in the notebooks." + "figures are shown in the notebooks.\n", + "This also better mimics the behavior you can expect in regular python scripts.\n" ] }, { @@ -244,10 +260,10 @@ "source": [ "ax.set_xlim([0.5, 4.5])\n", "ax.set_ylim([-2, 8])\n", - "ax.set_title('An Diferent Example Axes Tile')\n", + "ax.set_title('A Different Example Axes Title')\n", "ax.set_ylabel('Y-Axis (changed)')\n", "ax.set_xlabel('X-Axis (changed)')\n", - "fig.canvas.draw_idle()" + "plt.show()" ] }, { @@ -285,7 +301,7 @@ "fig = plt.figure()\n", "ax = fig.add_subplot(111)\n", "ax.plot([1, 2, 3, 4], [10, 20, 25, 30], color='lightblue', linewidth=3)\n", - "ax.scatter([0.3, 3.8, 1.2, 2.5], [11, 25, 9, 26], c=[1 ,2, 3, 5], marker='^')\n", + "ax.scatter([0.3, 3.8, 1.2, 2.5], [11, 25, 9, 26], c=[1, 2, 3, 5], marker='^')\n", "ax.set_xlim(0.5, 4.5)\n", "plt.show()" ] diff --git a/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb b/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb index 5c572bf..5f7c0e7 100644 --- a/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb +++ b/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb @@ -52,10 +52,12 @@ "### Hex values\n", "Colors can also be specified by supplying a HTML/CSS hex string, such as `'#0000FF'` for blue. Support for an optional alpha channel was added for v2.0.\n", "\n", + "### 256 Shades of Gray\n", + "A gray level can be given instead of a color by passing a string representation of a number between 0 and 1, inclusive. `'0.0'` is black, while `'1.0'` is white. `'0.75'` would be a light shade of gray.\n", + "\n", "### Cycle references\n", "With the advent of fancier color cycles coming from the many available styles, users needed a way to reference those colors in the style without explicitly knowing what they are. So, in v2.0, the ability to reference the first 10 iterations of the color cycle was added. Whereever one could specify a color, you can supply a 2 character string of 'C#'. So, 'C0' would be the first color, 'C1' would be the second, and so on and so forth up to 'C9'.\n", "\n", - "\n", "### RGB[A] tuples\n", "You may come upon instances where the previous ways of specifying colors do not work. When all else fails, the universal language of colors for matplotlib is the RGB[A] tuple. This is the \"Red\", \"Green\", \"Blue\", and sometimes \"Alpha\" tuple of floats in the range of [0, 1]. One means full saturation of that channel, so a red RGBA tuple would be `(1.0, 0.0, 0.0, 1.0)`, whereas a partly transparent green RGBA tuple would be `(0.0, 1.0, 0.0, 0.75)`. The documentation will usually specify whether it accepts RGB or RGBA tuples. Sometimes, a list of tuples would be required for multiple colors, and you can even supply a Nx3 or Nx4 numpy array in such cases.\n", "\n", diff --git a/exercises/1.1-subplots_and_basic_plotting.py b/exercises/1.1-subplots_and_basic_plotting.py index 1e4df45..1ff79ca 100644 --- a/exercises/1.1-subplots_and_basic_plotting.py +++ b/exercises/1.1-subplots_and_basic_plotting.py @@ -1,8 +1,6 @@ import numpy as np import matplotlib.pyplot as plt -plt.style.use('classic') - # Try to reproduce the figure shown in images/exercise_1-1.png # Our data... diff --git a/solutions/1.1-subplots_and_basic_plotting.py b/solutions/1.1-subplots_and_basic_plotting.py index cd23241..4a641d6 100644 --- a/solutions/1.1-subplots_and_basic_plotting.py +++ b/solutions/1.1-subplots_and_basic_plotting.py @@ -1,8 +1,6 @@ import numpy as np import matplotlib.pyplot as plt -plt.style.use('classic') - x = np.linspace(0, 10, 100) y1, y2, y3 = np.cos(x), np.cos(x + 1), np.cos(x + 2) names = ['Signal 1', 'Signal 2', 'Signal 3'] From 1cb4797c70bb20a242fb6a7cb19534295d2cdb80 Mon Sep 17 00:00:00 2001 From: Benjamin Root Date: Mon, 9 Jul 2018 17:21:52 -0400 Subject: [PATCH 09/22] Fix some typos in part3 and a dead link --- AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb b/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb index 5f7c0e7..d7bbf0e 100644 --- a/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb +++ b/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb @@ -43,7 +43,7 @@ "- k: black\n", "- w: white\n", "\n", - "Other colornames that are allowed are the HTML/CSS colornames such as \"burlywood\" and \"chartreuse\". See the [full list](http://www.w3schools.com/html/html_colornames.asp) of the 147 colornames. \n", + "Other colornames that are allowed are the HTML/CSS colornames such as \"burlywood\" and \"chartreuse\". See the [full list](https://www.w3schools.com/Colors/colors_names.asp) of the 140 color names. \n", "\n", "Matplotlib supports the [xkcd color names](https://xkcd.com/color/rgb/) prefxed by `'xkcd:'`.\n", "\n", @@ -112,7 +112,7 @@ "1 | tickright ||5 | caretright ||\">\" | triangle_right||\"4\" | tri_right\n", "2 | tickup ||6 | caretup ||\"^\" | triangle_up ||\"2\" | tri_up\n", "3 | tickdown ||7 | caretdown ||\"v\" | triangle_down ||\"1\" | tri_down\n", - "\"None\" | nothing ||`None` | nothing ||\" \" | nothing ||\"\" | nothing" + "\"None\" | nothing ||`None` | default ||\" \" | nothing ||\"\" | nothing" ] }, { @@ -128,7 +128,7 @@ " \"octagon\", \"square\", \"pentagon\", \"star\", \"vertical bar\", \"horizontal bar\", \"hexagon 1\", \"hexagon 2\",\n", " \"tick left\", \"caret left\", \"triangle left\", \"tri left\", \"tick right\", \"caret right\", \"triangle right\", \"tri right\",\n", " \"tick up\", \"caret up\", \"triangle up\", \"tri up\", \"tick down\", \"caret down\", \"triangle down\", \"tri down\",\n", - " \"Nothing\", \"Nothing\", \"Nothing\", \"Nothing\"]\n", + " \"Nothing\", \"default\", \"Nothing\", \"Nothing\"]\n", "fig, ax = plt.subplots(1, 1, figsize=(7.5, 4))\n", "for x, y, m, d in zip(xs.T.flat, ys.T.flat, markers, descripts):\n", " ax.scatter(x, y, marker=m, s=100)\n", From 7fc0e25fadd477c4138979ffc5b522fcacf4c146 Mon Sep 17 00:00:00 2001 From: Benjamin Root Date: Mon, 9 Jul 2018 17:41:40 -0400 Subject: [PATCH 10/22] Updated link for tick_params and added a bit about categoricals --- AnatomyOfMatplotlib-Part4-Limits_Legends_and_Layouts.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AnatomyOfMatplotlib-Part4-Limits_Legends_and_Layouts.ipynb b/AnatomyOfMatplotlib-Part4-Limits_Legends_and_Layouts.ipynb index 534fc87..c62c8c4 100644 --- a/AnatomyOfMatplotlib-Part4-Limits_Legends_and_Layouts.ipynb +++ b/AnatomyOfMatplotlib-Part4-Limits_Legends_and_Layouts.ipynb @@ -288,7 +288,7 @@ "* A Tick Label is the text that is displayed at that tick.\n", "* A [`Ticker`](http://matplotlib.org/api/ticker_api.html#module-matplotlib.ticker) automatically determines the ticks for an Axis and formats the tick labels.\n", "\n", - "[`tick_params()`](http://matplotlib.org/api/axes_api.html#matplotlib.axes.Axes.tick_params) is often used to help configure your tickers." + "[`tick_params()`](https://matplotlib.org/api/axes_api.html#ticks-and-tick-labels) is often used to help configure your tickers." ] }, { @@ -317,7 +317,7 @@ "source": [ "A commonly-asked question is \"How do I plot non-numerical categories?\"\n", " \n", - "Currently, the easiest way to do this is to \"fake\" the x-values and then change the tick labels to reflect the category.\n", + "Currently, the most reliable way to do this is to \"fake\" the x-values and then change the tick labels to reflect the category. There are some new approaches that work in newer versions of mpl, but the developers are still working out the details of how it should work. In the meantime, \"faking\" the values is the most reliable.\n", "\n", "For example:" ] From 681b78a9e329f2680ae8a812944ad70d6e8b36c7 Mon Sep 17 00:00:00 2001 From: Benjamin Root Date: Mon, 9 Jul 2018 17:56:03 -0400 Subject: [PATCH 11/22] Fix some links in Part 5, and a bare zip() in a solution --- AnatomyOfMatplotlib-Part5-Artists.ipynb | 4 ++-- solutions/5.1-goldstar.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/AnatomyOfMatplotlib-Part5-Artists.ipynb b/AnatomyOfMatplotlib-Part5-Artists.ipynb index c52cd26..4da8545 100644 --- a/AnatomyOfMatplotlib-Part5-Artists.ipynb +++ b/AnatomyOfMatplotlib-Part5-Artists.ipynb @@ -161,7 +161,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "To see what properties are set for an artist, use [`getp()`](http://matplotlib.org/api/artist_api.html#matplotlib.artist.getp)" + "To see what properties are set for an artist, use [`getp()`](https://matplotlib.org/api/artist_api.html#functions)" ] }, { @@ -182,7 +182,7 @@ "metadata": {}, "source": [ "# Collections\n", - "In addition to the Figure and Axes containers, there is another special type of container called a [`Collection`](http://matplotlib.org/api/collections_api.html). A Collection usually contains a list of primitives of the same kind that should all be treated similiarly. For example, a [`CircleCollection`](http://matplotlib.org/api/collections_api.html#matplotlib.collections.CircleCollection) would have a list of [`Circle`](http://matplotlib.org/api/artist_api.html#matplotlib.patches.Circle) objects all with the same color, size, and edge width. Individual property values for artists in the collection can also be set (in some cases)." + "In addition to the Figure and Axes containers, there is another special type of container called a [`Collection`](http://matplotlib.org/api/collections_api.html). A Collection usually contains a list of primitives of the same kind that should all be treated similiarly. For example, a [`CircleCollection`](http://matplotlib.org/api/collections_api.html#matplotlib.collections.CircleCollection) would have a list of [`Circle`](https://matplotlib.org/api/_as_gen/matplotlib.patches.Circle.html) objects all with the same color, size, and edge width. Individual property values for artists in the collection can also be set (in some cases)." ] }, { diff --git a/solutions/5.1-goldstar.py b/solutions/5.1-goldstar.py index 21f3272..7a04d3e 100644 --- a/solutions/5.1-goldstar.py +++ b/solutions/5.1-goldstar.py @@ -3,7 +3,7 @@ fig, ax = plt.subplots(1, 1) -offsets = zip([0.2, 0.4, 0.6, 0.8], [0.5] * 4) +offsets = list(zip([0.2, 0.4, 0.6, 0.8], [0.5] * 4)) collection = StarPolygonCollection(5, offsets=offsets, transOffset=ax.transData, From 4538f29bddc02871069a6e36509d574841277bc3 Mon Sep 17 00:00:00 2001 From: Benjamin Root Date: Mon, 9 Jul 2018 23:53:30 -0400 Subject: [PATCH 12/22] Fix a couple of URLs in Part 1. --- AnatomyOfMatplotlib-Part1-Figures_Subplots_and_layouts.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AnatomyOfMatplotlib-Part1-Figures_Subplots_and_layouts.ipynb b/AnatomyOfMatplotlib-Part1-Figures_Subplots_and_layouts.ipynb index efa6b8a..bece646 100644 --- a/AnatomyOfMatplotlib-Part1-Figures_Subplots_and_layouts.ipynb +++ b/AnatomyOfMatplotlib-Part1-Figures_Subplots_and_layouts.ipynb @@ -58,7 +58,7 @@ "[Matplotlib](https://github.com/matplotlib) is hosted by GitHub.\n", "\n", "### Bug Reports and feature requests\n", - "So, you think you found a bug? Or maybe you think some feature is just too difficult to use? Or missing altogether? Submit your bug reports [here](https://github.com/matplotlib/matplotlib/issues) at Matplotlib's issue tracker. We even have a process for submitting and discussing Matplotlib Enhancement Proposals ([MEPs](http://matplotlib.org/devdocs/devel/MEP/index.html))." + "So, you think you found a bug? Or maybe you think some feature is just too difficult to use? Or missing altogether? Submit your bug reports [here](https://github.com/matplotlib/matplotlib/issues) at Matplotlib's issue tracker. We even have a process for submitting and discussing Matplotlib Enhancement Proposals ([MEPs](https://matplotlib.org/devel/MEP/index.html))." ] }, { @@ -200,7 +200,7 @@ "\n", "However, while we're on the topic, you can control the size of the figure through the ``figsize`` argument, which expects a tuple of ``(width, height)`` in inches. \n", "\n", - "A really useful utility function is [`figaspect`](http://matplotlib.org/api/figure_api.html?highlight=figaspect#matplotlib.figure.figaspect)" + "A really useful utility function is [`figaspect`](https://matplotlib.org/api/_as_gen/matplotlib.figure.figaspect.html?highlight=figaspect#matplotlib.figure.figaspect)" ] }, { From 7f673d8ca0c57855e96523606e58c810c839dd98 Mon Sep 17 00:00:00 2001 From: Benjamin Root Date: Tue, 10 Jul 2018 00:24:51 -0400 Subject: [PATCH 13/22] Adopted some of the changes in PR #23 for categoricals --- ...OfMatplotlib-Part4-Limits_Legends_and_Layouts.ipynb | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/AnatomyOfMatplotlib-Part4-Limits_Legends_and_Layouts.ipynb b/AnatomyOfMatplotlib-Part4-Limits_Legends_and_Layouts.ipynb index c62c8c4..ec20839 100644 --- a/AnatomyOfMatplotlib-Part4-Limits_Legends_and_Layouts.ipynb +++ b/AnatomyOfMatplotlib-Part4-Limits_Legends_and_Layouts.ipynb @@ -315,9 +315,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "A commonly-asked question is \"How do I plot non-numerical categories?\"\n", - " \n", - "Currently, the most reliable way to do this is to \"fake\" the x-values and then change the tick labels to reflect the category. There are some new approaches that work in newer versions of mpl, but the developers are still working out the details of how it should work. In the meantime, \"faking\" the values is the most reliable.\n", + "A commonly-asked question is \"How do I plot categories?\"\n", + "\n", + "Starting in version 2.0 of mpl, just like any other data.\n", "\n", "For example:" ] @@ -334,9 +334,7 @@ "fruit, value = zip(*data)\n", "\n", "fig, ax = plt.subplots()\n", - "x = np.arange(len(fruit))\n", - "ax.bar(x, value, align='center', color='gray')\n", - "ax.set(xticks=x, xticklabels=fruit)\n", + "ax.bar(fruit, value, align='center', color='gray')\n", "plt.show()" ] }, From 9b79d529b091dabbe87c9771643f791bb2282c65 Mon Sep 17 00:00:00 2001 From: Benn Roth Date: Wed, 11 Jul 2018 13:53:25 -0500 Subject: [PATCH 14/22] Add knot to Ugly Tie shape Added geometry to the Ugly Tie polygon to look like a knot. It remains a single polygon so color will affect both visible parts. At large zooms/resolutions a connection between the right side of the knot and the main tie is visible because the points on right side of the knot are not perfectly in-line with the upper right corner of the tie where the two larger parts of the shape are visible. If this becomes an issue, doing some math to find evenly dividing, aligned points near the current values would make the connecting section of the polygon zero width. --- AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb b/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb index d7bbf0e..70384ab 100644 --- a/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb +++ b/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb @@ -512,8 +512,8 @@ "source": [ "mpl.rc('axes', prop_cycle=cycler('color', ['r', 'orange', 'c', 'y']) +\n", " cycler('hatch', ['x', 'xx-', '+O.', '*']))\n", - "x = np.array([0.4, 0.2, 0.5, 0.8, 0.6])\n", - "y = [0, -5, -6, -5, 0]\n", + "x = np.array([0.7, 0.3, 0.385, 0.6153, 0.6, 0.4, 0.2, 0.5, 0.8, 0.6])\n", + "y = [0.65, 0.65, 0.1, 0.1, 0, 0, -5, -6, -5, 0]\n", "plt.fill(x+1, y)\n", "plt.fill(x+2, y)\n", "plt.fill(x+3, y)\n", From 2fd6c31b53cd05ecd77cca1118d9655a94bb5133 Mon Sep 17 00:00:00 2001 From: Benn Roth Date: Fri, 13 Jul 2018 09:27:04 -0500 Subject: [PATCH 15/22] Removed invisible connecting geometry repeated first point in 5th position to close knot shape. Added `np.nan` non-rending connection point. --- AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb b/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb index 70384ab..110301a 100644 --- a/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb +++ b/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb @@ -512,8 +512,8 @@ "source": [ "mpl.rc('axes', prop_cycle=cycler('color', ['r', 'orange', 'c', 'y']) +\n", " cycler('hatch', ['x', 'xx-', '+O.', '*']))\n", - "x = np.array([0.7, 0.3, 0.385, 0.6153, 0.6, 0.4, 0.2, 0.5, 0.8, 0.6])\n", - "y = [0.65, 0.65, 0.1, 0.1, 0, 0, -5, -6, -5, 0]\n", + "x = np.array([0.7, 0.3, 0.385, 0.6153, 0.7, np.nan, 0.6, 0.4, 0.2, 0.5, 0.8, 0.6])\n", + "y = [0.65, 0.65, 0.1, 0.1, 0.65, np.nan, 0, 0, -5, -6, -5, 0]\n", "plt.fill(x+1, y)\n", "plt.fill(x+2, y)\n", "plt.fill(x+3, y)\n", From c96a9255ef1479d1b8263d30aecefdab4f9b97ab Mon Sep 17 00:00:00 2001 From: ggodreau Date: Sat, 27 Oct 2018 19:00:33 -0500 Subject: [PATCH 16/22] Fixes #26 - /mpl-data/sample_data/axes_grid folder appears to no longer exists as of matplotlib v2.2.2 - added /assets folder in repo containing dependent numpy pickle, 'bivariate_normal.npy' file - revised load of data in AnatomyOfMatplotlib-Part2-Plotting_Methods_Overview.ipynb to reflect this change - tested successfully with matplotlib v2.2.2 and python v3.6.6 --- ...tlib-Part2-Plotting_Methods_Overview.ipynb | 38 ++++++++++++++++-- assets/bivariate_normal.npy | Bin 0 -> 1880 bytes 2 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 assets/bivariate_normal.npy diff --git a/AnatomyOfMatplotlib-Part2-Plotting_Methods_Overview.ipynb b/AnatomyOfMatplotlib-Part2-Plotting_Methods_Overview.ipynb index 6ab58e8..f36cef2 100644 --- a/AnatomyOfMatplotlib-Part2-Plotting_Methods_Overview.ipynb +++ b/AnatomyOfMatplotlib-Part2-Plotting_Methods_Overview.ipynb @@ -269,6 +269,38 @@ "# Now you're on your own!\n" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "np.random.seed(1)\n", + "\n", + "# Generate data...\n", + "y_raw = np.random.randn(1000).cumsum() + 15\n", + "x_raw = np.linspace(0, 24, y_raw.size)\n", + "\n", + "# Get averages of every 100 samples...\n", + "x_pos = x_raw.reshape(-1, 100).min(axis=1)\n", + "y_avg = y_raw.reshape(-1, 100).mean(axis=1)\n", + "y_err = y_raw.reshape(-1, 100).ptp(axis=1)\n", + "\n", + "bar_width = x_pos[1] - x_pos[0]\n", + "\n", + "# Make a made up future prediction with a fake confidence\n", + "x_pred = np.linspace(0, 30)\n", + "y_max_pred = y_avg[0] + y_err[0] + 2.3 * x_pred\n", + "y_min_pred = y_avg[0] - y_err[0] + 1.2 * x_pred\n", + "\n", + "# Just so you don't have to guess at the colors...\n", + "barcolor, linecolor, fillcolor = 'wheat', 'salmon', 'lightblue'\n", + "\n", + "# Now you're on your own!\n" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -305,7 +337,7 @@ "outputs": [], "source": [ "from matplotlib.cbook import get_sample_data\n", - "data = np.load(get_sample_data('axes_grid/bivariate_normal.npy'))\n", + "data = np.load('assets/bivariate_normal.npy')\n", "\n", "fig, ax = plt.subplots()\n", "im = ax.imshow(data, cmap='gist_earth')\n", @@ -370,7 +402,7 @@ "outputs": [], "source": [ "from matplotlib.cbook import get_sample_data\n", - "data = np.load(get_sample_data('axes_grid/bivariate_normal.npy'))\n", + "data = np.load('assets/bivariate_normal.npy')\n", "\n", "fig, ax = plt.subplots()\n", "im = ax.imshow(data, cmap='seismic')\n", @@ -462,7 +494,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.5" + "version": "3.6.6" } }, "nbformat": 4, diff --git a/assets/bivariate_normal.npy b/assets/bivariate_normal.npy new file mode 100644 index 0000000000000000000000000000000000000000..b6b8dacdd0daecd53ef685f2a2dc29c98d5c6861 GIT binary patch literal 1880 zcmX|AeLNJ{8m6?@w|k|AjJb2;&S58qN?3txDq(VtzzprVUv_Y441f^WSsc=Xu`qKIa^c$D#jt9aU9vR$&lB zLg^=HL=v9pK(!}Y;EB{|S}ZLnDj=E`5~|pD4vM6Q%J=DEK{26nY`)vp0>9gKhXwu& zer;)XC8WM!i3iBmwDbomR~N~ihZ~C3XZ4}%zny5C?zirrU0wAhA)iNf_0{U#pm~9u=Sn}O;-UsA2dr9o+Gdcy=6|PX zM-V^V8_WtMZjtUm5PtQz)3-ar;hf`EI|pVYgsfrgTD^3Q@4Keoyyh3|^4XvEm~iXp z>?m1!<8yz)Ldte#^A50Y^?RHW>jrO(zQ3SXZ~{a+ea~N*@DItNg(P>Z(4!;qaR#+uP@$%uz zLzbLh)UuQpAlC;xcy0aXzC2(Q{LkoAay&@aJKto@RPt) zH>Y6?wk~bbDA_22FMdB#WLqYL+Pq~#(b=0|RpD7G@n?cFZX4UDCIChzoO<^?`wE`U zlXzjAEJzDEa6kFCUtxyXi?DAVg7&FW45w!p#1y@9-#IB@2!-z>3+7-lvx~>wxd1h{ z-{q7g&H;Ogq*<6Mg=9YFO?t}^2(t=(jHT^>cPb_S;Cu_(nI?6)b_pOf<4^DXNJSL> z5!Iiaspw+tmO*w{8cf$uZ45T$LVJ>PQ)qq%l%Fuh9ZnjCO9K;?jaV6E7Yo%>tLNaO z53@n1a~`myTexrV@4)lf;(jOI1k95<>1LECAYpyb&g#!Zl5N~yr)v1CAYjZA1xRpz2V`x%qD=sc8E5;z#`oDJEd$B$aNwZO3kisnkW z2qvseE7_EnuyIfE6Vtc-U^r`r`^2~c@jcik%HR;n_mwnrzmuRs+$dKtAw`TRejHcz zHM-@Jv>=HRqpbP9;6ILtP}kE8_i%>}6xWn!(U?(zis?bQfiD`7V8riWn?@UYK4j=q zaIG7)x!U*M_3uUN{+dmfJoJ)YqbqhS_GHpK^yRlP1%`Bemo&6hC4D4dG7W|Kd-v_SavZ6Q z^K$!y7hygB_4_mV`&;hVSiLeI{oRJ<^}U_QF78vIQ++2o{Y7eW^Okl*v)mjzRMdn_ zp0-vv+SMUhsm-z1!@nRepFCj&)) Date: Sat, 27 Oct 2018 19:08:06 -0500 Subject: [PATCH 17/22] Fixes #26 - removed redundant cell (typo on my part), line 272 --- ...tlib-Part2-Plotting_Methods_Overview.ipynb | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/AnatomyOfMatplotlib-Part2-Plotting_Methods_Overview.ipynb b/AnatomyOfMatplotlib-Part2-Plotting_Methods_Overview.ipynb index f36cef2..8239f9e 100644 --- a/AnatomyOfMatplotlib-Part2-Plotting_Methods_Overview.ipynb +++ b/AnatomyOfMatplotlib-Part2-Plotting_Methods_Overview.ipynb @@ -269,38 +269,6 @@ "# Now you're on your own!\n" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "np.random.seed(1)\n", - "\n", - "# Generate data...\n", - "y_raw = np.random.randn(1000).cumsum() + 15\n", - "x_raw = np.linspace(0, 24, y_raw.size)\n", - "\n", - "# Get averages of every 100 samples...\n", - "x_pos = x_raw.reshape(-1, 100).min(axis=1)\n", - "y_avg = y_raw.reshape(-1, 100).mean(axis=1)\n", - "y_err = y_raw.reshape(-1, 100).ptp(axis=1)\n", - "\n", - "bar_width = x_pos[1] - x_pos[0]\n", - "\n", - "# Make a made up future prediction with a fake confidence\n", - "x_pred = np.linspace(0, 30)\n", - "y_max_pred = y_avg[0] + y_err[0] + 2.3 * x_pred\n", - "y_min_pred = y_avg[0] - y_err[0] + 1.2 * x_pred\n", - "\n", - "# Just so you don't have to guess at the colors...\n", - "barcolor, linecolor, fillcolor = 'wheat', 'salmon', 'lightblue'\n", - "\n", - "# Now you're on your own!\n" - ] - }, { "cell_type": "markdown", "metadata": {}, From bcf3d08fa31c9297c052efb977fb5ffd1e0cc9c5 Mon Sep 17 00:00:00 2001 From: JarnoRFB Date: Mon, 22 Apr 2019 16:38:36 +0200 Subject: [PATCH 18/22] Fix markers table for display in JupyterLab Before the changes, the table was not rendered properly. --- AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb b/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb index 110301a..fd654f2 100644 --- a/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb +++ b/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb @@ -102,17 +102,17 @@ "# Markers\n", "[Markers](http://matplotlib.org/api/markers_api.html) are commonly used in [`plot()`](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.plot) and [`scatter()`](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.scatter) plots, but also show up elsewhere. There is a wide set of markers available, and custom markers can even be specified.\n", "\n", - "marker | description ||marker | description ||marker | description ||marker | description \n", - ":----------|:--------------||:---------|:--------------||:---------|:--------------||:---------|:--------------\n", - "\".\" | point ||\"+\" | plus ||\",\" | pixel ||\"x\" | cross\n", - "\"o\" | circle ||\"D\" | diamond ||\"d\" | thin_diamond || |\n", - "\"8\" | octagon ||\"s\" | square ||\"p\" | pentagon ||\"\\*\" | star\n", - "\"|\" | vertical line||\"\\_\" | horizontal line ||\"h\" | hexagon1 ||\"H\" | hexagon2\n", - "0 | tickleft ||4 | caretleft ||\"<\" | triangle_left ||\"3\" | tri_left\n", - "1 | tickright ||5 | caretright ||\">\" | triangle_right||\"4\" | tri_right\n", - "2 | tickup ||6 | caretup ||\"^\" | triangle_up ||\"2\" | tri_up\n", - "3 | tickdown ||7 | caretdown ||\"v\" | triangle_down ||\"1\" | tri_down\n", - "\"None\" | nothing ||`None` | default ||\" \" | nothing ||\"\" | nothing" + "marker | description | marker | description |marker | description | marker | description \n", + ":----------|:--------------| :---------|:-------------- |:---------|:--------------| :---------|:--------------\n", + "\".\" | point | \"+\" | plus |\",\" | pixel | \"x\" | cross\n", + "\"o\" | circle | \"D\" | diamond |\"d\" | thin_diamond | |\n", + "\"8\" | octagon | \"s\" | square |\"p\" | pentagon | \"\\*\" | star\n", + "\"|\" | vertical line| \"\\_\" | horizontal line | \"h\" | hexagon1 | \"H\" | hexagon2\n", + "0 | tickleft | 4 | caretleft |\"<\" | triangle_left | \"3\" | tri_left\n", + "1 | tickright | 5 | caretright |\">\" | triangle_right| \"4\" | tri_right\n", + "2 | tickup | 6 | caretup |\"^\" | triangle_up | \"2\" | tri_up\n", + "3 | tickdown | 7 | caretdown |\"v\" | triangle_down | \"1\" | tri_down\n", + "\"None\" | nothing | `None` | default |\" \" | nothing |\"\" | nothing" ] }, { @@ -607,9 +607,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.5" + "version": "3.7.3" } }, "nbformat": 4, - "nbformat_minor": 1 + "nbformat_minor": 2 } From 47313848fbf84d580447d751b968381c4cae68fe Mon Sep 17 00:00:00 2001 From: JarnoRFB Date: Tue, 23 Apr 2019 22:47:07 +0200 Subject: [PATCH 19/22] Make text table more consistent --- AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb b/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb index fd654f2..e3c93fe 100644 --- a/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb +++ b/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb @@ -102,17 +102,17 @@ "# Markers\n", "[Markers](http://matplotlib.org/api/markers_api.html) are commonly used in [`plot()`](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.plot) and [`scatter()`](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.scatter) plots, but also show up elsewhere. There is a wide set of markers available, and custom markers can even be specified.\n", "\n", - "marker | description | marker | description |marker | description | marker | description \n", - ":----------|:--------------| :---------|:-------------- |:---------|:--------------| :---------|:--------------\n", - "\".\" | point | \"+\" | plus |\",\" | pixel | \"x\" | cross\n", - "\"o\" | circle | \"D\" | diamond |\"d\" | thin_diamond | |\n", - "\"8\" | octagon | \"s\" | square |\"p\" | pentagon | \"\\*\" | star\n", - "\"|\" | vertical line| \"\\_\" | horizontal line | \"h\" | hexagon1 | \"H\" | hexagon2\n", - "0 | tickleft | 4 | caretleft |\"<\" | triangle_left | \"3\" | tri_left\n", - "1 | tickright | 5 | caretright |\">\" | triangle_right| \"4\" | tri_right\n", - "2 | tickup | 6 | caretup |\"^\" | triangle_up | \"2\" | tri_up\n", - "3 | tickdown | 7 | caretdown |\"v\" | triangle_down | \"1\" | tri_down\n", - "\"None\" | nothing | `None` | default |\" \" | nothing |\"\" | nothing" + "marker | description | marker | description | marker | description | marker | description \n", + ":----------|:--------------|:----------|:----------------|:---------|:--------------|:----------|:--------------\n", + "\".\" | point | \"+\" | plus | \",\" | pixel | \"x\" | cross\n", + "\"o\" | circle | \"D\" | diamond | \"d\" | thin_diamond | |\n", + "\"8\" | octagon | \"s\" | square | \"p\" | pentagon | \"\\*\" | star\n", + "\"|\" | vertical line| \"\\_\" | horizontal line | \"h\" | hexagon1 | \"H\" | hexagon2\n", + "0 | tickleft | 4 | caretleft | \"<\" | triangle_left | \"3\" | tri_left\n", + "1 | tickright | 5 | caretright | \">\" | triangle_right| \"4\" | tri_right\n", + "2 | tickup | 6 | caretup | \"^\" | triangle_up | \"2\" | tri_up\n", + "3 | tickdown | 7 | caretdown | \"v\" | triangle_down | \"1\" | tri_down\n", + "\"None\" | nothing | `None` | default | \" \" | nothing | \"\" | nothing" ] }, { From 4aa4074aa3c7c376cd9e9b2262012f73edbb0dfb Mon Sep 17 00:00:00 2001 From: Jess Tiu Date: Mon, 21 Oct 2019 22:23:18 +0800 Subject: [PATCH 20/22] Add explanation for imshow usage --- solutions/2.2-vmin_vmax_imshow_and_colorbars.py | 1 + 1 file changed, 1 insertion(+) diff --git a/solutions/2.2-vmin_vmax_imshow_and_colorbars.py b/solutions/2.2-vmin_vmax_imshow_and_colorbars.py index 2bc76a8..0fd5630 100644 --- a/solutions/2.2-vmin_vmax_imshow_and_colorbars.py +++ b/solutions/2.2-vmin_vmax_imshow_and_colorbars.py @@ -15,6 +15,7 @@ # Now you're on your own! for ax, data in zip(axes, [data1, data2, data3]): + # Display data, explicitly making the colormap cover values from 0 to 3 im = ax.imshow(data, vmin=0, vmax=3, interpolation='nearest') fig.colorbar(im, cax=cax, orientation='horizontal') From 21339aabbed1b0f0f5f77e812f48b04bb1d9eada Mon Sep 17 00:00:00 2001 From: Jess Tiu Date: Mon, 21 Oct 2019 22:55:51 +0800 Subject: [PATCH 21/22] Fix alignment --- solutions/2.2-vmin_vmax_imshow_and_colorbars.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/2.2-vmin_vmax_imshow_and_colorbars.py b/solutions/2.2-vmin_vmax_imshow_and_colorbars.py index 0fd5630..208e6ea 100644 --- a/solutions/2.2-vmin_vmax_imshow_and_colorbars.py +++ b/solutions/2.2-vmin_vmax_imshow_and_colorbars.py @@ -15,7 +15,7 @@ # Now you're on your own! for ax, data in zip(axes, [data1, data2, data3]): - # Display data, explicitly making the colormap cover values from 0 to 3 + # Display data, explicitly making the colormap cover values from 0 to 3 im = ax.imshow(data, vmin=0, vmax=3, interpolation='nearest') fig.colorbar(im, cax=cax, orientation='horizontal') From f8bc59ffe1f84b900989de41e685e85a6835ba76 Mon Sep 17 00:00:00 2001 From: Canute <46291012+canute24@users.noreply.github.com> Date: Sat, 7 Aug 2021 10:16:21 +0530 Subject: [PATCH 22/22] Updated with changes as per newer matplotlib api to remove deprecation warning Updated `bar.set(color='salmon', edgecolor='darkred', linewidth=3)` to pass `color` before `edgecolor` to fix `MatplotlibDeprecationWarning` --- AnatomyOfMatplotlib-Part2-Plotting_Methods_Overview.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AnatomyOfMatplotlib-Part2-Plotting_Methods_Overview.ipynb b/AnatomyOfMatplotlib-Part2-Plotting_Methods_Overview.ipynb index 8239f9e..ac00986 100644 --- a/AnatomyOfMatplotlib-Part2-Plotting_Methods_Overview.ipynb +++ b/AnatomyOfMatplotlib-Part2-Plotting_Methods_Overview.ipynb @@ -116,7 +116,7 @@ "# We could have also done this with two separate calls to `ax.bar` and numpy boolean indexing.\n", "for bar, height in zip(vert_bars, y):\n", " if height < 0:\n", - " bar.set(edgecolor='darkred', color='salmon', linewidth=3)\n", + " bar.set(color='salmon', edgecolor='darkred', linewidth=3)\n", "\n", "plt.show()" ] pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy