├── .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
--------------------------------------------------------------------------------