Saving plot from ipython notebook produces a cut image - python

I am plotting a plot with 2 ylabels using ipython notebook and the image looks good when visualized inside the notebook.
Here is how I do it:
import matplotlib.pyplot as plt
fig, ax1 = plt.subplots()
plt.title('TITLE')
plt.xlabel('X')
plt.plot(x, y1, '-', color='blue', label='SNR')
ax1.set_ylabel('y1', color='blue')
for tl in ax1.get_yticklabels():
tl.set_color('blue')
ax2 = ax1.twinx()
plt.plot(x, y2, '--', color='red', label='Ngal')
ax2.set_ylabel('y2', color='red')
for tl in ax2.get_yticklabels():
tl.set_color('red')
The problem is that when I try to save it with the command
plt.savefig('output.png', dpi=300)
since the output will be an image which is cut on the right side: basically I don't see the right ylabel if the right numbers are large.

By default, matplotlib leaves very little room for x and y axis labels and tick labels, therefore you need to adjust the figure to include more padding. Fortunately this could not be easier to do. Before you call savefig, you can call call
fig.tight_layout()
plt.savefig('output.png', dpi=300)
Alternatively, you can pass bbox_inches='tight' to savefig which will also adjust the figure to include all of the x and y labels
plt.savefig('output.png', dpi=300, bbox_inches='tight')

Related

Setting different colors for markers and lines in matplotlib and show them in legend

I would like to create a plot, consisting of lines and markers, but using different colors for both. My approach was to use two averlapped plots:
#!/usr/bin/env python3
import matplotlib.pyplot as plt
fig,ax1 = plt.subplots()
x=[0,1,2,3]
y=[10,20,40,80]
ax1.plot(x, y,color='#FF0000', alpha=0.5, linewidth=2.2,label='Example line',zorder=9)
ax1.scatter(x, y ,marker='o',s=80,color='black',alpha=1,label='Example marker',zorder=10)
ax1.set_ylim([0,150])
ax1.set_xlim([0,5])
ax1.legend(loc='upper right')
plt.show()
plt.close()
Output:
The problem here is that, naturally, line (----) and marker (X) are showed separately in legend.
Would you know a way to show both marker and line together in legend, that is to say, in a composed line and marker (---X---) label?
Perhaps just specify your marker attributes in the first plot call... e.g.
ax1.plot(x, y,color='#FF0000', linewidth=2.2, label='Example line',
marker='o', mfc='black', mec='black', ms=10)

How to decide which bars are plotted on top/last in overlay of 2 Pandas bar plots where one plot uses alpha [duplicate]

In pyplot, you can change the order of different graphs using the zorder option or by changing the order of the plot() commands. However, when you add an alternative axis via ax2 = twinx(), the new axis will always overlay the old axis (as described in the documentation).
Is it possible to change the order of the axis to move the alternative (twinned) y-axis to background?
In the example below, I would like to display the blue line on top of the histogram:
import numpy as np
import matplotlib.pyplot as plt
import random
# Data
x = np.arange(-3.0, 3.01, 0.1)
y = np.power(x,2)
y2 = 1/np.sqrt(2*np.pi) * np.exp(-y/2)
data = [random.gauss(0.0, 1.0) for i in range(1000)]
# Plot figure
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx()
ax2.hist(data, bins=40, normed=True, color='g',zorder=0)
ax2.plot(x, y2, color='r', linewidth=2, zorder=2)
ax1.plot(x, y, color='b', linewidth=2, zorder=5)
ax1.set_ylabel("Parabola")
ax2.set_ylabel("Normal distribution")
ax1.yaxis.label.set_color('b')
ax2.yaxis.label.set_color('r')
plt.show()
Edit: For some reason, I am unable to upload the image generated by this code. I will try again later.
You can set the zorder of an axes, ax.set_zorder(). One would then need to remove the background of that axes, such that the axes below is still visible.
ax2 = ax1.twinx()
ax1.set_zorder(10)
ax1.patch.set_visible(False)

PyPlot move alternative y axis to background

