← Back to list

Python Data Visualisation Made Easy with Plotnine: A How-To Guide

Introduction

Suraj Bansal · 2023-10-06 16:34 · 7 claps · 15.3 min read
#visualization-in-python #plotnine #ggplot #grammer-of-visualization
Open on Medium ↗

Python Data Visualisation Made Easy with Plotnine: A How-To Guide

Introduction

Alright, fellow data enthusiasts, brace yourselves for a wild ride through the data visualisation jungle. 🌐📊 We’re about to dive headfirst into the thrilling world of one of Python’s hottest data viz library: Plotnine. 🐍🚀

In a data-driven era where every pixel counts, Plotnine stands tall as the ‘cool kid’ on the data block, turning your boring spreadsheets into eye-popping visual masterpieces that’ll have your boss saying, ‘Dude, where’d you learn to make those charts?’ 📈💥

Whether you’re a seasoned data wizard or just a newbie in this concrete data jungle, Plotnine is the trusty sidekick you never knew you needed. So, grab your Python fedora 🕵️‍♂️, buckle up, and let’s explore why PlotNine is the swaggering superstar in the world of data visualisation!” 🌟💫🎉

Hold on tight as we embark on this exhilarating journey through Python’s data wilderness, where we’ll uncover the secret sauce behind Plotnine’s prowess. Together, we’ll delve into its unparalleled features and capabilities, all while mastering the art of transforming raw data into spellbinding visual narratives.

Note: If you prefer to follow along with this tutorial in a Jupyter Notebook, we’ve got you covered. You can access it here.

What is Plotnine?

Plotnine is built on the foundation of the widely acclaimed ggplot2 package from the R programming language. It brings the expressive power of the grammar of graphics to Python, allowing users to create complex and customizable plots with ease. The grammar of graphics is a powerful framework that allows you to compose plots by explicitly mapping variables in a dataframe to the visual objects that make up the plot. This approach makes it intuitive to build both simple and complex visualizations, as the grammar provides a consistent and logical structure to the plotting process.

Setting Up Your Environment

Before delving into the world of Plotnine, it’s crucial to ensure your environment is properly configured. To start, you’ll need to install Plotnine and its required components. You can follow the official release installation instructions provided in the Plotnine documentation. Alternatively, if you prefer to work with the latest development version, you can choose the development installation option. Once everything is installed, you’ll be all set to harness the power of Plotnine!” 🚀🌐📦

To start, you can install Plotnine using the popular Python package manager, pip. If you’re planning to run this command within a Jupyter Notebook cell, don’t forget to prepend ‘!’ before the pip command.

pip install plotnine

Building Your First Plot With Plotnine

To begin exploring Plotnine’s potential, we’ll kick things off by constructing a basic plot. We’ll work with the mtcars dataset, a collection of data on different car models. Our objective is to craft a scatter plot that effectively illustrates the connection between a car’s weight (wt) and its miles per gallon (mpg) rating. We’ll add a touch of color to the plot, using it to signify the number of gears each car boasts.

Let’s start by importing the Plotnine package and the supported datasets within the Plotnine library.

from plotnine import *
from plotnine.data import mtcars

Peeking at the initial records of the mtcars dataframe. 🧐📋

mtcars.head()

Coding our first plot 💻

(ggplot(data=mtcars)
 + geom_point(mapping=aes(x="wt", y="mpg", color="factor(gear)"))
 + facet_wrap("~gear"))

When working with Plotnine, your journey starts by invoking the ggplot() function. This function establishes a canvas, a coordinate system, upon which you can add layers. The first argument within ggplot() is dedicated to specifying the dataset for your graph. For instance, ggplot(data=mtcars) creates an initial graph, although it may not appear particularly captivating in its nascent form.

To truly bring your visualization to life, you build upon this foundation by incorporating one or more layers into ggplot(). Here, the geom_point() function takes center stage, adding a layer of points that materialize into a scatterplot. Plotnine offers an array of geom functions, each designed to introduce a unique layer type to your plot. As you progress through this tutorial, you’ll become well-acquainted with these functions.

Within Plotnine’s geom functions, you’ll consistently encounter a mapping argument. This crucial element defines how variables in your dataset correspond to visual attributes. The aes() function always accompanies the mapping argument, and the x and y parameters within aes() specify which dataset variables should be mapped to the x and y axes. Plotnine scours the dataset provided in the data argument, in this case, mtcars, for the variables you’ve mapped. To further enhance our visualization, we incorporate a facet_wrap layer, which divides the plot into distinct panels, each based on the number of gears.

