Wakan Tanka
Wakan Tanka

Reputation: 8042

plt.setp alternative for subplots or how to set text rotation on x axis for subplot

I have this code in which I am able to control attributes like: range of x axis, title, xlabel, ylabel, legend, grid, rotation of text on x labels:

#!/usr/bin/python
import datetime
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
from matplotlib.dates import DateFormatter
############################################
# generate data
x = np.arange(0,10)
y0 = np.arange(0,10)
y1 = np.random.rand(10)
y2 = np.random.rand(10)
############################################
# initialize (sub)plot(s)
fig, ax = plt.subplots()
############################################
# width of x axis
x_min_index = 0
x_max_index = 3

x_min = x[x_min_index]
x_max = x[x_max_index]
############################################
# create (sub)plot
l, = plt.plot(x,y0, label="plot1a")
l, = plt.plot(x,y1, label="plot1b")
l, = plt.plot(x,y2, label="plot1c")

# (sub)plot - set values
plt.title("plot1")
plt.xlabel('xlabel')
plt.ylabel('ylabel')
plt.legend()
plt.grid()
############################################
# apply for all (sub)plot(s)
plt.subplots_adjust(bottom=0.25)
############################################
# (sub)plot - get values
# plt.axis(x_min, x_max, y_min, y_max)
y_min = plt.axis()[2]
y_max = plt.axis()[3]
print y_min
print y_max
############################################
# (sub)plot - set values
# change only x values
# y values are set to same value
# plt.axis([x_min, x_max, y_min, y_max])

# (sub)plot - set values
# change only x values
plt.xlim(x_min, x_max)
############################################
# (sub)plot - get values
locs, labels = plt.xticks()
print locs
print labels
############################################
# (sub)plot - set values
plt.setp(labels, rotation=45)

plt.show()

This code returns this figure: enter image description here

I want to be able to control all those attributes but create multiple subplots for, my attempt to this is here:

#!/usr/bin/python
import datetime
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
from matplotlib.dates import DateFormatter
############################################
# generate data
x = np.arange(0,10)
y0 = np.arange(0,10)
y1 = np.random.rand(10)
y2 = np.random.rand(10)
############################################
# initialize (sub)plot(s)
fig, axarr = plt.subplots(2)

# http://stackoverflow.com/questions/6541123/improve-subplot-size-spacing-with-many-subplots-in-matplotlib
fig.tight_layout()
############################################
# width of x axis
x_min_index = 0
x_max_index = 3

x_min = x[x_min_index]
x_max = x[x_max_index]
############################################
# 1st (sub)plot
line0 = axarr[0].plot(x,y1, label="plot1a")
line0 = axarr[0].plot(x,y2, label="plot1b")
line0 = axarr[0].legend()
line0 = axarr[0].set_title('plot1')
line0 = axarr[0].set_xlabel('xlabel1')
line0 = axarr[0].set_ylabel('ylabel1')
line0 = axarr[0].grid()
############################################
# 2st (sub)plot
line1 = axarr[1].plot(x,y0, label="plot2", color="red")
line1 = axarr[1].legend()
line1 = axarr[1].set_title('plot2')
line1 = axarr[1].set_xlabel('xlabel2')
line1 = axarr[1].set_ylabel('ylabel2')
line1 = axarr[1].grid()
############################################
# apply for all (sub)plot(s)
plt.subplots_adjust(bottom=0.25)
############################################
# OLD CODE
# (sub)plot - get values
# plt.axis(x_min, x_max, y_min, y_max)
# y_min = plt.axis()[2]
# y_max = plt.axis()[3]
# print y_min
# print y_max

# NEW ALTERNATIVE
l0_x_min, l0_x_max = axarr[0].get_xlim()
l0_y_min, l0_y_max = axarr[0].get_ylim()

l1_x_min, l1_x_max = axarr[1].get_xlim()
l1_y_min, l1_y_max = axarr[1].get_ylim()

print l0_x_min
print l0_x_max
print l0_y_min
print l0_y_max

print l1_x_min
print l1_x_max
print l1_y_min
print l1_y_max
############################################
# OLD CODE
# (sub)plot - set values
# change only x values
# y values are set to same value
# plt.axis([x_min, x_max, y_min, y_max])