In pyplot, you can change the order of different graphs using the zorder option or by changing the order of the plot() commands. However, when you add an alternative axis via ax2 = twinx(), the new axis will always overlay the old axis (as described in the documentation).
Is it possible to change the order of the axis to move the alternative (twinned) y-axis to background?
In the example below, I would like to display the blue line on top of the histogram:
import numpy as np
import matplotlib.pyplot as plt
import random
# Data
x = np.arange(-3.0, 3.01, 0.1)
y = np.power(x,2)
y2 = 1/np.sqrt(2*np.pi) * np.exp(-y/2)
data = [random.gauss(0.0, 1.0) for i in range(1000)]
# Plot figure
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx()
ax2.hist(data, bins=40, normed=True, color='g',zorder=0)
ax2.plot(x, y2, color='r', linewidth=2, zorder=2)
ax1.plot(x, y, color='b', linewidth=2, zorder=5)
ax1.set_ylabel("Parabola")
ax2.set_ylabel("Normal distribution")
ax1.yaxis.label.set_color('b')
ax2.yaxis.label.set_color('r')
plt.show()
Edit: For some reason, I am unable to upload the image generated by this code. I will try again later.
You can set the zorder of an axes, ax.set_zorder(). One would then need to remove the background of that axes, such that the axes below is still visible.
ax2 = ax1.twinx()
ax1.set_zorder(10)
ax1.patch.set_visible(False)

figure/subplot confusion with regard to x/y limits

I am trying to set the x and y limits on a subplot but am having difficultly. I suspect that the difficultly stems from my fundamental lack of understanding of how figures and subplots work. I have read these two questions:
question 1
question 2
I tried to use that approach, but neither had any effect on the x and y limits. Here's my code:
fig = plt.figure(figsize=(9,6))
ax = plt.subplot(111)
ax.hist(sub_dict['b'], bins=30, color='r', alpha=0.3)
ax.set_ylim=([0,200])
ax.set_xlim=([0,100])
plt.xlabel('x')
plt.ylabel('y')
plt.title('title')
plt.show()
I am confused as whether to apply commands to fig or ax? For instance .xlabel and .title don't seem to be available for ax. Thanks
Why don't you do:
Ax = fig.add_subplot(111)
import matplotlib.pyplot as plt
import numpy as np
mu, sigma = 100, 15
x = mu + sigma*np.random.randn(100)
fig = plt.figure(figsize=(9,6))
ax = fig.add_subplot(111)
ax.hist(x, bins=30, color='r', alpha=0.3)
ax.set_ylim=(0, 200)
ax.set_xlim=(0, 100)
plt.xlabel('x')
plt.ylabel('y')
plt.title('title')
plt.show()
I've run your code on some sample code, and I'm attaching the screenshot. I'm not sure this is the desired result but this is what I got.
For a multiplot, where you have subplots in a single figure, you can have several xlabel and one title
fig.title("foobar")
ax.set_xlabel("x")
This is explained in great detail here on the Matplotlib website.
You in your case, use a subplot for just a single plot. This is possible, just doesn't make a lot of sense. Plots like the one below are supposed to be created with the subplot feature:
To answer your question: you can set the x- and y-limits on a per-subplot and per-axis basis by simply addressing the respective subplot directly (ax for subplot 1) and them calling the set_xlabel member function to set the label on the x-axis.
EDIT
For your updated question:
Use this code as inspiration, I had to generate some data on my own so no guarantees:
import matplotlib.pyplot as plt
plt.hist(sub_dict['b'], bins=30, color='r', alpha=0.3)
plt.ylim(0,200)
plt.xlim(0,100)
plt.xlabel('x')
plt.ylabel('y')
plt.title('title')
plt.show()
Bit more googling and I got the following that has worked:
sub_dict = subset(data_dict, 'b', 'a', greater_than, 10)
fig = plt.figure(figsize=(9,6))
ax = fig.add_subplot(111)
ax.hist(sub_dict['b'], bins=30, color='r', alpha=0.3)
plt.ylim(0,250)
plt.xlim(0,100)
plt.xlabel('x')
plt.ylabel('y')
plt.title('title')
plt.show()

Why I get additional empty plot in matplotlib?

I have the following code in my IPython notebook:
import matplotlib.pyplot as plt
plt.setp(plt.xticks()[1], rotation=45)
plt.figure(figsize=(17, 10)) # <--- This is the problematic line!!!!!!!!!!!!!
plt.plot_date(df['date'],df['x'], color='black', linestyle='-')
plt.plot_date(df['date'],df['y'], color='red', linestyle='-')
plt.plot_date(df['date'],df['z'], color='green', linestyle='-')
In the above example df is pandas data frame.
Without the marked line (containig figsize) the plot is too small. With the mentioned line I have an increased image as I want but before it I have an additional empty plot.
Does anybody know why it happens an how this problem can be resolved?
Try reversing the first two lines after the import. plt.setp is opening a figure.
here's how I would do this:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(17, 10))
plt.setp(plt.xticks()[1], rotation=45)
ax.plot_date(df['date'],df['x'], color='black', linestyle='-')
ax.plot_date(df['date'],df['y'], color='red', linestyle='-')
ax.plot_date(df['date'],df['z'], color='green', linestyle='-')
It's a good practice to explicitly create and operate on your your Figure and Axes objects.

Categories

Resources