Matplotlib plt object getting shared across plots - matplotlib

I have 2 functions , one plots a time series line, other plots the autocrrelation.
def plotacorr(dfasst):
# Plot autocorrelation
plt.acorr(dfasst, maxlags=3)
# Add labels to autocorrelation plot
plt.title('Autocorrelation of Asset Balances with previous Months Balances')
plt.xlabel('Lag in Months')
plt.ylabel('Autocorrelation')
# Display the autocorrelation plot
#plt.show()
plt.savefig('C:/acorr_assets.jpeg')
def plottrend(df_acctsmry2):
fig, ax = plt.subplots()
fmt = '${x:,.0f}'
tick = mtick.StrMethodFormatter(fmt)
ax.yaxis.set_major_formatter(tick)
df_acctsmry2.plot(x='REPORTING_DATE',ax=ax,figsize=(20,12))
plt.xticks(fontsize=20)
plt.yticks(fontsize=20)
plt.xlabel('REPORTING_DATE', fontsize=18)
#plt.show()
plt.savefig('C:/output.jpeg')
I first call plottrend, followed by plotacorr
But it seems that somehow the plt object is getting sharedbetween the 2 plots, so in the autocorrelation plot, I see the same result as plottrend.

Uncomment the plt.show() on each function, that should do it (or call a plt.show() between the call to functions).

Related

Add a secondary label to a plot x-axis for events

I have an ax.stackplot showing population of different groups over time. The x-axis is time and the y-axis is population. I am showing time at major labels 1 year and minor labels 1 month, however, changes in the data occur more frequently at "events". I'd like to show labels for these events along the x-axis, kind of how I have it sketched out in the image here:
I've attempted adding a second axis with plt.axes(), but this second axis is overwriting the ticks of my first axis for some reason. Does anyone have any suggestions for how to accomplish this?
Thank you!
If you don't have too many points, I think the best way to do this is adding text to your axes using ax.text:
from matplotlib import pyplot
import matplotlib
import numpy as np
# Random plot
t = np.arange(0.0, 2.0, 0.01)
s = 1 + np.sin(2 * np.pi * t)
fig, ax = pyplot.subplots()
ax.plot(t, s)
# ax.text(x, y, text, rotation)
ax.text(0, -0.35, "Event 1", rotation=90) # rotation=90 is easier to read, for me
ax.text(0.5, -0.35, "Event 2", rotation=-90) # opposite rotation
ax.text(0.75, -0.35, "Event 3", rotation=-90)
# This gives some space at the bottom of the figure
# so that the text is visible
fig.subplots_adjust(bottom=0.2)
pyplot.show()
Result:
Check the Axes.text documentation for more info.
Thank you for the responses, I was able to come up with a solution based on your suggestions. The solution involves using ax.twiny() to create a second axes object, and then specifying the second x-axis data points and labels. Below is a simple example for those interested:
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
# Create some meaningless data for testing.
x = np.arange(0, 10)
y = np.full(10, len(x))
# Set up figure and set axes parameters.
fig = plt.figure(num=None, figsize=(10, 8), dpi=80, facecolor='w', edgecolor='k')
ax = plt.axes()
ax.xaxis.set_minor_locator(ticker.FixedLocator([1, 3, 5, 7, 9]))
# Get a second axes (for secondary labels) and set parameters.
axl = ax.twiny()
axl.tick_params(axis='x', bottom=True, labelbottom=True, labeltop=False, top=False, length=15, colors=[.5,.5,.5])
# Plot data on primary axes
ax.bar(x, y)
interval = ax.xaxis.get_view_interval()
# Set label properties on secondary axes (for secondary labels)
axl.xaxis.set_view_interval(*interval)
axl.xaxis.set_ticklabels(['a', 'b'])
axl_loc = ticker.FixedLocator([0.5, 4.75])
axl.xaxis.set_major_locator(axl_loc)
plt.show()

Matplolib subplots what is the purpose of the fig and axs variables

