Matplotlib legend too wide - python

I am plotting a graph with six curves, where each curve has a label. The legend is placed below the graph, but it's wider than the figure. Please see code and screenshot.
#!/usr/bin/python
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(10)
fig = plt.figure()
ax = plt.subplot(111)
for i in xrange(6):
ax.plot(x, i * x, label='long_long_name = %ix$' % i)
#ax.legend()
ax.legend(loc='upper center', bbox_to_anchor=(0.5, -0.05),
fancybox=True, shadow=True, ncol=3)
fig.tight_layout(rect=[0, 0.1, 1, 0.95])
plt.show()
How to configure the proper graph and legend size/position?
I looked at Legend Guide and this post, but couldn't figure out how to make the legend narrower.

I would simply recommend you change either the legend font size or the plot figure size. For doing so:
fig = plt.figure(figsize=(x_size, y_size))
Try using x_size = 8 and y_size = 5.
Or
ax.legend(loc='upper center', bbox_to_anchor=(0.5, -0.05),
fancybox=True, shadow=True, ncol=3, fontsize = size)
Try using size = 8.

Related

Left aligning markers in legend with legend title using matplotlib

I'm trying to make a plot with Matplotlib, and I would look to have the legend on the top left. Without a legend title this is working fine with the code below, but when I add a legend title which is longer than the legend labels, the markers shift.
Is there any way I can prevent this and have them all align to the left?
import numpy as np
import matplotlib.pyplot as plt
# Data
x = np.arange(0, 4 * np.pi ,0.1)
y = np.sin(x)
fig, axs = plt.subplots(1, 2, figsize=(8, 4))
# Working fine without legend title
axs[0].plot(x, y, label='sin')
axs[0].legend(title='', loc='lower left', bbox_to_anchor=(0,1), facecolor='white', edgecolor='white', framealpha=1)
# Position shifts when using long legend title
axs[1].plot(x, y, label='sin')
axs[1].legend(title='Some longer title', loc='lower left', bbox_to_anchor=(0,1), facecolor='white', edgecolor='white', framealpha=1)
plt.show()
For me, your code does something similar to what you want to have by me simply changing the bbox_to_anchor argument from the axs[1].legend() command.
Now it reads: bbox_to_anchor=(-0.1,1) and it produces the below. Of course, you can change the first value to -0.15 or so if you want it to be more to the left.
Full code:
import numpy as np
import matplotlib.pyplot as plt
# Data
x = np.arange(0, 4 * np.pi ,0.1)
y = np.sin(x)
fig, axs = plt.subplots(1, 2, figsize=(8, 4))
# Working fine without legend title
axs[0].plot(x, y, label='sin')
axs[0].legend(title='', loc='lower left', bbox_to_anchor=(0,1), facecolor='white', edgecolor='white', framealpha=1)
# Position shifts when using long legend title
axs[1].plot(x, y, label='sin')
axs[1].legend(title='Some longer title', loc='lower left', bbox_to_anchor=(-0.1,1), facecolor='white', edgecolor='white', framealpha=1)
plt.show()
I found a workaround in a still unresolved issue on GitHub. Apparently the default alignment is "center", which can be changed like this.
axs[1].get_legend()._legend_box.align = "left"

How do you controle zorder across twinx in matplotlib?

I'm trying to control the zorder of different plots across twinx axes. How can I get the blue noisy plots to appear in the background and the orange smoothed plots to appear in the foreground in this plot?
from matplotlib import pyplot as plt
import numpy as np
from scipy.signal import savgol_filter
random = np.random.RandomState(0)
x1 = np.linspace(-10,10,500)**3 + random.normal(0, 100, size=500)
x2 = np.linspace(-10,10,500)**2 + random.normal(0, 100, size=500)
fig,ax1 = plt.subplots()
ax1.plot(x1, zorder=0)
ax1.plot(savgol_filter(x1,99,2), zorder=1)
ax2 = ax1.twinx()
ax2.plot(x2, zorder=0)
ax2.plot(savgol_filter(x2,99,2), zorder=1)
plt.show()
Similar to this thread, though not ideal, this is an approach using twiny along with twinx.
# set up plots
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax3 = ax1.twiny()
ax4 = ax2.twiny()
# background
ax1.plot(x1)
ax2.plot(x2)
# smoothed
ax3.plot(savgol_filter(x1,99,2), c='orange')
ax4.plot(savgol_filter(x2,99,2), c='orange')
# turn off extra ticks and labels
ax3.tick_params(axis='x', which='both', bottom=False, top=False)
ax4.tick_params(axis='x', which='both', bottom=False, top=False)
ax3.set_xticklabels([])
ax4.set_xticklabels([])
# fix zorder
ax1.set_zorder(1)
ax2.set_zorder(2)
ax3.set_zorder(3)
ax4.set_zorder(4)
plt.show()
Output:

ax.grid overwrites ticks labels when spine is in centre