If you find yourself a bit perplexed at this point, don’t worry; we’ll walk through each and every step to ensure you grasp the concepts thoroughly.🚶‍♂️🚶‍♀️🤝

Understanding the Grammer of Graphics

Plotnine’s foundation rests upon the grammar of graphics, a structured framework for crafting visualisations systematically. This grammar comprises distinct components that seamlessly interlock to construct compelling plots. Let’s delve deeper into these components.

Data: The Wellspring of Information

At the heart of this grammar lies the data itself — a fundamental component without which visualization remains a hollow endeavor. Plotnine empowers you to wield diverse data formats, including CSV files, Excel spreadsheets, and SQL databases. Moreover, you can seamlessly generate data within your Python code, leveraging the capabilities of libraries like pandas.

Aesthetics: Define Variables for Each Axis

Aesthetics define how variables are visually represented in the plot. In Plotnine, you can map variables to different aesthetics, such as x and y positions, color, size, and shape. By mapping variables to aesthetics, you can create visual representations that convey information effectively.

Suppose, in the previous plot, you desire to gain insights into the correlation between a car’s miles per gallon (mpg) and its weight 1000lbs (wt), all while visually differentiating by colouring them based on the number of gears (gear). Here’s how you can achieve this.

(ggplot(data=mtcars)
 + geom_point(aes("wt", "mpg", color="factor(gear)"))
)

Note: When we wrap the factor function around the “gear” column, it signifies that we want to treat this variable as a factor type rather than numeric. Alternatively, you can achieve the same result by first converting this column to a string type. This way, you won't need to factor it separately.

In the plot above, it’s evident that cars with both high weight and a low number of gears — specifically, 3 gears in this instance — tend to exhibit remarkably low average miles per gallon (mpg).

In the example above, we associated the “gear” variable with the color aesthetic, but it’s worth noting that we could have just as easily linked “gear’”to the size aesthetic in a similar fashion. In such a scenario, the size of each point would precisely indicate the number of gears.

(ggplot(data=mtcars)
 + geom_point(aes("wt", "mpg", size="factor(gear)"))
)

Notably, this approach may not be very intuitive, as it can make the plot challenging to interpret. Additionally, you might have received a warning stating “Using size for a discrete variable is not advised”. But I hope you got the gist of what size aesthetic can do.

Curious to explore the effects of experimenting with the shape and alpha aesthetics? Feel free to give it a shot, or for detailed examples, you can refer to the notebook available in the GitHub repository shared above. In a nutshell, the alpha aesthetic governs the transparency of the points, while the shape aesthetic dictates the shape of the points.

What if our aim is to assign the same color to all data points? Here’s how you can achieve that.

(ggplot(data=mtcars)
+ geom_point(aes("wt", "mpg"), color='red')
)

In this scenario, color isn’t being used to represent any specific data variable; instead, it’s employed solely to modify the plot’s visual appearance. To manually define an aesthetic, you can specify it by name as an argument within your geom function, placing it outside of the aes() function. When doing this, it’s important to select an appropriate value for the chosen aesthetic.

Facets: Plot Subsets of Data Into Panels in the Same Plot

Facets provide a means to divide a single plot into separate panels, each showcasing a distinct portion of the dataset. This becomes especially valuable when your goal is to compare various groups or categories within your data. Plotnine offers the facet_wrap function, enabling the creation of panels organized by a categorical variable.

In the plot below, we’ve applied faceting based on the “gear” variable rather than just colouring by it. The result is not only more aesthetically pleasing but also mirrors the initial graph we created. The difference now lies in our deeper understanding of the underlying mechanics. Superb progress!🌟

(ggplot(data=mtcars)
 + geom_point(aes("wt", "mpg", color="factor(gear)"))
 + facet_wrap("gear")
)

Additionally, you can employ the facet_grid function to construct panels based on combinations of two categorical variables. Let’s experiment with faceting by both “gear” and “am” (representing the mode of transmission), where “0” signifies manual and “1” signifies automatic transmission.

(ggplot(data=mtcars)
 + geom_point(aes("wt", "mpg", color="factor(gear)"))
 + facet_grid("gear~am")
)

Oops, we’ve stumbled upon an interesting observation: there are no data points for cars with 3 gears and automatic transmission, and cars with manual transmission and 5 gears. Nevertheless, this exercise has provided us with valuable insight into faceting by two variables.

Themes: Improve the Look of Your Visualisation

