How to rotate axis label and hide some of them? - python

I was trying to plot a time series and its differentiation.
However, I have two problems with the x axis label:
it's not rotating;
there is too many months and too little space in the canvas.
How can I rotate all labels and hide a few dates?
I can't show the data because of confidentiality. But it's basically a (numeric) column with the series and the (date) index.
This is what I've done so far:
import numpy as np, pandas as pd
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
import matplotlib.pyplot as plt
plt.rcParams.update({'figure.figsize':(9,7), 'figure.dpi':120})
# Original Series
fig, axes = plt.subplots(3, 2, sharex=True);
axes[0, 0].plot(df.teste);
axes[0, 0].set_title('Original Series');
axes[0,0].set_xticklabels(df.index,rotation=90)
plot_acf(df.teste, ax=axes[0, 1]);
# 1st Differencing
axes[1, 0].plot(df.teste.diff());
axes[1, 0].set_title('1st Order Differencing');
plot_acf(df.teste.diff().dropna(), ax=axes[1, 1]);
# 2nd Differencing
axes[2, 0].plot(df.teste.diff().diff());
axes[2, 0].set_title('2nd Order Differencing');
axes[2,0].set_xticklabels(df.index,rotation=90)
plot_acf(df.teste.diff().diff().dropna(), ax=axes[2, 1]);
This is the output:

Check this code:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 1000)
y = np.sin(x)
fig, ax = plt.subplots(1, 2, figsize = (8, 4))
ax[0].plot(x, y, 'r-', lw = 2)
ax[0].set_xticks(np.arange(0, 10, 0.25))
ax[1].plot(x, y, 'r-', lw = 2)
ax[1].set_xticks(np.arange(0, 10, 1))
locs, labels = plt.xticks()
plt.setp(labels, rotation = 90)
plt.show()
which gives me this plot as an example:
As you can see, both graph have the same options, but in the second one (on the right side) I set:
ax[1].set_xticks(np.arange(0, 10, 1))
to space the xticks in order to remove some of them, and
locs, labels = plt.xticks()
plt.setp(labels, rotation = 90)
to rotate their orientations.

Related

Difference between plotting a graph with/without axes with/without the same axes name inside a subplot

What is the difference between plotting a graph with/without axes with/without the same name inside a subplot? They all output the same graph.
Plotting a graph with axes with the same name inside a subplot:
from matplotlib import pyplot as plt
plt.figure(figsize=(10,5))
ax = plt.subplot(1, 2, 1)
ax.plot(temperature, months)
ax = plt.subplot(1, 2, 2)
ax.plot(temperature, flights_to_hawaii, 'o')
Plotting a graph with axes with the different names inside a subplot:
from matplotlib import pyplot as plt
plt.figure(figsize=(10,5))
ax1 = plt.subplot(1, 2, 1)
ax1.plot(temperature, months)
ax2 = plt.subplot(1, 2, 2)
ax2.plot(temperature, flights_to_hawaii, 'o')
Plotting a graph without axes inside a subplot:
from matplotlib import pyplot as plt
plt.figure(figsize=(10,5))
plt.subplot(1, 2, 1)
plt.plot(temperature, months)
plt.subplot(1, 2, 2)
plt.plot(temperature, flights_to_hawaii, 'o')
This is actually a great question and the first comment points to a good answer.
The summary is this:
They are both the same for simple plots where there is one line and one axis.
The difference is best highlighted here with this piece of code where we can see the usage of two separate axis (with different colours and scales). ax1 and ax2 will be different.
import numpy as np
from matplotlib import pyplot as plt
# generate some data
time = np.arange(0., 10., 0.2)
velocity = np.zeros_like(time, dtype=float)
distance = np.zeros_like(time, dtype=float)
g = 9.8 # m/s^2
velocity = g * time
distance = 0.5 * g * np.power(time, 2)
# create a plot with TWO acis
fig, ax1 = plt.subplots()
ax1.set_ylabel("distance (m)", color="blue")
ax1.set_xlabel("time")
ax1.plot(time, distance, "blue")
ax1.set_yticks(np.linspace(*ax1.get_ybound(), 10))
ax1.tick_params(axis="y", labelcolor="blue")
ax1.xaxis.grid()
ax1.yaxis.grid()
ax2 = ax1.twinx() # create another y-axis sharing a common x-axis
ax2.set_ylabel("velocity (m/s)", color="green")
ax2.set_xlabel("time")
ax2.tick_params(axis="y", labelcolor="green")
ax2.plot(time, velocity, "green")
ax2.set_yticks(np.linspace(*ax2.get_ybound(), 10))
fig.set_size_inches(7,5)
fig.set_dpi(100)
fig.legend(["Distance", "Velocity"])
plt.show()
Which gives this:
Here we have controlled the two separate axis: ax1 and ax2 and plotted on the same chart.

NonUniformImage with nonlinear axes