Consider the following code:
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(19680801)
data = np.random.randn(2, 100)
fig, axs = plt.subplots(2, 2, figsize=(5, 5))
axs[0, 0].hist(data[0])
axs[1, 0].scatter(data[0], data[1])
axs[0, 1].plot(data[0], data[1])
axs[1, 1].hist2d(data[0], data[1])
plt.show()
I am aware that in order to create subplots you ned to write the line:
fig, axs = plt.subplots(2, 2, figsize=(5, 5)
However my question is concerning the meaning of this line, as in what does it actually achieve by producing the variables fig and axs, and why later on we use ax[0,0] as opposed to fig[0,0]
fig describes the figure as a whole, but the axs in this case refers to all the subplots within the figure. Since you defined 2 rows and 2 columns of subplots, you call each subplot with axs[0,0] for the top left and axs[1,1] for the bottom right subplot. In order to change the size of a subplot you have to change the size of the overall figure in which the subplots are embedded.
The difference is subtle, but multiple subplots or just one subplot can be found in a figure. So to plot a line you would do this on the subplot axes and not on the figure.

Why is matplotlib's plt.draw() not updating xticklabels?

I would like to modify my xticklabels before plotting, but plt.draw() does not seem to update the values. How can I get these values updated prior to plotting with plt.show()?
import numpy as np
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
num_bins = 50
x = 100 + 15 * np.random.randn(10000)
# the histogram of the data
n, bins, patches = plt.hist(x, num_bins, facecolor='green', alpha=0.5)
ax.set_ylabel('Number')
ax.set_xlabel('Distance')
ax.set_title('Distance vs. Number')
# Draw the canvas, otherwise the labels won't be positioned and have values
ax.get_figure().canvas.draw()
fig.canvas.draw()
plt.draw()
# Tweak spacing to prevent clipping of ylabel
plt.subplots_adjust(left=0.15)
for xl in ax.get_xticklabels(): print xl # Values not set
plt.show()
for xl in ax.get_xticklabels(): print xl # Values set
You do not need plt.draw() to achieve the desired outcome.
The labels are in fact updated beofre you plot them - so your figure shows the intent. However, reading the correct labels from the axis does not work until after the plot was created.
Consider this example (add a line to assign only two xticks and labels):
plt.xticks([20,135],['one', 'two'])
for xl in ax.get_xticklabels(): print xl # Values not set
plt.show()
for xl in ax.get_xticklabels(): print xl # Values set
The output you see is:
Text(0,0,u'one')
Text(0,0,u'two')
This plot opens:
Text(20,0,u'one')
Text(135,0,u'two')
The actual location - though assigned - cannot be read from the plot before it was created.
This plot was created without the following lines of code from your example:
ax.get_figure().canvas.draw()
fig.canvas.draw()
plt.draw()

Matplotlib Subplots -- Get Rid of Tick Labels Altogether

Is there a way to get rid of tick labels altogether when creating an array of subplots in Matplotlib? I am currently needing to specify each plot based on the row and column of a larger data set to which the plot corresponds. I've attempted to use the ax.set_xticks([]) and the similar y-axis command, to no avail.
I recognize that it's probably an unusual request to want to make a plot with no axis data whatsoever, but that's what I need. And I need it to automatically apply to all of the subplots in the array.
You have the right method. Maybe you are not applying the set_xticks to the correct axes.
An example:
import matplotlib.pyplot as plt
import numpy as np
ncols = 5
nrows = 3
# create the plots
fig = plt.figure()
axes = [ fig.add_subplot(nrows, ncols, r * ncols + c) for r in range(0, nrows) for c in range(0, ncols) ]
# add some data
for ax in axes:
ax.plot(np.random.random(10), np.random.random(10), '.')
# remove the x and y ticks
for ax in axes:
ax.set_xticks([])
ax.set_yticks([])
This gives:
Note that each axis instance is stored in a list (axes) and then they can be easily manipulated. As usual, there are several ways of doing this, this is just an example.
Even more concise than #DrV 's answer, remixing #mwaskom's comment, a complete and total one-liner to get rid of all axes in all subplots:
# do some plotting...
plt.subplot(121),plt.imshow(image1)
plt.subplot(122),plt.imshow(image2)
# ....
# one liner to remove *all axes in all subplots*
plt.setp(plt.gcf().get_axes(), xticks=[], yticks=[]);
Note: this must be called before any calls to plt.show()
The commands are the same for subplots
fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)
ax1.plot([1,2])
ax1.tick_params(
axis='x', # changes apply to the x-axis
which='both', # both major and minor ticks are affected
bottom='off', # ticks along the bottom edge are off
top='off', # ticks along the top edge are off
labelbottom='off' # labels along the bottom edge are off)
)
plt.draw()
You can get rid of the default subplot x and y ticks with simply running the following codes:
fig, ax = plt.subplots()
ax.xaxis.set_major_locator(plt.NullLocator())
ax.yaxis.set_major_locator(plt.NullLocator())
for i in range(3):
ax = fig.add_subplot(3, 1, i+1)
...
Just by adding the 2 aforementioned lines just after fig, ax = plt.subplots() you can remove the default ticks.
One can remove the xticks or yticks by
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
If you want to turn off also the spines, so having no axis at all, you can use:
ax.spines['bottom'].set_visible(False)
ax.spines['left'].set_visible(False)
And if you want to turn everything off at once, use:
ax.axis("off")

Copying axis limits from one subplot ('equal' aspect) to another

In a figure with 2x2 subplots, I need both the subplots on the right to share the x-axis, but the ones on the left not to share their axis. In addition, I need the subplot that is determining the x-axis limits to have 'equal' aspect ratio. I tried this:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(2, 2, figsize=(12, 9))
# Subplot [0,1]
ax[0,1].axis('equal')
ax[0,1].plot(...)
[xmin01, xmax01, ymin01, ymax01] = self.ax[0,1].axis()
# Subplot [1,1]
ax[1,1].plot(...)
ax[1,1].set_xlim(left=xmin01, right=xmax01)
This is not working: the limits of the x-axis returned by axis() are near the data limits and are not the real limits shown in the graphed subplot. Changing the position of ax[0,1].axis('equal') after the plot command has no effect. Any idea?
Looking into the pyplot source code I discovered that axis('equal') is calling the method set_aspect(). This latter method is modifying the variable self._aspect but it is not further updating anything related! Then, I looked for and found the method that is really updating the aspect ratio: it is named apply_aspect(). So, it doesn't seem very elegant, but at least my problem is solved as shown:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(2, 2, figsize=(12, 9))
# Subplot [0,1]
ax[0,1].axis('equal')
ax[0,1].plot(...)
ax[0,1].apply_aspect()
[xmin01, xmax01, ymin01, ymax01] = self.ax[0,1].axis()
# Subplot [1,1]
ax[1,1].plot(...)
ax[1,1].set_xlim(left=xmin01, right=xmax01)