├── .DS_Store ├── .gitignore ├── Data ├── AristotleSparkNotesTrends.csv ├── HopperOstromTrends.csv ├── SparkNotesFall2019.csv ├── WeatherAug1415Trends.csv ├── finalFourTrend.csv └── readme.md ├── Demos ├── Adding a Font.ipynb ├── Color_Title_Demo.ipynb ├── Directed_Graph_Demo.ipynb ├── NYT_Line_Chart_Replication.ipynb ├── README.md ├── Sloping Text.ipynb └── Spiral Chart.ipynb ├── LICENSE-code ├── LICENSE-text ├── README.md ├── figures ├── .DS_Store ├── mathplots │ ├── .DS_Store │ ├── arc-graph.pdf │ ├── bad-slope.pdf │ ├── circle-grad.pdf │ ├── circle-graph.pdf │ ├── circle.pdf │ ├── ellipse-tform.pdf │ ├── no-slope.pdf │ ├── r-triangle.pdf │ ├── slope-label.pdf │ ├── tony-hawk.pdf │ ├── tony-hawk.png │ ├── unit-circle-shift.pdf │ └── unit-circle.pdf ├── poetryplots │ ├── .DS_Store │ ├── dag-argue.pdf │ ├── df-plot.pdf │ ├── heat-basic.pdf │ ├── heat-cbar.pdf │ ├── heat-log.pdf │ ├── hockey-heat.pdf │ ├── mpl-table.pdf │ ├── speedometer.pdf │ ├── speedometers.pdf │ ├── violin-bar.pdf │ ├── violin-cal.pdf │ └── violin-streak.pdf ├── proseplots │ ├── .DS_Store │ ├── 0000.pdf │ ├── 0001.pdf │ ├── 0002.pdf │ ├── add-subplot.pdf │ ├── annotate-arrow.pdf │ ├── arrow-axes.pdf │ ├── arrow-only.pdf │ ├── artists.pdf │ ├── ax-dates.pdf │ ├── axis-grid.pdf │ ├── cdf-pdf.pdf │ ├── chart.pdf │ ├── circle-clip.pdf │ ├── color-cube-back.pdf │ ├── color-cube.pdf │ ├── color-cube.png │ ├── color-map.pdf │ ├── color-title-ex.pdf │ ├── color_title_ex.pdf │ ├── colorful.pdf │ ├── colors.pdf │ ├── connect-path.pdf │ ├── coord-horizon.pdf │ ├── coord-sys.pdf │ ├── coord-trans.pdf │ ├── coords.pdf │ ├── date-fmt.pdf │ ├── date-fmt2.pdf │ ├── default-axes.pdf │ ├── default-axis.pdf │ ├── default-grid.pdf │ ├── default-z.pdf │ ├── direct-annotation.pdf │ ├── dual-bad.pdf │ ├── dual-norm-b.pdf │ ├── dual-norm.pdf │ ├── dual-ok.pdf │ ├── empty-square.pdf │ ├── empty.pdf │ ├── expanding-lims.pdf │ ├── figparams.pdf │ ├── font.pdf │ ├── front-axes.pdf │ ├── front-xaxis.pdf │ ├── gettersetter.pdf │ ├── gettersettertmp.pdf │ ├── gradient.pdf │ ├── grid-false.pdf │ ├── grid-true.pdf │ ├── grids-auto.pdf │ ├── grids-multi.pdf │ ├── gridspec.pdf │ ├── irisbox.pdf │ ├── label-data.pdf │ ├── legend-bb-loc.pdf │ ├── legend-bb.pdf │ ├── legend-labels.pdf │ ├── legend-shape.pdf │ ├── legend-transform.pdf │ ├── live-laugh-love.pdf │ ├── matlab-plot.pdf │ ├── mult-locator.pdf │ ├── multicolor-inexact.pdf │ ├── multicolor-title.pdf │ ├── no-axis.pdf │ ├── norm-pdf.pdf │ ├── nyt-refactor.pdf │ ├── nyt-rep1.pdf │ ├── oop-plot.pdf │ ├── pad-title-.pdf │ ├── pad-title.pdf │ ├── pd-dates.pdf │ ├── pd-legend.pdf │ ├── py-styled.pdf │ ├── reverse-z.pdf │ ├── spine-mod-ex.pdf │ ├── spine-mod2-ex.pdf │ ├── spine-vis-bottom.pdf │ ├── spine-vis-left.pdf │ ├── spine-vis-right.pdf │ ├── spine-vis-top.pdf │ ├── style1.pdf │ ├── style2.pdf │ ├── subplots-1d-vert.pdf │ ├── subplots-1d.pdf │ ├── subplots-2d.pdf │ ├── subtitle.pdf │ ├── suptitle.pdf │ ├── tall-ballers.pdf │ ├── testing.pdf │ ├── text-align.pdf │ ├── text-default-align.pdf │ ├── text-methods.pdf │ ├── text-rotation05.pdf │ ├── text-rotation1.pdf │ ├── text-rotation2.pdf │ ├── thick-spines.pdf │ ├── tick-right.pdf │ ├── ticks1.pdf │ ├── tiny-style-ex.pdf │ ├── title-loc.pdf │ ├── title-no-pad.pdf │ ├── title-pad.pdf │ ├── trivial-sub.pdf │ ├── window-extent.pdf │ ├── y-grid-false.pdf │ ├── y-grid-true.pdf │ ├── yes-axis.pdf │ └── zero-spines.pdf └── specialplots │ ├── .DS_Store │ ├── A-minus-B.pdf │ ├── basic-ternary.pdf │ ├── bins-hist.pdf │ ├── clean-hist.pdf │ ├── color-ternary.pdf │ ├── default-hist.pdf │ ├── error-stack.pdf │ ├── error-stack.png │ ├── errors-stacked.pdf │ ├── event-A.pdf │ ├── grid-ternary.pdf │ ├── heat-rps.pdf │ ├── intersection.pdf │ ├── intersection.png │ ├── mds-circles.pdf │ ├── normal-pdf.pdf │ ├── one-tail-norm.pdf │ ├── powerstacked_no_label.pdf │ ├── rps-br-lines.pdf │ ├── rps-br-zones.pdf │ ├── sampling-dist.pdf │ ├── scatter-ternary.pdf │ └── union.pdf ├── images ├── .DS_Store ├── DomenichinounicornPalFarnese.jpeg ├── MDS1.pdf ├── MDS_social.pdf ├── MultAxesNorm.pdf ├── NewtonBlake.jpg ├── QuinceCabbageMelonandCucumber.jpg ├── Stanczyk.jpg ├── by-nc-sa.png ├── calmdownpythag.jpg ├── monetgrapes.jpg ├── nytATUS.png ├── predators.png ├── style1.pdf ├── style2.pdf ├── tikz_simplex_blank.pdf └── venicefloor.jpg ├── main.bbl ├── main.lol ├── main.pdf ├── main.tex ├── python ├── .DS_Store ├── .ipynb_checkpoints │ ├── Math-Interlude-Figure-Dev-checkpoint.ipynb │ ├── Poetry-Figure-Dev-checkpoint.ipynb │ ├── Prose-Figure-Dev-checkpoint.ipynb │ └── Special-Figure-Dev-checkpoint.ipynb ├── A-minus-B.py ├── Math-Interlude-Figure-Dev.ipynb ├── Poetry-Figure-Dev.ipynb ├── Prose-Figure-Dev.ipynb ├── Special-Figure-Dev.ipynb ├── add-subplot.py ├── annotate-arrow.py ├── arc-graph.py ├── arrow-axes.py ├── arrow-only.py ├── artists.py ├── ax-dates.py ├── basic-ternary.py ├── bins-hist.py ├── cdf-pdf.py ├── chart.py ├── circle-clip.py ├── circle-grad.py ├── circle-graph.py ├── circle.py ├── clean-hist.py ├── color-cube.py ├── color-map.py ├── color-ternary.py ├── color-title-ex.py ├── color-title.py ├── color_title.py ├── colorful.py ├── colors.py ├── connect-path.py ├── coord-horizon.py ├── coord-trans.py ├── coords.py ├── dag-argue.py ├── dag-edge.py ├── dag-node.py ├── date-fmt.py ├── date-fmt2.py ├── default-axes.py ├── default-axis.py ├── default-hist.py ├── default-z.py ├── direct-annotation.py ├── dual-bad.py ├── dual-norm-b.py ├── dual-norm.py ├── dual-ok.py ├── ellipse-tform.py ├── empty-square.py ├── empty.py ├── error-stack.py ├── event-A.py ├── expanding-lims.py ├── figparams.py ├── font.py ├── front-axes.py ├── front-xaxis.py ├── get-fonts.py ├── gettersetter.py ├── gradient.py ├── grid-false.py ├── grid-ternary.py ├── grid-true.py ├── grids-auto.py ├── grids-multi.py ├── gridspec.py ├── heat-basic.py ├── heat-cbar.py ├── heat-log.py ├── heat-rps.py ├── hockey-heat.py ├── imports.py ├── intersection.py ├── irisbox.py ├── label-data.py ├── legend-bb-loc.py ├── legend-bb.py ├── legend-labels.py ├── legend-shape.py ├── legend-transform.py ├── matlab-chart.py ├── matlab-plot.py ├── mds-circles.py ├── mpl-table.py ├── mult-locator.py ├── multicolor-inexact.py ├── multicolor-title.py ├── no-axis.py ├── no-slope.py ├── norm-pdf.py ├── normal-pdf.py ├── nyt-helper-data.py ├── nyt-helper-function.py ├── nyt-refactor.py ├── nyt-rep1.py ├── one-tail-norm.py ├── oop-plot.py ├── pd-dates.py ├── pd-legend.py ├── py-styled.py ├── r-triangle.py ├── reverse-z.py ├── rps-br-helper.py ├── rps-br-lines.py ├── rps-br-zones.py ├── rps-helper.py ├── sampling-dist.py ├── scatter-ternary.py ├── slope-label.py ├── speedo-functions.py ├── speedometer.py ├── speedometers.py ├── spine-mod-ex.py ├── spine-mod.py ├── spine-mod2-ex.py ├── spine-mod2.py ├── spine-mod3.py ├── spine-vis.py ├── style-changes.py ├── style-manual.py ├── style-rc.py ├── subplots-1d-vert.py ├── subplots-1d.py ├── subplots-2d.py ├── subtitle.py ├── suptitle.py ├── tall-ballers.py ├── text-align.py ├── text-default-align.py ├── text-formatting.py ├── text-methods.py ├── text-rotation05.py ├── text-rotation1.py ├── text-rotation2.py ├── tform-matrix.py ├── thick-spines.py ├── tick-right.py ├── ticks1.py ├── tiny-style-ex.py ├── title-loc.py ├── title-pad.py ├── tony-hawk.py ├── trivial-sub.py ├── union.py ├── unit-circle-shift.py ├── unit-circle.py ├── violin-bar.py ├── violin-cal.py ├── violin-streak.py ├── window-extent.py ├── y-grid-false.py ├── y-grid-true.py ├── yes-axis.py └── zero-spines.py ├── requirements.txt ├── stylelib ├── nyt-helper.mplstyle └── tiny-style.mplstyle └── tex ├── .DS_Store ├── .ipynb_checkpoints └── mpl-tex-searcher-checkpoint.ipynb ├── codeTOC.tex ├── copyright.tex ├── customcolors.sty ├── ghostcites.tex ├── kdp.cls ├── math └── math.tex ├── mpl-tex-searcher.ipynb ├── mplbib.bib ├── mplstyle.sty ├── mycommands.sty ├── poetry ├── .DS_Store ├── calendar.tex ├── dag.tex ├── heat.tex ├── poetryArtist.tex ├── poetrychap.tex └── speedometer.tex ├── preface ├── .DS_Store ├── resourcesinsp.tex ├── techandprereq.tex ├── textorg.tex ├── whympl.tex └── writingorwell.tex ├── prose ├── .DS_Store ├── colors.tex ├── dates.tex ├── elements.tex ├── multi.tex ├── oop.tex ├── styconfig.tex ├── ticks.tex └── titles.tex └── special ├── MDS.tex ├── stats.tex └── ternary.tex /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # LaTeX build artifacts 2 | *.aux 3 | *.log 4 | *.toc 5 | *.lof 6 | *.lot 7 | *.fls 8 | *.out 9 | *.bbl 10 | *.blg 11 | *.lol 12 | *.fdb_latexmk 13 | *.synctex.gz 14 | 15 | # Python artifacts 16 | __pycache__/ 17 | *.py[cod] 18 | 19 | # macOS Finder metadata 20 | .DS_Store 21 | -------------------------------------------------------------------------------- /Data/AristotleSparkNotesTrends.csv: -------------------------------------------------------------------------------- 1 | Week,Aristotle,SparkNotes 2 | 2019-01-06,14,62 3 | 2019-01-13,15,76 4 | 2019-01-20,16,75 5 | 2019-01-27,17,85 6 | 2019-02-03,19,97 7 | 2019-02-10,18,100 8 | 2019-02-17,18,81 9 | 2019-02-24,21,99 10 | 2019-03-03,16,90 11 | 2019-03-10,15,77 12 | 2019-03-17,14,85 13 | 2019-03-24,16,81 14 | 2019-03-31,14,82 15 | 2019-04-07,15,90 16 | 2019-04-14,14,79 17 | 2019-04-21,15,91 18 | 2019-04-28,15,99 19 | 2019-05-05,15,93 20 | 2019-05-12,14,76 21 | 2019-05-19,10,64 22 | 2019-05-26,10,48 23 | 2019-06-02,10,39 24 | 2019-06-09,8,22 25 | 2019-06-16,9,9 26 | 2019-06-23,7,11 27 | 2019-06-30,8,14 28 | 2019-07-07,8,15 29 | 2019-07-14,8,14 30 | 2019-07-21,9,16 31 | 2019-07-28,7,17 32 | 2019-08-04,7,23 33 | 2019-08-11,10,38 34 | 2019-08-18,12,43 35 | 2019-08-25,14,61 36 | 2019-09-01,17,74 37 | 2019-09-08,22,82 38 | 2019-09-15,22,83 39 | 2019-09-22,19,84 40 | 2019-09-29,23,83 41 | 2019-10-06,20,81 42 | 2019-10-13,19,69 43 | 2019-10-20,21,78 44 | 2019-10-27,15,80 45 | 2019-11-03,15,88 46 | 2019-11-10,17,84 47 | 2019-11-17,17,92 48 | 2019-11-24,9,36 49 | 2019-12-01,15,86 50 | 2019-12-08,17,78 51 | 2019-12-15,14,53 52 | 2019-12-22,5,6 53 | 2019-12-29,6,16 54 | 2020-01-05,10,52 55 | 2020-01-12,13,64 56 | 2020-01-19,12,65 57 | 2020-01-26,15,77 58 | 2020-02-02,16,76 59 | 2020-02-09,19,79 60 | 2020-02-16,16,70 61 | 2020-02-23,17,86 62 | 2020-03-01,12,76 63 | 2020-03-08,13,64 64 | 2020-03-15,10,34 65 | 2020-03-22,11,46 66 | 2020-03-29,13,56 67 | 2020-04-05,11,48 68 | 2020-04-12,14,44 69 | 2020-04-19,15,55 70 | 2020-04-26,16,51 71 | 2020-05-03,16,43 72 | 2020-05-10,13,38 73 | 2020-05-17,9,29 74 | 2020-05-24,8,22 75 | 2020-05-31,8,18 76 | 2020-06-07,10,16 77 | 2020-06-14,9,10 78 | 2020-06-21,9,9 79 | 2020-06-28,8,8 80 | 2020-07-05,8,12 81 | 2020-07-12,9,10 82 | 2020-07-19,10,9 83 | 2020-07-26,7,11 84 | 2020-08-02,8,14 85 | 2020-08-09,8,17 86 | 2020-08-16,12,23 87 | 2020-08-23,18,30 88 | 2020-08-30,20,43 89 | 2020-09-06,22,47 90 | 2020-09-13,23,53 91 | 2020-09-20,22,53 92 | 2020-09-27,22,51 93 | 2020-10-04,20,46 94 | 2020-10-11,17,36 95 | 2020-10-18,15,34 96 | 2020-10-25,13,34 97 | 2020-11-01,10,29 98 | 2020-11-08,13,34 99 | 2020-11-15,13,34 100 | 2020-11-22,8,16 101 | 2020-11-29,11,32 102 | 2020-12-06,13,28 103 | 2020-12-13,12,22 104 | 2020-12-20,7,8 105 | 2020-12-27,6,5 106 | -------------------------------------------------------------------------------- /Data/HopperOstromTrends.csv: -------------------------------------------------------------------------------- 1 | Month,Grace Hopper,Elinor Ostrom 2 | 2004-01,7,0 3 | 2004-02,7,0 4 | 2004-03,12,0 5 | 2004-04,8,0 6 | 2004-05,3,0 7 | 2004-06,6,1 8 | 2004-07,3,1 9 | 2004-08,5,1 10 | 2004-09,10,1 11 | 2004-10,8,3 12 | 2004-11,8,1 13 | 2004-12,3,1 14 | 2005-01,4,1 15 | 2005-02,7,1 16 | 2005-03,13,1 17 | 2005-04,7,1 18 | 2005-05,8,1 19 | 2005-06,1,1 20 | 2005-07,3,2 21 | 2005-08,6,1 22 | 2005-09,4,1 23 | 2005-10,5,1 24 | 2005-11,5,1 25 | 2005-12,2,1 26 | 2006-01,4,1 27 | 2006-02,3,2 28 | 2006-03,5,1 29 | 2006-04,5,1 30 | 2006-05,5,0 31 | 2006-06,3,0 32 | 2006-07,2,0 33 | 2006-08,4,1 34 | 2006-09,3,1 35 | 2006-10,4,1 36 | 2006-11,3,1 37 | 2006-12,6,1 38 | 2007-01,2,0 39 | 2007-02,5,3 40 | 2007-03,5,1 41 | 2007-04,2,1 42 | 2007-05,3,1 43 | 2007-06,3,1 44 | 2007-07,2,0 45 | 2007-08,2,1 46 | 2007-09,4,1 47 | 2007-10,7,1 48 | 2007-11,3,1 49 | 2007-12,2,1 50 | 2008-01,7,0 51 | 2008-02,3,2 52 | 2008-03,4,1 53 | 2008-04,2,0 54 | 2008-05,4,1 55 | 2008-06,3,2 56 | 2008-07,2,1 57 | 2008-08,2,0 58 | 2008-09,3,1 59 | 2008-10,4,1 60 | 2008-11,2,1 61 | 2008-12,2,1 62 | 2009-01,1,1 63 | 2009-02,2,0 64 | 2009-03,3,1 65 | 2009-04,3,1 66 | 2009-05,3,1 67 | 2009-06,1,0 68 | 2009-07,1,0 69 | 2009-08,2,1 70 | 2009-09,4,1 71 | 2009-10,2,13 72 | 2009-11,2,2 73 | 2009-12,2,2 74 | 2010-01,3,1 75 | 2010-02,2,1 76 | 2010-03,2,1 77 | 2010-04,3,1 78 | 2010-05,6,1 79 | 2010-06,1,1 80 | 2010-07,1,1 81 | 2010-08,2,1 82 | 2010-09,3,1 83 | 2010-10,2,1 84 | 2010-11,1,1 85 | 2010-12,2,0 86 | 2011-01,1,1 87 | 2011-02,2,1 88 | 2011-03,3,1 89 | 2011-04,1,1 90 | 2011-05,1,1 91 | 2011-06,1,0 92 | 2011-07,1,1 93 | 2011-08,2,1 94 | 2011-09,3,1 95 | 2011-10,2,1 96 | 2011-11,3,1 97 | 2011-12,1,1 98 | 2012-01,2,1 99 | 2012-02,3,1 100 | 2012-03,2,0 101 | 2012-04,2,1 102 | 2012-05,1,1 103 | 2012-06,1,2 104 | 2012-07,1,0 105 | 2012-08,2,1 106 | 2012-09,4,1 107 | 2012-10,3,0 108 | 2012-11,1,0 109 | 2012-12,1,1 110 | 2013-01,1,1 111 | 2013-02,1,1 112 | 2013-03,2,1 113 | 2013-04,2,1 114 | 2013-05,2,0 115 | 2013-06,2,1 116 | 2013-07,1,0 117 | 2013-08,1,1 118 | 2013-09,4,1 119 | 2013-10,3,1 120 | 2013-11,1,1 121 | 2013-12,100,0 122 | 2014-01,3,0 123 | 2014-02,2,1 124 | 2014-03,3,0 125 | 2014-04,2,1 126 | 2014-05,2,0 127 | 2014-06,1,0 128 | 2014-07,2,0 129 | 2014-08,3,0 130 | 2014-09,4,0 131 | 2014-10,7,1 132 | 2014-11,2,1 133 | 2014-12,2,1 134 | 2015-01,3,0 135 | 2015-02,3,1 136 | 2015-03,4,1 137 | 2015-04,3,1 138 | 2015-05,3,1 139 | 2015-06,3,0 140 | 2015-07,2,0 141 | 2015-08,4,0 142 | 2015-09,4,1 143 | 2015-10,7,0 144 | 2015-11,3,0 145 | 2015-12,3,0 146 | 2016-01,2,0 147 | 2016-02,3,0 148 | 2016-03,3,1 149 | 2016-04,3,1 150 | 2016-05,3,0 151 | 2016-06,2,0 152 | 2016-07,4,0 153 | 2016-08,2,0 154 | 2016-09,4,0 155 | 2016-10,7,1 156 | 2016-11,5,1 157 | 2016-12,2,0 158 | 2017-01,2,0 159 | 2017-02,6,0 160 | 2017-03,3,1 161 | 2017-04,3,1 162 | 2017-05,3,0 163 | 2017-06,3,1 164 | 2017-07,5,1 165 | 2017-08,4,0 166 | 2017-09,7,0 167 | 2017-10,8,1 168 | 2017-11,2,1 169 | 2017-12,2,0 170 | 2018-01,3,0 171 | 2018-02,3,1 172 | 2018-03,3,1 173 | 2018-04,2,1 174 | 2018-05,3,0 175 | 2018-06,3,1 176 | 2018-07,5,0 177 | 2018-08,4,0 178 | 2018-09,10,1 179 | 2018-10,5,1 180 | 2018-11,3,0 181 | 2018-12,2,0 182 | 2019-01,2,0 183 | 2019-02,3,1 184 | 2019-03,5,0 185 | 2019-04,3,1 186 | 2019-05,3,0 187 | 2019-06,3,0 188 | 2019-07,4,0 189 | 2019-08,4,0 190 | 2019-09,6,0 191 | 2019-10,8,1 192 | 2019-11,2,0 193 | 2019-12,2,0 194 | 2020-01,3,0 195 | 2020-02,3,0 196 | 2020-03,3,0 197 | 2020-04,2,0 198 | 2020-05,2,0 199 | 2020-06,2,0 200 | 2020-07,3,0 201 | 2020-08,3,0 202 | 2020-09,5,1 203 | 2020-10,2,0 204 | 2020-11,1,0 205 | 2020-12,2,0 206 | 2021-01,1,1 207 | 2021-02,1,0 208 | 2021-03,2,1 209 | 2021-04,2,0 210 | 2021-05,1,1 211 | 2021-06,1,0 212 | 2021-07,2,1 213 | -------------------------------------------------------------------------------- /Data/SparkNotesFall2019.csv: -------------------------------------------------------------------------------- 1 | Category: All categories 2 | 3 | Day,sparknotes: (United States) 4 | 2019-08-01,18 5 | 2019-08-02,14 6 | 2019-08-03,15 7 | 2019-08-04,13 8 | 2019-08-05,17 9 | 2019-08-06,18 10 | 2019-08-07,26 11 | 2019-08-08,19 12 | 2019-08-09,13 13 | 2019-08-10,20 14 | 2019-08-11,21 15 | 2019-08-12,33 16 | 2019-08-13,31 17 | 2019-08-14,30 18 | 2019-08-15,26 19 | 2019-08-16,30 20 | 2019-08-17,14 21 | 2019-08-18,22 22 | 2019-08-19,38 23 | 2019-08-20,36 24 | 2019-08-21,35 25 | 2019-08-22,28 26 | 2019-08-23,29 27 | 2019-08-24,13 28 | 2019-08-25,31 29 | 2019-08-26,49 30 | 2019-08-27,49 31 | 2019-08-28,54 32 | 2019-08-29,57 33 | 2019-08-30,39 34 | 2019-08-31,15 35 | 2019-09-01,20 36 | 2019-09-02,38 37 | 2019-09-03,67 38 | 2019-09-04,79 39 | 2019-09-05,76 40 | 2019-09-06,58 41 | 2019-09-07,18 42 | 2019-09-08,40 43 | 2019-09-09,85 44 | 2019-09-10,75 45 | 2019-09-11,76 46 | 2019-09-12,79 47 | 2019-09-13,47 48 | 2019-09-14,14 49 | 2019-09-15,31 50 | 2019-09-16,92 51 | 2019-09-17,79 52 | 2019-09-18,75 53 | 2019-09-19,65 54 | 2019-09-20,54 55 | 2019-09-21,18 56 | 2019-09-22,35 57 | 2019-09-23,80 58 | 2019-09-24,95 59 | 2019-09-25,67 60 | 2019-09-26,76 61 | 2019-09-27,60 62 | 2019-09-28,13 63 | 2019-09-29,36 64 | 2019-09-30,74 65 | 2019-10-01,75 66 | 2019-10-02,77 67 | 2019-10-03,80 68 | 2019-10-04,71 69 | 2019-10-05,12 70 | 2019-10-06,23 71 | 2019-10-07,77 72 | 2019-10-08,76 73 | 2019-10-09,62 74 | 2019-10-10,78 75 | 2019-10-11,57 76 | 2019-10-12,13 77 | 2019-10-13,24 78 | 2019-10-14,65 79 | 2019-10-15,70 80 | 2019-10-16,56 81 | 2019-10-17,74 82 | 2019-10-18,57 83 | 2019-10-19,15 84 | 2019-10-20,28 85 | 2019-10-21,72 86 | 2019-10-22,72 87 | 2019-10-23,79 88 | 2019-10-24,72 89 | 2019-10-25,54 90 | 2019-10-26,15 91 | 2019-10-27,31 92 | 2019-10-28,87 93 | 2019-10-29,84 94 | 2019-10-30,69 95 | 2019-10-31,61 96 | 2019-11-01,56 97 | 2019-11-02,15 98 | 2019-11-03,31 99 | 2019-11-04,88 100 | 2019-11-05,76 101 | 2019-11-06,78 102 | 2019-11-07,82 103 | 2019-11-08,51 104 | 2019-11-09,16 105 | 2019-11-10,24 106 | 2019-11-11,73 107 | 2019-11-12,90 108 | 2019-11-13,77 109 | 2019-11-14,78 110 | 2019-11-15,61 111 | 2019-11-16,16 112 | 2019-11-17,24 113 | 2019-11-18,92 114 | 2019-11-19,100 115 | 2019-11-20,78 116 | 2019-11-21,75 117 | 2019-11-22,59 118 | 2019-11-23,15 119 | 2019-11-24,18 120 | 2019-11-25,62 121 | 2019-11-26,55 122 | 2019-11-27,17 123 | 2019-11-28,11 124 | 2019-11-29,4 125 | 2019-11-30,13 126 | 2019-12-01,33 127 | 2019-12-02,70 128 | 2019-12-03,86 129 | 2019-12-04,86 130 | 2019-12-05,67 131 | 2019-12-06,72 132 | 2019-12-07,16 133 | 2019-12-08,34 134 | 2019-12-09,83 135 | 2019-12-10,68 136 | 2019-12-11,66 137 | 2019-12-12,74 138 | 2019-12-13,66 139 | 2019-12-14,14 140 | 2019-12-15,21 141 | 2019-12-16,66 142 | 2019-12-17,51 143 | 2019-12-18,52 144 | 2019-12-19,46 145 | 2019-12-20,30 146 | 2019-12-21,7 147 | 2019-12-22,4 148 | 2019-12-23,1 149 | 2019-12-24,5 150 | 2019-12-25,4 151 | 2019-12-26,7 152 | 2019-12-27,6 153 | 2019-12-28,7 154 | 2019-12-29,8 155 | 2019-12-30,7 156 | 2019-12-31,5 157 | -------------------------------------------------------------------------------- /Data/finalFourTrend.csv: -------------------------------------------------------------------------------- 1 | Category: All categories 2 | 3 | Month,Final four: (United States) 4 | 2004-01,4 5 | 2004-02,8 6 | 2004-03,38 7 | 2004-04,15 8 | 2004-05,1 9 | 2004-06,2 10 | 2004-07,1 11 | 2004-08,1 12 | 2004-09,1 13 | 2004-10,2 14 | 2004-11,2 15 | 2004-12,4 16 | 2005-01,4 17 | 2005-02,8 18 | 2005-03,43 19 | 2005-04,17 20 | 2005-05,2 21 | 2005-06,1 22 | 2005-07,1 23 | 2005-08,1 24 | 2005-09,1 25 | 2005-10,1 26 | 2005-11,3 27 | 2005-12,3 28 | 2006-01,5 29 | 2006-02,7 30 | 2006-03,48 31 | 2006-04,17 32 | 2006-05,1 33 | 2006-06,1 34 | 2006-07,1 35 | 2006-08,1 36 | 2006-09,1 37 | 2006-10,1 38 | 2006-11,2 39 | 2006-12,3 40 | 2007-01,4 41 | 2007-02,6 42 | 2007-03,46 43 | 2007-04,10 44 | 2007-05,1 45 | 2007-06,1 46 | 2007-07,1 47 | 2007-08,1 48 | 2007-09,<1 49 | 2007-10,1 50 | 2007-11,3 51 | 2007-12,2 52 | 2008-01,3 53 | 2008-02,4 54 | 2008-03,27 55 | 2008-04,27 56 | 2008-05,1 57 | 2008-06,1 58 | 2008-07,1 59 | 2008-08,1 60 | 2008-09,1 61 | 2008-10,1 62 | 2008-11,2 63 | 2008-12,2 64 | 2009-01,2 65 | 2009-02,4 66 | 2009-03,25 67 | 2009-04,21 68 | 2009-05,1 69 | 2009-06,1 70 | 2009-07,1 71 | 2009-08,1 72 | 2009-09,1 73 | 2009-10,1 74 | 2009-11,1 75 | 2009-12,2 76 | 2010-01,3 77 | 2010-02,4 78 | 2010-03,32 79 | 2010-04,21 80 | 2010-05,1 81 | 2010-06,1 82 | 2010-07,1 83 | 2010-08,1 84 | 2010-09,<1 85 | 2010-10,1 86 | 2010-11,1 87 | 2010-12,2 88 | 2011-01,3 89 | 2011-02,4 90 | 2011-03,39 91 | 2011-04,29 92 | 2011-05,1 93 | 2011-06,2 94 | 2011-07,1 95 | 2011-08,1 96 | 2011-09,1 97 | 2011-10,1 98 | 2011-11,2 99 | 2011-12,2 100 | 2012-01,2 101 | 2012-02,4 102 | 2012-03,34 103 | 2012-04,13 104 | 2012-05,1 105 | 2012-06,1 106 | 2012-07,1 107 | 2012-08,1 108 | 2012-09,1 109 | 2012-10,1 110 | 2012-11,2 111 | 2012-12,2 112 | 2013-01,3 113 | 2013-02,4 114 | 2013-03,21 115 | 2013-04,48 116 | 2013-05,1 117 | 2013-06,1 118 | 2013-07,1 119 | 2013-08,1 120 | 2013-09,1 121 | 2013-10,1 122 | 2013-11,1 123 | 2013-12,1 124 | 2014-01,2 125 | 2014-02,3 126 | 2014-03,27 127 | 2014-04,43 128 | 2014-05,1 129 | 2014-06,1 130 | 2014-07,1 131 | 2014-08,<1 132 | 2014-09,<1 133 | 2014-10,1 134 | 2014-11,2 135 | 2014-12,2 136 | 2015-01,2 137 | 2015-02,3 138 | 2015-03,31 139 | 2015-04,57 140 | 2015-05,1 141 | 2015-06,1 142 | 2015-07,<1 143 | 2015-08,<1 144 | 2015-09,1 145 | 2015-10,1 146 | 2015-11,1 147 | 2015-12,2 148 | 2016-01,2 149 | 2016-02,2 150 | 2016-03,31 151 | 2016-04,37 152 | 2016-05,1 153 | 2016-06,1 154 | 2016-07,1 155 | 2016-08,1 156 | 2016-09,1 157 | 2016-10,1 158 | 2016-11,1 159 | 2016-12,2 160 | 2017-01,3 161 | 2017-02,3 162 | 2017-03,53 163 | 2017-04,65 164 | 2017-05,1 165 | 2017-06,1 166 | 2017-07,1 167 | 2017-08,1 168 | 2017-09,1 169 | 2017-10,1 170 | 2017-11,2 171 | 2017-12,2 172 | 2018-01,3 173 | 2018-02,3 174 | 2018-03,55 175 | 2018-04,23 176 | 2018-05,1 177 | 2018-06,1 178 | 2018-07,1 179 | 2018-08,1 180 | 2018-09,1 181 | 2018-10,1 182 | 2018-11,2 183 | 2018-12,3 184 | 2019-01,3 185 | 2019-02,3 186 | 2019-03,30 187 | 2019-04,100 188 | 2019-05,1 189 | 2019-06,1 190 | 2019-07,1 191 | 2019-08,<1 192 | 2019-09,1 193 | 2019-10,<1 194 | 2019-11,1 195 | 2019-12,2 196 | 2020-01,1 197 | 2020-02,2 198 | 2020-03,3 199 | 2020-04,1 200 | 2020-05,<1 201 | 2020-06,<1 202 | 2020-07,<1 203 | 2020-08,<1 204 | 2020-09,<1 205 | 2020-10,<1 206 | 2020-11,1 207 | 2020-12,1 208 | 2021-01,1 209 | 2021-02,1 210 | 2021-03,19 211 | 2021-04,37 212 | 2021-05,1 213 | 2021-06,1 214 | 2021-07,1 215 | -------------------------------------------------------------------------------- /Data/readme.md: -------------------------------------------------------------------------------- 1 | # Data 2 | 3 | This folder contains CSV files used in the examples throughout *Matplotlib for Storytellers*. All of the files were downloaded from [Google Trends](https://trends.google.com) and contain normalized search interest values ranging from 0–100. The data is provided here for educational use and remains subject to Google's Terms of Service. 4 | 5 | ## Files 6 | 7 | - **AristotleSparkNotesTrends.csv** – Weekly U.S. search interest for "Aristotle" and "SparkNotes" from January 2019 through December 2020. 8 | - **SparkNotesFall2019.csv** – Daily U.S. search interest for "SparkNotes" covering August–December 2019. 9 | - **finalFourTrend.csv** – Monthly U.S. search interest for "Final four" from January 2004 through July 2021. 10 | - **HopperOstromTrends.csv** – Monthly U.S. search interest for "Grace Hopper" and "Elinor Ostrom" from January 2004 through July 2021. 11 | - **WeatherAug1415Trends.csv** – Minute-level search interest for "weather" collected August 14–15, 2021 (time zone −04:00). 12 | 13 | -------------------------------------------------------------------------------- /Demos/README.md: -------------------------------------------------------------------------------- 1 | # Demos 2 | 3 | Here are notebook files for further demonstrations of applications from the book. We use matplotlib to create a directed graph, create a multi-colored title, and replicate a NYT line chart. 4 | 5 | ## Colab Notebooks 6 | 7 | 1. [Directed Graphs](https://colab.research.google.com/drive/1ylMl88dN-DLlC_pd00y7YRBMGVLzE5Rj?usp=sharing) 8 | 9 | 10 | 11 | 2. [Multi-colored Titles](https://colab.research.google.com/drive/1vMDHaP7jNi1wkQ9rrwMyHoKjAIVLbZlA?usp=sharing) 12 | 13 | 14 | 15 | 3. [New York Times Line Chart Replication](https://colab.research.google.com/drive/1HbGlXNpsE7R1y-4Whuy1E9FEMyxfPenz?usp=sharing) 16 | 17 | 18 | 19 | 4. [Add a Font](https://colab.research.google.com/drive/1zb8_9OsKMX-Aav0QYIjRV3dDumRd56Wd?usp=sharing) 20 | 21 | 22 | 23 | ## MVP 24 | 25 | 5. [Spiral Charts](https://colab.research.google.com/drive/1mUkMoPb3Kmrk9dRm7jvhi5NoVqeAaCYt?usp=sharing) 26 | 27 | 28 | 6. Sloping Text 29 | 30 | -------------------------------------------------------------------------------- /LICENSE-code: -------------------------------------------------------------------------------- 1 | This applies to the code. 2 | 3 | MIT License 4 | 5 | Copyright (c) 2021 Alexander Clark 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /LICENSE-text: -------------------------------------------------------------------------------- 1 | This text is released under the Creative Commons Attribute-NonCommercial-ShareAlike 4.0 International License. 2 | 3 | https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode 4 | https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Matplotlib for Storytellers 2 | This is a Python data visualization book. It is a work in progress. 3 | 4 | ## Why? 5 | This book is written for frustrated and reluctant matplotlib users who care about crafting good data visuals. Matplotlib can be a blank canvas, offering more room for customization than you might find in Microsoft Excel, and offers the advantages of reproducibility and automation that come from working with Python. Still, becoming comfortable with matplotlib requires a lot of patience. I wrote this book to help make that easier and put some essentials in one place. 6 | 7 | ## Installation 8 | Before building the book or running the examples you will need to install the 9 | Python packages used throughout the scripts and notebooks. You can install them 10 | all at once with 11 | 12 | ```bash 13 | pip install -r requirements.txt 14 | ``` 15 | 16 | The list of required packages is maintained in `requirements.txt`. 17 | 18 | ## Gallery 19 | 20 | 21 | 22 | 23 | 24 | 25 | ## Demos 26 | #### Notebooks 27 | Go to the [Demos](https://github.com/alexanderthclark/Matplotlib-for-Storytellers/tree/main/Demos) folder for Jupyter notebooks demonstrating some applications in the book. 28 | 29 | 30 | #### YouTube Videos 31 | [Plot Title with Multiple Colors in Matplotlib (Python)](https://youtu.be/3nKYXhUjqJE) 32 | 33 | [Make NYT Viz in Python](https://youtu.be/oYlJWTfJmj4) 34 | 35 | [Add a Font in Matplotlib](https://youtu.be/-0Pp81n5QNE) 36 | 37 | ## Support 38 | Support this book on [LeanPub](https://leanpub.com/mplforstorytellers). 39 | 40 | ## License 41 | 42 | ### Code 43 | The code in this repository is released under the [MIT license](LICENSE-code). Read more at the [Open Source Initiative](https://opensource.org/licenses/MIT). 44 | 45 | ### Text 46 | The text content of the book is released under the [CC BY-NC-SA 4.0 license](LICENSE-text). Read more at [Creative Commons](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en). 47 | -------------------------------------------------------------------------------- /figures/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/.DS_Store -------------------------------------------------------------------------------- /figures/mathplots/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/mathplots/.DS_Store -------------------------------------------------------------------------------- /figures/mathplots/arc-graph.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/mathplots/arc-graph.pdf -------------------------------------------------------------------------------- /figures/mathplots/bad-slope.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/mathplots/bad-slope.pdf -------------------------------------------------------------------------------- /figures/mathplots/circle-grad.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/mathplots/circle-grad.pdf -------------------------------------------------------------------------------- /figures/mathplots/circle-graph.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/mathplots/circle-graph.pdf -------------------------------------------------------------------------------- /figures/mathplots/circle.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/mathplots/circle.pdf -------------------------------------------------------------------------------- /figures/mathplots/ellipse-tform.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/mathplots/ellipse-tform.pdf -------------------------------------------------------------------------------- /figures/mathplots/no-slope.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/mathplots/no-slope.pdf -------------------------------------------------------------------------------- /figures/mathplots/r-triangle.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/mathplots/r-triangle.pdf -------------------------------------------------------------------------------- /figures/mathplots/slope-label.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/mathplots/slope-label.pdf -------------------------------------------------------------------------------- /figures/mathplots/tony-hawk.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/mathplots/tony-hawk.pdf -------------------------------------------------------------------------------- /figures/mathplots/tony-hawk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/mathplots/tony-hawk.png -------------------------------------------------------------------------------- /figures/mathplots/unit-circle-shift.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/mathplots/unit-circle-shift.pdf -------------------------------------------------------------------------------- /figures/mathplots/unit-circle.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/mathplots/unit-circle.pdf -------------------------------------------------------------------------------- /figures/poetryplots/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/poetryplots/.DS_Store -------------------------------------------------------------------------------- /figures/poetryplots/dag-argue.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/poetryplots/dag-argue.pdf -------------------------------------------------------------------------------- /figures/poetryplots/df-plot.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/poetryplots/df-plot.pdf -------------------------------------------------------------------------------- /figures/poetryplots/heat-basic.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/poetryplots/heat-basic.pdf -------------------------------------------------------------------------------- /figures/poetryplots/heat-cbar.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/poetryplots/heat-cbar.pdf -------------------------------------------------------------------------------- /figures/poetryplots/heat-log.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/poetryplots/heat-log.pdf -------------------------------------------------------------------------------- /figures/poetryplots/hockey-heat.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/poetryplots/hockey-heat.pdf -------------------------------------------------------------------------------- /figures/poetryplots/mpl-table.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/poetryplots/mpl-table.pdf -------------------------------------------------------------------------------- /figures/poetryplots/speedometer.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/poetryplots/speedometer.pdf -------------------------------------------------------------------------------- /figures/poetryplots/speedometers.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/poetryplots/speedometers.pdf -------------------------------------------------------------------------------- /figures/poetryplots/violin-bar.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/poetryplots/violin-bar.pdf -------------------------------------------------------------------------------- /figures/poetryplots/violin-cal.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/poetryplots/violin-cal.pdf -------------------------------------------------------------------------------- /figures/poetryplots/violin-streak.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/poetryplots/violin-streak.pdf -------------------------------------------------------------------------------- /figures/proseplots/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/.DS_Store -------------------------------------------------------------------------------- /figures/proseplots/0000.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/0000.pdf -------------------------------------------------------------------------------- /figures/proseplots/0001.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/0001.pdf -------------------------------------------------------------------------------- /figures/proseplots/0002.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/0002.pdf -------------------------------------------------------------------------------- /figures/proseplots/add-subplot.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/add-subplot.pdf -------------------------------------------------------------------------------- /figures/proseplots/annotate-arrow.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/annotate-arrow.pdf -------------------------------------------------------------------------------- /figures/proseplots/arrow-axes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/arrow-axes.pdf -------------------------------------------------------------------------------- /figures/proseplots/arrow-only.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/arrow-only.pdf -------------------------------------------------------------------------------- /figures/proseplots/artists.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/artists.pdf -------------------------------------------------------------------------------- /figures/proseplots/ax-dates.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/ax-dates.pdf -------------------------------------------------------------------------------- /figures/proseplots/axis-grid.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/axis-grid.pdf -------------------------------------------------------------------------------- /figures/proseplots/cdf-pdf.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/cdf-pdf.pdf -------------------------------------------------------------------------------- /figures/proseplots/chart.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/chart.pdf -------------------------------------------------------------------------------- /figures/proseplots/circle-clip.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/circle-clip.pdf -------------------------------------------------------------------------------- /figures/proseplots/color-cube-back.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/color-cube-back.pdf -------------------------------------------------------------------------------- /figures/proseplots/color-cube.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/color-cube.pdf -------------------------------------------------------------------------------- /figures/proseplots/color-cube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/color-cube.png -------------------------------------------------------------------------------- /figures/proseplots/color-map.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/color-map.pdf -------------------------------------------------------------------------------- /figures/proseplots/color-title-ex.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/color-title-ex.pdf -------------------------------------------------------------------------------- /figures/proseplots/color_title_ex.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/color_title_ex.pdf -------------------------------------------------------------------------------- /figures/proseplots/colorful.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/colorful.pdf -------------------------------------------------------------------------------- /figures/proseplots/colors.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/colors.pdf -------------------------------------------------------------------------------- /figures/proseplots/connect-path.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/connect-path.pdf -------------------------------------------------------------------------------- /figures/proseplots/coord-horizon.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/coord-horizon.pdf -------------------------------------------------------------------------------- /figures/proseplots/coord-sys.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/coord-sys.pdf -------------------------------------------------------------------------------- /figures/proseplots/coord-trans.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/coord-trans.pdf -------------------------------------------------------------------------------- /figures/proseplots/coords.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/coords.pdf -------------------------------------------------------------------------------- /figures/proseplots/date-fmt.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/date-fmt.pdf -------------------------------------------------------------------------------- /figures/proseplots/date-fmt2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/date-fmt2.pdf -------------------------------------------------------------------------------- /figures/proseplots/default-axes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/default-axes.pdf -------------------------------------------------------------------------------- /figures/proseplots/default-axis.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/default-axis.pdf -------------------------------------------------------------------------------- /figures/proseplots/default-grid.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/default-grid.pdf -------------------------------------------------------------------------------- /figures/proseplots/default-z.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/default-z.pdf -------------------------------------------------------------------------------- /figures/proseplots/direct-annotation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/direct-annotation.pdf -------------------------------------------------------------------------------- /figures/proseplots/dual-bad.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/dual-bad.pdf -------------------------------------------------------------------------------- /figures/proseplots/dual-norm-b.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/dual-norm-b.pdf -------------------------------------------------------------------------------- /figures/proseplots/dual-norm.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/dual-norm.pdf -------------------------------------------------------------------------------- /figures/proseplots/dual-ok.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/dual-ok.pdf -------------------------------------------------------------------------------- /figures/proseplots/empty-square.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/empty-square.pdf -------------------------------------------------------------------------------- /figures/proseplots/empty.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/empty.pdf -------------------------------------------------------------------------------- /figures/proseplots/expanding-lims.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/expanding-lims.pdf -------------------------------------------------------------------------------- /figures/proseplots/figparams.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/figparams.pdf -------------------------------------------------------------------------------- /figures/proseplots/font.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/font.pdf -------------------------------------------------------------------------------- /figures/proseplots/front-axes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/front-axes.pdf -------------------------------------------------------------------------------- /figures/proseplots/front-xaxis.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/front-xaxis.pdf -------------------------------------------------------------------------------- /figures/proseplots/gettersetter.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/gettersetter.pdf -------------------------------------------------------------------------------- /figures/proseplots/gettersettertmp.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/gettersettertmp.pdf -------------------------------------------------------------------------------- /figures/proseplots/gradient.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/gradient.pdf -------------------------------------------------------------------------------- /figures/proseplots/grid-false.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/grid-false.pdf -------------------------------------------------------------------------------- /figures/proseplots/grid-true.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/grid-true.pdf -------------------------------------------------------------------------------- /figures/proseplots/grids-auto.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/grids-auto.pdf -------------------------------------------------------------------------------- /figures/proseplots/grids-multi.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/grids-multi.pdf -------------------------------------------------------------------------------- /figures/proseplots/gridspec.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/gridspec.pdf -------------------------------------------------------------------------------- /figures/proseplots/irisbox.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/irisbox.pdf -------------------------------------------------------------------------------- /figures/proseplots/label-data.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/label-data.pdf -------------------------------------------------------------------------------- /figures/proseplots/legend-bb-loc.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/legend-bb-loc.pdf -------------------------------------------------------------------------------- /figures/proseplots/legend-bb.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/legend-bb.pdf -------------------------------------------------------------------------------- /figures/proseplots/legend-labels.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/legend-labels.pdf -------------------------------------------------------------------------------- /figures/proseplots/legend-shape.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/legend-shape.pdf -------------------------------------------------------------------------------- /figures/proseplots/legend-transform.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/legend-transform.pdf -------------------------------------------------------------------------------- /figures/proseplots/live-laugh-love.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/live-laugh-love.pdf -------------------------------------------------------------------------------- /figures/proseplots/matlab-plot.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/matlab-plot.pdf -------------------------------------------------------------------------------- /figures/proseplots/mult-locator.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/mult-locator.pdf -------------------------------------------------------------------------------- /figures/proseplots/multicolor-inexact.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/multicolor-inexact.pdf -------------------------------------------------------------------------------- /figures/proseplots/multicolor-title.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/multicolor-title.pdf -------------------------------------------------------------------------------- /figures/proseplots/no-axis.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/no-axis.pdf -------------------------------------------------------------------------------- /figures/proseplots/norm-pdf.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/norm-pdf.pdf -------------------------------------------------------------------------------- /figures/proseplots/nyt-refactor.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/nyt-refactor.pdf -------------------------------------------------------------------------------- /figures/proseplots/nyt-rep1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/nyt-rep1.pdf -------------------------------------------------------------------------------- /figures/proseplots/oop-plot.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/oop-plot.pdf -------------------------------------------------------------------------------- /figures/proseplots/pad-title-.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/pad-title-.pdf -------------------------------------------------------------------------------- /figures/proseplots/pad-title.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/pad-title.pdf -------------------------------------------------------------------------------- /figures/proseplots/pd-dates.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/pd-dates.pdf -------------------------------------------------------------------------------- /figures/proseplots/pd-legend.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/pd-legend.pdf -------------------------------------------------------------------------------- /figures/proseplots/py-styled.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/py-styled.pdf -------------------------------------------------------------------------------- /figures/proseplots/reverse-z.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/reverse-z.pdf -------------------------------------------------------------------------------- /figures/proseplots/spine-mod-ex.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/spine-mod-ex.pdf -------------------------------------------------------------------------------- /figures/proseplots/spine-mod2-ex.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/spine-mod2-ex.pdf -------------------------------------------------------------------------------- /figures/proseplots/spine-vis-bottom.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/spine-vis-bottom.pdf -------------------------------------------------------------------------------- /figures/proseplots/spine-vis-left.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/spine-vis-left.pdf -------------------------------------------------------------------------------- /figures/proseplots/spine-vis-right.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/spine-vis-right.pdf -------------------------------------------------------------------------------- /figures/proseplots/spine-vis-top.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/spine-vis-top.pdf -------------------------------------------------------------------------------- /figures/proseplots/style1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/style1.pdf -------------------------------------------------------------------------------- /figures/proseplots/style2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/style2.pdf -------------------------------------------------------------------------------- /figures/proseplots/subplots-1d-vert.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/subplots-1d-vert.pdf -------------------------------------------------------------------------------- /figures/proseplots/subplots-1d.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/subplots-1d.pdf -------------------------------------------------------------------------------- /figures/proseplots/subplots-2d.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/subplots-2d.pdf -------------------------------------------------------------------------------- /figures/proseplots/subtitle.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/subtitle.pdf -------------------------------------------------------------------------------- /figures/proseplots/suptitle.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/suptitle.pdf -------------------------------------------------------------------------------- /figures/proseplots/tall-ballers.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/tall-ballers.pdf -------------------------------------------------------------------------------- /figures/proseplots/testing.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/testing.pdf -------------------------------------------------------------------------------- /figures/proseplots/text-align.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/text-align.pdf -------------------------------------------------------------------------------- /figures/proseplots/text-default-align.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/text-default-align.pdf -------------------------------------------------------------------------------- /figures/proseplots/text-methods.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/text-methods.pdf -------------------------------------------------------------------------------- /figures/proseplots/text-rotation05.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/text-rotation05.pdf -------------------------------------------------------------------------------- /figures/proseplots/text-rotation1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/text-rotation1.pdf -------------------------------------------------------------------------------- /figures/proseplots/text-rotation2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/text-rotation2.pdf -------------------------------------------------------------------------------- /figures/proseplots/thick-spines.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/thick-spines.pdf -------------------------------------------------------------------------------- /figures/proseplots/tick-right.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/tick-right.pdf -------------------------------------------------------------------------------- /figures/proseplots/ticks1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/ticks1.pdf -------------------------------------------------------------------------------- /figures/proseplots/tiny-style-ex.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/tiny-style-ex.pdf -------------------------------------------------------------------------------- /figures/proseplots/title-loc.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/title-loc.pdf -------------------------------------------------------------------------------- /figures/proseplots/title-no-pad.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/title-no-pad.pdf -------------------------------------------------------------------------------- /figures/proseplots/title-pad.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/title-pad.pdf -------------------------------------------------------------------------------- /figures/proseplots/trivial-sub.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/trivial-sub.pdf -------------------------------------------------------------------------------- /figures/proseplots/window-extent.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/window-extent.pdf -------------------------------------------------------------------------------- /figures/proseplots/y-grid-false.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/y-grid-false.pdf -------------------------------------------------------------------------------- /figures/proseplots/y-grid-true.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/y-grid-true.pdf -------------------------------------------------------------------------------- /figures/proseplots/yes-axis.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/yes-axis.pdf -------------------------------------------------------------------------------- /figures/proseplots/zero-spines.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/proseplots/zero-spines.pdf -------------------------------------------------------------------------------- /figures/specialplots/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/specialplots/.DS_Store -------------------------------------------------------------------------------- /figures/specialplots/A-minus-B.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/specialplots/A-minus-B.pdf -------------------------------------------------------------------------------- /figures/specialplots/basic-ternary.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/specialplots/basic-ternary.pdf -------------------------------------------------------------------------------- /figures/specialplots/bins-hist.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/specialplots/bins-hist.pdf -------------------------------------------------------------------------------- /figures/specialplots/clean-hist.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/specialplots/clean-hist.pdf -------------------------------------------------------------------------------- /figures/specialplots/color-ternary.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/specialplots/color-ternary.pdf -------------------------------------------------------------------------------- /figures/specialplots/default-hist.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/specialplots/default-hist.pdf -------------------------------------------------------------------------------- /figures/specialplots/error-stack.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/specialplots/error-stack.pdf -------------------------------------------------------------------------------- /figures/specialplots/error-stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/specialplots/error-stack.png -------------------------------------------------------------------------------- /figures/specialplots/errors-stacked.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/specialplots/errors-stacked.pdf -------------------------------------------------------------------------------- /figures/specialplots/event-A.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/specialplots/event-A.pdf -------------------------------------------------------------------------------- /figures/specialplots/grid-ternary.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/specialplots/grid-ternary.pdf -------------------------------------------------------------------------------- /figures/specialplots/heat-rps.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/specialplots/heat-rps.pdf -------------------------------------------------------------------------------- /figures/specialplots/intersection.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/specialplots/intersection.pdf -------------------------------------------------------------------------------- /figures/specialplots/intersection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/specialplots/intersection.png -------------------------------------------------------------------------------- /figures/specialplots/mds-circles.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/specialplots/mds-circles.pdf -------------------------------------------------------------------------------- /figures/specialplots/normal-pdf.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/specialplots/normal-pdf.pdf -------------------------------------------------------------------------------- /figures/specialplots/one-tail-norm.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/specialplots/one-tail-norm.pdf -------------------------------------------------------------------------------- /figures/specialplots/powerstacked_no_label.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/specialplots/powerstacked_no_label.pdf -------------------------------------------------------------------------------- /figures/specialplots/rps-br-lines.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/specialplots/rps-br-lines.pdf -------------------------------------------------------------------------------- /figures/specialplots/rps-br-zones.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/specialplots/rps-br-zones.pdf -------------------------------------------------------------------------------- /figures/specialplots/sampling-dist.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/specialplots/sampling-dist.pdf -------------------------------------------------------------------------------- /figures/specialplots/scatter-ternary.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/specialplots/scatter-ternary.pdf -------------------------------------------------------------------------------- /figures/specialplots/union.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/figures/specialplots/union.pdf -------------------------------------------------------------------------------- /images/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/images/.DS_Store -------------------------------------------------------------------------------- /images/DomenichinounicornPalFarnese.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/images/DomenichinounicornPalFarnese.jpeg -------------------------------------------------------------------------------- /images/MDS1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/images/MDS1.pdf -------------------------------------------------------------------------------- /images/MDS_social.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/images/MDS_social.pdf -------------------------------------------------------------------------------- /images/MultAxesNorm.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/images/MultAxesNorm.pdf -------------------------------------------------------------------------------- /images/NewtonBlake.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/images/NewtonBlake.jpg -------------------------------------------------------------------------------- /images/QuinceCabbageMelonandCucumber.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/images/QuinceCabbageMelonandCucumber.jpg -------------------------------------------------------------------------------- /images/Stanczyk.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/images/Stanczyk.jpg -------------------------------------------------------------------------------- /images/by-nc-sa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/images/by-nc-sa.png -------------------------------------------------------------------------------- /images/calmdownpythag.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/images/calmdownpythag.jpg -------------------------------------------------------------------------------- /images/monetgrapes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/images/monetgrapes.jpg -------------------------------------------------------------------------------- /images/nytATUS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/images/nytATUS.png -------------------------------------------------------------------------------- /images/predators.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/images/predators.png -------------------------------------------------------------------------------- /images/style1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/images/style1.pdf -------------------------------------------------------------------------------- /images/style2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/images/style2.pdf -------------------------------------------------------------------------------- /images/tikz_simplex_blank.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/images/tikz_simplex_blank.pdf -------------------------------------------------------------------------------- /images/venicefloor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/images/venicefloor.jpg -------------------------------------------------------------------------------- /main.lol: -------------------------------------------------------------------------------- 1 | \contentsline {lstlisting}{\numberline {1}{\ignorespaces imports.py}}{vii}{lstlisting.0.1}% 2 | -------------------------------------------------------------------------------- /main.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/main.pdf -------------------------------------------------------------------------------- /python/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/python/.DS_Store -------------------------------------------------------------------------------- /python/A-minus-B.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(edgecolor = 'black'), plt.axes() 2 | ax.set_aspect(1) 3 | ax.set_xlim(-1.6,1.6) 4 | ax.set_ylim(-1.1,1.4) 5 | ax.axis('off') 6 | 7 | # Add circles with color fill 8 | left_circle = plt.Circle((-0.5, 0), 1, 9 | edgecolor = 'black', 10 | facecolor = 'gray', 11 | linewidth = 2) 12 | left_circle_helper = plt.Circle((-0.5, 0), 1, 13 | edgecolor = 'black', 14 | facecolor = (1,1,1,0), 15 | linewidth = 2) 16 | right_circle = plt.Circle((0.5, 0), 1, 17 | edgecolor = 'black', 18 | facecolor = 'white', 19 | linewidth = 2) 20 | ax.add_artist(left_circle) 21 | ax.add_artist(right_circle) 22 | ax.add_artist(left_circle_helper) 23 | 24 | # Label 25 | ax.text(0, 1.05, 26 | s = r"$A \cap B^C$", 27 | va = 'bottom', 28 | ha = 'center', 29 | size = 30) -------------------------------------------------------------------------------- /python/add-subplot.py: -------------------------------------------------------------------------------- 1 | fig = plt.figure() 2 | for i in range(1,7): 3 | ax = fig.add_subplot(2,3,i) 4 | ax.text(0.5, 0.5, 5 | s = str(i), 6 | ha = 'center', 7 | va = 'center', 8 | fontsize = 30) 9 | ax.set_yticks([]) 10 | ax.set_xticks([]) 11 | fig.tight_layout() -------------------------------------------------------------------------------- /python/annotate-arrow.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | 3 | x = np.linspace(0,1,100) # Pr(heads) 4 | x = x[(x!=0) & (x!=1)] 5 | entropy = -x*np.log2(x) - (1-x)*np.log2(1-x) 6 | ax.plot(x,entropy) 7 | ax.annotate('fair coin', 8 | xy = (0.5,1), 9 | xytext = (0.5, 0.1), 10 | arrowprops=dict(facecolor='white', 11 | edgecolor = 'black', 12 | width = 3, 13 | headwidth = 10, 14 | linewidth = 1), 15 | ha = 'center', 16 | va= 'top', # text alignment around xytext 17 | size = 12) 18 | 19 | ax.set_title("Coin Flip Entropy") -------------------------------------------------------------------------------- /python/arc-graph.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | x = np.linspace(0,1,4) 3 | ax.plot(x, np.zeros(4), 4 | marker = 'o', 5 | linestyle = '', 6 | markersize = 13) 7 | 8 | angles = np.linspace(0,np.pi,100) 9 | for point in x: 10 | # connect other points 11 | other_x = x[x > point] 12 | # construct a half circle 13 | unit_x, unit_y = np.cos(angles), np.sin(angles) 14 | for other in other_x: 15 | # arc is centered between the two points 16 | shift = np.mean([point,other]) 17 | r = (other - point)/2 18 | new_x = r*unit_x + shift 19 | new_y = r*unit_y 20 | ax.plot(new_x, new_y, zorder = -1) 21 | 22 | ax.axis('off') 23 | ax.set_aspect(1.5) -------------------------------------------------------------------------------- /python/arrow-axes.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | ax.set_title("Zero Spines and Arrows") 3 | ax.plot([-1,1], [-1,1]) 4 | for spine in 'top', 'right': 5 | ax.spines[spine].set_visible(False) 6 | for spine in 'bottom', 'left': 7 | ax.spines[spine].set_position('zero') 8 | 9 | # get current limits 10 | xlims = ax.get_xlim() 11 | ylims = ax.get_ylim() 12 | 13 | # Add arrows 14 | ax.plot(xlims[1], 0, ">k", clip_on = False) 15 | ax.plot(0, ylims[1], "^k", clip_on = False) 16 | 17 | # revert limits to before the arrows 18 | ax.set_xlim(xlims) 19 | ax.set_ylim(ylims) -------------------------------------------------------------------------------- /python/arrow-only.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | 3 | # no arrow, no text 4 | # this does nothing 5 | ax.annotate('', 6 | xy = (0.1, 0.8), 7 | xytext = (0.9, 0.9)) 8 | 9 | # arrow 10 | ax.annotate('', xy = (0.2, 0.2), 11 | xytext = (0.8, 0.2), 12 | arrowprops = dict(color = 'black')) -------------------------------------------------------------------------------- /python/artists.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | ax.set_aspect(1) 3 | 4 | # Patches 5 | rect = plt.Rectangle(xy = (0.2, 0.2), 6 | width = 0.6, 7 | height = .6, 8 | facecolor = 'C0', 9 | edgecolor = 'C1') 10 | patch = ax.add_artist(rect) 11 | 12 | # Lines 13 | x, y = [0.5, 0.5], [0, 1] 14 | line, = ax.plot(x, y) 15 | lines = ax.plot(y,x) 16 | 17 | # Text 18 | text = ax.text(0.2, 0.8, 'Matlotlib', size = 13) -------------------------------------------------------------------------------- /python/ax-dates.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | ax.plot(df.Time, df.weather) -------------------------------------------------------------------------------- /python/basic-ternary.py: -------------------------------------------------------------------------------- 1 | figure, tax = ternary.figure()# A tuple of plot objects 2 | figure.set_size_inches(4,4) 3 | tax.set_background_color('orange') -------------------------------------------------------------------------------- /python/bins-hist.py: -------------------------------------------------------------------------------- 1 | #data = np.random.normal(size = 30) 2 | fig, ax = plt.subplots(1,4, figsize = (9,3)) 3 | 4 | for key, b in enumerate([4, 8, 10, 15]): 5 | ax[key].hist(data, edgecolor = 'black', bins = b) 6 | ax[key].set_yticks([]) 7 | for s in 'left', 'top', 'right': 8 | ax[key].spines[s].set_visible(False) -------------------------------------------------------------------------------- /python/cdf-pdf.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | x = np.linspace(-3,3,200) 3 | pdf_y = stats.norm.pdf(x) 4 | cdf_y = stats.norm.cdf(x) 5 | ax.plot(x,pdf_y, label = 'PDF') 6 | ax.plot(x,cdf_y, label = 'CDF') 7 | ax.legend() -------------------------------------------------------------------------------- /python/chart.py: -------------------------------------------------------------------------------- 1 | x = np.linspace(0,1,2) 2 | plt.plot(x,x) 3 | plt.title("My Chart") 4 | 5 | ax = plt.gca() 6 | print(ax.title) 7 | 8 | ax.plot(x, 1 - x) 9 | ax.set_title('My Wholesome Chart') 10 | print(ax.title) -------------------------------------------------------------------------------- /python/circle-clip.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | ax.set_aspect(1) 3 | 4 | # Create a unit circle 5 | u = np.linspace(0,2*np.pi,100) 6 | x = np.cos(u) 7 | y = np.sin(u) 8 | 9 | # Default, clip_on = True 10 | ax.plot(x-1, y) 11 | 12 | # Unclipped, extends beyond the axes 13 | ax.plot(x+1, y, clip_on = False) 14 | 15 | ax.set_xlim(-1,1) -------------------------------------------------------------------------------- /python/circle-grad.py: -------------------------------------------------------------------------------- 1 | # make a circle gradient 2 | start_color = 255/256, 59/256, 48/256 # red 3 | end_color = 255/256, 255/256, 85/256 # yellow 4 | 5 | # How many color changes 6 | segments = 130 7 | 8 | # Create figure 9 | fig, ax = plt.figure(figsize = (8,8)), plt.axes() 10 | 11 | # Start at 90 degrees and return clockwise 12 | angles = np.linspace(2.5*np.pi, np.pi/2, segments + 1) 13 | 14 | # Create the intermediate colors 15 | colors = dict() 16 | for i in range(3): 17 | colors[i] = np.linspace(start_color[i], end_color[i], segments) 18 | 19 | # plot each arc 20 | for i in range(segments): 21 | 22 | start_angle = angles[i] 23 | end_angle = angles[i+1] 24 | angle_slice = np.linspace(start_angle, end_angle, 100) 25 | 26 | x_values = np.cos(angle_slice) 27 | y_values = np.sin(angle_slice) 28 | 29 | rgb = colors[0][i], colors[1][i], colors[2][i] 30 | 31 | ax.plot(x_values, y_values, 32 | color = rgb, 33 | linewidth = 20, 34 | solid_capstyle = 'round') 35 | 36 | ax.set_aspect('equal') 37 | ax.axis('off') -------------------------------------------------------------------------------- /python/circle-graph.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | 3 | n_points = 4 4 | 5 | # Draw vertices 6 | angles = np.linspace(0, 2*np.pi, n_points + 1)[0:n_points] 7 | x = np.cos(angles) 8 | y = np.sin(angles) 9 | ax.plot(x, y, 10 | marker = 'o', 11 | linestyle = '', 12 | markersize = 13) 13 | 14 | # Draw Edges 15 | points = [p for p in zip(x,y)] 16 | counter = 1 17 | for point, other in combinations(points,2): 18 | 19 | x = [p[0] for p in (point, other)] 20 | y = [p[1] for p in (point, other)] 21 | ax.plot(x, y, zorder = -1) 22 | 23 | # add a label 24 | label_point = .65*np.array(point) + .35*np.array(other) 25 | 26 | run = x[1]-x[0] 27 | rotation = 90 28 | ha = 'left' 29 | if run != 0: 30 | line_slope = (y[1]-y[0])/(x[1]-x[0]) 31 | rotation = math.atan(line_slope) 32 | rotation = math.degrees(rotation) 33 | ha = 'center' 34 | else: 35 | print(point, other, rotation) 36 | 37 | # get rgb then blend with white 38 | line_color = mpl.colors.to_rgb("C"+str(counter)) 39 | lighter = .8*np.ones(3) + .2*np.array(line_color) 40 | ax.text(label_point[0], label_point[1], 41 | 'label', rotation = rotation, 42 | bbox = dict(facecolor = lighter), 43 | va = 'center', 44 | ha = 'center' 45 | ) 46 | counter += 1 47 | 48 | ax.axis('off') 49 | ax.set_aspect('equal') -------------------------------------------------------------------------------- /python/circle.py: -------------------------------------------------------------------------------- 1 | n_points = 10 2 | pie_angle = 360/n_points # angle of each slice 3 | starting_angle = 90 4 | 5 | fig, ax = plt.subplots() 6 | 7 | for i in range(n_points): 8 | 9 | angle = starting_angle + i*pie_angle 10 | angle = math.radians(angle) 11 | x = math.cos(angle) 12 | y = math.sin(angle) 13 | 14 | ax.plot([x],[y], 'o', markersize = 17 - i) 15 | 16 | ax.set_aspect('equal') 17 | ax.axis('off') -------------------------------------------------------------------------------- /python/clean-hist.py: -------------------------------------------------------------------------------- 1 | #data = np.random.normal(size = 30) 2 | fig, ax = plt.figure(), plt.axes() 3 | ax.hist(data, edgecolor = 'black') 4 | ax.set_yticks([]) 5 | for s in 'left', 'top', 'right': 6 | ax.spines[s].set_visible(False) -------------------------------------------------------------------------------- /python/color-cube.py: -------------------------------------------------------------------------------- 1 | light_gray = [.98]*3 2 | fig = plt.figure(figsize = (6,6), 3 | facecolor = light_gray) 4 | ax = plt.axes(projection='3d', 5 | facecolor = light_gray) 6 | 7 | # control how many cubes/color changes 8 | pieces = 10 9 | grid = np.linspace(0, 1, pieces)[:-1] 10 | width = grid[1] - grid[0] 11 | 12 | # Make smaller cube units 13 | for x in grid: 14 | for y in grid: 15 | for z in grid: 16 | vertices = list() 17 | for prod in product([x,x+width],[y,y+width], [z,z+width]): 18 | vertices.append(list(prod)) 19 | 20 | faces = list() 21 | for key, face in enumerate([x,y,z]): 22 | # face is 0 23 | helper0 = [x for x in vertices if x[key] == face] 24 | helper1 = [x for x in vertices if x[key] == face + width] 25 | helper0.sort() 26 | helper0 = helper0[0:2] + helper0[::-1][0:2] 27 | helper1.sort() 28 | helper1 = helper1[0:2] + helper1[::-1][0:2] 29 | faces.append((helper0)) 30 | faces.append(helper1) 31 | 32 | facecolor = (x + width / 2, 33 | y + width / 2, 34 | z + width / 2) 35 | pc = Poly3DCollection(faces, 36 | facecolor = facecolor, 37 | edgecolor = 'black') 38 | ax.add_collection3d(pc) 39 | 40 | # Label Axes 41 | ax.set_xlabel("Red") 42 | ax.set_ylabel('Green') 43 | ax.set_zlabel("Blue") 44 | 45 | # Set Ticks 46 | ax.set_xticks([0,1]) 47 | ax.set_yticks([0,1]) 48 | ax.set_zticks([0,1]) 49 | # Change padding 50 | ax.xaxis.set_tick_params(pad = 0.1) 51 | ax.yaxis.set_tick_params(pad = 0.1) 52 | ax.zaxis.set_tick_params(pad = 0.1) 53 | # Change azimuth 54 | angle = 45 # + 180 # for second cube 55 | ax.view_init(elev = None, azim = angle) 56 | # Zoom out so labels are not cut off 57 | ax.set_box_aspect([1,1,1], zoom = 0.86) -------------------------------------------------------------------------------- /python/color-map.py: -------------------------------------------------------------------------------- 1 | # Set Colors 2 | blue = mpl.colors.ColorConverter().to_rgb('C0') 3 | orange = mpl.colors.ColorConverter().to_rgb('C1') 4 | 5 | n_colors = 10 6 | color_strings = dict() 7 | for i in range(n_colors): 8 | color_strings[i] = 'C'+str(i) 9 | segments = 1000 # How many color changes 10 | 11 | fig, ax = plt.subplots(figsize = (14,8)) 12 | 13 | for c in range(n_colors - 1): 14 | color1 = mpl.colors.ColorConverter().to_rgb(color_strings[c]) 15 | color2 = mpl.colors.ColorConverter().to_rgb(color_strings[c+1]) 16 | 17 | interval_starts = np.linspace(c, c+1, segments) 18 | colors = dict() 19 | for i in range(3): 20 | colors[i] = np.linspace(color1[i], color2[i], segments) 21 | 22 | for i in range(segments-1): 23 | 24 | rgb = colors[0][i], colors[1][i], colors[2][i] 25 | 26 | x = interval_starts[i], interval_starts[i+1] 27 | y = [0.3,0.5] 28 | 29 | ax.plot(x, y, 30 | color = rgb, 31 | linewidth = 20, 32 | solid_capstyle = 'round') 33 | 34 | ax.text(c, .51, 35 | s = 'C'+str(c), 36 | va = 'bottom', 37 | size = 12, 38 | ha = 'center') 39 | 40 | ax.text(9, .51, 41 | s = 'C9', 42 | va = 'bottom', 43 | size = 12, 44 | ha = 'center') 45 | 46 | ax.set_aspect('equal') 47 | ax.axis('off') -------------------------------------------------------------------------------- /python/color-ternary.py: -------------------------------------------------------------------------------- 1 | # Create the Plot 2 | scale = 1 # length of the sides 3 | figure, tax = ternary.figure(scale=scale) 4 | 5 | # Draw Boundary 6 | tax.boundary(linewidth= 2.0, 7 | axes_colors = {'l':'red', 'r': 'blue', 'b': 'green'}) -------------------------------------------------------------------------------- /python/color-title-ex.py: -------------------------------------------------------------------------------- 1 | x = range(101) 2 | # Create a Gaussian random walk starting at 0 3 | start = np.zeros(1) 4 | y1 = np.concatenate( [start,np.random.normal(0,1,100)] ).cumsum() 5 | y2 = np.concatenate( [start,np.random.normal(0,1,100)] ).cumsum() 6 | 7 | fig, ax = plt.figure(), plt.axes() 8 | plt.tight_layout() 9 | # Color arguments added to make defaults explicit 10 | ax.plot(x,y1, color = 'C0') 11 | ax.plot(x,y2, color = 'C1') 12 | 13 | labels = ['Stock Performance: ', 'GenericCo', ' & ', 'PerfunctoryInc'] 14 | colors = ['black', 'C0', 'black', 'C1'] 15 | color_title(labels, colors) -------------------------------------------------------------------------------- /python/color-title.py: -------------------------------------------------------------------------------- 1 | def color_title(labels, colors, textprops ={'size':'large'}, ax = None, y = 1.013, 2 | precision = 10**-2): 3 | 4 | "Creates a centered title with multiple colors. " 5 | 6 | if ax == None: 7 | ax = plt.gca() 8 | 9 | plt.gcf().canvas.draw() 10 | transform = ax.transAxes # use axes coords 11 | 12 | # initial params 13 | xT = 0 # where the text ends in x-axis coords 14 | shift = 0 # where the text starts 15 | 16 | # for text objects 17 | text = dict() 18 | 19 | while (np.abs(shift - (1-xT)) > precision) and (shift <= xT) : 20 | x_pos = shift 21 | 22 | for label, col in zip(labels, colors): 23 | 24 | try: 25 | text[label].remove() 26 | except KeyError: 27 | pass 28 | 29 | text[label] = ax.text(x_pos, y, label, 30 | transform = transform, 31 | ha = 'left', 32 | color = col, 33 | **textprops) 34 | 35 | x_pos = text[label].get_window_extent()\ 36 | .transformed(transform.inverted()).x1 37 | 38 | xT = x_pos # where all text ends 39 | 40 | shift += precision/2 # increase for next iteration 41 | 42 | if x_pos > 1: # guardrail 43 | break -------------------------------------------------------------------------------- /python/color_title.py: -------------------------------------------------------------------------------- 1 | savepy('multicolor-inexact') -------------------------------------------------------------------------------- /python/colorful.py: -------------------------------------------------------------------------------- 1 | # OOP Start 2 | fig, ax = plt.figure(figsize = (8,5)), plt.axes() 3 | 4 | x = np.linspace(0,100,2) 5 | ax.plot(x, x, color = 'gray') 6 | 7 | ax.set_xlim([0,100]) 8 | ax.set_ylim([0,100]) 9 | 10 | # Back to pyplot functions 11 | for i in range(101): 12 | plt.axvline(i,0, i / 100, color = 'C' + str(i)) 13 | plt.axvline(i, i/100, 1, color = 'C' + str(i+5)) 14 | 15 | plt.axis('off') 16 | plt.savefig('colorful.pdf') -------------------------------------------------------------------------------- /python/colors.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | for i in range(12): 3 | # Plot color automatically cycles through color map 4 | ax.plot([0,1], np.ones(2)*i) 5 | 6 | # Text with default color on the left 7 | ax.text(0, i, 'C' + str(i), 8 | va = 'center', ha = 'right') 9 | 10 | # Text with variable color on the right 11 | ax.text(1, i, 'C' + str(i), 12 | va = 'center', ha = 'left', 13 | color = 'C'+str(i)) 14 | ax.axis('off') -------------------------------------------------------------------------------- /python/connect-path.py: -------------------------------------------------------------------------------- 1 | fig = plt.figure(figsize = (7,6)) 2 | 3 | # Generate random data 4 | n = 100 5 | x = np.random.normal(size = n) 6 | y = np.random.normal(size = n) 7 | # z is determined by x except for one outlier 8 | z = np.concatenate([np.array([4]), 1- x[1:]**2]) 9 | 10 | # Add x,y scatter plot 11 | ax12 = fig.add_subplot(2,2,(1,2)) 12 | ax12.scatter(x,y, alpha = 0.5) 13 | 14 | # Add x,z scatter plot 15 | ax3 = fig.add_subplot(2,2,3) 16 | ax3.scatter(x,z, alpha = 0.5) 17 | 18 | # Add y,z scatter plot 19 | ax4 = fig.add_subplot(2,2,4) 20 | ax4.scatter(y,z, alpha = 0.5) 21 | 22 | # Draw lines connecting the outlier as it appears in each scatter plot 23 | con = ConnectionPatch( 24 | xyA = (x[0], y[0]), 25 | coordsA = ax12.transData, 26 | xyB = (x[0], z[0]), 27 | coordsB = ax3.transData, 28 | arrowstyle = "<->", 29 | shrinkA = 2, 30 | shrinkB = 0) 31 | fig.add_artist(con) 32 | 33 | con = ConnectionPatch( 34 | xyA = (x[0],y[0]), 35 | coordsA = ax12.transData, 36 | xyB = (y[0], z[0] ), 37 | coordsB = ax4.transData, 38 | arrowstyle = "<->", 39 | shrinkA = 2, 40 | shrinkB = 0) 41 | fig.add_artist(con) 42 | 43 | ax12.set_xlabel("$x$") 44 | ax12.set_ylabel("$y$") 45 | ax3.set_ylabel("$z$") 46 | ax3.set_xlabel("$x$") 47 | ax4.set_ylabel("$z$") 48 | ax4.set_xlabel("$y$") 49 | plt.tight_layout() -------------------------------------------------------------------------------- /python/coord-horizon.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | ax.axis('off') 3 | # lines to horizon 4 | for i in np.linspace(0,1,50): 5 | ax.plot([i,.5], [0.00, .5], 6 | transform = ax.transAxes, 7 | linewidth = 2, 8 | zorder = 10-(i-0.5)**2) 9 | 10 | # fill bottom half 11 | green = (.1, .5, .1) 12 | ax.fill_between(x = (0,1), 13 | y1 = 0, 14 | y2 = 0.5, 15 | transform = ax.transAxes, 16 | color = green) 17 | 18 | # fill top half 19 | ax.fill_between(x = (0,1), 20 | y1 = 0.5, 21 | y2 = 1, 22 | transform = ax.transAxes, 23 | color = 'lightblue') -------------------------------------------------------------------------------- /python/coord-trans.py: -------------------------------------------------------------------------------- 1 | # Plot setup 2 | fig, ax = plt.figure(), plt.axes() 3 | x = np.linspace(0, 2*np.pi) 4 | sin, = ax.plot(x, 3*np.sin(x)) 5 | ax.set_xlim(0, 10) 6 | ax.set_ylim(-4, 6) 7 | fig.tight_layout() 8 | 9 | # Vertical line with axes coordinates 10 | middle = [0.5, 0.5] 11 | bottom_half = [0, 0.5] 12 | ax.plot(middle, bottom_half, 13 | transform = ax.transAxes) 14 | 15 | # Continue vertical line with data coordinates 16 | mid_in_display = ax.transAxes.transform([0.5, 0.5]) 17 | mid_in_data = ax.transData.inverted().transform(mid_in_display) 18 | top_mid_in_display = ax.transAxes.transform([0.5, 1]) 19 | top_mid_in_data = ax.transData.inverted()\ 20 | .transform(top_mid_in_display) 21 | x = mid_in_data[0], top_mid_in_data[0] 22 | y = mid_in_data[1], top_mid_in_data[1] 23 | ax.plot(x, y, linestyle = 'dashed') 24 | 25 | # Horizontal lines in figure coordinates 26 | top_wave_display = ax.transData.transform([np.pi/2, 3]) 27 | top_wave_figure = fig.transFigure.inverted()\ 28 | .transform(top_wave_display) 29 | 30 | y = top_wave_figure[1], top_wave_figure[1] 31 | ax.plot([0,1], y, 32 | transform = fig.transFigure, 33 | linestyle = 'dotted', 34 | clip_on = False) -------------------------------------------------------------------------------- /python/coords.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(facecolor = 'lightgray'), plt.axes() 2 | 3 | ax.plot([0, 1], [0, 1], 4 | linewidth = 3, 5 | transform = ax.transAxes, 6 | label = 'axes') 7 | 8 | ax.plot([0, 1], [0, 1], 9 | color = 'C1', 10 | linewidth = 1, 11 | transform = fig.transFigure, 12 | clip_on = False, 13 | label = 'figure') 14 | 15 | ax.plot([0, 1], [0, 1], 16 | color = 'C2', 17 | linestyle = 'dashed', 18 | clip_on = False, 19 | label = 'data') 20 | 21 | ax.set_xlim(0,2) 22 | ax.legend() -------------------------------------------------------------------------------- /python/dag-argue.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | ax.set_aspect(1) 3 | ax.set_xlim(-4,4) 4 | ax.set_ylim(-3,3) 5 | ax.axis('off') 6 | 7 | persuasive = make_node((0,1.5), 1, 'Persuasiveness') 8 | logic = make_node((2.5,-1.5), 1, 'Logic') 9 | decibels = make_node((-2.5,-1.5), 1, 'Decibels') 10 | 11 | directed_edge(logic, persuasive) 12 | directed_edge(decibels, persuasive) -------------------------------------------------------------------------------- /python/dag-edge.py: -------------------------------------------------------------------------------- 1 | def directed_edge(c1, c2, ax = None): 2 | """Draw an arrow from c1 to c2.""" 3 | 4 | if ax is None: 5 | ax = plt.gca() 6 | 7 | center1 = c1.center 8 | center2 = c2.center 9 | 10 | length = np.linalg.norm(np.array(center1) - np.array(center2)) 11 | 12 | r1 = c1.get_radius() 13 | r2 = c2.get_radius() 14 | 15 | x1, x2 = center1[0], center2[0] 16 | y1, y2 = center1[1], center2[1] 17 | 18 | # Find start and end of arrow based on circle radii 19 | # based on linear weights from convex combos 20 | tail_weight = r1 / length 21 | tail_x = (1-tail_weight)*x1 + tail_weight*x2 22 | tail_y = (1-tail_weight)*y1 + tail_weight*y2 23 | 24 | head_weight = r2/ length 25 | head_x = (1-head_weight)*x2 + head_weight*x1 26 | head_y = (1-head_weight)*y2 + head_weight*y1 27 | 28 | ax.annotate('', xy = (head_x, head_y), 29 | xytext = (tail_x, tail_y), 30 | arrowprops = dict(headwidth = 14, 31 | linewidth = .1, 32 | width = 2)) -------------------------------------------------------------------------------- /python/dag-node.py: -------------------------------------------------------------------------------- 1 | def make_node(center, radius = 'auto', label = '', ax = None): 2 | """Plot labeled circle object to represent a node. 3 | Rrun after any changes to axes limits, aspect changes, etc if using radius = 'auto'.""" 4 | if ax is None: 5 | ax = plt.gca() 6 | t = ax.text(center[0], center[1], label, ha = 'center', va = 'center') 7 | if radius == 'auto': 8 | plt.gcf().canvas.draw() 9 | box = t.get_window_extent().transformed(ax.transData.inverted()) 10 | width = box.x1 - box.x0 11 | radius = (width/2)*1.2 12 | c = plt.Circle(center, radius, 13 | facecolor = (.9,.99,.9), 14 | edgecolor = 'black') 15 | ax.add_artist(c) 16 | return c -------------------------------------------------------------------------------- /python/date-fmt.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | xformatter = mdates.DateFormatter('%H:%M') 3 | ax.plot(df.Time, df.weather) 4 | ax.set_title("Searches for \"weather\" spike in the morning.") 5 | ax.set_xlabel("Time (UTC)") 6 | ax.xaxis.set_major_formatter(xformatter) -------------------------------------------------------------------------------- /python/date-fmt2.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | xformatter = mdates.DateFormatter('%-I%p') 3 | ax.plot(df.Time, df.weather) 4 | ax.set_title("Searches for \"weather\" spike in the morning.") 5 | ax.set_xlabel("Time (UTC)") 6 | ax.xaxis.set_major_formatter(xformatter) -------------------------------------------------------------------------------- /python/default-axes.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | for i in [0, 0.25, .5, .75]: 3 | ax.fill_between([i,1], 0.3 - i/10, .7 - i/20, 4 | zorder = 2-i) 5 | ax.grid(True, linewidth = 3) 6 | ax.set_xlim(0,1) 7 | ax.set_ylim(0,1) 8 | print(ax.get_zorder()) -------------------------------------------------------------------------------- /python/default-axis.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | for i in [0, 0.25, .5, .75]: 3 | ax.fill_between([i,1], 0.3 - i/10, .7 - i/20, 4 | zorder = 2-i) 5 | ax.grid(True, linewidth = 3) 6 | ax.set_xlim(0,1) 7 | ax.set_ylim(0,1) 8 | print(ax.get_zorder()) -------------------------------------------------------------------------------- /python/default-hist.py: -------------------------------------------------------------------------------- 1 | data = np.random.normal(size = 30) 2 | fig, ax = plt.figure(), plt.axes() 3 | ax.hist(data) -------------------------------------------------------------------------------- /python/default-z.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | ax.set_xlim(0,1) 3 | ax.set_ylim(0,1) 4 | ax.set_xticks([]) 5 | ax.set_yticks([]) 6 | 7 | # make colors 8 | green = (.9, .99, .9) 9 | blue = (.9, .9, .99) 10 | red = (.99, .9, .9) 11 | 12 | # Text with default zorder of 3 13 | text = ax.text(0.5, 0.5, "Hello, world!", 14 | size = 30, 15 | ha = 'center', 16 | va = 'center') 17 | 18 | # Lines with default zorder of 2 19 | line1 = ax.axvline(0.65, 20 | linewidth = 10, 21 | color = blue) 22 | line2 = ax.plot([0.35, 0.35], [.05, .95], 23 | linewidth = 10, 24 | color = blue) 25 | 26 | # Patches with default zorder of 1 27 | patch1 = ax.fill_between([0,1], 0.45, .55, 28 | facecolor = green, 29 | edgecolor = 'black') 30 | patch2 = ax.fill_between([.48,.52], 0, 1, 31 | facecolor = red, 32 | edgecolor = 'black', 33 | linewidth = 2) 34 | 35 | # Check zorders 36 | print(text.get_zorder()) 37 | print(line1.get_zorder()) 38 | print(line2[0].get_zorder()) 39 | print(patch1.get_zorder()) 40 | print(patch2.get_zorder()) -------------------------------------------------------------------------------- /python/direct-annotation.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | x = np.arange(-10,6,1) 3 | past = x[x<=0] 4 | future = x[x>=0] 5 | y_historical = np.random.normal(0,1,size = len(past)) 6 | y_projected = np.concatenate([y_historical[-1:], 7 | np.random.normal(0,3, size = len(future)-1)]) 8 | z_historical = np.random.normal(1,1,size = len(past)) 9 | z_projected = np.concatenate([z_historical[-1:], 10 | np.random.normal(3,1, size = len(future)-1)]) 11 | ax.plot(past, y_historical) 12 | a_line, = ax.plot(future, y_projected, linestyle = 'dashed', color = 'C0') 13 | ax.plot(past, z_historical, color = 'C1') 14 | b_line, = ax.plot(future, z_projected, linestyle = 'dashed', color = 'C1') 15 | 16 | # Label Data 17 | ax.annotate('Series A', 18 | xy = (1, y_projected[-1]), 19 | xycoords = (a_line, 'data'), 20 | color = 'C0', 21 | size = 12) 22 | 23 | ax.annotate('Series B', 24 | xy = (1, z_projected[-1]), 25 | xycoords = (b_line, 'data'), 26 | color = 'C1', 27 | size = 12) 28 | 29 | ax.set_xlim(ax.get_xlim()[0], 9) 30 | ax.set_title("Two Lines Zero Legends") -------------------------------------------------------------------------------- /python/dual-bad.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | ax2 = ax.twinx() 3 | 4 | x = np.linspace(0,1,2) 5 | ax.plot(x, x, label = 'a') 6 | ax2.plot(x, 10-x, label = 'b') 7 | 8 | ax.set_xlabel("A Label") 9 | 10 | # This does nothing 11 | ax2.set_xlabel("Label Attempt") 12 | 13 | ax.set_ylabel("Left Y Label") 14 | ax2.set_ylabel("Right Y Label") 15 | 16 | ax.set_title("Positive Slope") 17 | ax2.set_title("Negative Slope") 18 | 19 | ax.legend() 20 | ax2.legend() 21 | fig.legend(facecolor = 'lightyellow') -------------------------------------------------------------------------------- /python/dual-norm-b.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | ax2 = ax.twiny() 3 | 4 | # Plot PDF 5 | x = np.linspace(-3,3,200) 6 | y = stats.norm.pdf(x) 7 | ax.plot(x,y) 8 | 9 | # Set x ticks for bottom x-axis 10 | xticks = np.linspace(-2,2,6) 11 | ax.set_xticks(xticks) 12 | 13 | # Get corresponding CDF values for each tick 14 | labels2 = list() 15 | for tick in xticks: 16 | cumulative = stats.norm.cdf(tick) 17 | labels2.append(round(cumulative,2)) 18 | 19 | # Add ticks to top x-axis 20 | ax2.set_xticks(xticks) 21 | ax2.set_xticklabels(labels2, color = 'red') 22 | 23 | # Clear y ticks 24 | ax.set_yticks([]) 25 | 26 | # Set Limits 27 | xlims = -3,3 28 | ax2.set_xlim(xlims) 29 | ax.set_xlim(xlims) 30 | 31 | # Label and change color 32 | ax.set_xlabel("Value") 33 | ax2.set_xlabel("Percentile", color = 'red') 34 | ax2.spines['top'].set_color('red') 35 | ax2.tick_params(axis ='x', colors = 'red') -------------------------------------------------------------------------------- /python/dual-norm.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | ax2 = ax.twinx() 3 | x = np.linspace(-3,3,200) 4 | pdf_y = stats.norm.pdf(x) 5 | cdf_y = stats.norm.cdf(x) 6 | 7 | # Plot Curves 8 | ax2.plot(x, cdf_y, 9 | color = 'darkgray', 10 | linestyle = 'dashed', 11 | linewidth =2) 12 | ax.plot(x, pdf_y, 13 | linewidth = 3) 14 | 15 | ax.set_title("Normal Distribution") 16 | 17 | # Change Ticks 18 | # Use LaTeX \mathbf to make ticks bold 19 | bolded_ticks = [r'$\mathbf{'+"{:.2f}".format(x)+r"}$" for x in ax.get_yticks()] 20 | ax.set_yticklabels(bolded_ticks) 21 | ax.tick_params(axis ='y', 22 | colors = 'C0', 23 | labelsize = 11) 24 | ax2.tick_params(axis ='y', 25 | colors = (.25,.25,.25)) # darker gray -------------------------------------------------------------------------------- /python/dual-ok.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | ax2 = ax.twinx() 3 | 4 | x = np.linspace(0,1,2) 5 | ax.plot(x, x, label = 'a') 6 | ax2.plot(x, 10-x, 7 | label = 'b', 8 | color = 'C2', 9 | linestyle = 'dotted', 10 | linewidth = 2) 11 | 12 | ax.set_title("Title") 13 | 14 | ax.set_xlabel("A Label") 15 | ax.set_ylabel("Left Y Label\n(a)") 16 | ax2.set_ylabel("Right Y Label\n(b)") 17 | 18 | fig.legend(facecolor = 'lightyellow', 19 | bbox_to_anchor = (.5,.92), 20 | ncol = 2, 21 | loc = 'center', 22 | bbox_transform = ax.transAxes) -------------------------------------------------------------------------------- /python/ellipse-tform.py: -------------------------------------------------------------------------------- 1 | # Create a circle of points 2 | angles = np.linspace(0, 2*np.pi, 100) 3 | x_vals = np.cos(angles) 4 | y_vals = np.sin(angles) 5 | 6 | # Begin plot 7 | fig, ax = plt.subplots(1,2) 8 | 9 | # simplify axes names 10 | ax0, ax1 = ax[0], ax[1] 11 | 12 | # Plot a circle 13 | ax0.plot(x_vals, y_vals) 14 | 15 | # Mark the y and x directions/axes 16 | # vertical axis 17 | height = 1.2 18 | p1 = np.array([0,-height]) 19 | p2 = np.array([0,height]) 20 | points = [p1,p2] 21 | x_vertical = [p[0] for p in points] 22 | y_vertical = [p[1] for p in points] 23 | ax0.plot(x_vertical, y_vertical) 24 | 25 | # horizontal axis 26 | width = height 27 | p1 = np.array([height,0]) 28 | p2 = np.array([-height,0]) 29 | points = [p1,p2] 30 | x_horiz = [p[0] for p in points] 31 | y_horiz = [p[1] for p in points] 32 | ax0.plot(x_horiz, y_horiz) 33 | 34 | # Make Ellipse 35 | new_points = [transformation * np.matrix(p).T for p in zip(x_vals,y_vals)] 36 | 37 | new_x = [np.array(x).flatten()[0] for x in new_points] 38 | new_y = [np.array(x).flatten()[1] for x in new_points] 39 | 40 | # new vertical axis 41 | new_vertical = [transformation * np.matrix(p).T for p in zip(x_vertical, y_vertical)] 42 | new_x_vertical = [np.array(x).flatten()[0] for x in new_vertical] 43 | new_y_vertical = [np.array(x).flatten()[1] for x in new_vertical] 44 | 45 | # new horizontal axis 46 | new_horiz = [transformation * np.matrix(p).T for p in zip(x_horiz, y_horiz)] 47 | new_x_horiz = [np.array(x).flatten()[0] for x in new_horiz] 48 | new_y_horiz = [np.array(x).flatten()[1] for x in new_horiz] 49 | 50 | # Plot ellipse etc 51 | ax1.plot(new_x, new_y) 52 | ax1.plot(new_x_vertical, new_y_vertical) 53 | ax1.plot(new_x_horiz, new_y_horiz) 54 | 55 | # Change axes appearance 56 | args = -2,2 57 | for ax_ in ax0, ax1: 58 | ax_.set_xlim(args) 59 | ax_.set_ylim(args) 60 | ax_.set_xticks(np.linspace(*args,5)) 61 | ax_.set_yticks(np.linspace(*args,5)) 62 | ax0.set_aspect('equal') 63 | ax1.set_aspect('equal') -------------------------------------------------------------------------------- /python/empty-square.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | ax.set_aspect('equal') -------------------------------------------------------------------------------- /python/empty.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() -------------------------------------------------------------------------------- /python/error-stack.py: -------------------------------------------------------------------------------- 1 | x = np.linspace(-3,5, 100_000) 2 | 3 | fig = plt.figure(figsize = (10,5)) 4 | ax0 = fig.add_subplot(211, zorder = 99) 5 | ax1 = fig.add_subplot(212) 6 | 7 | for center, ax in zip([0, 2], [ax0, ax1]): 8 | # add normal curve 9 | norm_pdf = stats.norm.pdf(x, center, 1) 10 | ax.plot(x, norm_pdf, lw = 3) 11 | 12 | # Clean plot 13 | for s in 'left', 'right', 'top': 14 | ax.spines[s].set_visible(False) 15 | ax.yaxis.set_ticks([]) 16 | ax.set_ylim(0, .42) 17 | 18 | # draw rejection region 19 | ax = ax0 20 | alpha = 0.05 21 | critical_value = stats.norm.ppf(1 - alpha) # for one-sided 22 | rejection_x = x[x > critical_value] 23 | ax.fill_between(rejection_x, 24 | stats.norm.pdf(x, 0, 1)[-len(rejection_x):], 25 | color = 'C1', 26 | alpha = 0.2) 27 | # label 28 | ax.text(2.2, stats.norm.pdf(2), 'Type I Error') 29 | 30 | # Draw critical value line through both plots 31 | trans = mpl.transforms.blended_transform_factory(ax.transData, fig.transFigure) 32 | ax.plot([critical_value, critical_value], 33 | [0, 1], 34 | color='black', 35 | linestyle = 'dotted', 36 | lw=2, 37 | transform = trans, 38 | clip_on= False, 39 | zorder = 99) 40 | 41 | # Draw type II error region 42 | fail_to_reject_region = x[x <= critical_value] 43 | ax1.fill_between(fail_to_reject_region, 44 | stats.norm.pdf(x, 2, 1)[0:len(fail_to_reject_region)], 45 | color = 'C4', 46 | alpha = 0.2) 47 | ax1.text(.1, stats.norm.pdf(.3, 2, 1), 'Type II Error', ha = 'right') -------------------------------------------------------------------------------- /python/event-A.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | ax.set_aspect(1) 3 | ax.set_xlim(-1.6,1.6) 4 | ax.set_ylim(-1.1,1.4) 5 | ax.axis('off') 6 | 7 | # Add circles with color fill 8 | left_circle = plt.Circle((-0.5, 0), 1, 9 | edgecolor = 'black', 10 | facecolor = 'gray', 11 | linewidth = 2) 12 | right_circle = plt.Circle((0.5, 0), 1, 13 | edgecolor = 'black', 14 | facecolor = (1, 1, 1, 0), # transparent 15 | linewidth = 2, 16 | zorder = 5) 17 | ax.add_artist(left_circle) 18 | ax.add_artist(right_circle) 19 | 20 | # Labels 21 | ax.text(0, 1.05, 22 | s = r"$A$", 23 | va = 'bottom', 24 | ha = 'center', 25 | size = 30) 26 | ax.text(-1, 0, 27 | s = r'$A$', 28 | ha = 'right', 29 | va = 'center', 30 | size = 20) 31 | ax.text(1, 0, 32 | s = r'$B$', 33 | ha = 'left', 34 | va = 'center', 35 | size = 20) -------------------------------------------------------------------------------- /python/expanding-lims.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | 3 | for i in range(1,4): 4 | ax.plot([0,i], [i,i]) 5 | bottom_y, top_y = ax.get_ylim() 6 | left_x, right_x = ax.get_xlim() 7 | ax.fill_between(x = [left_x,right_x], 8 | y1 = bottom_y, 9 | y2 = top_y, 10 | alpha = 0.5/i) 11 | 12 | # Prevent limits from automatically stretching further 13 | # The last fill_between would stretch limits again 14 | ax.set_ylim(bottom_y, top_y) 15 | ax.set_xlim(left_x, right_x) -------------------------------------------------------------------------------- /python/figparams.py: -------------------------------------------------------------------------------- 1 | fig = plt.figure(figsize = (2,3), 2 | facecolor = 'gray') 3 | ax = plt.axes(facecolor = 'lightyellow') -------------------------------------------------------------------------------- /python/font.py: -------------------------------------------------------------------------------- 1 | # font download 2 | # https://fonts.google.com/specimen/Pacifico 3 | # access font and add to font manager 4 | font_dirs = ['Downloads/Pacifico'] # change depending on where you downloaded it 5 | font_files = font_manager.findSystemFonts(fontpaths=font_dirs) 6 | for font_file in font_files: 7 | font_manager.fontManager.addfont(font_file) 8 | 9 | # Make Figure 10 | fig, ax = plt.figure(), plt.axes() 11 | t = fig.text(0.5,0.5, 12 | 'Live Laugh Love', 13 | ha = 'center', 14 | va = 'center') 15 | ax.axis('off') 16 | t.set_size(50) 17 | t.set_name("Pacifico") 18 | t.set_color('yellow') 19 | fig.set_facecolor('brown') -------------------------------------------------------------------------------- /python/front-axes.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | for i in [0, 0.25, .5, .75]: 3 | ax.fill_between([i,1], 0.3 - i/10, .7 - i/20, 4 | zorder = 2-i) 5 | ax.grid(True, linewidth = 3) 6 | ax.set_xlim(0,1) 7 | ax.set_ylim(0,1) 8 | ax.set_axisbelow(False) 9 | print(ax.get_zorder()) -------------------------------------------------------------------------------- /python/front-xaxis.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | for i in [0, 0.25, .5, .75]: 3 | ax.fill_between([i,1], 0.3 - i/10, .7 - i/20, 4 | zorder = 2-i) 5 | ax.grid(True, linewidth = 3) 6 | ax.set_xlim(0,1) 7 | ax.set_ylim(0,1) 8 | ax.xaxis.set_zorder(3) -------------------------------------------------------------------------------- /python/get-fonts.py: -------------------------------------------------------------------------------- 1 | font_list = font_manager.get_font_names() 2 | for f in font_list: 3 | plt.plot() 4 | plt.gcf().text(0.5, 0.5, 5 | s = f, 6 | size = 20, 7 | ha = 'center', 8 | fontname = f) 9 | plt.axis('off') 10 | plt.show() -------------------------------------------------------------------------------- /python/gettersetter.py: -------------------------------------------------------------------------------- 1 | x = np.linspace(0,1,2) 2 | fig, ax = plt.figure(figsize = (8,4)), plt.axes() 3 | ax.plot(x, x) 4 | ax.plot(x, 1 - x) 5 | ax.set_title("My Chart") 6 | print(ax.title) 7 | print(ax.get_title()) # Similar to above line 8 | ax.set_title("My Wholesome Chart") 9 | print(ax.get_title()) # long -------------------------------------------------------------------------------- /python/gradient.py: -------------------------------------------------------------------------------- 1 | # Set Colors 2 | green = 76, 217, 100 3 | green = np.array(green)/255 4 | blue = 90, 200, 250 5 | blue = np.array(blue)/255 6 | 7 | # How many color changes 8 | segments = 100 9 | interval_starts = np.linspace(0, 1, segments) 10 | 11 | fig, ax = plt.subplots(figsize = (8,8)) 12 | 13 | colors = dict() 14 | for i in range(3): 15 | colors[i] = np.linspace(blue[i], green[i], segments) 16 | 17 | for i in range(segments-1): 18 | rgb = colors[0][i], colors[1][i], colors[2][i] 19 | x = interval_starts[i], interval_starts[i+1] 20 | y = (0.5, 0.5) 21 | ax.plot(x, y, color = rgb, 22 | linewidth = 20, 23 | solid_capstyle = 'round') 24 | 25 | ax.set_aspect('equal') 26 | ax.axis('off') -------------------------------------------------------------------------------- /python/grid-false.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | x = np.linspace(0,10,100) 3 | ax.plot(x, np.cos(x)**3) 4 | ax.grid(False) -------------------------------------------------------------------------------- /python/grid-ternary.py: -------------------------------------------------------------------------------- 1 | scale = 1 2 | figure, tax = ternary.figure(scale=scale) 3 | tax.set_background_color('orange', 4 | alpha = 0.5) 5 | 6 | # Add ticks along the triangle edges 7 | tax.ticks(axis = 'lbr', 8 | multiple = .25, 9 | tick_formats = '%.2f', 10 | offset= 0.02, 11 | linewidth = 0) 12 | 13 | tax.gridlines(multiple = .25, 14 | color = 'gray', 15 | linewidth = 0.5, 16 | linestyle = 'solid') 17 | 18 | points = [(0.25, 0.25, 0.5)] 19 | tax.scatter(points, 20 | marker = 'o', 21 | color = ['black'], 22 | s = 100) 23 | 24 | tax.boundary(linewidth= 2.0) 25 | tax.get_axes().axis('equal') 26 | tax.get_axes().axis('off') -------------------------------------------------------------------------------- /python/grid-true.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | x = np.linspace(0,10,100) 3 | ax.plot(x, np.cos(x)**3) 4 | ax.grid(True) -------------------------------------------------------------------------------- /python/grids-auto.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | ax.xaxis.grid(False) 3 | ax.yaxis.grid(True, linewidth = 3) 4 | ax.yaxis.grid(True, which = 'minor', linewidth = 0.5) 5 | ax.yaxis.set_minor_locator(mpl.ticker.AutoMinorLocator()) -------------------------------------------------------------------------------- /python/grids-multi.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | ax.xaxis.grid(False) 3 | ax.yaxis.grid(True, linewidth = 3) 4 | ax.yaxis.grid(True, which = 'minor', linewidth = 0.5) 5 | ax.yaxis.set_minor_locator(mpl.ticker.MultipleLocator(.1)) -------------------------------------------------------------------------------- /python/gridspec.py: -------------------------------------------------------------------------------- 1 | fig = plt.figure(figsize=(12,6)) 2 | spec = gridspec.GridSpec(ncols=4, 3 | nrows=2, 4 | figure=fig) 5 | x = np.random.normal(0, 10, size = 300) 6 | y = x**2 + np.random.normal(0, 100, size = 300) 7 | 8 | ax1 = fig.add_subplot(spec[0, 0:3]) 9 | ax1.plot(x, y, 10 | linestyle='None', 11 | marker='.', 12 | alpha=0.5) 13 | 14 | ax2 = fig.add_subplot(spec[0, 3:4], sharey = ax1) 15 | ax2.hist(y, orientation='horizontal', bins=40) 16 | 17 | ax3 = fig.add_subplot(spec[1, 0:3], sharex = ax1) 18 | ax3.hist(x, bins = 40) 19 | ax3.invert_yaxis() 20 | plt.tight_layout() -------------------------------------------------------------------------------- /python/heat-basic.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(figsize = (10,3)), plt.axes() 2 | ax.imshow(df.T, 3 | aspect = 20, 4 | cmap = 'Oranges') 5 | ax.set_title("Google Search Trends") -------------------------------------------------------------------------------- /python/heat-cbar.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.subplots(figsize = (10,5)) 2 | s = ax.imshow(df.T, 3 | aspect = 20, 4 | cmap = 'Oranges', 5 | vmax = 50) 6 | 7 | thinning = 12 8 | ax.set_xticks(range(0,len(df),thinning)) 9 | ax.set_xticklabels(list(df.T)[::thinning], 10 | rotation = 30, 11 | ha = 'left') 12 | 13 | ax.set_yticks(range(2)) 14 | ax.set_yticklabels(df.T.index) 15 | ax.xaxis.set_tick_params(labeltop = True, 16 | labelbottom = False, 17 | labelsize = 10, 18 | tick2On= True, 19 | tick1On = True) 20 | cbar = fig.colorbar(mappable = s, 21 | ax = ax, 22 | orientation = 'horizontal', 23 | pad = 0.04, 24 | extend = 'max') 25 | 26 | ax.set_title("Google Search Trends", 27 | size = 18, 28 | pad = 12, 29 | loc = 'center') -------------------------------------------------------------------------------- /python/heat-log.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.subplots(figsize = (10,3)) 2 | ax.imshow(df.T, 3 | aspect = 20, 4 | cmap = 'Oranges', 5 | norm = mpl.colors.LogNorm()) 6 | ax.set_title("Google Search Trends") 7 | 8 | thinning = 12 # label every 12th month 9 | ax.set_xticks(range(0,len(df),thinning)) 10 | ax.set_xticklabels(list(df.T)[::thinning], 11 | rotation = 30) 12 | ax.set_yticks(range(2)) 13 | ax.set_yticklabels(df.T.index) -------------------------------------------------------------------------------- /python/heat-rps.py: -------------------------------------------------------------------------------- 1 | figure, tax = ternary.figure(scale = 20) 2 | # vary scale above for higher resolution 3 | figure.set_size_inches(9, 8) 4 | 5 | # Add Heatmap 6 | tax.heatmapf(winning_pct, boundary=True, 7 | style="triangular", 8 | cmap = 'Purples', 9 | colorbar = False) 10 | 11 | tax.boundary(linewidth=2.0) 12 | 13 | title = 'Net Winning % If I Choose Rock' 14 | tax.set_title(title + " \n") 15 | 16 | tax.right_corner_label('Rock', 17 | position = (.88,0.05,.09), fontsize=10) 18 | tax.top_corner_label('Paper', 19 | position = (.01,1.11,.005),fontsize=10) 20 | tax.left_corner_label('Scissors', 21 | position = (.07,0.05,1), fontsize=10) 22 | 23 | tax.get_axes().axis('off') 24 | # Workaround for a bug with labels 25 | tax._redraw_labels() -------------------------------------------------------------------------------- /python/hockey-heat.py: -------------------------------------------------------------------------------- 1 | from PIL import Image 2 | 3 | fig, ax = plt.subplots(figsize = (10,10), facecolor = (.98, .98, .98)) 4 | teams = 'ABCDEF' 5 | years = range(2002,2009) 6 | ax.set_aspect('equal') 7 | ax.axis('off') 8 | 9 | y_pad = -1 10 | for team_key, team in enumerate(teams): 11 | for year_key, year in enumerate(years): 12 | 13 | year_str = str(year)[-2:] + "-" + str(year+1)[-2:] 14 | 15 | record = min(1,np.random.random()**(team_key+1) + .05) 16 | if year != 2004: 17 | circ = plt.Circle((year_key, y_pad*team_key), 18 | radius = .25 + (record/2), 19 | color = 'C0', 20 | alpha = record) 21 | ax.add_artist(circ) 22 | ax.text(year_key, y_pad*team_key, 23 | s = str(round(100*record))+"%", 24 | va= 'center', 25 | ha = 'center') 26 | 27 | if year_key == 0: 28 | ax.text(year_key - 1, y_pad*team_key, 29 | s = team, 30 | ha = 'right', 31 | va= 'center') 32 | if team_key == 0: 33 | ax.text(year_key, y_pad*team_key + 1, 34 | s = year_str, 35 | ha = 'center', 36 | va= 'bottom') 37 | 38 | ax.set_ylim(y_pad*5 - 1, 1) 39 | ax.set_xlim(-1.5, len(years)) 40 | 41 | # lockout annotation 42 | string = 'No Season Due To Lockout' 43 | ax.text(2, 0, 44 | s = '\n'.join(string), 45 | va= 'top', 46 | ha = 'center', 47 | size = 15) 48 | 49 | # Add Logo 50 | file = '../../images/predators.png' 51 | img = np.asarray(Image.open(file)) 52 | off_img = mpl.offsetbox.OffsetImage(img, zoom=.016) 53 | ab = mpl.offsetbox.AnnotationBbox(off_img, (-1, 0), 54 | xycoords='data', 55 | frameon = False) 56 | #ax.add_artist(ab) 57 | ax.text(.5, 1.05, 58 | s = "Hockey Regular Season Records", 59 | size = 20, 60 | ha = 'center', 61 | va = 'bottom', 62 | transform = ax.transAxes) -------------------------------------------------------------------------------- /python/imports.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | import math 4 | from itertools import combinations 5 | from itertools import product 6 | from sklearn.datasets import load_iris 7 | 8 | # matplotlib specific 9 | import matplotlib as mpl 10 | import matplotlib.pyplot as plt 11 | 12 | # For Special Topics 13 | # import ternary # requires install 14 | # from ternary.helpers import simplex_iterator 15 | from sklearn.manifold import MDS 16 | from sklearn.decomposition import PCA 17 | from scipy import stats 18 | 19 | # Made redundant in the text 20 | from matplotlib.patches import ConnectionPatch 21 | from matplotlib.patches import Rectangle 22 | import matplotlib.gridspec as gridspec 23 | from matplotlib.ticker import MultipleLocator 24 | from matplotlib.colors import colorConverter 25 | from mpl_toolkits.mplot3d import Axes3D 26 | from mpl_toolkits.mplot3d.art3d import Poly3DCollection 27 | import matplotlib.dates as mdates 28 | from matplotlib import font_manager -------------------------------------------------------------------------------- /python/intersection.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | ax.set_aspect(1) 3 | ax.set_xlim(-1.6,1.6) 4 | ax.set_ylim(-1.1,1.4) 5 | ax.axis('off') 6 | 7 | # Add Circles 8 | k = 10_000 9 | angles = np.linspace(0, 2*np.pi, k) 10 | x = np.cos(angles) 11 | y = np.sin(angles) 12 | ax.plot(x - 0.5, y, color = 'black') 13 | ax.plot(x + 0.5, y, color = 'black') 14 | 15 | # fill circles in two pieces 16 | x = np.cos(angles) - 0.5 17 | t = 0 18 | while x[t] > 0: 19 | t += 1 20 | ax.fill_between(x[:t], -y[0:t], y[0:t], 21 | color = 'gray', zorder = -1) 22 | ax.fill_between(-x[:t] , -y[0:t], y[0:t], 23 | color = 'gray', zorder = -1) 24 | 25 | # Label 26 | ax.text(0, 1.05, 27 | s = r"$A \cap B$", 28 | va = 'bottom', 29 | ha = 'center', 30 | size = 30) -------------------------------------------------------------------------------- /python/irisbox.py: -------------------------------------------------------------------------------- 1 | from sklearn.datasets import load_iris 2 | data = load_iris()['data'] 3 | df = pd.DataFrame(data) 4 | 5 | fig, ax = plt.figure(), plt.axes() 6 | 7 | df.plot.box(ax = ax) 8 | ax.yaxis.grid(True) 9 | ax.xaxis.grid(False) 10 | 11 | plt.tight_layout() 12 | plt.savefig('irisbox.pdf') -------------------------------------------------------------------------------- /python/label-data.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | x = np.arange(-10,6,1) 3 | past = x[x<=0] 4 | future = x[x>=0] 5 | 6 | y_historical = np.random.normal(0,1,size = len(past)) 7 | y_projected = np.concatenate([y_historical[-1:], 8 | np.random.normal(0,3, size = len(future)-1)]) 9 | 10 | z_historical = np.random.normal(1,1,size = len(past)) 11 | z_projected = np.concatenate([z_historical[-1:], 12 | np.random.normal(3,1, size = len(future)-1)]) 13 | 14 | ax.plot(past, y_historical) 15 | ax.plot(future, y_projected, linestyle = 'dashed', color = 'C0') 16 | 17 | ax.plot(past, z_historical, color = 'C1') 18 | ax.plot(future, z_projected, linestyle = 'dashed', color = 'C1') 19 | 20 | # Label Data 21 | ax.text(future[-1], y_projected[-1], 22 | s = 'Series A', 23 | va = 'center', 24 | color = 'C0', 25 | size = 13) 26 | ax.text(future[-1], z_projected[-1], 27 | s = 'Series B', 28 | va = 'center', 29 | color = 'C1', 30 | size = 13) 31 | 32 | ax.set_xlim(ax.get_xlim()[0], 9) 33 | ax.set_title("Two Lines Zero Legends") -------------------------------------------------------------------------------- /python/legend-bb-loc.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | x = np.linspace(0,2*np.pi,100) 3 | ax.plot(x, np.sin(x), label = 'sine') 4 | ax.plot(x, np.cos(x), label = 'cosine') 5 | ax.plot(x, np.sin(x)**3, label = r'sine$^3$') 6 | 7 | # Construct legend 8 | ax.legend(bbox_to_anchor = (0.5,1), 9 | loc = 'lower right') -------------------------------------------------------------------------------- /python/legend-bb.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | x = np.linspace(0,2*np.pi,100) 3 | ax.plot(x, np.sin(x), label = 'sine') 4 | ax.plot(x, np.cos(x), label = 'cosine') 5 | ax.plot(x, np.sin(x)**3, label = r'sine$^3$') 6 | 7 | # Construct legend 8 | ax.legend(bbox_to_anchor = (0.5,1)) -------------------------------------------------------------------------------- /python/legend-labels.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | x = np.linspace(0,2*np.pi,100) 3 | 4 | # Label in one go 5 | ax.plot(x, np.sin(x), label = 'sine') 6 | 7 | # Label as Artist method 8 | cos, = ax.plot(x, np.cos(x)) 9 | cos.set_label('cosine') 10 | 11 | # Label as Artist method 12 | sine3 = ax.plot(x, np.sin(x)**3) 13 | sine3[0].set_label(r'sine$^3$') 14 | 15 | # Construct legend 16 | ax.legend() -------------------------------------------------------------------------------- /python/legend-shape.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | 3 | x = np.linspace(0,2*np.pi,100) 4 | 5 | ax.plot(x, np.sin(x), label = 'sine') 6 | ax.plot(x, np.cos(x), label = 'cosine') 7 | ax.plot(x, np.sin(x)**3, label = r'sine$^3$') 8 | 9 | # Construct legend 10 | ax.legend(bbox_to_anchor = (0.5,-0.3), 11 | loc = 'lower center', 12 | ncol = 3, 13 | facecolor = 'lightgray', 14 | edgecolor = 'gray', 15 | shadow = True, 16 | title = 'Legend') -------------------------------------------------------------------------------- /python/legend-transform.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(facecolor = 'lightgray'), plt.axes() 2 | x = np.linspace(0,2*np.pi,100) 3 | ax.plot(x, np.sin(x), label = 'sine') 4 | ax.plot(x, np.cos(x), label = 'cosine') 5 | ax.plot(x, np.sin(x)**3, label = r'sine$^3$') 6 | 7 | # Construct legend 8 | ax.legend(bbox_to_anchor = (0.5,0), 9 | loc = 'lower center', 10 | bbox_transform = fig.transFigure) -------------------------------------------------------------------------------- /python/matlab-chart.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | x = 1,0 3 | y = 0,1 4 | 5 | plt.plot(x,y) 6 | plt.title("My Chart") -------------------------------------------------------------------------------- /python/matlab-plot.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | x = 1,0 3 | y = 0,1 4 | 5 | plt.plot(x,y) 6 | plt.title("My Plot") -------------------------------------------------------------------------------- /python/mds-circles.py: -------------------------------------------------------------------------------- 1 | white = colorConverter.to_rgba('white', alpha = 0) 2 | grey = colorConverter.to_rgba('gray', alpha = 0.8) 3 | 4 | fig, ax = plt.figure(), plt.axes() 5 | 6 | # point a 7 | c = plt.Circle((0, 0), radius = 1, facecolor = white, edgecolor = 'black', alpha = 1) 8 | ax.add_artist(c) 9 | ax.plot([0],[0], marker = 'o', markersize = 3) 10 | ax.text(0,0,'$a$', va = 'bottom', ha = 'left') 11 | 12 | # point b 13 | c = plt.Circle((0, 1), radius = 1, facecolor = white, edgecolor = grey) 14 | ax.add_artist(c) 15 | ax.plot([0],[1], marker = 'o', markersize = 3) 16 | ax.text(0,1,'$b$', va = 'bottom', ha = 'left') 17 | 18 | # Add point c 19 | angle = math.asin(0.5) 20 | c1 = math.cos(angle) 21 | c2 = math.sin(angle) 22 | ax.plot([c1],[c2], marker = 'o', markersize = 3) 23 | ax.text(c1,c2,'$c$', va = 'bottom', ha = 'left')# = 1) 24 | c = plt.Circle((c1, c2), radius = 1, facecolor = white, edgecolor = grey) 25 | ax.add_artist(c) 26 | 27 | # Where does d go? 28 | ax.text(1.4,1.4,'$d$?', va = 'bottom', ha = 'left') 29 | 30 | ax.axis('off') 31 | ax.set_aspect('equal') 32 | 33 | v = 2.1 34 | ax.set_xlim([-1.1,v]) 35 | ax.set_ylim([-1.1,v]) -------------------------------------------------------------------------------- /python/mpl-table.py: -------------------------------------------------------------------------------- 1 | url = 'https://github.com/alexanderthclark/MPL-Data/raw/main/HopperOstromTrends.csv' 2 | df = pd.read_csv(url, index_col = 'Month') 3 | fig, ax = plt.subplots() 4 | ax.axis('off') 5 | n = 10 # how many rows 6 | ax.table(cellText = df.head(n).values, 7 | rowLabels = df.head(n).index, 8 | colLabels = list(df), 9 | loc = 'center') -------------------------------------------------------------------------------- /python/mult-locator.py: -------------------------------------------------------------------------------- 1 | x = np.linspace(0, np.pi * 2, 100) 2 | 3 | fig, ax = plt.figure(), plt.axes() 4 | ax.plot(x, np.sin(x)) 5 | 6 | ax.xaxis.set_major_locator(MultipleLocator(np.pi)) -------------------------------------------------------------------------------- /python/multicolor-inexact.py: -------------------------------------------------------------------------------- 1 | x = range(101) 2 | 3 | # Create a Gaussian random walk starting at 0 4 | start = np.zeros(1) 5 | y1 = np.concatenate( [start,np.random.normal(0,1,100)] ).cumsum() 6 | y2 = np.concatenate( [start,np.random.normal(0,1,100)] ).cumsum() 7 | 8 | fig, ax = plt.figure(), plt.axes() 9 | plt.tight_layout() 10 | # Color arguments added to make defaults explicit 11 | ax.plot(x,y1, color = 'C0') 12 | ax.plot(x,y2, color = 'C1') 13 | 14 | ax.text(0.4, 1.05, ' GenericCo', 15 | transform = ax.transAxes, 16 | ha = 'left', 17 | fontsize = 13, 18 | color = 'C0') 19 | 20 | ax.text(0.4, 1.05, 'Stock Performance:', 21 | transform = ax.transAxes, 22 | ha = 'right', 23 | fontsize = 13, 24 | color = 'black') 25 | 26 | ax.text(0.64, 1.05, '&', 27 | transform = ax.transAxes, 28 | ha = 'right', 29 | fontsize = 13, 30 | color = 'black') 31 | 32 | ax.text(0.64, 1.05, ' PerfunctoryInc', 33 | transform = ax.transAxes, 34 | ha = 'left', 35 | fontsize = 13, 36 | color = 'C1') -------------------------------------------------------------------------------- /python/multicolor-title.py: -------------------------------------------------------------------------------- 1 | x_len = 200 2 | x = range(0, x_len) 3 | 4 | # Create a Gaussian random walk starting at 0 5 | start = np.zeros(1) 6 | y1 = np.concatenate([start,np.random.normal(0, 1, x_len-1)]).cumsum() 7 | y2 = np.concatenate([start,np.random.normal(0, 1, x_len-1)]).cumsum() 8 | 9 | # Start plot 10 | fig, ax = plt.figure(figsize = (7,5)), plt.axes() 11 | fig.canvas.draw() 12 | 13 | # Color arguments added to make defaults explicit 14 | ax.plot(x, y1, color = 'C0') 15 | ax.plot(x, y2, color = 'C1') 16 | 17 | # Tuned by hand 18 | shift = .099814 # Where titling starts on x-axis 19 | y_level = 1.02 20 | transform = ax.transAxes # use axes coords 21 | 22 | t1 = ax.text(shift, y_level, 'Stock Performance:', 23 | transform = transform, 24 | ha = 'left', 25 | fontsize = 13, 26 | color = 'black') 27 | 28 | # Get where text ended 29 | x_pos = t1.get_window_extent()\ 30 | .transformed(transform.inverted()).x1 31 | 32 | t2 = ax.text(x_pos, y_level, ' GenericCo', 33 | transform = transform, 34 | ha = 'left', 35 | fontsize = 13, 36 | color = 'C0') 37 | 38 | x_pos = t2.get_window_extent()\ 39 | .transformed(transform.inverted()).x1 40 | 41 | t3 = ax.text(x_pos, y_level, ' &', 42 | transform = transform, 43 | ha = 'left', 44 | fontsize = 13, 45 | color = 'black') 46 | 47 | x_pos = t3.get_window_extent()\ 48 | .transformed(transform.inverted()).x1 49 | 50 | t4 = ax.text(x_pos, y_level, ' PerfunctoryInc', 51 | transform = transform, 52 | ha = 'left', 53 | fontsize = 13, 54 | color = 'C1') 55 | 56 | x_pos = t4.get_window_extent()\ 57 | .transformed(transform.inverted()).x1 58 | 59 | # compare distances to the edge 60 | # equal means perfect centering 61 | print(shift, 1-x_pos) -------------------------------------------------------------------------------- /python/no-axis.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | ax.set_title("Where did everyone go?") 3 | ax.axis('off') -------------------------------------------------------------------------------- /python/no-slope.py: -------------------------------------------------------------------------------- 1 | plt.plot([0,1], [0,1]) 2 | plt.text(0.65, 0.5, 3 | s = 'label', 4 | size = 30) 5 | 6 | ax = plt.gca() 7 | # Cosmetics 8 | ax.grid(False) 9 | ax.set_xticks([]) 10 | ax.set_yticks([]) -------------------------------------------------------------------------------- /python/norm-pdf.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | ax.set_xlim(-3.3, 3.3) 3 | x = np.linspace(-4, 4, 200) 4 | ax.plot(x, stats.norm.pdf(x), 5 | linewidth = 2) 6 | ax.set_title("Normal Distribution") 7 | 8 | # Choose a point 9 | z = 0.674 10 | pdfz = stats.norm.pdf(z) 11 | cdfz = stats.norm.cdf(z) 12 | 13 | # Indicate point on plot 14 | ax.plot([z, z], 15 | [0, pdfz], 16 | color = 'black', 17 | linestyle = 'dashed') 18 | ax.plot([z], [pdfz], 19 | color = 'black', 20 | marker = '.') 21 | ax.text(z + .1, pdfz, 22 | s = '$z = {:}$'.format(z) ) 23 | 24 | # Create fill to left 25 | x_vals = np.linspace(-3,z,100) 26 | ax.fill_between(x_vals, 27 | np.zeros(100), 28 | stats.norm.pdf(x_vals), 29 | color = 'gray', 30 | alpha = .2) 31 | 32 | # Area/cumulative density text 33 | ax.text(0, pdfz/2, 34 | s = "{:.2f}".format(cdfz), 35 | size = 15, 36 | ha = 'center') 37 | 38 | # Change axes styling 39 | ax.spines['bottom'].set_position('zero') 40 | ax.spines['top'].set_visible(False) 41 | ax.spines['right'].set_visible(False) -------------------------------------------------------------------------------- /python/normal-pdf.py: -------------------------------------------------------------------------------- 1 | x = np.linspace(-4, 4, 100_000) 2 | y = stats.norm.pdf(x) 3 | fig, ax = plt.figure(), plt.axes() 4 | ax.set_aspect(5) 5 | 6 | ax.plot(x,y, linewidth = 2, color = 'C0') 7 | ax.fill_between(x,y, color = 'C0') 8 | 9 | ax.set_yticks([]) 10 | for s in 'left', 'top', 'right': 11 | ax.spines[s].set_visible(False) 12 | 13 | ylims = ax.get_ylim() 14 | ax.set_ylim(0, ylims[1]) 15 | ax.set_title("Normal Distribution") -------------------------------------------------------------------------------- /python/nyt-helper-data.py: -------------------------------------------------------------------------------- 1 | data = {2019: [6, 4.3, 3.9], 2 | 2020: [7, 2.7, 4.4]} 3 | df = pd.DataFrame(data = data, 4 | index = ['Alone', 5 | 'With people outside household', 6 | 'With household members only']) 7 | -------------------------------------------------------------------------------- /python/nyt-helper-function.py: -------------------------------------------------------------------------------- 1 | def title_and_subtitle(title, subtitle = '', pad = 0.01, fig = None, ax = None): 2 | """Add a centered title and subtitle to a plot.""" 3 | if ax == None: 4 | ax = plt.gca() 5 | if fig == None: 6 | fig = plt.gcf() 7 | fig.canvas.draw() 8 | 9 | top_of_figure = 1 # axes coords 10 | # update if there are xticks on the top 11 | tick0 = ax.get_xticklabels()[0] 12 | top_of_ticklabels = tick0.get_window_extent().transformed(ax.transAxes.inverted()).y1 13 | top_of_figure = max([top_of_ticklabels,top_of_figure]) 14 | 15 | # Add subtitle 16 | if subtitle: 17 | subt = ax.text(0.5, top_of_figure + pad, 18 | s = subtitle, 19 | ha = 'center', 20 | va = 'bottom', 21 | size = '11', 22 | fontname = 'Helvetica', 23 | transform = ax.transAxes) 24 | # update top of figure to top of the subtitle 25 | top_of_figure = subt.get_window_extent().transformed(ax.transAxes.inverted()).y1 26 | 27 | # add title 28 | ax.text(0.5, top_of_figure + pad, 29 | s = title, 30 | ha = 'center', 31 | va = 'bottom', 32 | size = '18', 33 | fontname = 'Helvetica', 34 | fontweight = 'bold', 35 | transform = ax.transAxes, 36 | color = 'black') -------------------------------------------------------------------------------- /python/nyt-refactor.py: -------------------------------------------------------------------------------- 1 | with plt.style.context("../../stylelib/nyt-helper.mplstyle"): 2 | 3 | fig = plt.figure(figsize = (7,6.5)) 4 | ax = plt.axes(facecolor = (.94, .94, .96)) 5 | 6 | # plot the data 7 | colors = ['orange', 'purple', 'darkred'] 8 | df.T.plot(ax = ax, clip_on = False, color = colors) 9 | 10 | # annotate lines 11 | right_text_style = dict(ha = 'left', 12 | fontsize = 11, 13 | fontname = 'Helvetica', 14 | va = 'center') 15 | left_text_style = dict(ha = 'right', 16 | fontsize = 12, 17 | fontweight = 'bold', 18 | fontname = 'Helvetica') 19 | 20 | # alone 21 | ax.text(2019 - .02, 6, 'Alone', 22 | color = colors[0], 23 | va = 'center', 24 | **left_text_style) 25 | ax.text(2020.03, 7, '+57 min.', 26 | **right_text_style) 27 | 28 | # Within household 29 | ax.text(2019 - .02, 4.2, 'With people\noutside\nhousehold', 30 | color = colors[1], 31 | va = 'bottom', 32 | **left_text_style) 33 | ax.text(2020.03, 2.7, '-1 hour and 33 min.', 34 | **right_text_style) 35 | 36 | # Outside household 37 | ax.text(2019 - .02, 4, 'With\nhousehold\nmembers only', 38 | color = colors[2], 39 | va = 'top', 40 | **left_text_style) 41 | ax.text(2020.03, 4.4, '+31 min.', 42 | **right_text_style) 43 | 44 | 45 | # Title and sub 46 | t = 'A lonely year' 47 | s = 'Average time spent per day during waking hours, May through\nDecember in 2020 vs. 2019' 48 | title_and_subtitle(t,s, fig = fig, ax = ax, pad = .03) 49 | 50 | # Clean ticks etc 51 | yticks = range(0,9,2) 52 | ax.set_yticks(yticks) 53 | ax.set_ylim(0,8) 54 | # add custom labels for y ticks 55 | for tick in yticks: 56 | label = "{} hours".format(tick) 57 | if tick == 0: 58 | label = 'No Time' # custom label 59 | ax.text(2019.5, tick + .01, label, 60 | va = 'bottom', 61 | ha = 'center') 62 | 63 | # move x-tick labels to horizontally align 64 | ax.legend().set_visible(False) 65 | x_vals = [2019,2020] 66 | ax.set_xticks(x_vals) 67 | ax.set_xlim(x_vals) 68 | xticks = ax.get_xticklabels() 69 | xticks[0].set_ha('left') 70 | xticks[-1].set_ha('right') -------------------------------------------------------------------------------- /python/nyt-rep1.py: -------------------------------------------------------------------------------- 1 | ig = plt.figure(figsize = (7,6.5)) 2 | ax = plt.axes(facecolor = (.94, .94, .96)) 3 | 4 | ## Add data and annotations 5 | plot_style = dict(marker = 'o', 6 | clip_on = False, # don't clip markers at axes boundary 7 | linewidth = 3, 8 | markersize = 8) 9 | right_text_style = dict(ha = 'left', fontsize = 11, 10 | fontname = 'Helvetica', 11 | color = (.3,.3,.3), 12 | va = 'center') 13 | left_text_style = dict(ha = 'right', 14 | fontsize = 12, 15 | fontweight = 'bold', 16 | fontname = 'Helvetica') 17 | x_vals = [2019,2020] 18 | # alone 19 | col = 'orange' 20 | ax.plot(x_vals, [6,7], 21 | color = col, 22 | **plot_style) 23 | ax.text(2019 - .02, 6, 'Alone', 24 | color = col, 25 | va = 'center', 26 | **left_text_style) 27 | ax.text(2020.03, 7, '+57 min.', 28 | **right_text_style) 29 | 30 | # within household 31 | col = 'purple' 32 | ax.plot(x_vals, [4.3,2.7], 33 | color = col, 34 | **plot_style) 35 | ax.text(2019 - .02, 4.2, 'With people\noutside\nhousehold', 36 | color = col, 37 | va = 'bottom', 38 | **left_text_style) 39 | ax.text(2020.03, 2.7, '-1 hour and 33 min.', 40 | **right_text_style) 41 | 42 | # outside household 43 | col = 'darkred' 44 | ax.plot(x_vals, [3.9,4.4], color = col, 45 | **plot_style) 46 | ax.text(2019 - .02, 4, 'With\nhousehold\nmembers only', color = col, 47 | va = 'top', 48 | **left_text_style) 49 | 50 | ax.text(2020.03, 4.4, '+31 min.', 51 | **right_text_style) 52 | 53 | 54 | # Label Gridlines 55 | text_style = dict(color = (.3,.3,.3), 56 | va = 'bottom', 57 | ha = 'center', 58 | fontname = 'Helvetica', 59 | fontsize = 11) 60 | 61 | ax.text(2019.5, 0.01, "No Time", **text_style) 62 | for y in [2,4,6,8]: 63 | ax.text(2019.5, y+.04, "{} hours".format(y), 64 | **text_style) 65 | 66 | # Label 2020/2021 for x-axis 67 | year_text_style = dict(color = (.3,.3,.3), 68 | va = 'bottom', 69 | fontname = 'Helvetica', 70 | fontsize = 12) 71 | ax.text(2019, 8.05, '2019', 72 | ha = 'left', **year_text_style) 73 | ax.text(2020, 8.05, '2020', 74 | ha = 'right', **year_text_style) 75 | 76 | # set main title 77 | ax.set_title("A lonely year", pad = 55, fontweight = 'bold', 78 | fontname = 'Helvetica', 79 | fontsize = 18) 80 | 81 | # set subtitle 82 | s = 'Average time spent per day during waking hours, May through\nDecember in 2020 vs. 2019' 83 | ax.text(2019.5, 8.5, s, **text_style) 84 | 85 | # x axis 86 | ax.set_xticks([]) 87 | ax.set_xlim(2019,2020) 88 | 89 | # y axis 90 | ax.yaxis.grid(True, color = 'white') 91 | ax.set_yticks([0,2,4,6,8]) 92 | ax.set_yticklabels([]) 93 | ax.set_ylim([-.02,8]) 94 | ax.yaxis.set_tick_params(length = 0, grid_linewidth = 2) 95 | 96 | # spines 97 | for i in ['top','left','right']: 98 | ax.spines[i].set_visible(False) 99 | ax.spines['bottom'].set_color('darkgray') 100 | ax.spines['bottom'].set_linewidth(2) -------------------------------------------------------------------------------- /python/one-tail-norm.py: -------------------------------------------------------------------------------- 1 | # One-sided test 2 | from statsmodels.stats.proportion import proportions_ztest 3 | z_oneside, pval_oneside = proportions_ztest( 4 | count = 18, 5 | nobs = 30, 6 | value = .5, 7 | prop_var = 0.5, 8 | alternative = 'larger') 9 | 10 | # one tail norm 11 | x = np.linspace(-4,4, 100_000) 12 | norm_pdf = stats.norm.pdf(x) 13 | 14 | # Make empty figure 15 | fig, axx = plt.subplots(2, 1, 16 | figsize = (10,5), 17 | sharey = True) 18 | 19 | for ax in axx: 20 | # add normal curve 21 | ax.plot(x, norm_pdf, lw = 3) 22 | 23 | # add z stat 24 | ax.axvline(z_oneside, linestyle = 'dashed') 25 | ax.text(z_oneside, 0.3, ' $z$', ha = 'left', size = 12, color = 'C0') 26 | 27 | # Clean plot 28 | for s in 'left', 'right', 'top': 29 | ax.spines[s].set_visible(False) 30 | ax.yaxis.set_ticks([]) 31 | ax.set_ylim(0,.42) 32 | ax.set_xlim(-3.1, 3.1) 33 | 34 | # draw rejection region 35 | ax = axx[0] 36 | alpha = .05 37 | critical_value = stats.norm.ppf(1 - alpha) # for one-sided 38 | rejection_x = x[x>critical_value] 39 | ax.fill_between(rejection_x, norm_pdf[-len(rejection_x):], 40 | color = 'red', 41 | alpha = 0.2) 42 | ax.text(3.1, .14, 43 | s = 'Rejection Region', 44 | fontsize = 19, 45 | color = (.6, .2, .2), 46 | ha = 'right') 47 | 48 | # shade p-value 49 | ax = axx[1] 50 | more_extreme_x = x[x>z_oneside] 51 | ax.fill_between(more_extreme_x, norm_pdf[-len(more_extreme_x):], 52 | color = (.2, .2, .2), 53 | alpha = 0.2) 54 | ax.text(3.1, .13, 55 | s = 'P-Value', 56 | fontsize = 19, 57 | color = (.3, .3, .3), 58 | ha = 'right') -------------------------------------------------------------------------------- /python/oop-plot.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | ax.plot(x,y) 3 | ax.set_title("My Plot") -------------------------------------------------------------------------------- /python/pd-dates.py: -------------------------------------------------------------------------------- 1 | url = 'https://github.com/alexanderthclark/MPL-Data/raw/main/WeatherAug1415Trends.csv' 2 | df = pd.read_csv(url, parse_dates = ['Time']) 3 | 4 | fig, ax = plt.figure(), plt.axes() 5 | df.set_index("Time").plot(ax = ax) 6 | ax.set_title("Searches for \"weather\" spike in the morning.") 7 | ax.legend().set_visible(False) -------------------------------------------------------------------------------- /python/pd-legend.py: -------------------------------------------------------------------------------- 1 | # Construct DataFrame 2 | n = 100 3 | sqrts = np.concatenate([np.zeros(1),np.ones(n).cumsum()**0.5] ) 4 | ser1 = pd.Series(data = -sqrts, name = 'Lower Bound') 5 | ser2 = pd.Series(data = sqrts, name = 'Upper Bound') 6 | df = pd.DataFrame([ser1,ser2]).T 7 | 8 | # Add random walk 9 | df['Walk'] = np.concatenate([np.zeros(1),np.random.normal(size = n).cumsum()]) 10 | 11 | # Plot 12 | fig, ax = plt.subplots() 13 | df['Lower Bound'].plot(color = 'black', label = 'Boundary') 14 | df['Upper Bound'].plot(color = 'black', label = '_nolegend_') 15 | df['Walk'].plot() 16 | 17 | ax.legend() -------------------------------------------------------------------------------- /python/py-styled.py: -------------------------------------------------------------------------------- 1 | plt.style.use('default') 2 | %run ../../python/style-changes.py 3 | 4 | x = np.linspace(0,2*np.pi,100) 5 | plt.plot(x, np.sin(x)) 6 | plt.plot(x, np.cos(x)) 7 | plt.title('Hello') -------------------------------------------------------------------------------- /python/r-triangle.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | 3 | a = (1,2) 4 | b = (7,6) 5 | 6 | # rise over run 7 | slope = (a[1] - b[1]) / (a[0] - b[0]) 8 | angle = math.atan(slope) # radians 9 | degrees = math.degrees(angle) 10 | 11 | top_angle = math 12 | 13 | ## add angle semi-circle 14 | x = np.linspace(0, angle, 100) 15 | ax.plot(0.5 * np.cos(x) + a[0], 16 | 0.5 * np.sin(x) + a[1], 17 | color = 'black') 18 | ax.text(0.5*np.cos(angle/2) + 1.1, 0.5*np.sin(angle/2) + 2, 19 | s = r"${:.1f}".format(degrees) + r"^{\circ}$") 20 | 21 | # top slope measured relative to a 90-deg rotation 22 | top_slope = (b[0]-a[0])/(b[1]-a[1]) 23 | top_angle = math.atan(top_slope) 24 | x = np.linspace(1.5*np.pi, 1.5*np.pi - top_angle, 100) 25 | ax.plot(0.5*np.cos(x) + b[0], 26 | 0.5*np.sin(x) + b[1], 27 | color = 'black') 28 | label_angle = 1.5*np.pi - top_angle/2 29 | ax.text(0.5*np.cos(label_angle) + b[0] - 0.13, 0.5*np.sin(label_angle) + b[1] - 0.2, 30 | s = r"${:.1f}".format(math.degrees(top_angle)) + r"^{\circ}$", 31 | ha = 'center') 32 | 33 | 34 | # points on left and top 35 | ax.plot([a[0], b[0]], [a[1], b[1]], linestyle = '', marker = 'o', color = 'black') 36 | 37 | # make a right triangle 38 | ax.plot([a[0], b[0]], [a[1], b[1]], linestyle = 'dashed', marker = 'o', color = 'gray', zorder = -1) 39 | ax.plot([a[0], b[0]], [a[1], a[1]], linestyle = 'dashed', color = 'gray', zorder = -1) 40 | ax.plot([b[0], b[0]], [a[1], b[1]], linestyle = 'dashed', color = 'gray', zorder = -1) 41 | ax.axis('off') -------------------------------------------------------------------------------- /python/reverse-z.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | 3 | print(fig.get_zorder()) 4 | print(ax.get_zorder()) 5 | 6 | for i in [0, 0.25, .5, .75]: 7 | 8 | t = ax.fill_between([i, 1], 0.4 - i/10, .6 - i/20, 9 | zorder = 1 - i) 10 | print(t.get_zorder()) 11 | 12 | ax.set_xlim(0,1) 13 | ax.set_ylim(0,1) -------------------------------------------------------------------------------- /python/rps-br-helper.py: -------------------------------------------------------------------------------- 1 | def color_point(x, y, z): 2 | """Given an opponent plays rock at chance x, paper at y, and scissors at z, what is the best response? 3 | Best responses are mapped to RGB colors.""" 4 | 5 | # winning pcts for possible responses 6 | rock_net = z - y 7 | paper_net = x - z 8 | scissors_net = y - x 9 | 10 | # get best response as highest net winning pct 11 | list_ = [rock_net, paper_net, scissors_net] 12 | best = list_.index(max(list_)) 13 | 14 | # map into RGB color weights 15 | colors = [0, 0, 0] 16 | colors[best] = 1 17 | 18 | # return RGB tuple with fourth value for opacity (alpha) 19 | return (*tuple(colors), 1.) -------------------------------------------------------------------------------- /python/rps-br-lines.py: -------------------------------------------------------------------------------- 1 | scale = 1 2 | figure, tax = ternary.figure(scale = scale) 3 | # vary scale above for higher resolution 4 | figure.set_size_inches(9, 8) 5 | 6 | # Rock > Paper 7 | # s - p > r - s 8 | # 2s > r + p 9 | p1 = (2/3, 0, 1/3) # rps ordering 10 | p1 = scale * np.array(p1) 11 | p2 = (0, 2/3, 1/3) 12 | p2 = scale * np.array(p2) 13 | 14 | tax.line(p1, p2, 15 | linewidth=3., 16 | marker='s', 17 | color='green', 18 | linestyle=":") 19 | tax.annotate(' R < P', (.75*p1 + .25*p2), 20 | color = 'green', 21 | ha = 'left', 22 | va = 'top') 23 | tax.annotate('R > P ', (.75*p1 + .25*p2), 24 | color = 'green', 25 | ha = 'right', 26 | va= 'bottom') 27 | 28 | # Rock > Scissors 29 | # s - p > p - r 30 | # s + r > 2p 31 | p1 = (2/3, 1/3, 0) # rps ordering 32 | p1 = scale * np.array(p1) 33 | p2 = (0, 1/3, 2/3) 34 | p2 = scale * np.array(p2) 35 | 36 | tax.line(p1, p2, 37 | linewidth = 3., 38 | marker = 's', 39 | color = 'blue', 40 | linestyle = ":", 41 | label = 'RockScissors') 42 | tax.annotate('R > S', (.75*p1 + .25*p2), 43 | color = 'blue', 44 | ha = 'left', 45 | va = 'top') 46 | tax.annotate('R < S', (.75*p1 + .25*p2), 47 | color = 'blue', 48 | ha = 'right', 49 | va= 'bottom') 50 | 51 | # Paper > Scissors 52 | # r - s > p - r 53 | # 2r > p + s 54 | p1 = (1/3, 2/3, 0) # rps ordering 55 | p1 = scale * np.array(p1) 56 | p2 = (1/3, 0, 2/3) 57 | p2 = scale * np.array(p2) 58 | 59 | tax.line(p1, p2, 60 | linewidth = 3, 61 | marker = 's', 62 | color = 'red', 63 | linestyle = ":") 64 | 65 | 66 | tax.annotate('S > P ', (.75*p1 + .25*p2), 67 | color = 'red', 68 | ha = 'left', 69 | va = 'top') 70 | tax.annotate(' S < P', (.75*p1 + .25*p2), 71 | color = 'red', 72 | ha = 'right', 73 | va= 'bottom') 74 | 75 | tax.boundary(linewidth=2.0) 76 | 77 | # Make pretty as desired 78 | title = 'Pairwise Comparisons' 79 | tax.set_title(title + " \n") 80 | 81 | tax.right_corner_label('Rock', 82 | position = (.88,0.05,.09), 83 | fontsize=10) 84 | tax.top_corner_label('Paper', 85 | position = (.01,1.11,.005), 86 | fontsize=10) 87 | tax.left_corner_label('Scissors', 88 | position = (.07,0.05,1), 89 | fontsize=10) 90 | 91 | tax.get_axes().axis('off') 92 | tax._redraw_labels() -------------------------------------------------------------------------------- /python/rps-br-zones.py: -------------------------------------------------------------------------------- 1 | # Adapted from https://github.com/marcharper/python-ternary/blob/master/README.md RGBA section 2 | def generate_heatmap_data(scale=10): 3 | from ternary.helpers import simplex_iterator 4 | d = dict() 5 | for (i, j, k) in simplex_iterator(scale): 6 | d[(i, j, k)] = color_point(i, j, k) 7 | return d 8 | 9 | # Scale should be chosen high enough for sharp resolution 10 | scale = 200 11 | data = generate_heatmap_data(scale) 12 | figure, tax = ternary.figure(scale=scale) 13 | figure.set_size_inches(9, 8) 14 | 15 | tax.heatmap(data, style="hexagonal", 16 | use_rgba=True, colorbar = False) 17 | tax.boundary() 18 | tax.set_title("Best Response Zones") 19 | 20 | 21 | # Label the corners 22 | labels = 'Rock', 'Paper', 'Scissors' 23 | tax.right_corner_label(labels[0], 24 | position = (.88,0.05,.09), fontsize=10) 25 | tax.top_corner_label(labels[1], 26 | position = (.01,1.11,.005),fontsize=10) 27 | tax.left_corner_label(labels[2], 28 | position = (.07,0.05,1), fontsize=10) 29 | 30 | # Label best response zones 31 | tax.annotate("Play Rock", 32 | (.1* scale,.1 * scale,.8 * scale), weight = 'bold') 33 | tax.annotate("Play Paper", 34 | (.8*scale, .1*scale, .1*scale), ha = 'right', weight = 'bold') 35 | tax.annotate("Play Scissors", 36 | (.15*scale, .7*scale, .15*scale), ha = 'center', 37 | color = 'white', weight = 'bold') 38 | 39 | # Clear background and axes 40 | tax.clear_matplotlib_ticks() 41 | tax.get_axes().axis('off') 42 | tax._redraw_labels() -------------------------------------------------------------------------------- /python/rps-helper.py: -------------------------------------------------------------------------------- 1 | def winning_pct(p, action = 'rock'): 2 | 3 | """What is the net winning percentage given a choice of action and an opponent's strategy p, where p is a probability distribution over rock, paper, and scissors.""" 4 | 5 | if action.lower() == 'rock': 6 | 7 | winning_pct = p[2] # pr win 8 | net = p[2] - p[1] # pr win - pr lose 9 | 10 | elif action.lower() == 'paper': 11 | 12 | winning_pct = p[0] 13 | net = p[0] - p[2] 14 | 15 | elif action.lower() == 'scissors': 16 | 17 | winning_pct = p[1] 18 | net = p[1] - p[0] 19 | else: 20 | raise ValueError("Input is not a valid action") 21 | 22 | return net -------------------------------------------------------------------------------- /python/sampling-dist.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | x = np.linspace(-4,4, 100_000) 3 | norm_pdf = stats.norm.pdf(x) 4 | ax.plot(x, norm_pdf) 5 | ax.set_title("Sampling Distribution") 6 | 7 | # Clean background elements 8 | ax.set_yticks([]) 9 | for s in 'left', 'top', 'right': 10 | ax.spines[s].set_visible(False) 11 | 12 | # Start y-axis at 0 13 | ylims = ax.get_ylim() 14 | ax.set_ylim(0, ylims[1]) 15 | 16 | # Set x-axis ticks and labels 17 | ax.set_xticks([-1, 0,1]) 18 | ax.set_xticklabels([r"$-\bar{x}$", r'$\mu$', r'$\bar{x}$']) 19 | 20 | # Vertical dashed line 21 | x0 = 0,0 22 | y0 = [0,stats.norm.pdf(0)] 23 | ax.plot(x0, y0, linestyle = 'dashed', color = 'gray') 24 | 25 | # Fill area for a more extreme sample mean 26 | x_right = x[x > 1] 27 | y_right = norm_pdf[-len(x_right):] 28 | ax.fill_between(x_right, y_right) 29 | 30 | x_left = x[x < -1] 31 | y_left = norm_pdf[:len(x_left)] 32 | ax.fill_between(x_left, y_left, color = 'C0') -------------------------------------------------------------------------------- /python/scatter-ternary.py: -------------------------------------------------------------------------------- 1 | scale = 1 2 | figure, tax = ternary.figure(scale=scale) 3 | 4 | # Draw Boundary 5 | tax.boundary(linewidth= 2.0) 6 | 7 | # Scatter Points 8 | points = [(1,0,0), (0,1,0), (0,0,1), (1/3, 1/3, 1/3)] 9 | tax.scatter(points, 10 | marker = 'o', 11 | color = ['red', 'yellow', 'green', 'blue'], 12 | s = 100) -------------------------------------------------------------------------------- /python/slope-label.py: -------------------------------------------------------------------------------- 1 | x1, y1 = 0, 0 2 | x2, y2 = 1, 1 3 | x = (x1, x2) 4 | y = (y1, y2) 5 | 6 | # plot 7 | fig, ax = plt.figure(), plt.axes() 8 | ax.plot(x,y) 9 | 10 | # Find angles and then insert text 11 | slope = (y2 - y1) / (x2 - x1) 12 | true_angle = math.degrees(math.atan(slope)) 13 | 14 | # dummy_array is the point where the angles are anchored 15 | dummy_array = np.array([[0,0]]) # doesn't matter what pair you use 16 | # matplotlib.org/stable/api/transformations.html#matplotlib.transforms.Transform.transform_angles 17 | 18 | plot_angle = ax.transData.transform_angles( 19 | np.array((true_angle,)), 20 | dummy_array)[0] 21 | 22 | ax.text(np.mean(x), np.mean(y), 23 | s = 'label', 24 | rotation = plot_angle, 25 | fontsize = 30, 26 | va = 'top', 27 | ha = 'center') 28 | 29 | ax.grid(False) 30 | ax.set_xticks([]) 31 | ax.set_yticks([]) 32 | print(true_angle, plot_angle) -------------------------------------------------------------------------------- /python/speedo-functions.py: -------------------------------------------------------------------------------- 1 | def rotation(theta): 2 | """Construct rotation matrix for angle theta in radians.""" 3 | rotation_matrix = np.matrix([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]]) 4 | return rotation_matrix 5 | 6 | 7 | def speedometer(percentile, ax = None, fsize = 20): 8 | """Constructor speedometer plot along the half circle from 0 to pi.""" 9 | # Make half circle from 0 to pi 10 | angles = np.linspace(0, np.pi, 100) 11 | x = np.cos(angles) 12 | y = np.sin(angles) 13 | if ax is None: 14 | ax = plt.gca() 15 | ax.set_aspect('equal') 16 | ax.axis('off') 17 | ax.plot(x,y, linewidth = 3, color = 'black') 18 | 19 | # Calculate angle for percentile 20 | theta = -np.pi * (percentile/100) 21 | 22 | # Draw hand initialized at 180 degrees 23 | length = 0.8 24 | base = np.matrix([0,0]) 25 | tip = np.matrix([-length,0]) 26 | points = [base,tip] 27 | new_points = [rotation(theta)*p.T for p in points] 28 | x = [np.array(p).flatten()[0] for p in new_points] 29 | y = [np.array(p).flatten()[1] for p in new_points] 30 | 31 | ax.plot(x,y, color = 'darkred', 32 | linewidth = 4, solid_capstyle = 'round') 33 | ax.plot(0,0, marker = 'o', 34 | color = 'darkred', markersize = 10) 35 | 36 | # Mark every 10pp 37 | ticks = np.linspace(0,180, 11) 38 | for angle in ticks: #np.arange(0,181, step = step): 39 | radians = math.radians(angle) 40 | 41 | # tick line 42 | x1, y1 = np.cos(radians), np.sin(radians) 43 | x2, y2 = .95*x1, .95*y1 44 | ax.plot([x1,x2], [y1,y2], 45 | color = 'black', zorder = -1) 46 | 47 | # place text label by tick 48 | raw = 180 - angle 49 | ptile = raw/180 * 100 50 | s = "{:.0f}%".format(ptile) 51 | ax.text(.9*x2, .9*y2, s, 52 | ha = 'center', zorder = -1) 53 | 54 | # ghost in the value bc why not 55 | # edit to include raw value or whatever desired 56 | ax.text(0.04, .15, '{:.0f}%'.format(percentile), 57 | va= 'bottom', 58 | ha = 'center', 59 | size = fsize, 60 | alpha = 0.2) -------------------------------------------------------------------------------- /python/speedometer.py: -------------------------------------------------------------------------------- 1 | speedometer(100, fsize = 65) -------------------------------------------------------------------------------- /python/speedometers.py: -------------------------------------------------------------------------------- 1 | fig, axx = plt.subplots(1,3, figsize = (10,3)) 2 | 3 | for ax, p in zip(axx, [20, 50, 80]): 4 | speedometer(p, ax = ax, fsize = 33) -------------------------------------------------------------------------------- /python/spine-mod-ex.py: -------------------------------------------------------------------------------- 1 | x = np.linspace(0,2*np.pi,100) 2 | plt.plot(x, np.sin(x)) 3 | plt.plot(x, np.cos(x)) 4 | plt.title('Spine Mods') 5 | 6 | %run ../../python/spine-mod.py -------------------------------------------------------------------------------- /python/spine-mod.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | 3 | plt.gca().spines['left'].set_position('zero') 4 | plt.gca().spines['bottom'].set_position('zero') 5 | 6 | plt.gca().spines['top'].set_visible(False) 7 | plt.gca().spines['right'].set_visible(False) -------------------------------------------------------------------------------- /python/spine-mod2-ex.py: -------------------------------------------------------------------------------- 1 | x = np.linspace(0, 2*np.pi, 100) 2 | fig, ax = plt.figure(), plt.axes() 3 | ax.plot(x, np.sin(x)) 4 | ax.plot(x, np.cos(x)) 5 | ax.set_title('Spine Mods') 6 | %run -i ../../python/spine-mod2.py -------------------------------------------------------------------------------- /python/spine-mod2.py: -------------------------------------------------------------------------------- 1 | ax.spines['left'].set_position('zero') 2 | ax.spines['bottom'].set_position('zero') 3 | ax.spines['top'].set_visible(False) 4 | ax.spines['right'].set_visible(False) -------------------------------------------------------------------------------- /python/spine-mod3.py: -------------------------------------------------------------------------------- 1 | for ax in fig.axes: 2 | ax.spines['left'].set_position('zero') 3 | ax.spines['bottom'].set_position('zero') 4 | ax.spines['top'].set_visible(False) 5 | ax.spines['right'].set_visible(False) -------------------------------------------------------------------------------- /python/spine-vis.py: -------------------------------------------------------------------------------- 1 | for spine in 'bottom', 'top', 'left', 'right': 2 | fig, ax = plt.figure(), plt.axes() 3 | ax.set_title("No " + spine.title() + " Spine") 4 | ax.spines[spine].set_visible(False) 5 | plt.show() 6 | -------------------------------------------------------------------------------- /python/style-changes.py: -------------------------------------------------------------------------------- 1 | import matplotlib as mpl 2 | mpl.rcParams['axes.spines.left'] = True 3 | mpl.rcParams['axes.spines.right'] = False 4 | mpl.rcParams['axes.spines.bottom'] = True 5 | mpl.rcParams['axes.spines.top'] = False 6 | mpl.rcParams['axes.titlesize'] = 25 7 | mpl.rcParams['xtick.labelsize'] = 'large' 8 | mpl.rcParams['font.family'] = 'Times' -------------------------------------------------------------------------------- /python/style-manual.py: -------------------------------------------------------------------------------- 1 | x = np.linspace(0,1,2) 2 | 3 | fig1, ax = plt.figure(), plt.axes() 4 | ax.plot(x, x) 5 | ax.grid(True) 6 | ax.spines['top'].set_visible(False) 7 | ax.spines['right'].set_visible(False) 8 | plt.show() 9 | 10 | fig2, ax = plt.figure(), plt.axes() 11 | ax.plot(x, 1 - x) 12 | ax.grid(True) 13 | ax.spines['top'].set_visible(False) 14 | ax.spines['right'].set_visible(False) 15 | plt.show() -------------------------------------------------------------------------------- /python/style-rc.py: -------------------------------------------------------------------------------- 1 | # Use rcParams 2 | mpl.rcParams['axes.grid'] = True 3 | mpl.rcParams['axes.spines.top'] = False 4 | mpl.rcParams['axes.spines.right'] = False 5 | 6 | x = np.linspace(0,1,2) 7 | plt.plot(x,x) 8 | plt.savefig("style1.pdf") 9 | plt.show() 10 | 11 | plt.plot(x, 1-x) 12 | plt.savefig("style2.pdf") 13 | plt.show() -------------------------------------------------------------------------------- /python/subplots-1d-vert.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.subplots(2,1) 2 | ax[0].set_title("1D Array Index 0") 3 | ax[1].set_title("1D Array Index 1") 4 | plt.tight_layout() -------------------------------------------------------------------------------- /python/subplots-1d.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.subplots(1,2) 2 | ax[0].set_title("1D Array Index 0") 3 | ax[1].set_title("1D Array Index 1") 4 | plt.tight_layout() -------------------------------------------------------------------------------- /python/subplots-2d.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.subplots(2,2) 2 | ax[0][0].set_title("0, 0") 3 | ax[0][1].set_title("0, 1") 4 | ax[1][0].set_title("1, 0") 5 | ax[1][1].set_title("1, 1") 6 | plt.tight_layout() -------------------------------------------------------------------------------- /python/subtitle.py: -------------------------------------------------------------------------------- 1 | x = np.linspace(0,2,2) 2 | fig, ax = plt.figure(), plt.axes() 3 | ax.plot(x,x) 4 | 5 | ax.set_title("Title", 6 | weight = 'bold', 7 | color = 'purple', 8 | pad = 24) 9 | 10 | ax.text(0.5, 1.05, 11 | s = '(Parenthetical)', 12 | transform = ax.transAxes, 13 | ha = 'center') -------------------------------------------------------------------------------- /python/suptitle.py: -------------------------------------------------------------------------------- 1 | fig = plt.figure(facecolor = 'lightgray') 2 | 3 | for i in range(1,7): 4 | ax = fig.add_subplot(2,3,i) 5 | ax.text(0.5, 0.5, 6 | s = str(i), 7 | ha = 'center', 8 | va = 'center', 9 | fontsize = 30) 10 | ax.set_yticks([]) 11 | ax.set_xticks([]) 12 | ax.set_title("Title", 13 | fontsize = 12, 14 | fontname = 'Times New Roman') 15 | 16 | fig.suptitle('SupTitle') 17 | fig.tight_layout(rect = (0,0,1,1)) # no change -------------------------------------------------------------------------------- /python/tall-ballers.py: -------------------------------------------------------------------------------- 1 | heights = pd.Series( {'Shaq': 7 + (1/12), 2 | 'Yao Ming': 7.5, 3 | 'Delle Donne': 6 + (5/12)}) 4 | 5 | fig, ax = plt.figure(figsize = (4,7)), plt.axes() 6 | 7 | heights.plot.bar(ax = ax, 8 | color = ['#FDB927', '#BA0C2F', '#0C2340'], 9 | edgecolor = ['#552583', '#041E42', '#C8102E'], 10 | linewidth = 2) 11 | # https://teamcolorcodes.com/ 12 | # LA Lakers and Houston Rockets and DC Mystics 13 | 14 | # Get rid of ticks on x-axis, rotate text 15 | ax.xaxis.set_tick_params(length = 0, which = 'major', 16 | rotation = 0) 17 | 18 | ylim0, ylim1 = 0,8 19 | ax.set_ylim([ylim0, ylim1]) 20 | 21 | ax.set_yticks(range(ylim0, ylim1+1)) 22 | #ax.yaxis.set_major_locator(MultipleLocator(1)) 23 | 24 | ax.yaxis.set_minor_locator(MultipleLocator(1/12)) 25 | ax.yaxis.set_tick_params(length = 1, which = 'minor') 26 | ax.yaxis.set_tick_params(length = 2, which = 'major') 27 | 28 | ax.set_ylabel("Height (feet)") 29 | ax.set_title("Pro Basketball Players are Tall") -------------------------------------------------------------------------------- /python/text-align.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | 3 | x1, x2, y = 0.49, 0.51, 0.5 4 | ax.scatter([x1,x2], [y,y]) 5 | 6 | va_options = ['top', 'bottom', 'center'] 7 | ha_options = ['left', 'right', 'center'] 8 | 9 | counter = 0 # for color cycling 10 | for va in va_options: 11 | for ha in ha_options: 12 | # first letter of each option 13 | label = va[0] + "-" + ha[0] 14 | 15 | # assign label to point 16 | x = x1 17 | if 'c' in label: 18 | x = x2 19 | 20 | ax.text(x, y, 21 | label, 22 | va = va, 23 | ha = ha, 24 | fontsize = 20, 25 | color = 'C'+str(counter)) 26 | counter += 1 27 | 28 | ax.axis('off') -------------------------------------------------------------------------------- /python/text-default-align.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | x, y = 0.5, 0.5 3 | ax.scatter([x], [y]) 4 | ax.text(x,y, 'text', fontsize = 20) 5 | ax.axis('off') -------------------------------------------------------------------------------- /python/text-formatting.py: -------------------------------------------------------------------------------- 1 | for i in range(3): 2 | fig, ax = plt.figure(), plt.axes() 3 | label = '{:0>4}'.format(i) 4 | ax.set_title("Plot " + label, 5 | fontname = 'Courier New', 6 | weight = 'bold', 7 | fontsize = 30) 8 | fig.tight_layout() 9 | fig.savefig(label + ".pdf") 10 | plt.show() -------------------------------------------------------------------------------- /python/text-methods.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | 3 | ax.set_xlim([0,10]) 4 | ax.set_ylim([0,10]) 5 | 6 | fig.text(0.5, 0.5, 'Figure Text') 7 | ax.text(0.5, 0.5, 'Axes Text') -------------------------------------------------------------------------------- /python/text-rotation05.py: -------------------------------------------------------------------------------- 1 | x = np.linspace(0,10) 2 | fig, ax = plt.figure(), plt.axes() 3 | ax.plot(x,x) 4 | ax.set_aspect(0.5) 5 | ax.text(5,5, 6 | 'Wello, horld!', 7 | rotation = 45) -------------------------------------------------------------------------------- /python/text-rotation1.py: -------------------------------------------------------------------------------- 1 | x = np.linspace(0,10) 2 | fig, ax = plt.figure(), plt.axes() 3 | ax.plot(x,x) 4 | ax.set_aspect(1) 5 | ax.text(5,5, 6 | 'Hello, world!', 7 | rotation = 45) -------------------------------------------------------------------------------- /python/text-rotation2.py: -------------------------------------------------------------------------------- 1 | x = np.linspace(0,10) 2 | fig, ax = plt.figure(), plt.axes() 3 | ax.plot(x,x) 4 | ax.set_aspect(2) 5 | ax.text(5,5, 6 | 'Hello, world!', 7 | rotation = 45) -------------------------------------------------------------------------------- /python/tform-matrix.py: -------------------------------------------------------------------------------- 1 | theta = np.pi / 4 2 | rotation_matrix = np.matrix([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]]) 3 | 4 | x_scale = 0.5 5 | x_stretch = np.matrix([[x_scale, 0], [0, 1]]) 6 | 7 | y_scale = 2 8 | y_stretch = np.matrix([[1, 0], [0, y_scale]]) 9 | 10 | transformation = rotation_matrix * y_stretch * x_stretch -------------------------------------------------------------------------------- /python/thick-spines.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes(facecolor = 'lightyellow') 2 | ax.set_title("Thick Spines") 3 | for spine in 'bottom', 'top', 'left', 'right': 4 | ax.spines[spine].set_color('black') 5 | ax.spines[spine].set_linewidth(4) 6 | ax.set_xlim(0,1) 7 | ax.set_ylim(0,1) -------------------------------------------------------------------------------- /python/tick-right.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | x = np.arange(10, 30, 1) 3 | y = np.random.normal(size = len(x)) 4 | ax.plot(x,y) 5 | 6 | # set what ticks are shown 7 | ax.xaxis.set_ticks(x) 8 | 9 | # move the ticks 10 | ax.yaxis.tick_right() 11 | ax.xaxis.set_ticks_position('top') 12 | 13 | ax.set_title("Some Plot") -------------------------------------------------------------------------------- /python/ticks1.py: -------------------------------------------------------------------------------- 1 | x = np.linspace(0, np.pi * 2, 100) 2 | 3 | fig, ax = plt.figure(), plt.axes() 4 | ax.plot(x, np.sin(x)) 5 | 6 | # Y axis 7 | ax.set_yticks( [-0.5, 0, 0.5] ) 8 | ax.set_yticklabels( [r"$-\frac{1}{2}$", 0, r"$\frac{1}{2}$"] ) 9 | 10 | # X axis 11 | ax.xaxis.set_ticks([np.pi]) 12 | ax.xaxis.set_ticklabels([r"$\pi$"]) -------------------------------------------------------------------------------- /python/tiny-style-ex.py: -------------------------------------------------------------------------------- 1 | plt.style.use('../../stylelib/tiny-style.mplstyle') 2 | 3 | fig, ax = plt.figure(), plt.axes() 4 | x = np.linspace(0,2*np.pi,100) 5 | plt.plot(x, np.sin(x)) 6 | plt.plot(x, np.cos(x)) 7 | plt.title('Hello') 8 | 9 | # Inspect the updated rcParams 10 | #print(mpl.rcParams) -------------------------------------------------------------------------------- /python/title-loc.py: -------------------------------------------------------------------------------- 1 | x = np.linspace(0,2,2) 2 | fig, ax = plt.figure(), plt.axes() 3 | 4 | ax.plot(x,x) 5 | ax.set_title("Left Title", 6 | loc = 'left') 7 | ax.set_title("Right Title", 8 | loc = 'right') 9 | ax.set_title("I won't be long for this world.", 10 | loc = 'center') 11 | 12 | # This only overwrites the center title above 13 | ax.set_title("Center Title") -------------------------------------------------------------------------------- /python/title-pad.py: -------------------------------------------------------------------------------- 1 | x = np.linspace(0,2,2) 2 | fig, ax = plt.figure(), plt.axes() 3 | 4 | ax.plot(x,x) 5 | ax.set_title("Title\n(with Padding)", 6 | fontsize = 'xx-large', 7 | weight = 'bold', 8 | color = 'purple', 9 | loc = 'left', 10 | pad = 10) -------------------------------------------------------------------------------- /python/tony-hawk.py: -------------------------------------------------------------------------------- 1 | thetas = np.linspace(0,2*np.pi,8)[0:-1] 2 | fig = plt.figure(figsize = (12,3)) 3 | 4 | # Set radius for skateboard wheels 5 | radius = 0.1 6 | 7 | # Make individual subplots 8 | for key, theta in enumerate(thetas): 9 | rotation_matrix = np.matrix([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]]) 10 | 11 | # Create panel for one frame 12 | ax = fig.add_subplot(1, len(thetas), key+1) 13 | ax.set_aspect('equal') 14 | 15 | # Plot the loop itself 16 | angles = np.linspace(0, 2*np.pi, 100) 17 | x = np.cos(angles) 18 | y = np.sin(angles) 19 | ax.plot(x,y) 20 | 21 | # Make skateboard wheels at bottom of the ramp 22 | # and then rotate them counter-clockwise according to theta 23 | centers = list() 24 | for ang in 1.5*np.pi, 1.6*np.pi: 25 | center = (1-radius)*np.cos(ang), (1-radius)*np.sin(ang) 26 | 27 | # rotate 28 | point = np.matrix(center).T 29 | rotated_point = rotation_matrix*point 30 | rotated_point = np.array(rotated_point).flatten() 31 | centers.append(rotated_point) 32 | 33 | # make wheel around new center 34 | wheel_x = radius*x + rotated_point[0] 35 | wheel_y = radius*y + rotated_point[1] 36 | 37 | ax.plot(wheel_x, wheel_y) 38 | 39 | # connect the two wheel centers 40 | c1, c2 = centers 41 | ax.plot([c1[0],c2[0]], [c1[1],c2[1]]) 42 | 43 | ax.axis('off') 44 | 45 | xlim = ax.get_xlim() 46 | ax.plot(xlim, [-1,-1], 47 | color = 'C0', 48 | zorder = -1) -------------------------------------------------------------------------------- /python/trivial-sub.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.subplots() 2 | ax.set_title("Simplest Grid Possible") -------------------------------------------------------------------------------- /python/union.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | ax.set_aspect(1) 3 | ax.set_xlim(-1.6,1.6) 4 | ax.set_ylim(-1.1,1.4) 5 | ax.axis('off') 6 | 7 | # Add circles with color fill 8 | left_circle = plt.Circle((-0.5, 0), 1, 9 | edgecolor = 'black', 10 | facecolor = 'gray', 11 | linewidth = 2) 12 | left_circle_helper = plt.Circle((-0.5, 0), 1, 13 | edgecolor = 'black', 14 | facecolor = (1, 1, 1, 0), 15 | linewidth = 2) 16 | right_circle = plt.Circle((0.5, 0), 1, 17 | edgecolor = 'black', 18 | facecolor = 'gray', 19 | linewidth = 2) 20 | ax.add_artist(left_circle) 21 | ax.add_artist(right_circle) 22 | ax.add_artist(left_circle_helper) 23 | 24 | # Label 25 | ax.text(0, 1.05, 26 | s = r"$A \cup B$", 27 | va = 'bottom', 28 | ha = 'center', 29 | size = 30) -------------------------------------------------------------------------------- /python/unit-circle-shift.py: -------------------------------------------------------------------------------- 1 | angles = np.linspace(0, 2*np.pi, 100) 2 | 3 | fig, ax = plt.figure(), plt.axes() 4 | ax.set_aspect('equal') 5 | 6 | # Unit Circle 7 | x = np.cos(angles) 8 | y = np.sin(angles) 9 | ax.plot(x, y, color = 'gray', linewidth = 1) 10 | 11 | # Shifted 12 | new_radius = 0.5 13 | new_center = np.cos(np.pi/4)/2, np.sin(np.pi/4)/2 14 | shift_x = new_radius*x + new_center[0] 15 | shift_y = new_radius*y + new_center[1] 16 | ax.plot(shift_x, shift_y, linewidth = 2) 17 | 18 | %run ../../python/spine-mod.py 19 | 20 | ax.set_xticks([-1, 1]) 21 | ax.set_yticks([-1, 0, 1]) -------------------------------------------------------------------------------- /python/unit-circle.py: -------------------------------------------------------------------------------- 1 | angles = np.linspace(0, 2*np.pi, 101) 2 | x = np.cos(angles) 3 | y = np.sin(angles) 4 | 5 | fig, ax = plt.figure(figsize = (5,5)), plt.axes() 6 | ax.set_aspect('equal') 7 | 8 | # Make circle 9 | ax.plot(x,y) 10 | 11 | # Plot example right triangle 12 | angle = np.pi/3 13 | 14 | # make hypotenuse 15 | ax.plot([0,np.cos(angle)], [0,np.sin(angle)], 16 | linestyle = 'dashed', color ='gray', linewidth = 2)# 17 | 18 | # mark point on circle 19 | ax.plot([np.cos(angle)], [np.sin(angle)], 20 | marker = 'o', color ='gray', markersize = 11) 21 | 22 | # dashed lines for opposite and adjacent 23 | ax.plot([0,np.cos(angle)], [0,0], 24 | linestyle = 'dashed', color ='gray', linewidth = 2) 25 | ax.plot([np.cos(angle),np.cos(angle)], [0,np.sin(angle)], 26 | linestyle = 'dashed', color ='gray', linewidth = 2) 27 | 28 | # Triangle side lengths 29 | fontsize = 14 30 | ax.text(0.5*np.cos(angle) - .02, 0.5*np.sin(angle)+.02, 31 | '1', rotation = math.degrees(angle), ha = 'center', va = 'bottom', size = fontsize) 32 | ax.text(0.5*np.cos(angle), -.02, r"$\cos(\theta)$", 33 | rotation = 0, ha = 'center', va = 'top', size = fontsize) 34 | ax.text(np.cos(angle) + .02, 0.5*np.sin(angle), r"$\sin(\theta)$", 35 | rotation = 0, ha = 'left', va = 'center', size = fontsize) 36 | 37 | 38 | # make small arc and mark angle 39 | x = np.cos(angles[angles<= angle]) 40 | y = np.sin(angles[angles<= angle]) 41 | ax.plot(0.2*x,0.2*y, color = 'black') 42 | ax.text(0.2*np.cos(np.pi/10), 0.2*np.sin(np.pi/10), 43 | r" $\theta$", size = 14) 44 | 45 | # clean appearance 46 | %run ../../python/spine-mod.py 47 | ax.set_xticks([-1, 1]) 48 | ax.set_yticks([-1, 1]) -------------------------------------------------------------------------------- /python/violin-bar.py: -------------------------------------------------------------------------------- 1 | violin_practice = {'Monday': 0, 2 | 'Tuesday': 20, 3 | 'Wednesday': 10, 4 | 'Thursday': 0, 5 | 'Friday': 40, 6 | 'Saturday': 30, 7 | 'Sunday': 0} 8 | 9 | pd.Series(violin_practice).plot.bar() 10 | plt.axhline(30) 11 | plt.ylabel('Minutes of Practice') 12 | plt.text(0, 30, 'Goal', color = 'C0') 13 | plt.title('Violin Practice') -------------------------------------------------------------------------------- /python/violin-cal.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(figsize = (8,5)), plt.axes() 2 | spacing_scale = 2.5 3 | 4 | for idx, day in enumerate(violin_practice): 5 | hit_target = violin_practice[day] >= 30 6 | 7 | facecolor = 'black' if hit_target else 'white' 8 | c = plt.Circle((idx*spacing_scale, 1), 9 | radius = .4, 10 | facecolor = facecolor, 11 | edgecolor = 'black') 12 | ax.add_artist(c) 13 | ax.text(idx*spacing_scale, 0, 14 | s = day, 15 | ha = 'center', 16 | va = 'center') 17 | 18 | # Eliminate Clutter 19 | ax.set_aspect('equal') 20 | ax.axis('off') 21 | 22 | # Set plot window 23 | ax.set_xlim([-1, 6*spacing_scale+1]) 24 | ax.set_ylim([0, 2]) -------------------------------------------------------------------------------- /python/violin-streak.py: -------------------------------------------------------------------------------- 1 | violin_practice = {'Monday': 30, 2 | 'Tuesday': 0, 3 | 'Wednesday': 30, 4 | 'Thursday': 30, 5 | 'Friday': 40, 6 | 'Saturday': 0, 7 | 'Sunday': 60} 8 | 9 | fig, ax = plt.figure(figsize = (8,5)), plt.axes() 10 | spacing_scale = 2.5 11 | 12 | streak = 0 13 | for idx, day in enumerate(violin_practice): 14 | 15 | hit_target = violin_practice[day] >= 30 16 | streak += 1*hit_target 17 | streak = streak if hit_target else 0 18 | 19 | facecolor = 'black' if hit_target else 'white' 20 | edgecolor = 'yellow' if hit_target else 'black' 21 | c = plt.Circle((idx*spacing_scale,1), 22 | radius = .4, 23 | facecolor = facecolor, 24 | edgecolor = edgecolor, 25 | linewidth = 0.5 + streak) 26 | ax.add_artist(c) 27 | ax.text(idx*spacing_scale, 0, 28 | s = day, 29 | ha = 'center', 30 | va = 'center') 31 | 32 | # Eliminate Clutter 33 | ax.set_aspect('equal') 34 | ax.axis('off') 35 | 36 | # Set plot window 37 | ax.set_xlim([-1, 6*spacing_scale+1]) 38 | ax.set_ylim([0, 2]) -------------------------------------------------------------------------------- /python/window-extent.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | 3 | center_text = ax.text(0.5, 0.5, 4 | 'centered text', 5 | ha = 'center') 6 | 7 | fig.canvas.draw() 8 | box = center_text.get_window_extent() 9 | data_box = ax.transData.inverted().transform(box) 10 | 11 | # left limit 12 | ax.axvline(data_box[0][0], 13 | color = 'green', 14 | linestyle = 'dashed') 15 | 16 | # right limit 17 | ax.axvline(data_box[1][0], 18 | color = 'black') -------------------------------------------------------------------------------- /python/y-grid-false.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | 3 | x = np.linspace(0, 10, 100) 4 | y = 10 + .2*x 5 | points = y + np.random.normal(size = len(x)) 6 | ax.scatter(x,points) 7 | 8 | ax.set_ylim(0,30) 9 | ax.set_xticks([]) -------------------------------------------------------------------------------- /python/y-grid-true.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | 3 | x = np.linspace(0,10, 100) 4 | y = 10 + .2*x 5 | points = y + np.random.normal(size = len(x)) 6 | ax.scatter(x,points) 7 | 8 | ax.set_ylim(0,30) 9 | ax.set_xticks([]) 10 | 11 | # Add grid and line of best fit 12 | ax.yaxis.grid(True) 13 | ax.plot(x, y, color = 'black') -------------------------------------------------------------------------------- /python/yes-axis.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | ax.set_title("Where did everyone go?") -------------------------------------------------------------------------------- /python/zero-spines.py: -------------------------------------------------------------------------------- 1 | fig, ax = plt.figure(), plt.axes() 2 | ax.set_title("Zero Spines") 3 | ax.plot([-1,1], [-1,1]) 4 | for spine in 'top', 'right': 5 | ax.spines[spine].set_visible(False) 6 | for spine in 'bottom', 'left': 7 | ax.spines[spine].set_position('zero') -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | matplotlib 2 | nbformat 3 | numpy 4 | pandas 5 | pillow 6 | scikit-learn 7 | scipy 8 | statsmodels 9 | ternary 10 | -------------------------------------------------------------------------------- /stylelib/nyt-helper.mplstyle: -------------------------------------------------------------------------------- 1 | axes.linewidth: 2 2 | axes.facecolor: (.94, .94, .96) 3 | axes.grid.axis: y 4 | axes.grid: True 5 | grid.color: white 6 | grid.linewidth: 2 7 | axes.spines.bottom: True 8 | axes.spines.top: False 9 | axes.spines.left: False 10 | axes.spines.right: False 11 | axes.edgecolor: darkgray 12 | xtick.bottom: False 13 | xtick.top: False 14 | ytick.left: False 15 | xtick.labeltop: True 16 | xtick.labelbottom : False 17 | ytick.labelleft: False 18 | xtick.color: (.3,.3,.3) 19 | text.color: (.3,.3,.3) 20 | font.size: 12 21 | lines.marker: o 22 | lines.markersize: 8 23 | lines.linewidth: 3 24 | axes.titlesize: 18 25 | axes.titleweight: bold 26 | axes.formatter.useoffset: False 27 | -------------------------------------------------------------------------------- /stylelib/tiny-style.mplstyle: -------------------------------------------------------------------------------- 1 | axes.spines.left : True 2 | axes.spines.right : False 3 | axes.spines.bottom : True 4 | axes.spines.top : False 5 | xtick.labelsize : large 6 | font.family : Times 7 | -------------------------------------------------------------------------------- /tex/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/tex/.DS_Store -------------------------------------------------------------------------------- /tex/codeTOC.tex: -------------------------------------------------------------------------------- 1 | %\lstlistoflistings 2 | %\bigskip 3 | 4 | \noindent All code and data files are available on the book's \link{https://github.com/alexanderthclark/Matplotlib-for-Storytellers}{GitHub repository}. Note I exclude imports from the Python files in the main text. The imports below should cover the entire text. All of these should be included if you installed Anaconda, except for the ternary library, which I comment out below. When saving figures, I also sometimes run \code{plt.tight_layout()}, which is not always included in the Python files. See \texttt{Prose-Figure-Dev.ipynb}, \texttt{Math-Interlude-Figure-Dev.iypnb}, \texttt{Special-Figure-Dev.iypnb}, and \texttt{Poetry-Figure-Dev.iypnb} which contain the complete code for every figure. 5 | 6 | 7 | \pyfile{imports.py} 8 | -------------------------------------------------------------------------------- /tex/copyright.tex: -------------------------------------------------------------------------------- 1 | \begin{figure} 2 | \centering 3 | \includegraphics[width = .3\textwidth]{Images/by-nc-sa.png} 4 | %\caption{Caption} 5 | %\label{fig:my_label} 6 | \end{figure} 7 | 8 | \noindent This text is released under the \link{https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en}{Creative Commons Attribute-NonCommercial-ShareAlike 4.0 International} License. 9 | 10 | \smallskip 11 | \noindent The code is released under the MIT license. -------------------------------------------------------------------------------- /tex/customcolors.sty: -------------------------------------------------------------------------------- 1 | 2 | % Code colors for listings 3 | \definecolor{codegreen}{rgb}{0,0.6,0} 4 | \definecolor{codegray}{rgb}{0.5,0.5,0.5} 5 | \definecolor{codepurple}{rgb}{0.58,0,0.82} 6 | \definecolor{backcolour}{rgb}{0.95,0.95,0.92} 7 | 8 | % Colors for the hyperref package 9 | \definecolor{urlcolor}{rgb}{0,.145,.698} 10 | \definecolor{linkcolor}{rgb}{.71,0.21,0.01} 11 | \definecolor{citecolor}{rgb}{.12,.54,.11} 12 | 13 | % ANSI colors 14 | \definecolor{ansi-black}{HTML}{3E424D} 15 | \definecolor{ansi-black-intense}{HTML}{282C36} 16 | \definecolor{ansi-red}{HTML}{E75C58} 17 | \definecolor{ansi-red-intense}{HTML}{B22B31} 18 | \definecolor{ansi-green}{HTML}{00A250} 19 | \definecolor{ansi-green-intense}{HTML}{007427} 20 | \definecolor{ansi-yellow}{HTML}{DDB62B} 21 | \definecolor{ansi-yellow-intense}{HTML}{B27D12} 22 | \definecolor{ansi-blue}{HTML}{208FFB} 23 | \definecolor{ansi-blue-intense}{HTML}{0065CA} 24 | \definecolor{ansi-magenta}{HTML}{D160C4} 25 | \definecolor{ansi-magenta-intense}{HTML}{A03196} 26 | \definecolor{ansi-cyan}{HTML}{60C6C8} 27 | \definecolor{ansi-cyan-intense}{HTML}{258F8F} 28 | \definecolor{ansi-white}{HTML}{C5C1B4} 29 | \definecolor{ansi-white-intense}{HTML}{A1A6B2} 30 | \definecolor{ansi-default-inverse-fg}{HTML}{FFFFFF} 31 | \definecolor{ansi-default-inverse-bg}{HTML}{000000} -------------------------------------------------------------------------------- /tex/ghostcites.tex: -------------------------------------------------------------------------------- 1 | \nocite{knaflic2015storytelling} 2 | \nocite{schwabish2021better} 3 | \nocite{schwabish2014economist} 4 | 5 | \nocite{vanderplas2016python} 6 | \nocite{Turrell2021} 7 | 8 | \nocite{orwell2013politics} 9 | %\nocite{gowers1988complete} 10 | \nocite{borg2018applied} 11 | 12 | \nocite{pythonternary} 13 | -------------------------------------------------------------------------------- /tex/mpl-tex-searcher.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "51d117fd", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "# this file just helps me find the references and internal hyperlinks" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 2, 16 | "id": "8159cbc6", 17 | "metadata": {}, 18 | "outputs": [ 19 | { 20 | "name": "stdout", 21 | "output_type": "stream", 22 | "text": [ 23 | "codeTOC.tex \u001b[34mmath\u001b[m\u001b[m \u001b[34mpoetry\u001b[m\u001b[m\r\n", 24 | "copyright.tex mpl-tex-searcher.ipynb \u001b[34mpreface\u001b[m\u001b[m\r\n", 25 | "customcolors.sty mplbib.bib \u001b[34mprose\u001b[m\u001b[m\r\n", 26 | "ghostcites.tex mplstyle.sty \u001b[34mspecial\u001b[m\u001b[m\r\n", 27 | "kdp.cls mycommands.sty\r\n" 28 | ] 29 | } 30 | ], 31 | "source": [ 32 | "!ls" 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": 4, 38 | "id": "a96f90dd", 39 | "metadata": {}, 40 | "outputs": [ 41 | { 42 | "name": "stdout", 43 | "output_type": "stream", 44 | "text": [ 45 | " XX /codeTOC.tex\n", 46 | " XX /copyright.tex\n", 47 | " XX /ghostcites.tex\n", 48 | "math/math.tex\n", 49 | " XX poetry/calendar.tex\n", 50 | " XX poetry/dag.tex\n", 51 | " XX poetry/heat.tex\n", 52 | " XX poetry/poetryArtist.tex\n", 53 | " XX poetry/poetrychap.tex\n", 54 | " XX poetry/speedometer.tex\n", 55 | " XX preface/resourcesinsp.tex\n", 56 | " XX preface/techandprereq.tex\n", 57 | " XX preface/textorg.tex\n", 58 | " XX preface/whympl.tex\n", 59 | " XX preface/writingorwell.tex\n", 60 | " XX prose/colors.tex\n", 61 | " XX prose/dates.tex\n", 62 | " XX prose/elements.tex\n", 63 | " XX prose/multi.tex\n", 64 | " XX prose/oop.tex\n", 65 | " XX prose/styconfig.tex\n", 66 | " XX prose/ticks.tex\n", 67 | "prose/titles.tex\n", 68 | " XX special/MDS.tex\n", 69 | " XX special/stats.tex\n", 70 | " XX special/ternary.tex\n" 71 | ] 72 | } 73 | ], 74 | "source": [ 75 | "string1, string2 = r'{chapter:colors}', r'00asdfhasdf00000'\n", 76 | "\n", 77 | "for d in ['', 'math', 'poetry', 'preface', 'prose', 'special']:\n", 78 | " \n", 79 | " files = !ls $d\n", 80 | " files = [x for x in files if x.endswith(\".tex\")]\n", 81 | " for f in files:\n", 82 | " \n", 83 | " e = d + '/' if d else d\n", 84 | " with open(e + f) as tf:\n", 85 | " doc = tf.read()\n", 86 | " \n", 87 | " if (string1 in doc) or (string2 in doc):\n", 88 | " print(e + f)\n", 89 | " else:\n", 90 | " print(' XX ' + d + '/' + f)\n" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": null, 96 | "id": "21c79e15", 97 | "metadata": {}, 98 | "outputs": [], 99 | "source": [] 100 | } 101 | ], 102 | "metadata": { 103 | "kernelspec": { 104 | "display_name": "Python 3 (ipykernel)", 105 | "language": "python", 106 | "name": "python3" 107 | }, 108 | "language_info": { 109 | "codemirror_mode": { 110 | "name": "ipython", 111 | "version": 3 112 | }, 113 | "file_extension": ".py", 114 | "mimetype": "text/x-python", 115 | "name": "python", 116 | "nbconvert_exporter": "python", 117 | "pygments_lexer": "ipython3", 118 | "version": "3.9.13" 119 | } 120 | }, 121 | "nbformat": 4, 122 | "nbformat_minor": 5 123 | } 124 | -------------------------------------------------------------------------------- /tex/mycommands.sty: -------------------------------------------------------------------------------- 1 | % inline code 2 | \newcommand{\code}[1]{\lstinline[language = Python]{#1}} 3 | 4 | % color links blue 5 | \newcommand{\link}[2]{\textcolor{blue}{\href{#1}{#2}}} 6 | 7 | % for referencing a py file directly 8 | 9 | \newcommand{\gitlink}[1]{\link{https://github.com/alexanderthclark/Matplotlib-for-Storytellers/blob/main/python/#1}{#1}} 10 | 11 | \newcommand{\pyfilenolink}[1]{ 12 | \lstinputlisting[title = \hspace{\textwidth} \scalebox{.67}{\texttt{#1}}]{python/#1}} 13 | 14 | \newcommand{\pyfile}[1]{ 15 | \lstinputlisting[title = \hspace{\textwidth} \scalebox{.67}{\texttt{\gitlink{#1}}}]{python/#1}} 16 | 17 | \newcommand{\pyfiletoc}[1]{ 18 | \lstinputlisting[caption = {[#1]}, title = \hspace{\textwidth} \scalebox{.7}{\texttt{#1}}]{python/#1}} 19 | 20 | \newcommand{\mplstylefile}[1]{ 21 | \lstinputlisting[title = \hspace{\textwidth} \scalebox{.67}{\texttt{\gitlink{#1}}}]{stylelib/#1}} % still uses python formatting 22 | 23 | 24 | %%% for notebook-like tex 25 | % https://tex.stackexchange.com/question/223465/ipython-notebook-cells-with-listings 26 | %\newcommand{\output}[1]{\begin{tcolorbox}[breakable, size=fbox, boxrule=.5pt, pad at break*=1mm, opacityfill=0] 27 | %\prompt{Out}{outcolor}{1}{\boxspacing} 28 | %\begin{Verbatim}[commandchars=\\\{\}] 29 | %[#1] 30 | %\end{Verbatim} 31 | %\end{tcolorbox}} -------------------------------------------------------------------------------- /tex/poetry/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/tex/poetry/.DS_Store -------------------------------------------------------------------------------- /tex/poetry/calendar.tex: -------------------------------------------------------------------------------- 1 | Let's start with a prose bar chart and turn it into poetry. Suppose you have a goal to practice the violin for at least 30 minutes every day and you've tracked your practice time for a whole week. 2 | 3 | \pyfile{violin-bar.py} 4 | 5 | \begin{center} 6 | \includegraphics[width = 0.7\textwidth]{figures/poetryplots/violin-bar.pdf} 7 | \end{center} 8 | 9 | This creates a chart that is perfectly fine. But a poet might say, why futz with all the numbers and obfuscate the essential meaning? We only need to know if we hit the goal of 30 minutes or not. This kind of simplification might be more motivating. There's probably some psychology research that supports this, but we'll proceed without deferring to any such authority because those studies so often fail to replicate. Let's create a simple activity calendar of sorts. 10 | 11 | %intensity to communicate streaks 12 | 13 | \pyfile{violin-cal.py} 14 | 15 | \begin{center} 16 | \includegraphics[width = 0.9\textwidth]{figures/poetryplots/violin-cal.pdf} 17 | \end{center} 18 | 19 | You might have in mind ways to spice up this plot even further. Maybe there should be partial credit given to days some with violin practice, but not at least 30 minutes. Perhaps on those days, the circles can be filled with a light gray. The key here is that we're creating a plot that we might think will be more motivating. 20 | 21 | Apps like Duolingo or Peloton gamify the user experience, and part of that is rewarding activity streaks over consecutive days. Let's try to enhance the plot so that streaks stand out. We'll accomplish this by adding a yellow edge color and increasing its weight as a streak continues. This adds some visual reward for streaks that was not evident in the previous plot. 22 | 23 | \pyfile{violin-streak.py} 24 | 25 | \begin{center} 26 | \includegraphics[width = 0.9\textwidth]{figures/poetryplots/violin-streak.pdf} 27 | \end{center} -------------------------------------------------------------------------------- /tex/poetry/dag.tex: -------------------------------------------------------------------------------- 1 | %\subsection{Directed Graphs} 2 | Directed graphs arise in many settings. For plotting a large graph, like follower-following relationships in a social network, you might be best served making use of packages like networkx and nxviz. In other cases, you might do better working by hand. The \link{https://graphviz.readthedocs.io/en/stable/index.html}{graphviz} library is one possible solution. Here, we'll work directly with matplotlib. One directed graph use case might be in illustrating the directed acyclic graph (or DAG) representing a causal theory. In the directed acyclic graph framework (mostly associated with Judea Pearl's work in causal inference), a directed edge from $X$ to $Y$ means $X$ causes $Y$, at least in part. This lends itself well to plotting. Below we'll make a plot, using \code{plt.Circle()} to draw nodes and and creating edges with \code{ax.annotate()}. 3 | 4 | Here, we create the nodes as circle objects and then draw the edges using \code{ax.annotate()}. Below, the circular nodes are created with the function \code{make_node()}. Then, the directed edge is drawn with \code{directed_edge()}. This doesn't allow for an edge from one node back to itself. 5 | 6 | \pyfile{dag-node.py} 7 | 8 | \pyfile{dag-edge.py} 9 | 10 | The DAG plotted below describes the theory that the persuasiveness of an argument is caused by its logical soundness and the decibel level at which it is communicated. 11 | 12 | \pyfile{dag-argue.py} 13 | 14 | \begin{center} 15 | \includegraphics[width = 0.7\textwidth]{figures/poetryplots/dag-argue.pdf} 16 | \end{center} 17 | -------------------------------------------------------------------------------- /tex/poetry/poetryArtist.tex: -------------------------------------------------------------------------------- 1 | \chapter{Artist Objects} 2 | 3 | Artist objects are the water we've been swimming in this whole time. Everything rendered on a plot is some kind of Artist object. Even the figure and axes objects belong to this base class. Why notice Artist objects now? Because we're leaving the well-worn path of line plots, histograms, and so forth, and some appreciation of our surroundings will help. It will also provide some comfort as you continue to learn more and encounter more technical documentation. -------------------------------------------------------------------------------- /tex/poetry/poetrychap.tex: -------------------------------------------------------------------------------- 1 | \chapter{Poetry} 2 | President George W. Bush is reported to have been fascinated by satellite pictures showing North and South Korea at night. South Korea is covered in bright lights and its communist neighbor, dark, could be mistaken for a collection of dead pixels. The pictures, like any data visualization, communicate and distill a lot of information. Karen Hughes, Bush's former counselor, said that to Bush, the pictures showed ``the light and opportunity that comes with freedom, and the dark that comes with a regime that is oppressive.'' The pictures, like any data visualization, communicate and distill a lot of information. And like an effective novel data visualization, the pictures invite more active interest. 3 | 4 | With prose behind us, we approach that end of the spectrum. \cite{scruton2015poetry} argues that ``poetry is concerned with the truth as a kind of revelation,'' standing apart from the ``aboutness'' of prose. Scruton adds, ``When Keats writes his `Ode to the Nightingale,' he does not describe the bird and its song only: he endows it with value.'' So here we are, trying to endow some data with value through its presentation. 5 | 6 | This is a different kind of task you might take up once you've understood the important insights from your data and you have an editorial perspective. When the Bureau of Labor Statistics reports unemployment numbers, that should not be editorialized---prose line charts and tables will do. But sometimes your audience will benefit from receiving the data pre-chewed or more artfully presented. %Recognizing the importance of this service, Emerson called poets ``liberating gods'' (\cite{emerson2015poet}). 7 | 8 | To that end, this part aims to help you construct interesting charts, mostly with more considered use of Artist objects. This will also help you construct prosaic plots, as you might also use these objects to build plots from scratch if the easier way escapes you. This will be more laborious. Poets do write fewer words than prose writers over their careers. 9 | 10 | % poets are the unacknowledged legislators of the world 11 | % In "The Defence of Poetry" 1821, Shelley claimed that "poets are the unacknowledged legislators of the world". 12 | 13 | %https://www.newsweek.com/north-koreas-kim-jong-il-111871 14 | % During his first trip to Seoul, soon after his Axis of Evil speech in early 2002, Karen Hughes, then Bush's counselor, told reporters that the president was fascinated by satellite pictures of the Korean Peninsula at night, showing bright lights over the South and darkness over the power-starved North. To Bush, the pictures showed "the light and opportunity that comes with freedom, and the dark that comes with a regime that is oppressive," Hughes said. -------------------------------------------------------------------------------- /tex/poetry/speedometer.tex: -------------------------------------------------------------------------------- 1 | There's an allure to control rooms or all the gauges on the dashboard of a vehicle. If you can make your dashboards alluring, your stakeholders will visit them more often. We'll create a simple speedometer-like gauge to add some visual interest to reporting a single percentile value. We'll use what learned about rotating points in Section \ref{subsec:rotations} 2 | The gauge will have values running from 0\% to 100\%, and we'll place these along a half circle. The gauge's hand will point to a particular realized percentile value. We use a rotation matrix to find the correct angle at which to place the hand. 3 | 4 | \pyfile{speedo-functions.py} 5 | 6 | \pyfile{speedometer.py} 7 | 8 | \begin{center} 9 | \includegraphics[width = .75\textwidth]{figures/poetryplots/speedometer.pdf} 10 | \end{center} 11 | 12 | You might prefer to make further modifications to the sizing and spacing depending. Below, we see some crowding with the tick labels. 13 | 14 | \pyfile{speedometers.py} 15 | 16 | \begin{center} 17 | \includegraphics[width = .75\textwidth]{figures/poetryplots/speedometers.pdf} 18 | \end{center} -------------------------------------------------------------------------------- /tex/preface/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/tex/preface/.DS_Store -------------------------------------------------------------------------------- /tex/preface/resourcesinsp.tex: -------------------------------------------------------------------------------- 1 | Before you dive in, you ought to get excited about data visualization. While there is a glaring lack of major museum space devoted to data visualization (I just recall a disappointing exhibit at the Cooper Hewitt), you will find many wonderful displays if you only keep your eyes peeled. 2 | 3 | If you like to listen to people talk about data visualization, I recommend the \link{https://datastori.es}{Data Stories podcast}. 4 | 5 | If you'd like to start by reading one of the pioneers, check out \link{https://www.edwardtufte.com/tufte/}{Edward Tufte}, who continues to write new material. For more explicit or domain-specific guidance than Tufte might provide, see \link{https://www.storytellingwithdata.com/book/downloads}{Storytelling with Data} by Cole Nussbaumer Knaflic or \link{http://cup.columbia.edu/book/better-data-visualizations/9780231193115}{Better Data Visualization} by Jonathan Schwabish. Many of Schwabish's main themes are also communicated more briefly in \cite{schwabish2014economist}. I have limited patience for how-to guides when they edge toward being overly prescriptive (I've never read any books on how to write well either), but I've profited from these titles. They are useful for their treatment of fundamentals like preattentive processing and surfacing more variety in visualizations, helping to inspire a richer repertoire. Knaflic's book is oriented toward business professionals and Schwabish adds his own public policy background. As a result, Knaflic concentrates on what I call prosaic visuals and Schwabish pushes further into the realm of poetry. Schwabish discusses the tradeoffs between standard and nonstandard graphs, noting that novelty can encourage more active processing, providing further justification for using a less accurate graph in select, exploratory cases. 6 | %Media outlets 7 | 8 | Media outlets like the New York Times and Wall Street Journal usually make good use of data visualization. Take appropriate inspiration from these sources and from the \link{https://www.reddit.com/r/dataisbeautiful}{r/DataIsBeautiful} and \link{https://www.reddit.com/r/dataisugly/}{r/DataIsUgly} subreddits. 9 | 10 | The official matplotlib documentation continues to be a great resource, especially with new tutorials and galleries being added since I began work on this book. There is also a good Data Visualization section in \link{https://aeturrell.github.io/coding-for-economists/intro.html}{\emph{Coding for Economists}} by Arthur Turrell. For a more advanced treatment of matplotlib, check out \link{https://github.com/rougier/scientific-visualization-book}{Scientific Visualization: Python + Matplotlib}. 11 | -------------------------------------------------------------------------------- /tex/preface/techandprereq.tex: -------------------------------------------------------------------------------- 1 | I use Python 3.9 and matplotlib 3.7.1. I also make use of Jupyter notebook cell magics. I assume familiarity with basic Python programming, NumPy, pandas, and even matplotlib. In Part \ref{part:prose}, the premise is that you can make a plot, but now you want to polish it. Other parts assume less background knowledge. For those needing to review some Python before approaching this text, I recommend \link{https://jakevdp.github.io/WhirlwindTourOfPython/}{\emph{A Whirlwind Tour of Python}} and \link{https://jakevdp.github.io/PythonDataScienceHandbook/}{\emph{Python Data Science Handbook}}, both by Jake VanderPlas. 2 | 3 | %Because this is \emph{Matplotlib for Haters}, I assume some exposure to matplotlib so that I won't explain the most basic constructions. 4 | %upgraded to 3.71 from 3.5.1 on July 7 2023 -------------------------------------------------------------------------------- /tex/preface/textorg.tex: -------------------------------------------------------------------------------- 1 | Continuing the \hyperref[sec:writing]{parallel to writing}, I have built this text around two main parts: \hyperref[part:prose]{Prose} and \hyperref[part:poetry]{Poetry}, though the distinction between prose and poetry is surely less exact than the division I've created. Prose, or Part \ref{part:prose}, focuses on the fundamentals of customizing plots through the object-oriented interface. This section attempts to be reasonably thorough in breadth while providing only a minimal effective dose in depth. Then, after a mathematical interlude in Part \ref{part:math}, we reach poetry in Part \ref{part:poetry}. There can be no comprehensiveness to this section. I provide a guide to drawing in matplotlib, mostly with various \link{https://matplotlib.org/stable/api/artist_api.html\#artist-class}{artist} objects. The mathematical interlude is there for those who would like to review some trigonometry I use. Then, I introduce two special (for fun) topics in Part \ref{part:topics}, multi-dimensional scaling and ternary plots. 2 | %For those with the time and patience, I do recommend reading through the sections in order. The text isn't structured like a reference book, but you may still treat it as such. 3 | % is this a reference book? it's more expository 4 | 5 | %If you're in a hurry, I recommend reading Chapter \ref{chapter:oop}, then Chapter \ref{chapter:StyleConfig}, and then you can figure out how to skip around or use other resources to fill in the gaps. -------------------------------------------------------------------------------- /tex/preface/whympl.tex: -------------------------------------------------------------------------------- 1 | %These notes are an outgrowth of my general Python for Data Analysis lecture notes, expanding what was covered in under two two-hour lectures to what will take more. 2 | Though a bit aged, matplotlib is the standard in Python. matplotlib is integrated with pandas and Seaborn is based off matplotlib. You might prefer Plotnine if you already know R's ggplot2. You might prefer to leave Python and use D3 if you know javascript. You might prefer Microsoft Excel if you want consultants in your audience to feel at home. 3 | 4 | I recommend matplotlib to anyone who is already committed to working in Python (and with the Python community) and values reproducibility and customizability. By the time we get to Part \ref{part:poetry}, we'll be drawing more than plotting. This allows for more creativity than Excel allows and we'll maintain a reproducible Python-only workflow. -------------------------------------------------------------------------------- /tex/prose/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderthclark/Matplotlib-for-Storytellers/a31e024fbbb8fed36f7d3b906892562b2000ef2b/tex/prose/.DS_Store -------------------------------------------------------------------------------- /tex/prose/colors.tex: -------------------------------------------------------------------------------- 1 | Methods like \code{plot} and \code{text} include a color parameter, which we've already made use of. While you can get pretty far simply using \code{color = 'blue'}, you might also make use of colormaps or set your own colors using hex strings or RGB(A) tuples. 2 | 3 | \section{Colormaps} 4 | 5 | According to the style sheet you are using, there will be some colormap and you will cycle through those colors by default when plotting (but not for text). The colors can be identified by the strings \code{'C0'}, \code{'C1'}, \dots. If, as in the default, your color map has only 10 distinct colors, then the eleventh color \code{'C10'} is valid, but simply refers to \code{'C0'} and the colors cycle from there. You'll notice that with successive plot calls on the same axes, the colors will automatically move through the colormap. This is not the case with text, as is demonstrated in the program below. 6 | 7 | \pyfile{colors.py} 8 | 9 | \begin{center} 10 | \includegraphics[width = 0.7\textwidth]{figures/proseplots/colors.pdf} 11 | \end{center} 12 | 13 | 14 | \section{Red, Green, Blue, Alpha} 15 | 16 | An RGB color is given by three values, specifying the amount of red, green, and blue. In matplotlib, these values are between zero and one (you might also see RGB values between zero and 255 elsewhere). These colors live inside a cube, as a particular color is a triple $(r,g,b) \in [0,1]^3$. 17 | 18 | \begin{center} 19 | \includegraphics[width = .49\textwidth]{figures/proseplots/color-cube.pdf}\includegraphics[width = .49\textwidth]{figures/proseplots/color-cube-back.pdf} 20 | \end{center} 21 | % https://stackoverflow.com/questions/8130823/set-matplotlib-3d-plot-aspect-ratio/19933125 22 | 23 | I like working with RGB tuples because they can be manipulated with mathematical operations. Two colors can easily be averaged or we can create a gradient between two. 24 | 25 | \pyfile{gradient.py} 26 | 27 | \begin{center} 28 | \includegraphics[width=.8\textwidth]{figures/proseplots/gradient.pdf} 29 | \end{center} 30 | 31 | Any color can be made lighter by averaging it with white, $(1,1,1)$, or darker by averaging it with black $(0,0,0)$. We can also find the inverse of an RGB color by simply subtracting that triple from $(1,1,1)$. RGBA tuples are very similar, adding a fourth \emph{a}lpha value for the opacity. 32 | 33 | 34 | With RGB and RGBA colors being so handy, you might want to convert strings like \code{'C0'} into RGB. \code{ColorConverter()} lets us do this, with the \code{to_rgb()} and \code{to_rgba()} methods. Below, we create another color gradient between the default \code{'C0'} blue, to \code{'C1'} orange, and on to light blue \code{'C9'}. 35 | 36 | \pyfile{color-map.py} 37 | 38 | \begin{center} 39 | \includegraphics[width = .8\textwidth]{figures/proseplots/color-map.pdf} 40 | \end{center} 41 | 42 | 43 | 44 | \subsection*{Color Cube Code} 45 | Here is the code for one of the RGB color cubes. 46 | 47 | \pyfile{color-cube.py} -------------------------------------------------------------------------------- /tex/prose/dates.tex: -------------------------------------------------------------------------------- 1 | Matplotlib can handle dates, helping you to create better axis ticks and label formatting. Matplotlib's capabilities are built on the datetime and dateutil modules. 2 | 3 | 4 | \section{Plotting} 5 | Let's import some time series data. Below we use pandas integration and plot from a DataFrame with an index of pandas Timestamp values. Matplotlib recognizes these as dates and handles this reasonably well automatically, though the exact formatting could be improved. 6 | 7 | \pyfile{pd-dates.py} 8 | 9 | \begin{center} 10 | \includegraphics[width = .7\textwidth]{figures/proseplots/pd-dates.pdf} 11 | \end{center} 12 | 13 | Before we try to improve the formatting, see what happens if we try to use the axes plot method. 14 | 15 | \pyfile{ax-dates.py} 16 | 17 | \begin{center} 18 | \includegraphics[width = .7\textwidth]{figures/proseplots/ax-dates.pdf} 19 | \end{center} 20 | 21 | You might find code using \code{plot_date()}, which used to be used in place of \code{plot()}. This is no longer necessary. 22 | 23 | 24 | \subsection{Time Zone Handling} 25 | 26 | %\code{plot_date()} also plots the dates according to a default UTC timezone, sometimes converting dates given in a different timezone. This can be modified with the \code{tz} parameter, but this requires covering 27 | 28 | 29 | For a deeper knowledge, see the \code{datetime.tzinfo} class and the \code{pytz} library. TK 30 | 31 | \section{Ticks and Formatting} 32 | 33 | \subsection{Date Formats} 34 | 35 | The specific format of the displayed dates and times can be modified with \code{mdates.DateFormatter()}. This takes a format string and creates a formatter that can be passed to an axis method \code{set_major_formatter()} or \code{set_minor_formatter()}. 36 | 37 | Here are some common format codes, applied to Sunday January 30, 2000, 11:59PM, local to Louisville, Kentucky. These can all be verified with \code{pd.Timestamp(year = 2000, month = 1, day = 30, hour = 23, minute = 59, tz = 'America/Kentucky/Louisville').strftime()}. 38 | 39 | \begin{center} 40 | \begin{small} 41 | {\setlength{\tabcolsep}{2em} 42 | \begin{tabular}{ll} 43 | \toprule 44 | Code & Output/Example \\ 45 | \midrule 46 | \code{'\%Y'} & 4-Digit Year \\ 47 | \code{'\%m'} & Month Number \\ 48 | \code{'\%d'} & Day of Month \\ 49 | \code{'\%B'} & Month Name \\ 50 | \code{'\%H'} & 24-Hour Clock Hour \\ 51 | \code{'\%M'} & Minute \\ 52 | \code{'\%H'} & 12-Hour Clock Hour \\ 53 | \code{'\%p'} & AM or PM \\ 54 | \code{'\%A'} & Day of Week \\ 55 | \code{'\%Z'} & Timezone Name \\ 56 | \code{'\%Y-\%m'} & \code{'2000-01'}\\ 57 | \code{'\%Y\/\%m/\%d'} & \code{'2000/01/30'}\\ 58 | \code{'\%B \%y'} & \code{'January 00'}\\ 59 | \code{'\%H:\%M \%Z'} & \code{'23:59 EST'} \\ 60 | \code{'\%A \%I\%p'} & \code{'Sunday 11PM'}\\ 61 | \bottomrule 62 | \end{tabular}} 63 | \end{small} 64 | \end{center} 65 | 66 | A more complete list of format codes can be found at \link{https://strftime.org}{strftime.org}. Codes that generate actual names, like \code{'\%A'} or \code{'\%B'}, can be made lowercase to produce an abbreviated name. Notice that these formats create zero-padded numbers like \code{'07'} instead of \code{'7'}. On Mac or Linux, padding can be eliminated with the \code{'-'} modifier, using \code{'\%-H'} or \code{'\%-m'} 67 | instead of \code{'\%H'} or \code{'\%m'} for example. On Windows, use \code{'#'}. 68 | 69 | \pyfile{date-fmt.py} 70 | 71 | \begin{center} 72 | \includegraphics[width = .7\textwidth]{figures/proseplots/date-fmt.pdf} 73 | \end{center} 74 | 75 | \pyfile{date-fmt2.py} 76 | 77 | \begin{center} 78 | \includegraphics[width = .7\textwidth]{figures/proseplots/date-fmt2.pdf} 79 | \end{center} 80 | -------------------------------------------------------------------------------- /tex/special/MDS.tex: -------------------------------------------------------------------------------- 1 | %Dimensionality reduction techniques should be on the agenda for anyone interested in more visualizing complex data. 2 | 3 | Multi-dimensional scaling is a kind of dimensionality reduction, allowing one to translate a set of items and their predetermined pairwise distances into an arrangement of points in Cartesian space, typically in two dimensions. This is not a trivial task. Consider the meme below, which references social distancing guidance from the coronavirus pandemic. We have four individuals, forming six possible pairs, and any two individuals must maintain a six-foot distance. The graphic shows impossible right triangles that violate the Pythagorean Theorem when the distances are all exactly six feet. Indeed, there is no way to arrange four individuals in two-dimensional space so that they are all exactly six feet apart. This highlights one difficulty in multi-dimensional scaling---we must accept some error in our output. 4 | 5 | \begin{center} 6 | \includegraphics[width = 0.8\textwidth]{images/calmdownpythag.jpg} 7 | \end{center} 8 | 9 | \vspace{-2cm} 10 | 11 | The following diagram helps show why no alternative arrangement could be perfect. Each point $a,b,c$ is in the middle of a circle of six-foot radius. For $b$ to be six feet away from $a$, $b$ must lie on the circle centered at $a$. Similarly, for $b$ to be six feet away from $c$, $b$ must also lie on the circle centered at $c$. For three points, this arrangement is possible. But if we introduce $d$, $d$ must lie on all three of the circles centered at $a$, $b$, and $c$. But there is no point where all three circles intersect.\footnote{The code is (link TK).} 12 | 13 | \begin{center} 14 | \includegraphics[width = 0.96\textwidth]{figures/specialplots/mds-circles.pdf} 15 | \end{center} 16 | 17 | %\pyfile{mds-circles.py} 18 | 19 | Suppose we have four points, with unit pairwise distances for any two distinct points. Applying multi-dimensional scaling creates what is roughly a square. 20 | 21 | \begin{center} 22 | \includegraphics[width = 0.96\textwidth]{Images/MDS_social.pdf} 23 | \end{center} 24 | 25 | TKTK --------------------------------------------------------------------------------