diff --git a/config.toml b/config.toml index 8883ce1..aabfbc4 100644 --- a/config.toml +++ b/config.toml @@ -3,7 +3,7 @@ languageCode = "en-us" title = "Matplotblog" theme = "aether" canonifyurls = true -paginate = 3 +paginate = 4 [params] head_img = "/mpl_logo.png" @@ -14,3 +14,6 @@ link1_description = "About" [taxonomies] category = "categories" + +[markup.goldmark.renderer] + unsafe = true diff --git a/content/posts/GSoC_2021_Final/AitikGupta_GSoC.png b/content/posts/GSoC_2021_Final/AitikGupta_GSoC.png new file mode 100644 index 0000000..e769799 Binary files /dev/null and b/content/posts/GSoC_2021_Final/AitikGupta_GSoC.png differ diff --git a/content/posts/GSoC_2021_Final/index.md b/content/posts/GSoC_2021_Final/index.md new file mode 100644 index 0000000..c956f6e --- /dev/null +++ b/content/posts/GSoC_2021_Final/index.md @@ -0,0 +1,169 @@ +--- +title: "GSoC'21: Final Report" +date: 2021-08-17T17:36:40+05:30 +draft: false +categories: ["News", "GSoC"] +description: "Google Summer of Code 2021: Final Report - Aitik Gupta" +displayInList: true +author: Aitik Gupta + +resources: +- name: featuredImage + src: "AitikGupta_GSoC.png" + params: + showOnTop: true +--- + +**Matplotlib: Revisiting Text/Font Handling** + +To kick things off for the final report, here's a [meme](https://user-images.githubusercontent.com/43996118/129448683-bc136398-afeb-40ac-bbb7-0576757baf3c.jpg) to nudge about the [previous blogs](https://matplotlib.org/matplotblog/categories/gsoc/). +## About Matplotlib +Matplotlib is a comprehensive library for creating static, animated, and interactive visualizations, which has become a _de-facto Python plotting library_. + +Much of the implementation behind its font manager is inspired by [W3C](https://www.w3.org/) compliant algorithms, allowing users to interact with font properties like `font-size`, `font-weight`, `font-family`, etc. + +#### However, the way Matplotlib handled fonts and general text layout was not ideal, which is what Summer 2021 was all about. + +> By "not ideal", I do not mean that the library has design flaws, but that the design was engineered in the early 2000s, and is now _outdated_. + +(..more on this later) + +### About the Project +(PS: here's [the link](https://docs.google.com/document/d/11PrXKjMHhl0rcQB4p_W9JY_AbPCkYuoTT0t85937nB0/view#heading=h.feg5pv3x59u2) to my GSoC proposal, if you're interested) + +Overall, the project was divided into two major subgoals: +1. Font Subsetting +2. Font Fallback + +But before we take each of them on, we should get an idea about some basic terminology for fonts (which are a _lot_, and are rightly _confusing_) + +The [PR: Clarify/Improve docs on family-names vs generic-families](https://github.com/matplotlib/matplotlib/pull/20346/files) brings about a bit of clarity about some of these terms. The next section has a linked PR which also explains the types of fonts and how that is relevant to Matplotlib. +## Font Subsetting +An easy-to-read guide on Fonts and Matplotlib was created with [PR: [Doc] Font Types and Font Subsetting](https://github.com/matplotlib/matplotlib/pull/20450), which is currently live at [Matplotlib's DevDocs](https://matplotlib.org/devdocs/users/fonts.html). + +Taking an excerpt from one of my previous blogs (and [the doc](https://matplotlib.org/devdocs/users/fonts.html#subsetting)): + +> Fonts can be considered as a collection of these glyphs, so ultimately the goal of subsetting is to find out which glyphs are required for a certain array of characters, and embed only those within the output. + +PDF, PS/EPS and SVG output document formats are special, as in **the text within them can be editable**, i.e, one can copy/search text from documents (for eg, from a PDF file) if the text is editable. + +### Matplotlib and Subsetting +The PDF, PS/EPS and SVG backends used to support font subsetting, _only for a few types_. What that means is, before Summer '21, Matplotlib could generate Type 3 subsets for PDF, PS/EPS backends, but it *could not* generate Type 42 / TrueType subsets. + +With [PR: Type42 subsetting in PS/PDF](https://github.com/matplotlib/matplotlib/pull/20391) merged in, users can expect their PDF/PS/EPS documents to contains subsetted glyphs from the original fonts. + +This is especially benefitial for people who wish to use commercial (or [CJK](https://en.wikipedia.org/wiki/CJK_characters)) fonts. Licenses for many fonts ***require*** subsetting such that they can’t be trivially copied from the output files generated from Matplotlib. + +## Font Fallback +Matplotlib was designed to work with a single font at runtime. A user _could_ specify a `font.family`, which was supposed to correspond to [CSS](https://www.w3schools.com/cssref/pr_font_font-family.asp) properties, but that was only used to find a _single_ font present on the user's system. + +Once that font was found (which is almost always found, since Matplotlib ships with a set of default fonts), all the user text was rendered only through that font. (which used to give out "tofu" if a character wasn't found) + +--- + +It might seem like an _outdated_ approach for text rendering, now that we have these concepts like font-fallback, but these concepts weren't very well discussed in early 2000s. Even getting a single font to work _was considered a hard engineering problem_. + +This was primarily because of the lack of **any standardization** for representation of fonts (Adobe had their own font representation, and so did Apple, Microsoft, etc.) + + +|  |  | +|--------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------| +
+ Previous (notice Tofus) VS After (CJK font as fallback) +
+ +To migrate from a font-first approach to a text-first approach, there are multiple steps involved: + +### Parsing the whole font family +The very first (and crucial!) step is to get to a point where we have multiple font paths (ideally individual font files for the whole family). That is achieved with either: +- [PR: [with findfont diff] Parsing all families in font_manager](https://github.com/matplotlib/matplotlib/pull/20496), or +- [PR: [without findfont diff] Parsing all families in font_manager](https://github.com/matplotlib/matplotlib/pull/20549) + +Quoting one of my [previous](https://matplotlib.org/matplotblog/posts/gsoc_2021_prequarter/) blogs: +> Don’t break, a lot at stake! + +My first approach was to change the existing public `findfont` API to incorporate multiple filepaths. Since Matplotlib has a _very huge_ userbase, there's a high chance it would break a chunk of people's workflow: + +
+
+ First PR (left), Second PR (right)
+
+
+ Font-Fallback Algorithm
+
+
+ Consider contributing to Matplotlib (Open Source in general) ❤️
+
+
+
+## Getting started with Matplotlib
+It was around initial weeks of November last year, I was scanning through `Good First Issue` and `New Feature` labels, I realised a pattern - most Mathtext related issues were unattended.
+
+To make it simple, Mathtext is a part of Matplotlib which parses mathematical expressions and provides TeX-like outputs, for example:
+
+
+I scanned the related source code to try to figure out how to solve those Mathtext issues. Eventually, with the help of maintainers reviewing the PRs and a lot of verbose discussions on GitHub issues/pull requests and on the [Gitter](https://gitter.im/matplotlib/matplotlib) channel, I was able to get my initial PRs merged!
+
+## Learning throughout the process
+Most of us use libraries without understanding the underlining structure of them, which sometimes can cause downstream bugs!
+
+While I was studying Matplotlib's architecture, I figured that I could use the same ideology for one of my [own projects](https://aitikgupta.github.io/swi-ml/)!
+
+Matplotlib uses a global dictionary-like object named as `rcParams`, I used a smaller interface, similar to rcParams, in [swi-ml](https://pypi.org/project/swi-ml/) - a small Python library I wrote, implementing a subset of ML algorithms, with a switchable backend.
+
+
+## Where does GSoC fit?
+It was around January, I had a conversation with one of the maintainers (hey [Antony](https://github.com/anntzer)!) about the long-list of issues with the current ways of handling texts/fonts in the library.
+
+After compiling them into an order, after few tweaks from maintainers, [GSoC Idea-List](https://github.com/matplotlib/matplotlib/wiki/GSOC-2021-ideas) for Matplotlib was born. And so did my journey of building a strong proposal!
+
+## About the Project
+#### Proposal Link: [Google Docs](https://docs.google.com/document/d/11PrXKjMHhl0rcQB4p_W9JY_AbPCkYuoTT0t85937nB0/edit?usp=sharing) (will stay alive after GSoC), [GSoC Website](https://storage.googleapis.com/summerofcode-prod.appspot.com/gsoc/core_project/doc/6319153410998272_1617936740_GSoC_Proposal_-_Matplotlib.pdf?Expires=1621539234&GoogleAccessId=summerofcode-prod%40appspot.gserviceaccount.com&Signature=QU8uSdPnXpa%2FooDtzVnzclz809LHjh9eU7Y7iR%2FH1NM32CBgzBO4%2FFbMeDmMsoic91B%2BKrPZEljzGt%2Fx9jtQeCR9X4O53JJLPVjw9Bg%2Fzb2YKjGzDk0oFMRPXjg9ct%2BV58PD6f4De1ucqARLtHGjis5jhK1W08LNiHAo88NB6BaL8Q5hqcTBgunLytTNBJh5lW2kD8eR2WeENnW9HdIe53aCdyxJkYpkgILJRoNLCvp111AJGC3RLYba9VKeU6w2CdrumPfRP45FX6fJlrKnClvxyf5VHo3uIjA3fGNWIQKwGgcd1ocGuFN3YnDTS4xkX3uiNplwTM4aGLQNhtrMqA%3D%3D) (not so sure)
+
+### Revisiting Text/Font Handling
+The aim of the project is divided into 3 subgoals:
+
+1. **Font-Fallback**: A redesigned text-first font interface - essentially parsing all family before rendering a "tofu".
+
+ *(similar to specifying font-family in CSS!)*
+2. **Font Subsetting**: Every exported PS/PDF would contain embedded glyphs subsetted from the whole font.
+
+ *(imagine a plot with just a single letter "a", would you like it if the PDF you exported from Matplotlib to embed the whole font file within it?)*
+
+3. Most mpl backends would use the unified TeX exporting mechanism
+
+**Mentors** [Thomas A Caswell](https://github.com/tacaswell), [Antony Lee](https://github.com/anntzer), [Hannah](https://github.com/story645).
+
+Thanks a lot for spending time reading the blog! I'll be back with my progress in subsequent posts.
+
+
+##### NOTE: This blog post is also available at my [personal website](https://aitikgupta.github.io/gsoc-intro/)!
+
diff --git a/content/posts/GSoC_2021_MidTerm/AitikGupta_GSoC.png b/content/posts/GSoC_2021_MidTerm/AitikGupta_GSoC.png
new file mode 100644
index 0000000..e769799
Binary files /dev/null and b/content/posts/GSoC_2021_MidTerm/AitikGupta_GSoC.png differ
diff --git a/content/posts/GSoC_2021_MidTerm/index.md b/content/posts/GSoC_2021_MidTerm/index.md
new file mode 100644
index 0000000..dece87c
--- /dev/null
+++ b/content/posts/GSoC_2021_MidTerm/index.md
@@ -0,0 +1,88 @@
+---
+title: "GSoC'21: Mid-Term Progress"
+date: 2021-07-02T08:32:05+05:30
+draft: false
+categories: ["News", "GSoC"]
+description: "Mid-Term Progress with Google Summer of Code 2021 project under NumFOCUS: Aitik Gupta"
+displayInList: true
+author: Aitik Gupta
+
+resources:
+- name: featuredImage
+ src: "AitikGupta_GSoC.png"
+ params:
+ showOnTop: true
+---
+
+**"Aitik, how is your GSoC going?"**
+
+Well, it's been a while since I last wrote. But I wasn't spending time watching _Loki_ either! (that's a lie.)
+
+During this period the project took on some interesting (and stressful) curves, which I intend to talk about in this small writeup.
+## New Mentor!
+The first week of coding period, and I met one of my new mentors, [Jouni](https://github.com/jkseppan). Without him, along with [Tom](https://github.com/tacaswell) and [Antony](https://github.com/anntzer), the project wouldn't have moved _an inch_.
+
+It was initially Jouni's [PR](https://github.com/matplotlib/matplotlib/pull/18143) which was my starting point of the first milestone in my proposal, Font Subsetting.
+
+## What is Font Subsetting anyway?
+As was proposed by Tom, a good way to understand something is to document your journey along the way! (well, that's what GSoC wants us to follow anyway right?)
+
+Taking an excerpt from one of the paragraphs I wrote [here](https://github.com/matplotlib/matplotlib/blob/a94f52121cea4194a5d6f6fc94eafdfb03394628/doc/users/fonts.rst#subsetting):
+> Font Subsetting can be used before generating documents, to embed only the _required_ glyphs within the documents. Fonts can be considered as a collection of these glyphs, so ultimately the goal of subsetting is to find out which glyphs are required for a certain array of characters, and embed only those within the output.
+
+Now this may seem straightforward, right?
+#### Wrong.
+The glyph programs can call their own subprograms, for example, characters like `ä` could be composed by calling subprograms for `a` and `¨`; or `→` could be composed by a program that changes the display matrix and calls the subprogram for `←`.
+
+Since the subsetter has to find out _all such subprograms_ being called by _every glyph_ included in the subset, this is a generally difficult problem!
+
+Something which one of my mentors said which _really_ stuck with me:
+> Matplotlib isn't a font library, and shouldn't try to be one.
+
+It's really easy to fall into the trap of trying to do _everything_ within your own project, which ends up rather _hurting_ itself.
+
+Since this holds true even for Matplotlib, it uses external dependencies like [FreeType](https://www.freetype.org/), [ttconv](https://github.com/sandflow/ttconv), and newly proposed [fontTools](https://github.com/fonttools/fonttools) to handle font subsetting, embedding, rendering, and related stuff.
+
+PS: If that font stuff didn't make sense, I would recommend going through a friendly tutorial I wrote, which is all about [Matplotlib and Fonts](https://matplotlib.org/stable/users/fonts.html)!
+## Unexpected Complications
+Matplotlib uses an external dependency `ttconv` which was initially forked into Matplotlib's repository **in 2003**!
+> ttconv was a standalone commandline utility for converting TrueType fonts to subsetted Type 3 fonts (among other features) written in 1995, which Matplotlib forked in order to make it work as a library.
+
+Over the time, there were a lot of issues with it which were either hard to fix, or didn't attract a lot of attention. (See the above paragraph for a valid reason)
+
+One major utility which is still used is `convert_ttf_to_ps`, which takes a _font path_ as input and converts it into a Type 3 or Type 42 PostScript font, which can be embedded within PS/EPS output documents. The guide I wrote ([link](https://matplotlib.org/stable/users/fonts.html)) contains decent descriptions, the differences between these type of fonts, etc.
+
+#### So we need to convert that _font path_ input to a _font buffer_ input.
+Why do we need to? Type 42 subsetting isn't really supported by ttconv, so we use a new dependency called fontTools, whose 'full-time job' is to subset Type 42 fonts for us (among other things).
+
+> It provides us with a font buffer, however ttconv expects a font path to embed that font
+
+Easily enough, this can be done by Python's `tempfile.NamedTemporaryFile`:
+```python
+with tempfile.NamedTemporaryFile(suffix=".ttf") as tmp:
+ # fontdata is the subsetted buffer
+ # returned from fontTools
+ tmp.write(fontdata.getvalue())
+
+ # TODO: allow convert_ttf_to_ps
+ # to input file objects (BytesIO)
+ convert_ttf_to_ps(
+ os.fsencode(tmp.name),
+ fh,
+ fonttype,
+ glyph_ids,
+ )
+```
+
+***But this is far from a clean API; in terms of separation of \*reading\* the file from \*parsing\* the data.***
+
+What we _ideally_ want is to pass the buffer down to `convert_ttf_to_ps`, and modify the embedding code of `ttconv` (written in C++). And _here_ we come across a lot of unexplored codebase, _which wasn't touched a lot ever since it was forked_.
+
+Funnily enough, just yesterday, after spending a lot of quality time, me and my mentors figured out that the **whole logging system of ttconv was broken**, all because of a single debugging function. 🥲
+
+
+
+
+
+
+
+
+
+
+
diff --git a/content/posts/ipcc-sr15/pyam-header.png b/content/posts/ipcc-sr15/pyam-header.png
new file mode 100644
index 0000000..e1a67a7
Binary files /dev/null and b/content/posts/ipcc-sr15/pyam-header.png differ
diff --git a/content/posts/ipcc-sr15/sr15-fig2.15.png b/content/posts/ipcc-sr15/sr15-fig2.15.png
new file mode 100644
index 0000000..1e52d6f
Binary files /dev/null and b/content/posts/ipcc-sr15/sr15-fig2.15.png differ
diff --git a/content/posts/ipcc-sr15/sr15-fig2.4.png b/content/posts/ipcc-sr15/sr15-fig2.4.png
new file mode 100644
index 0000000..4634846
Binary files /dev/null and b/content/posts/ipcc-sr15/sr15-fig2.4.png differ
diff --git a/content/posts/pyplot-vs-object-oriented-interface/index.md b/content/posts/pyplot-vs-object-oriented-interface/index.md
index 5dc7dd2..290fc0f 100644
--- a/content/posts/pyplot-vs-object-oriented-interface/index.md
+++ b/content/posts/pyplot-vs-object-oriented-interface/index.md
@@ -60,7 +60,7 @@ This interface shares a lot of similarities in syntax and methodology with MATLA
import matplotlib.pyplot as plt
plt.figure(figsize=(9,7), dpi=100)
-plt.plot(distance,'bo-')
+plt.plot(time,distance,'bo-')
plt.xlabel("Time")
plt.ylabel("Distance")
plt.legend(["Distance"])
@@ -76,7 +76,7 @@ The plot shows how much distance was covered by the free-falling object with eac
```python
plt.figure(figsize=(9,7), dpi=100)
-plt.plot(velocity,'go-')
+plt.plot(time, velocity,'go-')
plt.xlabel("Time")
plt.ylabel("Velocity")
plt.legend(["Velocity"])
@@ -94,8 +94,8 @@ Let's try to see what kind of plot we get when we plot both distance and velocit
```python
plt.figure(figsize=(9,7), dpi=100)
-plt.plot(velocity,'g-')
-plt.plot(distance,'b-')
+plt.plot(time, velocity,'g-')
+plt.plot(time, distance,'b-')
plt.ylabel("Distance and Velocity")
plt.xlabel("Time")
plt.legend(["Distance", "Velocity"])
diff --git a/content/posts/python-graph-gallery.com/.DS_Store b/content/posts/python-graph-gallery.com/.DS_Store
new file mode 100644
index 0000000..5008ddf
Binary files /dev/null and b/content/posts/python-graph-gallery.com/.DS_Store differ
diff --git a/content/posts/python-graph-gallery.com/annotations.png b/content/posts/python-graph-gallery.com/annotations.png
new file mode 100644
index 0000000..8c22959
Binary files /dev/null and b/content/posts/python-graph-gallery.com/annotations.png differ
diff --git a/content/posts/python-graph-gallery.com/boxplot.png b/content/posts/python-graph-gallery.com/boxplot.png
new file mode 100644
index 0000000..59e0051
Binary files /dev/null and b/content/posts/python-graph-gallery.com/boxplot.png differ
diff --git a/content/posts/python-graph-gallery.com/home-page-overview.png b/content/posts/python-graph-gallery.com/home-page-overview.png
new file mode 100644
index 0000000..6616f9b
Binary files /dev/null and b/content/posts/python-graph-gallery.com/home-page-overview.png differ
diff --git a/content/posts/python-graph-gallery.com/index.md b/content/posts/python-graph-gallery.com/index.md
new file mode 100644
index 0000000..a902975
--- /dev/null
+++ b/content/posts/python-graph-gallery.com/index.md
@@ -0,0 +1,70 @@
+---
+title: "The Python Graph Gallery: hundreds of python charts with reproducible code."
+date: 2021-07-24T14:06:57+02:00
+draft: false
+description: "The Python Graph Gallery is a website that displays hundreds of chart examples made with python. It goes from very basic to highly customized examples and is based on common viz libraries like matplotlib, seaborn or plotly."
+categories: ["tutorials", "graphs"]
+displayInList: true
+author: Yan Holtz
+resources:
+- name: featuredImage
+ src: "home-page-overview.png"
+ params:
+ description: "An overview of the gallery homepage"
+ showOnTop: false
+---
+
+Data visualization is a key step in a data science pipeline. [Python](https://www.python.org) offers great possibilities when it comes to representing some data graphically, but it can be hard and time-consuming to create the appropriate chart.
+
+The [Python Graph Gallery](https://www.python-graph-gallery.com) is here to help. It displays many examples, always providing the reproducible code. It allows to build the desired chart in minutes.
+
+# About 400 charts in 40 sections
+
+The gallery currently provides more than [400 chart examples](https://www.python-graph-gallery.com/all-charts/). Those examples are organized in 40 sections, one for each chart types: [scatterplot](https://www.python-graph-gallery.com/scatter-plot/), [boxplot](https://www.python-graph-gallery.com/boxplot/), [barplot](https://www.python-graph-gallery.com/barplot/), [treemap](https://www.python-graph-gallery.com/treemap/) and so on. Those chart types are organized in 7 big families as suggested by [data-to-viz.com](https://www.data-to-viz.com): one for each visualization purpose.
+
+It is important to note that not only the most common chart types are covered. Lesser known charts like [chord diagrams](https://www.python-graph-gallery.com/chord-diagram/), [streamgraphs](https://www.python-graph-gallery.com/streamchart/) or [bubble maps](https://www.python-graph-gallery.com/bubble-map/) are also available.
+
+
+
+# Master the basics
+
+Each section always starts with some very basic examples. It allows to understand how to build a chart type in a few seconds. Hopefully applying the same technique on another dataset will thus be very quick.
+
+For instance, the [scatterplot section](https://www.python-graph-gallery.com/scatter-plot/) starts with this [matplotlib](https://matplotlib.org/) example. It shows how to create a dataset with [pandas](https://pandas.pydata.org/) and plot it with the `plot()` function. The main graph argument like `linestyle` and `marker` are described to make sure the code is understandable.
+
+[_blogpost overview_:](https://www.python-graph-gallery.com/130-basic-matplotlib-scatterplot)
+
+
+
+# Matplotlib customization
+
+The gallery uses several libraries like [seaborn](https://www.python-graph-gallery.com/seaborn/) or [plotly](https://www.python-graph-gallery.com/plotly/) to produce its charts, but is mainly focus on matplotlib. Matplotlib comes with great flexibility and allows to build any kind of chart without limits.
+
+A [whole page](https://www.python-graph-gallery.com/matplotlib/) is dedicated to matplotlib. It describes how to solve recurring issues like customizing [axes](https://www.python-graph-gallery.com/191-custom-axis-on-matplotlib-chart) or [titles](https://www.python-graph-gallery.com/190-custom-matplotlib-title), adding [annotations](https://www.python-graph-gallery.com/193-annotate-matplotlib-chart) (see below) or even using [custom fonts](https://www.python-graph-gallery.com/custom-fonts-in-matplotlib).
+
+
+
+The gallery is also full of non-straightforward examples. For instance, it has a [tutorial](https://www.python-graph-gallery.com/streamchart-basic-matplotlib) explaining how to build a streamchart with matplotlib. It is based on the `stackplot()` function and adds some smoothing to it:
+
+
+
+Last but not least, the gallery also displays some publication ready charts. They usually involve a lot of matplotlib code, but showcase the fine grain control one has over a plot.
+
+Here is an example with a post inspired by [Tuo Wang](https://www.r-graph-gallery.com/web-violinplot-with-ggstatsplot.html)'s work for the tidyTuesday project. (Code translated from R available [here](https://www.python-graph-gallery.com/web-ggbetweenstats-with-matplotlib))
+
+
+
+
+# Contributing
+
+The python graph gallery is an ever growing project. It is open-source, with all its related code hosted on [github](https://github.com/holtzy/The-Python-Graph-Gallery).
+
+Contributions are very welcome to the gallery. Each blogpost is just a jupyter notebook so suggestion should be very easy to do through issues or pull requests!
+
+# Conclusion
+
+The [python graph gallery](https://www.python-graph-gallery.com) is a project developed by [Yan Holtz](https://www.yan-holtz.com) in his free time. It can help you improve your technical skills when it comes to visualizing data with python.
+
+The gallery belongs to an ecosystem of educative websites. [Data to viz](https://www.data-to-viz.com) describes best practices in data visualization, the [R](https://www.r-graph-gallery.com), [python](https://www.python-graph-gallery.com) and [d3.js](https://www.d3-graph-gallery.com) graph galleries provide technical help to build charts with the 3 most common tools.
+
+For any question regarding the project, please say hi on twitter at [@R_Graph_Gallery](https://twitter.com/R_Graph_Gallery)!
diff --git a/content/posts/python-graph-gallery.com/scatterplot-example.png b/content/posts/python-graph-gallery.com/scatterplot-example.png
new file mode 100644
index 0000000..99d0869
Binary files /dev/null and b/content/posts/python-graph-gallery.com/scatterplot-example.png differ
diff --git a/content/posts/python-graph-gallery.com/sections-overview.png b/content/posts/python-graph-gallery.com/sections-overview.png
new file mode 100644
index 0000000..7a0da60
Binary files /dev/null and b/content/posts/python-graph-gallery.com/sections-overview.png differ
diff --git a/content/posts/python-graph-gallery.com/streamchart.png b/content/posts/python-graph-gallery.com/streamchart.png
new file mode 100644
index 0000000..1990a51
Binary files /dev/null and b/content/posts/python-graph-gallery.com/streamchart.png differ
diff --git a/content/posts/stellar-chart-alternative-radar-chart/index.md b/content/posts/stellar-chart-alternative-radar-chart/index.md
new file mode 100644
index 0000000..55e9cd2
--- /dev/null
+++ b/content/posts/stellar-chart-alternative-radar-chart/index.md
@@ -0,0 +1,182 @@
+---
+title: "Stellar Chart, a Type of Chart to Be on Your Radar"
+date: 2021-01-10T20:29:40Z
+draft: false
+description: "Learn how to create a simple stellar chart, an alternative to the radar chart."
+categories: ["tutorials"]
+displayInList: true
+author: João Palmeiro
+resources:
+ - name: featuredImage
+ src: "stellar_chart.png"
+ params:
+ description: "example of a stellar chart"
+ showOnTop: false
+---
+
+In May 2020, Alexandre Morin-Chassé published a blog post about the **stellar chart**. This type of chart is an (approximately) direct alternative to the **radar chart** (also known as web, spider, star, or cobweb chart) — you can read more about this chart [here](https://medium.com/nightingale/the-stellar-chart-an-elegant-alternative-to-radar-charts-ae6a6931a28e).
+
+
+
+In this tutorial, we will see how we can create a quick-and-dirty stellar chart. First of all, let's get the necessary modules/libraries, as well as prepare a dummy dataset (with just a single record).
+
+```python
+from itertools import chain, zip_longest
+from math import ceil, pi
+
+import matplotlib.pyplot as plt
+
+data = [
+ ("V1", 8),
+ ("V2", 10),
+ ("V3", 9),
+ ("V4", 12),
+ ("V5", 6),
+ ("V6", 14),
+ ("V7", 15),
+ ("V8", 25),
+]
+```
+
+We will also need some helper functions, namely a function to round up to the nearest 10 (`round_up()`) and a function to join two sequences (`even_odd_merge()`). In the latter, the values of the first sequence (a list or a tuple, basically) will fill the even positions and the values of the second the odd ones.
+
+```python
+def round_up(value):
+ """
+ >>> round_up(25)
+ 30
+ """
+ return int(ceil(value / 10.0)) * 10
+
+
+def even_odd_merge(even, odd, filter_none=True):
+ """
+ >>> list(even_odd_merge([1,3], [2,4]))
+ [1, 2, 3, 4]
+ """
+ if filter_none:
+ return filter(None.__ne__, chain.from_iterable(zip_longest(even, odd)))
+
+ return chain.from_iterable(zip_longest(even, odd))
+```
+
+That said, to plot `data` on a stellar chart, we need to apply some transformations, as well as calculate some auxiliary values. So, let's start by creating a function (`prepare_angles()`) to calculate the angle of each axis on the chart (`N` corresponds to the number of variables to be plotted).
+
+```python
+def prepare_angles(N):
+ angles = [n / N * 2 * pi for n in range(N)]
+
+ # Repeat the first angle to close the circle
+ angles += angles[:1]
+
+ return angles
+```
+
+Next, we need a function (`prepare_data()`) responsible for adjusting the original data (`data`) and separating it into several easy-to-use objects.
+
+```python
+def prepare_data(data):
+ labels = [d[0] for d in data] # Variable names
+ values = [d[1] for d in data]
+
+ # Repeat the first value to close the circle
+ values += values[:1]
+
+ N = len(labels)
+ angles = prepare_angles(N)
+
+ return labels, values, angles, N
+```
+
+Lastly, for this specific type of chart, we require a function (`prepare_stellar_aux_data()`) that, from the previously calculated angles, prepares two lists of auxiliary values: a list of **intermediate angles** for each pair of angles (`stellar_angles`) and a list of small **constant values** (`stellar_values`), which will act as the values of the variables to be plotted in order to achieve the **star-like shape** intended for the stellar chart.
+
+```python
+def prepare_stellar_aux_data(angles, ymax, N):
+ angle_midpoint = pi / N
+
+ stellar_angles = [angle + angle_midpoint for angle in angles[:-1]]
+ stellar_values = [0.05 * ymax] * N
+
+ return stellar_angles, stellar_values
+```
+
+At this point, we already have all the necessary _ingredients_ for the stellar chart, so let's move on to the Matplotlib side of this tutorial. In terms of **aesthetics**, we can rely on a function (`draw_peripherals()`) designed for this specific purpose (feel free to customize it!).
+
+```python
+def draw_peripherals(ax, labels, angles, ymax, outer_color, inner_color):
+ # X-axis
+ ax.set_xticks(angles[:-1])
+ ax.set_xticklabels(labels, color=outer_color, size=8)
+
+ # Y-axis
+ ax.set_yticks(range(10, ymax, 10))
+ ax.set_yticklabels(range(10, ymax, 10), color=inner_color, size=7)
+ ax.set_ylim(0, ymax)
+ ax.set_rlabel_position(0)
+
+ # Both axes
+ ax.set_axisbelow(True)
+
+ # Boundary line
+ ax.spines["polar"].set_color(outer_color)
+
+ # Grid lines
+ ax.xaxis.grid(True, color=inner_color, linestyle="-")
+ ax.yaxis.grid(True, color=inner_color, linestyle="-")
+```
+
+To **plot the data** and orchestrate (almost) all the steps necessary to have a stellar chart, we just need one last function: `draw_stellar()`.
+
+```python
+def draw_stellar(
+ ax,
+ labels,
+ values,
+ angles,
+ N,
+ shape_color="tab:blue",
+ outer_color="slategrey",
+ inner_color="lightgrey",
+):
+ # Limit the Y-axis according to the data to be plotted
+ ymax = round_up(max(values))
+
+ # Get the lists of angles and variable values
+ # with the necessary auxiliary values injected
+ stellar_angles, stellar_values = prepare_stellar_aux_data(angles, ymax, N)
+ all_angles = list(even_odd_merge(angles, stellar_angles))
+ all_values = list(even_odd_merge(values, stellar_values))
+
+ # Apply the desired style to the figure elements
+ draw_peripherals(ax, labels, angles, ymax, outer_color, inner_color)
+
+ # Draw (and fill) the star-shaped outer line/area
+ ax.plot(
+ all_angles,
+ all_values,
+ linewidth=1,
+ linestyle="solid",
+ solid_joinstyle="round",
+ color=shape_color,
+ )
+
+ ax.fill(all_angles, all_values, shape_color)
+
+ # Add a small hole in the center of the chart
+ ax.plot(0, 0, marker="o", color="white", markersize=3)
+```
+
+Finally, let's get our chart on a _blank canvas_ (figure).
+
+```python
+fig = plt.figure(dpi=100)
+ax = fig.add_subplot(111, polar=True) # Don't forget the projection!
+
+draw_stellar(ax, *prepare_data(data))
+
+plt.show()
+```
+
+
+
+It's done! Right now, you have an example of a stellar chart and the boilerplate code to add this type of chart to your _repertoire_. If you end up creating your own stellar charts, feel free to share them with the _world_ (and [me](https://twitter.com/joaompalmeiro)!). I hope this tutorial was useful and interesting for you!
diff --git a/content/posts/stellar-chart-alternative-radar-chart/radar_stellar_chart.png b/content/posts/stellar-chart-alternative-radar-chart/radar_stellar_chart.png
new file mode 100644
index 0000000..6699cc7
Binary files /dev/null and b/content/posts/stellar-chart-alternative-radar-chart/radar_stellar_chart.png differ
diff --git a/content/posts/stellar-chart-alternative-radar-chart/stellar_chart.png b/content/posts/stellar-chart-alternative-radar-chart/stellar_chart.png
new file mode 100644
index 0000000..1f73871
Binary files /dev/null and b/content/posts/stellar-chart-alternative-radar-chart/stellar_chart.png differ
diff --git a/content/posts/unc-biol222/fox.png b/content/posts/unc-biol222/fox.png
new file mode 100644
index 0000000..5d8307d
Binary files /dev/null and b/content/posts/unc-biol222/fox.png differ
diff --git a/content/posts/unc-biol222/index.md b/content/posts/unc-biol222/index.md
new file mode 100644
index 0000000..24640da
--- /dev/null
+++ b/content/posts/unc-biol222/index.md
@@ -0,0 +1,218 @@
+---
+title: "Art from UNC BIOL222"
+date: 2021-11-19T08:46:00-08:00
+draft: false
+description: "UNC BIOL222: Art created with Matplotlib"
+categories: ["art", "academia"]
+displayInList: true
+author: Joseph Lucas
+resources:
+- name: featuredImage
+ src: "fox.png"
+ params:
+ description: "Emily Foster's Fox"
+ showOnTop: true
+---
+
+As part of the University of North Carolina BIOL222 class, [Dr. Catherine Kehl](https://twitter.com/tylikcat) asked her students to "use `matplotlib.pyplot` to make art." BIOL222 is Introduction to Programming, aimed at students with no programming background. The emphasis is on practical, hands-on active learning.
+
+The students completed the assignment with festive enthusiasm around Halloween. Here are some great examples:
+
+Harris Davis showed an affinity for pumpkins, opting to go 3D!
+
+```python
+# get library for 3d plotting
+from mpl_toolkits.mplot3d import Axes3D
+
+# make a pumpkin :)
+rho = np.linspace(0, 3*np.pi,32)
+theta, phi = np.meshgrid(rho, rho)
+r, R = .5, .5
+X = (R + r * np.cos(phi)) * np.cos(theta)
+Y = (R + r * np.cos(phi)) * np.sin(theta)
+Z = r * np.sin(phi)
+
+# make the stem
+theta1 = np.linspace(0,2*np.pi,90)
+r1 = np.linspace(0,3,50)
+T1, R1 = np.meshgrid(theta1, r1)
+X1 = R1 * .5*np.sin(T1)
+Y1 = R1 * .5*np.cos(T1)
+Z1 = -(np.sqrt(X1**2 + Y1**2) - .7)
+Z1[Z1 < .3] = np.nan
+Z1[Z1 > .7] = np.nan
+
+# Display the pumpkin & stem
+fig = plt.figure()
+ax = fig.gca(projection = '3d')
+ax.set_xlim3d(-1, 1)
+ax.set_ylim3d(-1, 1)
+ax.set_zlim3d(-1, 1)
+ax.plot_surface(X, Y, Z, color = 'tab:orange', rstride = 1, cstride = 1)
+ax.plot_surface(X1, Y1, Z1, color = 'tab:green', rstride = 1, cstride = 1)
+plt.show()
+```
+
+Bryce Desantis stuck to the biological theme and demonstrated [fractal](https://en.wikipedia.org/wiki/Fractal) art.
+
+```python
+import numpy as np
+import matplotlib.pyplot as plt
+
+#Barnsley's Fern - Fractal; en.wikipedia.org/wiki/Barnsley_…
+
+#functions for each part of fern:
+#stem
+def stem(x,y):
+ return (0, 0.16*y)
+#smaller leaflets
+def smallLeaf(x,y):
+ return (0.85*x + 0.04*y, -0.04*x + 0.85*y + 1.6)
+#large left leaflets
+def leftLarge(x,y):
+ return (0.2*x - 0.26*y, 0.23*x + 0.22*y + 1.6)
+#large right leftlets
+def rightLarge(x,y):
+ return (-0.15*x + 0.28*y, 0.26*x + 0.24*y + 0.44)
+componentFunctions = [stem, smallLeaf, leftLarge, rightLarge]
+
+# number of data points and frequencies for parts of fern generated:
+#lists with all 75000 datapoints
+datapoints = 75000
+x, y = 0, 0
+datapointsX = []
+datapointsY = []
+#For 75,000 datapoints
+for n in range(datapoints):
+ FrequencyFunction = np.random.choice(componentFunctions, p=[0.01, 0.85, 0.07, 0.07])
+ x, y = FrequencyFunction(x,y)
+ datapointsX.append(x)
+ datapointsY.append(y)
+
+#Scatter plot & scaled down to 0.1 to show more definition:
+plt.scatter(datapointsX,datapointsY,s=0.1, color='g')
+#Title of Figure
+plt.title("Barnsley's Fern - Assignment 3")
+#Changing background color
+ax = plt.axes()
+ax.set_facecolor("#d8d7bf")
+```
+
+Grace Bell got a little trippy with this rotationally semetric art. It's pretty cool how she captured mouse events. It reminds us of a flower. What do you see?
+
+```python
+import matplotlib.pyplot as plt
+from matplotlib.tri import Triangulation
+from matplotlib.patches import Polygon
+import numpy as np
+
+#I found this sample code online and manipulated it to make the art piece!
+#was interested in because it combined what we used for functions as well as what we used for plotting with (x,y)
+def update_polygon(tri):
+ if tri == -1:
+ points = [0, 0, 0]
+ else:
+ points = triang.triangles[tri]
+ xs = triang.x[points]
+ ys = triang.y[points]
+ polygon.set_xy(np.column_stack([xs, ys]))
+
+def on_mouse_move(event):
+ if event.inaxes is None:
+ tri = -1
+ else:
+ tri = trifinder(event.xdata, event.ydata)
+ update_polygon(tri)
+ ax.set_title(f'In triangle {tri}')
+ event.canvas.draw()
+#this is the info that creates the angles
+n_angles = 14
+n_radii = 7
+min_radius = 0.1 #the radius of the middle circle can move with this variable
+radii = np.linspace(min_radius, 0.95, n_radii)
+angles = np.linspace(0, 2 * np.pi, n_angles, endpoint=False)
+angles = np.repeat(angles[..., np.newaxis], n_radii, axis=1)
+angles[:, 1::2] += np.pi / n_angles
+x = (radii*np.cos(angles)).flatten()
+y = (radii*np.sin(angles)).flatten()
+triang = Triangulation(x, y)
+triang.set_mask(np.hypot(x[triang.triangles].mean(axis=1),
+ y[triang.triangles].mean(axis=1))
+ < min_radius)
+
+trifinder = triang.get_trifinder()
+
+fig, ax = plt.subplots(subplot_kw={'aspect': 'equal'})
+ax.triplot(triang, 'y+-') #made the color of the plot yellow and there are "+" for the data points but you can't really see them because of the lines crossing
+polygon = Polygon([[0, 0], [0, 0]], facecolor='y')
+update_polygon(-1)
+ax.add_patch(polygon)
+fig.canvas.mpl_connect('motion_notify_event', on_mouse_move)
+plt.show()
+```
+
+As a bonus, did you like that fox in the banner? That was created (and well documented) by Emily Foster!
+```python
+import numpy as np
+import matplotlib.pyplot as plt
+
+plt.axis('off')
+
+#head
+xhead = np.arange(-50,50,0.1)
+yhead = -0.007*(xhead*xhead) + 100
+
+plt.plot(xhead, yhead, 'darkorange')
+
+#outer ears
+xearL = np.arange(-45.8,-9,0.1)
+yearL = -0.08*(xearL*xearL) -4*xearL + 70
+
+xearR = np.arange(9,45.8,0.1)
+yearR = -0.08*(xearR*xearR) + 4*xearR + 70
+
+plt.plot(xearL, yearL, 'black')
+plt.plot(xearR, yearR, 'black')
+
+#inner ears
+xinL = np.arange(-41.1,-13.7,0.1)
+yinL = -0.08*(xinL*xinL) -4*xinL + 59
+
+xinR = np.arange(13.7,41.1,0.1)
+yinR = -0.08*(xinR*xinR) + 4*xinR + 59
+
+plt.plot(xinL, yinL, 'salmon')
+plt.plot(xinR, yinR, 'salmon')
+
+# bottom of face
+xfaceL = np.arange(-49.6,-14,0.1)
+xfaceR = np.arange(14,49.3,0.1)
+xfaceM = np.arange(-14,14,0.1)
+
+plt.plot(xfaceL, abs(xfaceL), 'darkorange')
+plt.plot(xfaceR, abs(xfaceR), 'darkorange')
+plt.plot(xfaceM, abs(xfaceM), 'black')
+
+#nose
+xnose = np.arange(-14,14,0.1)
+ynose = -0.03*(xnose*xnose) + 20
+
+plt.plot(xnose, ynose, 'black')
+
+#whiskers
+xwhiskR = [50, 70, 55, 70, 55, 70, 49.3]
+xwhiskL = [-50, -70, -55, -70, -55, -70, -49.3]
+ywhisk = [82.6, 85, 70, 65, 60, 45, 49.3]
+
+plt.plot(xwhiskR, ywhisk, 'darkorange')
+plt.plot(xwhiskL, ywhisk, 'darkorange')
+
+#eyes
+plt.plot(20,60, color = 'black', marker = 'o', markersize = 15)
+plt.plot(-20,60,color = 'black', marker = 'o', markersize = 15)
+
+plt.plot(22,62, color = 'white', marker = 'o', markersize = 6)
+plt.plot(-18,62,color = 'white', marker = 'o', markersize = 6)
+```
+
+We look forward to seeing these students continue in their plotting and scientific adventures!
\ No newline at end of file
diff --git a/content/posts/unc-biol222/leaf.png b/content/posts/unc-biol222/leaf.png
new file mode 100644
index 0000000..448b82d
Binary files /dev/null and b/content/posts/unc-biol222/leaf.png differ
diff --git a/content/posts/unc-biol222/pumpkin.png b/content/posts/unc-biol222/pumpkin.png
new file mode 100644
index 0000000..76eeaf7
Binary files /dev/null and b/content/posts/unc-biol222/pumpkin.png differ
diff --git a/content/posts/unc-biol222/rotations.png b/content/posts/unc-biol222/rotations.png
new file mode 100644
index 0000000..dd9c045
Binary files /dev/null and b/content/posts/unc-biol222/rotations.png differ
diff --git a/content/posts/visualising-usage-using-batteries/Liverpool.png b/content/posts/visualising-usage-using-batteries/Liverpool.png
new file mode 100644
index 0000000..4114444
Binary files /dev/null and b/content/posts/visualising-usage-using-batteries/Liverpool.png differ
diff --git a/content/posts/visualising-usage-using-batteries/Liverpool_Usage_Chart.png b/content/posts/visualising-usage-using-batteries/Liverpool_Usage_Chart.png
new file mode 100644
index 0000000..b7586e4
Binary files /dev/null and b/content/posts/visualising-usage-using-batteries/Liverpool_Usage_Chart.png differ
diff --git a/content/posts/visualising-usage-using-batteries/battery.png b/content/posts/visualising-usage-using-batteries/battery.png
new file mode 100644
index 0000000..4a131c1
Binary files /dev/null and b/content/posts/visualising-usage-using-batteries/battery.png differ
diff --git a/content/posts/visualising-usage-using-batteries/data.PNG b/content/posts/visualising-usage-using-batteries/data.PNG
new file mode 100644
index 0000000..89f472e
Binary files /dev/null and b/content/posts/visualising-usage-using-batteries/data.PNG differ
diff --git a/content/posts/visualising-usage-using-batteries/head_data.PNG b/content/posts/visualising-usage-using-batteries/head_data.PNG
new file mode 100644
index 0000000..3f6d6cb
Binary files /dev/null and b/content/posts/visualising-usage-using-batteries/head_data.PNG differ
diff --git a/content/posts/visualising-usage-using-batteries/index.md b/content/posts/visualising-usage-using-batteries/index.md
new file mode 100644
index 0000000..b056466
--- /dev/null
+++ b/content/posts/visualising-usage-using-batteries/index.md
@@ -0,0 +1,220 @@
+---
+title: "Battery Charts - Visualise usage rates & more"
+date: 2021-08-19T16:52:58+05:30
+draft: false
+description: A tutorial on how to show usage rates and more using batteries
+categories: ["tutorials"]
+displayInList: true
+author: Rithwik Rajendran
+resources:
+- name: featuredImage
+ src: "Liverpool_Usage_Chart.png"
+ params:
+ description: "my image description"
+ showOnTop: true
+
+---
+
+# Introduction
+
+I have been creating common visualisations like scatter plots, bar charts, beeswarms etc. for a while and thought about doing something different. Since I'm an avid football fan, I thought of ideas to represent players' usage or involvement over a period (a season, a couple of seasons). I have seen some cool visualisations like donuts which depict usage and I wanted to make something different and simple to understand. I thought about representing batteries as a form of player usage and it made a lot of sense.
+
+For players who have been barely used (played fewer minutes) show a ***large amount of battery*** present since they have enough energy left in the tank. And for heavily used players, do the opposite i.e. show ***drained or less amount of battery***
+
+So, what is the purpose of a battery chart? You can use it to show usage, consumption, involvement, fatigue etc. (anything usage related).
+
+The image below is a sample view of how a battery would look in our figure, although a single battery isn't exactly what we are going to recreate in this tutorial.
+
+
+
+# Tutorial
+
+Before jumping on to the tutorial, I would like to make it known that the function can be tweaked to fit accordingly depending on the number of subplots or any other size parameter. Coming to the figure we are going to plot, there are a series of steps that is to be considered which we will follow one by one. The following are those steps:-
+
+1. Outlining what we are going to plot
+2. Import necessary libraries
+3. Write a function to draw the battery
+ - This is the function that will be called to plot the battery chart
+4. Read the data and plot the chart accordingly
+ - We will demonstrate it with an example
+
+
+## Plot Outline
+
+What is our use case?
+
+- We are given a dataset where we have data of Liverpool's players and their minutes played in the last 2 seasons (for whichever club they for played in that time period). We will use this data for our visualisation.
+- The final visualisation is the featured image of this blog post. We will navigate step-by-step as to how we'll create the visualisation.
+
+## Importing Libraries
+
+The first and foremost part is to import the essential libraries so that we can leverage the functions within. In this case, we will import the libraries we need.
+
+```python
+import pandas as pd
+import matplotlib.pyplot as plt
+from matplotlib.path import Path
+from matplotlib.patches import FancyBboxPatch, PathPatch, Wedge
+```
+
+The functions imported from `matplotlib.path` and `matplotlib.patches` will be used to draw lines, rectangles, boxes and so on to display the battery as it is.
+
+## Drawing the Battery - A function
+
+The next part is to define a function named `draw_battery()`, which will be used to draw the battery. Later on, we will call this function by specifying certain parameters to build the figure as we require. The following below is the code to build the battery -
+
+```python
+def draw_battery(fig, ax, percentage=0, bat_ec="grey",
+ tip_fc="none", tip_ec="grey",
+ bol_fc="#fdfdfd", bol_ec="grey", invert_perc=False):
+ '''
+ Parameters
+ ----------
+ fig : figure
+ The figure object for the plot
+ ax : axes
+ The axes/axis variable of the figure.
+ percentage : int, optional
+ This is the battery percentage - size of the fill. The default is 0.
+ bat_ec : str, optional
+ The edge color of the battery/cell. The default is "grey".
+ tip_fc : str, optional
+ The fill/face color of the tip of battery. The default is "none".
+ tip_ec : str, optional
+ The edge color of the tip of battery. The default is "grey".
+ bol_fc : str, optional
+ The fill/face color of the lighning bolt. The default is "#fdfdfd".
+ bol_ec : str, optional
+ The edge color of the lighning bolt. The default is "grey".
+ invert_perc : bool, optional
+ A flag to invert the percentage shown inside the battery. The default is False
+
+ Returns
+ -------
+ None.
+
+ '''
+ try:
+ fig.set_size_inches((15,15))
+ ax.set(xlim=(0, 20), ylim=(0, 5))
+ ax.axis("off")
+ if invert_perc == True:
+ percentage = 100 - percentage
+ # color options - #fc3d2e red & #53d069 green & #f5c54e yellow
+ bat_fc = "#fc3d2e" if percentage <= 20 else "#53d069" if percentage >= 80 else "#f5c54e"
+
+ '''
+ Static battery and tip of battery
+ '''
+ battery = FancyBboxPatch((5, 2.1), 10, 0.8,
+ "round, pad=0.2, rounding_size=0.5",
+ fc="none", ec=bat_ec, fill=True,
+ ls="-", lw=1.5)
+ tip = Wedge((15.35, 2.5), 0.2, 270, 90, fc="none",
+ ec=bat_ec, fill=True,
+ ls="-", lw=3)
+ ax.add_artist(battery)
+ ax.add_artist(tip)
+
+ '''
+ Filling the battery cell with the data
+ '''
+ filler = FancyBboxPatch((5.1, 2.13), (percentage/10)-0.2, 0.74,
+ "round, pad=0.2, rounding_size=0.5",
+ fc=bat_fc, ec=bat_fc, fill=True,
+ ls="-", lw=0)
+ ax.add_artist(filler)
+
+ '''
+ Adding a lightning bolt in the centre of the cell
+ '''
+ verts = [
+ (10.5, 3.1), #top
+ (8.5, 2.4), #left
+ (9.5, 2.4), #left mid
+ (9, 1.9), #bottom
+ (11, 2.6), #right
+ (10, 2.6), #right mid
+ (10.5, 3.1), #top
+ ]
+
+ codes = [
+ Path.MOVETO,
+ Path.LINETO,
+ Path.LINETO,
+ Path.LINETO,
+ Path.LINETO,
+ Path.LINETO,
+ Path.CLOSEPOLY,
+ ]
+ path = Path(verts, codes)
+ bolt = PathPatch(path, fc=bol_fc,
+ ec=bol_ec, lw=1.5)
+ ax.add_artist(bolt)
+ except Exception as e:
+ import traceback
+ print("EXCEPTION FOUND!!! SAFELY EXITING!!! Find the details below:")
+ traceback.print_exc()
+
+```
+
+## Reading the Data
+
+Once we have created the API or function, we can now implement the same. And for that, we need to feed in required data. In our example, we have a dataset that has the list of Liverpool players and the minutes they have played in the past two seasons. The data was collected from Football Reference aka FBRef.
+
+We use the read excel function in the pandas library to read our dataset that is stored as an excel file.
+
+```python
+data = pd.read_excel("Liverpool Minutes Played.xlsx")
+```
+
+Now, let us have a look at how the data looks by listing out the first five rows of our dataset -
+
+```python
+data.head()
+```
+
+
+## Plotting our data
+
+Now that everything is ready, we go ahead and plot the data. We have 25 players in our dataset, so a 5 x 5 figure is the one to go for. We'll also add some headers and set the colors accordingly.
+
+```python
+fig, ax = plt.subplots(5, 5, figsize=(5, 5))
+facecolor = "#00001a"
+fig.set_facecolor(facecolor)
+fig.text(0.35, 0.95, "Liverpool: Player Usage/Involvement", color="white", size=18, fontname="Libre Baskerville", fontweight="bold")
+fig.text(0.25, 0.92, "Data from 19/20 and 20/21 | Battery percentage indicate usage | less battery = played more/ more involved", color="white", size=12, fontname="Libre Baskerville")
+```
+
+We have now now filled in appropriate headers, figure size etc. The next step is to plot all the axes i.e. batteries for each and every player. `p` is the variable used to iterate through the dataframe and fetch each players data. The `draw_battery()` function call will obviously plot the battery. We also add the required labels along with that - player name and usage rate/percentage in this case.
+
+```python
+p = 0 #The variable that'll iterate through each row of the dataframe (for every player)
+for i in range(0, 5):
+ for j in range(0, 5):
+ ax[i, j].text(10, 4, str(data.iloc[p, 0]), color="white", size=14, fontname="Lora", va='center', ha='center')
+ ax[i, j].set_facecolor(facecolor)
+ draw_battery(fig, ax[i, j], round(data.iloc[p, 8]), invert_perc=True)
+ '''
+ Add the battery percentage as text if a label is required
+ '''
+ ax[i, j].text(5, 0.9, "Usage - "+ str(int(100 - round(data.iloc[p, 8]))) + "%", fontsize=12, color="white")
+ p += 1
+```
+
+Now that everything is almost done, we do some final touchup and this is a completely optional part anyway. Since the visualisation is focused on Liverpool players, I add Liverpool's logo and also add my watermark. Also, crediting the data source/provider is more of an ethical habit, so we go ahead and do that as well before displaying the plot.
+
+```python
+liv = Image.open('Liverpool.png', 'r')
+liv = liv.resize((80, 80))
+liv = np.array(liv).astype(np.float) / 255
+fig.figimage(liv, 30, 890)
+fig.text(0.11, 0.08, "viz: Rithwik Rajendran/@rithwikrajendra", color="lightgrey", size=14, fontname="Lora")
+fig.text(0.8, 0.08, "data: FBRef/Statsbomb", color="lightgrey", size=14, fontname="Lora")
+plt.show()
+```
+
+So, we have the plot below. You can customise the design as you want in the `draw_battery()` function - change size, colours, shapes etc
+
+
diff --git a/make_logo.py b/make_logo.py
index 1ba67a5..1f62aa7 100644
--- a/make_logo.py
+++ b/make_logo.py
@@ -1,9 +1,8 @@
import numpy as np
-import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import matplotlib.font_manager
-from matplotlib.patches import Circle, Rectangle, PathPatch
+from matplotlib.patches import Rectangle, PathPatch
from matplotlib.textpath import TextPath
import matplotlib.transforms as mtrans
@@ -131,6 +130,7 @@ def make_logo(height_px, lw_bars, lw_grid, lw_border, rgrid, with_text=False):
return fig, ax
+
make_logo(height_px=110, lw_bars=0.7, lw_grid=0.5, lw_border=1,
rgrid=[1, 3, 5, 7], with_text=True)
plt.savefig("mpl_logo.png")