I have an image in a nonuniform grid, and want to plot it with one of the axes scaled logarithmically. This is possible for imshow, however that requires regularly spaced data. I can plot my irregularly gridded data with NonUniformImage, however setting ax.set_xscale('log') only has an effect on the axis, not the image itself.
Is this possible to achieve with NonUniformImage, or even possible at all? Here is some code that shows what I mean (top row is imshow, bottom is NonUniformImage).
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.image import NonUniformImage
# Linear x array for cell centers:
x = np.linspace(1, 10, 10)
# Highly nonlinear x array:
x2 = x**3
# Linear y-array
y = np.linspace(1, 10, 10)
z = np.sqrt(x[np.newaxis, :]**2 + y[:, np.newaxis]**2)
fig, axs = plt.subplots(nrows=2, ncols=2)
fig.subplots_adjust(bottom=0.07, hspace=0.3)
# Uniform Grid, linear x-axis
ax = axs[0, 0]
im = ax.imshow(z, extent=(1, 10, 1, 10), aspect='auto',origin='lower')
ax.set_title("Uniform Grid, linear x-axis")
# Uniform Grid, log x-axis (image changes)
ax = axs[0, 1]
im = ax.imshow(z, extent=(1, 10, 1, 10),aspect='auto',origin='lower')
ax.set_xscale('log')
ax.set_title('Uniform Grid, log x-axis')
# Correct ticklabel formatting
from matplotlib.ticker import StrMethodFormatter, NullFormatter
ax.xaxis.set_major_formatter(StrMethodFormatter('{x:.0f}'))
ax.xaxis.set_minor_formatter(NullFormatter())
# NonUniform Grid, linear x-axis
ax = axs[1, 0]
im = NonUniformImage(ax, interpolation='nearest', extent=(1, 1000, 1, 10))
im.set_data(x2, y, z)
ax.images.append(im)
ax.set_xlim(1, 1000)
ax.set_ylim(1, 10)
ax.set_title('NonUniform Grid, lin x-axis')
# NonUniform Grid, logarithmic x-axis (this doesn't work as intended)
ax = axs[1, 1]
im = NonUniformImage(ax, interpolation='nearest', extent=(1, 1000, 1, 10))
im.set_data(x2, y, z)
ax.images.append(im)
ax.set_xlim(1, 1000)
ax.set_ylim(1, 10)
ax.set_xscale('log')
ax.set_title('NonUniform Grid, log x-axis')
plt.show()

Difference between axis('equal') and axis('scaled') in matplotlib

In the reference, they are described as:
axis('equal')
changes limits of x or y axis so that equal increments of x and y have the same length; a circle is
circular.:
axis('scaled')
achieves the same result by changing the dimensions of the plot box instead of the axis data limits.:
But I did not understand the part 'by changing the dimensions of the plot box'.
So I compared directly
import numpy as np
import matplotlib.pyplot as plt
plt.close('all')
x = np.array(np.linspace(-np.pi, np.pi))
y = np.sin(x)
ax1 = plt.subplot(2, 1, 1)
ax1 = plt.plot(x, y)
plt.axis('scaled')
ax1 = plt.subplot(2, 1, 2)
plt.plot(x, y)
plt.axis('equal')
There is only a slight difference that the width is shorter when plotted with plt.axis('scaled').
How can I know the difference better?
I think the difference becomes more apparent, if you use different data.
import numpy as np
import matplotlib.pyplot as plt
x = np.array(np.linspace(-np.pi, np.pi))
y = np.sin(x)*np.pi
ax1 = plt.subplot(2, 1, 1)
ax1 = plt.plot(x, y)
plt.axis('scaled')
ax1 = plt.subplot(2, 1, 2)
plt.plot(x, y)
plt.axis('equal')
plt.show()
So the difference is if the axes around the plot are changed according to the aspect, or if they stay the same as in a usual subplot and are scaled such, that the aspect of the plot data is equal.

Axes Subplot y size

I have two subplots that share the x-axes. The first one has data and a fit function, in the second one is the difference between the data and the fit function. In the figure both subplots have the same y axis size (in pixels). Now i want the y axis of the data and the fit to be bigger than the axis of the errors. my code is the following:
import matplotlib.pyplot as plt
f, axarr = plt.subplots(2, sharex=True,figsize=(15, 12))
axarr[0].scatter(x, data , facecolors='none', edgecolors='crimson')
axarr[0].plot(x, fit, color='g',linewidth=1.5)
axarr[0].set_ylim([18,10])
axarr[1].plot(x,data-fit,color='k',linewidth=width)
axarr[1].set_ylim([-0.4,0.4])
yticks[-1].label1.set_visible(False)
plt.subplots_adjust(hspace=0.)
is there any code that sets the size of the second plot?
Take a look at this example, using gridspec. I believe it is exactly what you want. Below is the example adopted for your case. Edited to also share the x-axis
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import gridspec
# generate some data
x = np.arange(0, 10, 0.2)
y = np.sin(x)
# plot it
fig = plt.figure(figsize=(8, 6))
gs = gridspec.GridSpec(2, 1, height_ratios=[3, 1])
ax0 = plt.subplot(gs[0])
ax1 = plt.subplot(gs[1], sharex=ax0) # <---- sharex=ax0 will share ax1 with ax2
ax0.plot(x, y)
ax1.plot(y, x)
plt.show()
Or even simpler by following Hagnes answer in the first link:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 10, 0.2)
y = np.sin(x)
f, (a0, a1) = plt.subplots(2,1, gridspec_kw = {'height_ratios':[1, 3]}, sharex=True) # <---- sharex=True will share the xaxis between the two axes
a0.plot(x, y)
a1.plot(y, x)
plt.show()