Themes offer a means to tailor the global aesthetics of your plot. Plotnine offers a selection of predefined themes, including options like “theme_gray” and “theme_minimal”, designed to deliver a unified and visually pleasing appearance (refer documentation for the list of available themes). Alternatively, you have the flexibility to craft your own personalized themes by adjusting elements like colors, fonts, and grid lines. Opting for the right theme empowers you to create a visually appealing visualisation that effectively conveys your intended message. 🎨

(ggplot(data=mtcars)
 + geom_point(aes("wt", "mpg"))
 + theme_dark()
)

Geometric Objects: Where Data Meets Artistry!

Geometric objects in PlotNine take your visualisations beyond the ordinary, injecting an extra dose of pizzazz and insight into your plots. They’re your secret sauce for turning data into stunning narratives. For instance, consider the mighty geom_smooth. This gem can transform your plot into a predictive powerhouse, adding trend lines that tell captivating stories about your data. So, let's dive into the enchanting world of geometric objects and see how they can elevate your visualisations to the next level!

(ggplot(data=mtcars)
 + geom_point(aes("wt", "mpg"))
 + geom_smooth(aes("wt", "mpg"), color="blue", method='lm')
)

But here’s the kicker: we’ve primarily been using lm as the method for plotting linear trend lines. However, Plotnine doesn’t stop there. It offers a treasure trove of other methods that apply intricate smoothing techniques. Give lowess a whirl, and you’ll be amazed by the results. Plus, there’s an added bonus: by default, you get a shaded region representing the standard error around the trend line, adding a layer of depth and precision to your visual narrative. 📊📈

Note: geom_smooth harnesses the power of off-the-shelf smoothening techniques. For more details, be sure to consult the documentation. 📚🔍

However, this approach leads to some redundancy in our code. Consider a scenario where you wish to switch the x-axis variable from “wt” to “qsec”. You’d have to make changes in two separate locations, which could potentially result in oversight. To streamline this process and prevent such repetition, you can instead pass a set of mappings directly to ggplot(). Plotnine interprets these mappings as global, applying them uniformly to each geom within the graph. In essence, the following code will generate an identical plot to the previous example.

(ggplot(data=mtcars, mapping=aes(x="wt", y="mpg"))
 + geom_point()
 + geom_smooth(color="blue", method="lm")
)

In case you’ve already spotted the usage of two geoms, pat yourself on the back! In reality, you can incorporate as many geoms as necessary, as long as your plot remains coherent and uncluttered. Plotnine boasts a rich variety of geom functions to suit various needs. For more details, please refer to the documentation.

Before we conclude this fantastic section, let’s experiment with a couple more geom functions. Our next venture involves crafting a bar plot that depicts the number of cars grouped by the cyl variable, representing the number of cylinders in the data.

cars_cnt_by_cyl = mtcars.groupby("cyl").agg(count = ("name", "count")).reset_index()

(ggplot(data=cars_cnt_by_cyl) 
 + geom_bar(aes(x="factor(cyl)", y="count"), stat="identity")
)

You can attain the same outcome by employing a statistical function available in Plotnine.

(ggplot(data=mtcars) 
 + stat_count(aes(x="factor(cyl)"))
)

It’s truly remarkable to witness how functions like stat_countautonomously perform calculations, relieving you of the need to write additional code for the same purpose. You will discover an abundance of stat functions conveniently located on the same page as geoms, expanding the realm of incredible flexibility that Plotnine offers.

Labels and Annotations: Where Information Finds Its Voice

In the above plot, the labels could be a bit perplexing, especially to an outsider. Terms like factor(cyl) might not immediately resonate with everyone. Fortunately, you can enhance the clarity of your labels using the labs function.

(ggplot(data=cars_cnt_by_cyl) 
 + geom_bar(aes(x="factor(cyl)", y="count"), stat="identity")
 + labs(x='no of cylinders', y='car count')
)

Another powerful tool in Plotnine’s arsenal is geom_text(), which enables you to overlay textual information onto your plots. This can be incredibly useful for labelling data points, highlighting key observations, or adding context to your visualisations. There are several ways to incorporate geom_text() into your plots. You can use it to annotate specific points by providing the x and y coordinates along with the text to display. Alternatively, you can use aesthetic mappings within aes() to dynamically label data points based on a variable which comes from the custom dataframe. Additionally, you have the flexibility to customize the appearance of the text, adjusting font size, color, and position to ensure your annotations are both informative and visually appealing. Whether you're adding data labels, annotations, or captions, geom_text() is a valuable tool for enhancing the storytelling aspect of your visualizations. For simpler use cases, you can also consider using the annotate() function, which provides a straightforward method for adding text annotations. Let’s start with a simple use case where we will attempt to add text that represents the mean mileage of all the cars tp the plot.

