I have made two plots by using the plotnine
in python. I know that is not really supported to draw subplots(here). I wonder if there is a way to work around and create the subplots in one figure.
I thought of making them a Figure with plotineplot.draw()
and then read it with matplotlib or save them first as a png and then read them with matplotlib and put them together. However, I am not very handy with matplotlib and every try till now is in vain.
Sample plotnine figure:
from plotnine import data
from plotnine import *
plot1 = (ggplot(data.mtcars, aes('wt', 'mpg', color='factor(gear)'))
+ geom_point()
+ stat_smooth(method='lm')
+ facet_wrap('~gear'))
Any help will be very helpful.
A subplot () function is a wrapper function which allows the programmer to plot more than one graph in a single figure by just calling it once.
plotnine is an implementation of a grammar of graphics in Python, it is based on ggplot2. The grammar allows users to compose plots by explicitly mapping data to the visual objects that make up the plot.
Adding a title To add a title, we include the option ggtitle and include the name of the graph as a string argument.
Eventually I created a work around that saves the plots as images and then loads them again and combines them. It is not the fastest or most efficient way but it works fine.
import plotnine as gg
import matplotlib.pyplot as plt
import matplotlib.image as img
import os
import numpy as np
def _check_plotnine_grid(plots_list, figsize):
if not type(plots_list) == list:
raise ValueError('Input plots_list is not a list')
if (not type(figsize) == tuple) or (not len(figsize) == 2):
raise ValueError('Input figsize should be a tuple of length 2')
def plotnine_grid(plots_list, row=None, col=1, height=None, width=None, dpi=500, ratio=None, pixels=10000,
figsize=(12, 8)):
"""
Create a grid of plotnine plots.
Function input
----------
plots_list : a list of plotnine.ggplots
row, col : numerics to indicate in how many rows and columns the plots should be ordered in the grid
defaults: row -> length of plots_list; col -> 1
height, width : the height and width of the individual subplots created by plotnine
can be automatically determined by a combination of dpi, ratio and pixels
dpi : the density of pixels in the image. Default: 500. Higher numbers could lead to crisper output,
depending on exact situation
ratio : the ratio of heigth to width in the output. Standard value is 1.5 x col/row.
Not used if height & width are given.
pixels : the total number of pixels used, default 10000. Not used if height & width are given.
figsize : tuple containing the size of the final output after making a grid, in pixels (default: (1200,800))
Function output
----------
A matplotlib figure that can be directly saved with output.savefig().
"""
_check_plotnine_grid(plots_list, figsize) # Check the input
# Assign values that have not been provided based on others. In the end, height and width should be provided.
if row is None:
row = len(plots_list)
if ratio is None:
ratio = 1.5 * col / row
if height is None and width is not None:
height = ratio * width
if height is not None and width is None:
width = height / ratio
if height is None and width is None:
area = pixels / dpi
width = np.sqrt(area/ratio)
height = ratio * width
# Do actual subplot creation and plot output.
i = 1
fig = plt.figure(figsize=figsize)
plt.autoscale(tight=True)
for image_sel in plots_list: # image_sel = plots_list[i]
image_sel.save('image' + str(i) + '.png', height=height, width=width, dpi=500, verbose=False)
fig.add_subplot(row, col, i)
plt.imshow(img.imread('image' + str(i) + '.png'), aspect='auto')
fig.tight_layout()
fig.get_axes()[i-1].axis('off')
i = i + 1
os.unlink('image' + str(i - 1) + '.png') # os.unlink is basically os.remove but in some cases quicker
fig.patch.set_visible(False)
return fig
Recently, I'm developing patchworklib, which is a subplot manager for matplotlib, inspired by patchwork. It allows you to quickly arrange multiple matplotlib plots including plotnine plots with a tidy layout using only /
and |
operators.
Here is the example code, which you can also run on Google colab:
import patchworklib as pw
from plotnine import *
from plotnine.data import *
g1 = (ggplot(mtcars) + geom_point(aes("mpg", "disp")))
g2 = (ggplot(mtcars) + geom_boxplot(aes("gear", "disp", group = "gear")))
g3 = (ggplot(mtcars, aes('wt', 'mpg', color='factor(gear)')) + geom_point() + stat_smooth(method='lm') + facet_wrap('~gear'))
g4 = (ggplot(data=diamonds) + geom_bar(mapping=aes(x="cut", fill="clarity"), position="dodge"))
g1 = pw.load_ggplot(g1, figsize=(2,3))
g2 = pw.load_ggplot(g2, figsize=(2,3))
g3 = pw.load_ggplot(g3, figsize=(3,3))
g4 = pw.load_ggplot(g4, figsize=(5,2))
g1234 = (g1|g2|g3)/g4
g1234.savefig()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With