Matplotlib different size subplots

I need to add two subplots to a figure. One subplot needs to be about three times as wide as the second (same height). I accomplished this using GridSpec and the colspan argument but I would like to do this using figure so I can save to PDF. I can adjust the first figure using the figsize argument in the constructor, but how do I change the size of the second plot?
As of matplotlib 3.6.0, width_ratios and height_ratios can now be passed directly as keyword arguments to plt.subplots and subplot_mosaic, as per What's new in Matplotlib 3.6.0 (Sep 15, 2022).
f, (a0, a1) = plt.subplots(1, 2, width_ratios=[3, 1])
f, (a0, a1, a2) = plt.subplots(3, 1, height_ratios=[1, 1, 3])
Another way is to use the subplots function and pass the width ratio with gridspec_kw
matplotlib Tutorial: Customizing Figure Layouts Using GridSpec and Other Functions
matplotlib.gridspec.GridSpec has available gridspect_kw options
import numpy as np
import matplotlib.pyplot as plt
# generate some data
x = np.arange(0, 10, 0.2)
y = np.sin(x)
# plot it
f, (a0, a1) = plt.subplots(1, 2, gridspec_kw={'width_ratios': [3, 1]})
a0.plot(x, y)
a1.plot(y, x)
f.tight_layout()
f.savefig('grid_figure.pdf')
Because the question is canonical, here is an example with vertical subplots.
# plot it
f, (a0, a1, a2) = plt.subplots(3, 1, gridspec_kw={'height_ratios': [1, 1, 3]})
a0.plot(x, y)
a1.plot(x, y)
a2.plot(x, y)
f.tight_layout()
You can use gridspec and figure:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import gridspec
# generate some data
x = np.arange(0, 10, 0.2)
y = np.sin(x)
# plot it
fig = plt.figure(figsize=(8, 6))
gs = gridspec.GridSpec(1, 2, width_ratios=[3, 1])
ax0 = plt.subplot(gs[0])
ax0.plot(x, y)
ax1 = plt.subplot(gs[1])
ax1.plot(y, x)
plt.tight_layout()
plt.savefig('grid_figure.pdf')
I used pyplot's axes object to manually adjust the sizes without using GridSpec:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.2)
y = np.sin(x)
# definitions for the axes
left, width = 0.07, 0.65
bottom, height = 0.1, .8
bottom_h = left_h = left+width+0.02
rect_cones = [left, bottom, width, height]
rect_box = [left_h, bottom, 0.17, height]
fig = plt.figure()
cones = plt.axes(rect_cones)
box = plt.axes(rect_box)
cones.plot(x, y)
box.plot(y, x)
plt.show()
Probably the simplest way is using subplot2grid, described in Customizing Location of Subplot Using GridSpec.
ax = plt.subplot2grid((2, 2), (0, 0))
is equal to
import matplotlib.gridspec as gridspec
gs = gridspec.GridSpec(2, 2)
ax = plt.subplot(gs[0, 0])
so bmu's example becomes:
import numpy as np
import matplotlib.pyplot as plt
# generate some data
x = np.arange(0, 10, 0.2)
y = np.sin(x)
# plot it
fig = plt.figure(figsize=(8, 6))
ax0 = plt.subplot2grid((1, 3), (0, 0), colspan=2)
ax0.plot(x, y)
ax1 = plt.subplot2grid((1, 3), (0, 2))
ax1.plot(y, x)
plt.tight_layout()
plt.savefig('grid_figure.pdf')
In a simple way, different size sub plotting can also be done without gridspec:
plt.figure(figsize=(12, 6))
ax1 = plt.subplot(2,3,1)
ax2 = plt.subplot(2,3,2)
ax3 = plt.subplot(2,3,3)
ax4 = plt.subplot(2,1,2)
axes = [ax1, ax2, ax3, ax4]
A nice way of doing this was added in matplotlib 3.3.0, subplot_mosaic.
You can make a nice layout using an "ASCII art" style.
For example
fig, axes = plt.subplot_mosaic("ABC;DDD")
will give you three axes on the top row and one spanning the full width on the bottom row like below
A nice thing about this method is that the axes returned from the function is a dictionary with the names you define, making it easier to keep track of what is what e.g.
axes["A"].plot([1, 2, 3], [1, 2, 3])
You can also pass a list of lists to subplot_mosaic if you want to use longer names
fig, axes = plt.subplot_mosaic(
[["top left", "top centre", "top right"],
["bottom row", "bottom row", "bottom row"]]
)
axes["top left"].plot([1, 2, 3], [1, 2, 3])
will produce the same figure

Categories

Resources