mean = round(mtcars['mpg'].mean(), 2)
(ggplot(mtcars, aes(x="wt", y="mpg"))
 + geom_point()
 + annotate("text", x=3.5, y=30, label=f"mean mileage: {mean}", color="red")
)

Please take note that in the code above, x and y denote the coordinates at which you intend to place the text. The remainder of the code is relatively straightforward.

Now, let’s venture into a more intricate scenario where we aim to address a sophisticated use case: adding the names of cars with the best mileage (mpg) within each gear group.

from adjustText import adjust_text
best_mpg_by_gear = (mtcars
                    .sort_values("mpg", ascending=True)
                    .groupby("gear")
                    .first()
                    )
(ggplot(mtcars, aes(x="wt", y="mpg"))
 + geom_point(aes(color="factor(gear)"))
 + geom_text(aes(label="name"), data=best_mpg_by_gear, adjust_text={"expand_points": (2.5, 2.5), "arrowprops":dict(arrowstyle="->", color="black")})
)

To utilize geom_text, you'll need a dataframe that includes the variable you intend to add to your plot. In our case, we're adding the “name” of cars. To enhance the visual presentation of text labels, we employ the adjust_text library, which optimizes the positioning of text to prevent overlaps and clutter. For detailed information about using adjust_text, please refer to the documentation. It's worth noting that you'll need to install adjust_text separately to harness its capabilities. You can easily do this by running pip install adjustTextin your Python environment.

To summarise this section, whether you’re adding data labels, annotations, or captions, geom_text() and annotate() are valuable tools for enhancing the storytelling aspect of your visualisations.

Extra Insights and Treats: The Bonus Section

Coordinate Systems

Coordinate systems merge the two position scales to establish a 2D location. Suppose you wish to flip the bar plot by interchanging the x and y axes; here’s the way to accomplish that

(ggplot(data=cars_cnt_by_cyl) 
 + geom_bar(aes(x="factor(cyl)", y="count"), stat="identity")
 + labs(x="no of cylinders", y="car count")
 + coord_flip()
)

Adjusting Scales

You can fine-tune your scales in PlotNine using functions like scale_x_continuous and scale_y_continuous. These tools offer the flexibility to customize the appearance and range of your plot’s axes, allowing you to achieve precise control over the visual representation of your data.

(ggplot(mtcars, aes(x="wt", y="mpg"))
 + geom_point(aes(color="factor(gear)"))
 + scale_y_continuous(breaks=range(10,36,2))
)

Keep in mind that Plotnine offers a plethora of scale functions to cater to various data types and needs. For instance, scale_color_brewer lets you apply crafted color palettes to your plots, while scale_fill_gradient enables smooth color transitions. When working with time series data, scale_x_datetime comes to the rescue, simplifying the task of handling date and time values on your x-axis with precision and ease.

Zooming

You can take command of your plot’s visual scope by applying specific ranges using xlim and ylim. These parameters allow you to zoom in on particular sections of your data, providing a closer look at the details that matter most. By defining the desired limits for the x and y-axes, you can focus your audience’s attention on specific data points or trends, effectively enhancing the granularity of your visualization. This level of control over the visual narrative ensures that your insights are clear and impactful.

(ggplot(mtcars, aes(x="wt", y="mpg"))
 + geom_point(aes(color="factor(gear)"))
 + xlim(3,4)
)

Saving plots

Saving your meticulously crafted plots in Plotnine is a breeze. Once you’ve honed your visualization to perfection, you can preserve it for future reference or sharing. Plotnine provides a variety of options for saving your plots in popular image formats such as png, jpeg, or svg. Whether it’s for including in reports, publications, or presentations, saving your plots ensures that your data insights are always at your fingertips, ready to be shared with the world.

density_plot = (ggplot(mtcars, aes(x="mpg"))
                + geom_density(color="red")
               )
density_plot.save("mpg_density.png")

Mastering Plotnine: A Plotful Recap

Let’s wrap up our journey by summarizing our newfound knowledge through the creation of a bonus plot. In this final exercise, we’ll bring together the various techniques we’ve explored — geometric objects, labels, scales — to craft a comprehensive and visually striking visualization. This bonus plot serves as a testament to your Plotnine prowess and showcases the skills you’ve acquired throughout this enlightening adventure. So, let’s dive in and conclude our exploration with a flourish!