# (sub)plot - set values
# change only x values
# plt.xlim(x_min, x_max)

# NEW ALTERNATIVE
axarr[0].set_xlim(x_min, x_max)
############################################
# OLD CODE
# (sub)plot - get values
# locs, labels = plt.xticks()
# print locs
# print labels

# NEW ALTERNATIVE
line0_xticks = axarr[0].get_xticks()
line0_labels = axarr[0].get_xticklabels()
print line0_xticks
print line0_labels

line1_xticks = axarr[1].get_xticks()
line1_labels = axarr[1].get_xticklabels()
print line1_xticks
print line1_labels
############################################
# OLD CODE
# (sub)plot - set values
# plt.setp(labels, rotation=45)

# NEW ALTERNATIVE
############################################
plt.show()

This code returns this figure: enter image description here

This code has an limitation because I cannot set the rotation of labels on x axis. I cannot find the proper method for subplots which will do this. So far I've figured out following methods which corresponds to each other:

PLOT                                    SUBPLOTS
plt.axis()                              axarr[0].get_xlim(), axarr[0].get_ylim()
plt.axis([x_min, x_max, y_min, y_max])  axarr[0].set_xlim(x_min, x_max), axarr[0].set_ylim(y_min, y_max)
plt.xlim(x_min, x_max)                  axarr[0].set_xlim(x_min, x_max)
plt.xticks()                            axarr[0].get_xticks(), axarr[0].get_xticklabels()
plt.setp(labels, rotation=45)           ???
plt.title("plot1")                      axarr[0].set_title('plot1')
plt.grid()                              axarr[0].grid()
plt.legend()                            axarr[0].legend()
plt.xlabel('xlabel')                    axarr[0].set_xlabel('xlabel')
plt.ylabel('xlabel')                    axarr[0].set_ylabel('xlabel')
plt.plot(x,y, label="plot")             axarr[0].plot(x,y, label="plot")

Questions:

  1. Does similar table exists but for all corresponding methods between plots and subplots?
  2. Probably more philosophical question; why two different naming convention?
  3. I've created this table as an trial error by running the code under ipdb, hitting tab, and writing down the familiar names of methods. Is there a better way? I can imagine something that will compare the method return types, arguments etc.
  4. How can I find alternative for any method from one set in another?
  5. Finally, how to rotate x label under subplots?

Upvotes: 6

Views: 12649

Answers (1)

hitzg
hitzg

Reputation: 12701

I will try to answer your questions 1 by 1. But before, you need to understand that there is no difference between a plot and a subplot. Whereas plot usually refers to a single axes in a figure, subplots refer to one of multiple axes in a figure. But to matplotlib they are both axes instances.

plt usually refers to the pyplot module (if imported as import matplotlib.pyplot as plt). This module has many functions, such as the ones you listed and also many plotting functions (e.g., plot, scatter, etc.). However, these are just for convenience and call the corresponding functions on the current axes instance. In a very simplified manner plt.plot is built up like this:

def plot(*args, **kwargs):
    ax = plt.gca()
    return ax.plot(*args, **kwargs)

Unfortunately, the naming is not consistent. But in general the axes method uses set_* and get_*, whereas the plt functions don't.

This means that you could create the first plot that you have posted, with using fig, ax = plt.subplots(1) and then continue to use the axes methods: ax.plot(...), etc.

As to your questions:

  1. I don't think so. But as a general advise, I would try to use the axes methods, as they offer all the functionality, whereas the plt equivalents are limited.
  2. matplotlib was inspired by the plotting functionality of Matlab. Thats where the plt functionality comes from.
  3. I'm not sure if there is a gerenal approach to this. Usually things can be guessed by the names (e.g. plt.title --> ax.set_title). Using matplotlib usually also means to have the documentation at hand.
  4. Again, by experience or by name. But you don't have to. You can also just use one!
  5. plt.setp is a helper function. It sets a property (hence its name) for a list of artists. Thus plt.setp(labels, rotation=45) does something like:

    for i in labels:
        i.set_rotation(45)
    

    The question is just how you get the reference to the list of labels. you can either get them via:

    labels = plt.xticklabels()
    

    or

    labels = ax.get_xticklabels()
    

Upvotes: 9

Related Questions