When using ax.grid() and moving the spines to the middle of the plot, the grid lines go over the axes labels. Any way to stop this and move the axes labels to "front"?
EDIT: It is the ticks labels (the numbers) I'm interested in fixing, not the axis label, which can be easily moved.
EDIT: made the MWE and image match exactly
EDIT: matplotlib version 2.0.0
#!/usr/bin/env python
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = plt.gca()
ax.minorticks_on()
ax.grid(b=True, which='major', color='k', linestyle='-',alpha=1,linewidth=1)
ax.grid(b=True, which='minor', color='k', linestyle='-',alpha=1,linewidth=1)
x = np.linspace(-5,5,100)
y = np.linspace(-5,5,100)
plt.plot(x,y)
plt.yticks([-5,-4,-3,-2,-1,0,1,2,3,4,5])
ax.spines['left'].set_position(('data', 0))
plt.show()

Creating sparklines using matplotlib in python

I am working on matplotlib and created some graphs like bar chart, bubble chart and others.
Can some one please explain with an example what is difference between line graph and sparkline graph and how to draw spark line graphs in python using matplotlib ?
for example with the following code
import matplotlib.pyplot as plt
import numpy as np
x=[1,2,3,4,5]
y=[5,7,2,6,2]
plt.plot(x, y)
plt.show()
the line graph generated is the following:
But I couldn't get what is the difference between a line chart and a spark lien chart for the same data. Please help me understand
A sparkline is the same as a line plot but without axes or coordinates. They can be used to show the "shape" of the data in a compact way.
You can cram several line plots in the same figure just by using subplots and changing properties of the resulting Axes for each subplot:
data = np.cumsum(np.random.rand(1000)-0.5)
data = data - np.mean(data)
fig = plt.figure()
ax1 = fig.add_subplot(411) # nrows, ncols, plot_number, top sparkline
ax1.plot(data, 'b-')
ax1.axhline(c='grey', alpha=0.5)
ax2 = fig.add_subplot(412, sharex=ax1)
ax2.plot(data, 'g-')
ax2.axhline(c='grey', alpha=0.5)
ax3 = fig.add_subplot(413, sharex=ax1)
ax3.plot(data, 'y-')
ax3.axhline(c='grey', alpha=0.5)
ax4 = fig.add_subplot(414, sharex=ax1) # bottom sparkline
ax4.plot(data, 'r-')
ax4.axhline(c='grey', alpha=0.5)
for axes in [ax1, ax2, ax3, ax4]: # remove all borders
plt.setp(axes.get_xticklabels(), visible=False)
plt.setp(axes.get_yticklabels(), visible=False)
plt.setp(axes.get_xticklines(), visible=False)
plt.setp(axes.get_yticklines(), visible=False)
plt.setp(axes.spines.values(), visible=False)
# bottom sparkline
plt.setp(ax4.get_xticklabels(), visible=True)
plt.setp(ax4.get_xticklines(), visible=True)
ax4.xaxis.tick_bottom() # but onlyt the lower x ticks not x ticks at the top
plt.tight_layout()
plt.show()
A sparkline graph is just a regular plot with all the axis removed. quite simple to do with matplotlib:
import matplotlib.pyplot as plt
import numpy as np
# create some random data
x = np.cumsum(np.random.rand(1000)-0.5)
# plot it
fig, ax = plt.subplots(1,1,figsize=(10,3))
plt.plot(x, color='k')
plt.plot(len(x)-1, x[-1], color='r', marker='o')
# remove all the axes
for k,v in ax.spines.items():
v.set_visible(False)
ax.set_xticks([])
ax.set_yticks([])
#show it
plt.show()

Bars width are wrong using log scale of x-axis

I need log scale x-axis. Here is my code:
plt.bar(critical_pressures_reversed, mercury_volume_scaled, bottom = 0, log = True, linewidth=0, align="center",width=.1)
plt.title("Mercury intrusion", fontsize=20)
plt.xlabel("Critical Pressure $P_c \, [kPa]$", fontsize=16)
plt.ylabel("Mercury volume $V_m \, [\mu m^3]$", fontsize=16)
plt.grid(b=True, which='major', color='black', linestyle='-', linewidth=1)
plt.grid(b=True, which='minor', color='gray', linestyle='-', linewidth=0.15)
frame = plt.gca()
figure = plt.gcf()
frame.set_xscale('log')
frame.set_axisbelow(True)
figure.set_size_inches(12, 6)
plt.savefig("intrusion_6n_press.png", dpi=300, bbox_inches='tight')
plt.close()
Resulting plot:
How to force pyplot to draw bars with constant width?
I am using matplotlib (1.4.2)
You could use plt.fill but the bar width should change based on the log. For instance, for a random dataset, the following lines:
import matplotlib.pyplot as plt
import numpy as np
x, y = np.random.randint(1,51,10), np.random.randint(1,51,10)
width = 1e-2
for i in range(len(x)):
plt.fill([10**(np.log10(x[i])-width), 10**(np.log10(x[i])-width), 10**(np.log10(x[i])+width), 10**(np.log10(x[i])+width)],[0, y[i], y[i], 0], 'r', alpha=0.4)
plt.bar(x,y, bottom = 0, log = True, linewidth=0, align="center",width=.1, alpha=0.4)
will produce the figure below. Everything you need to do is to choose a proper width parameter.

Categories

Resources