For our next visualization adventure, we’ll delve into the txhousing dataset available in the Plotnine library. Before we proceed, I recommend referring to the dataset's documentation to get acquainted with the data dictionary. Our objective here is to craft an insightful time series plot depicting sales trends in various cities. Given the abundance of data encompassing numerous cities, we'll streamline our focus by extracting the top three and bottom three cities based on total sales. This approach allows us to explore and compare the sales dynamics of select cities, providing a concise yet illuminating perspective on real estate trends.

import pandas as pd
from mizani.breaks import date_breaks
from plotnine.data import txhousing

# Modifying Existing Date column 
txhousing["date"] = pd.to_datetime(txhousing[["year", "month"]].assign(day=1), format="%Y-%m-%d")

# Get Total Sales for Every City and Fetch Top 3 and Bottom 3
sales_by_cities = (txhousing
                    .groupby("city")
                    .agg(sales=("sales", "sum"))
                    .sort_values("sales", ascending=False)
                    .reset_index()
                  )
cities = list(sales_by_cities.head(3)["city"]) + list(sales_by_cities.tail(3)["city"])
sample_data = txhousing[(txhousing["city"].isin(cities))]

# Create a plot
(
    ggplot(sample_data, aes(x="date", y="sales"))
    + geom_point(aes(color="median"))
    + geom_smooth(method="lowess")
    + scale_x_datetime(breaks=date_breaks("3 years"))    
    + facet_wrap("city", scales="free", ncol=3)
    + scale_color_continuous()
    + theme(figure_size=(20, 10), subplots_adjust={"wspace": 0.25, "hspace": 0.25})
)

I will take this opportunity to share some intriguing findings from the data. As expected, the median price in the real estate market has exhibited a general upward trend over time, a common phenomenon in this industry. What’s particularly noteworthy is the similarity in sales trends among Austin, Dallas, and Houston, despite differences in scale. Conversely, Kerrville and South Padre Island have experienced a distinct upward trend in sales. On the other hand, the San Marcos area saw a unique period between 2002 and 2004 marked by no sales activity, followed by a relatively steady pattern, albeit with a slight decline. These insights offer just a glimpse into the rich tapestry of real estate dynamics within the dataset. However, there’s much more valuable information waiting to be extracted through visualisation. I encourage you to delve further, explore different plots, and uncover meaningful insights that can provide a comprehensive understanding of the real estate landscape.

Parting Words: The PlotNine Adventure

Wrapping up our exploration of Plotnine, I want to express my heartfelt gratitude to the creators of ggplot2 in R and Plotnine in Python. Their dedication and ingenuity have opened up new horizons in the realm of data visualisation, enriching our ability to extract meaning from data and share it with the world.

As we conclude, let me emphasise that this post is not intended as a comparison between R and Python or Plotnine and any other visualisation library. It’s a celebration of the rich functionality of Plotnine, one of my personal favourites among visualisation tools. Every programming language and library has its own strengths and merits, and the choice between them often depends on specific needs and preferences.

Throughout this journey, we’ve embarked on a visual adventure through the world of data visualisation in Python, discovering the power and versatility of Plotnine. From understanding the essentials of creating stunning plots to mastering the art of customising every aspect of our visualisations, we’ve delved into geometric objects, scales, labels, facets, and more. We’ve witnessed how Plotnine can breathe life into data, making it more than just numbers and figures — it’s a dynamic story waiting to be told.

As we conclude this chapter of our data visualization journey, remember that Plotnine is your artistic canvas, and the data is your muse. The possibilities are limitless, and with each plot, you have the opportunity to tell a unique story. So, armed with the knowledge and tools we’ve acquired, I encourage you to continue exploring, experimenting, and uncovering the hidden narratives within your data. So, here’s to your future data-driven discoveries and the stories you’ll share with the world.

References

  1. https://plotnine.readthedocs.io/en/v0.12.3/
  2. https://realpython.com/ggplot-python/
  3. https://jeroenjanssens.com/plotnine/

메타데이터
post_id
f71e321bdef1
slug
python-data-visualisation-made-easy-with-plotnine-a-how-to-guide-f71e321bdef1
url
https://medium.com/@suraj_bansal/python-data-visualisation-made-easy-with-plotnine-a-how-to-guide-f71e321bdef1
canonical_url
https://medium.com/@suraj_bansal/python-data-visualisation-made-easy-with-plotnine-a-how-to-guide-f71e321bdef1
author_url
https://medium.com/@suraj_bansal
status
ok
fetched_at
2026-07-23 14:22:47