Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

plotnine - Any work around to have two plots in the same figure and print it

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.

like image 265
George Sotiropoulos Avatar asked Sep 14 '18 12:09

George Sotiropoulos


People also ask

What method is use to display multiple graphs on one figure?

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.

What is Plotnine Python?

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.

How do I add a title to Plotnine?

Adding a title To add a title, we include the option ggtitle and include the name of the graph as a string argument.


2 Answers

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
like image 149
George Sotiropoulos Avatar answered Nov 14 '22 23:11

George Sotiropoulos


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()

enter image description here

like image 41
Hideto Avatar answered Nov 14 '22 23:11

Hideto