I'm having a difficulty controlling the zorder of the elements of a polar plot superimposed on a cartesian plot.
Consider this example:
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(1, 1, marker='*', s=2000, c='r', zorder=2)
ax2 = fig.add_axes(ax.get_position(), frameon=False, polar=True)
ax2.scatter(1., 0.1, marker='*', s=1000, c='b', zorder=1)
plt.xlim(0, 2)
plt.ylim(0, 2)
plt.show()
The result is:
It looks like matplotlib ignored the zorder of scatter plots. I would expect the red star to be on top of the blue one.
Could you please explain what I'm doing wrong here?
I found one question, which is kind of similar to mine, but concerns ticklines and grids instead. Maybe it's the same bug?
P.S. I'm running Linux x86_64 with Python 2.7.6 and matplotlib 1.3.1.
The problem is that you are setting the z-order of the marks on different axes ax and ax2 but since ax2 has a greater z-order all the plots in it will be on top of ax. One solution could be to set a higher z-order to ax but then you need to make the background transparent or set frameon=False (and that's maybe not desirable for your case), this is a demonstration of what I'm saying:
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(1, 1, marker='*', s=2000, c='r', zorder=2)
ax2 = fig.add_axes(ax.get_position(), frameon=False, polar=True)
ax2.scatter(1., 0.1, marker='*', s=1000, c='b', zorder=1)
ax.set_zorder(3)
ax.patch.set_facecolor('none')
#ax.patch.set_visible(False)
plt.xlim(0, 2)
plt.ylim(0, 2)
plt.show()
Plot:
Related
I am working with matplotlib subplots. This is the skeleton of my code:
import matplotlib.pyplot as plt
from matplotlib import gridspec
plt.close('all')
f, axarr = plt.subplots(2, sharex=True,)
gs = gridspec.GridSpec(2, 1, height_ratios=[3, 1])
axarr[0] = plt.subplot(gs[0])
axarr[1] = plt.subplot(gs[1])
axarr[0].set_ylim([-10,10])
axarr[1].set_ylim([-1,1])
plt.tight_layout()
f.subplots_adjust(hspace=0)
plt.show()
This is the output that I get from this code.
As one can see, in the left y-axis, I get ytick labels which overlap on top of each other and 'weird' y-axis tick labels (0) in the y-axis on the right hand side. How can I solve this? I will be thankful to have help here.
Those are the x labels of the upper subplot which are only partially hidden by the lower subplot. Turn them off if you like,
axarr[0].set_xticklabels([])
In order for the ticklabels not to overlap you may change the ylimits of the axes,
axarr[0].set_ylim([-10.5,10])
axarr[1].set_ylim([-1,1.2])
I have a plot with a legend whose height is bigger than the axes height (like the result of the code below). Now, I would like to stretch the axes height in such a way that it ends at the legend's end.
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0., 10.5, 0.5)
fig, ax = plt.subplots()
for c in range(0, 20):
ax.plot(t, t*c/2, label='func {}'.format(c))
ax.legend(bbox_to_anchor=(1.01, 1), loc=2, borderaxespad=0.)
What I would like to have is something like that (it does not matter, if the bottom of the grid or the bottom of the ticks ends with the legend)
I tried to reach my goal with appending following code but without any effect (legend_h is always =1.0):
legend_h = ax.get_legend().get_window_extent().height
ax_height = ax.get_window_extent().height
if ax_height < legend_h:
fig.set_figheight(legend_h/ax_height * fig.get_figheight())
Further on, it would be nice if I could only change the properties of the axes itself and not of the whole figure.
Edit:
My main purpose is to run the figure generation from a script but I also tried it in the Ipython notebook. One try was also to temporarily store the figure before getting the heights and setting the new figure height. But that also did not produce correct results.
I think you can achieve what you want by simply adding plt.draw() to what you already have, e.g.
fig, ax = plt.subplots()
for c in range(0, 20):
ax.plot(t, t*c/2, label='func {}'.format(c))
ax.legend(bbox_to_anchor=(1.01, 1), loc=2, borderaxespad=0.)
plt.draw()
legend_h = ax.get_legend().get_window_extent().height
ax_height = ax.get_window_extent().height
if ax_height < legend_h:
fig.set_figheight(legend_h/ax_height * fig.get_figheight())
Update: Also, you can try (which should work from a script, and based on this answer):
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0., 10.5, 0.5)
fig, ax = plt.subplots()
for c in range(0, 20):
ax.plot(t, t*c/2, label='func {}'.format(c))
lgd = ax.legend(bbox_to_anchor=(1.01, 1), loc=2, borderaxespad=0.)
fig.tight_layout()
fig.savefig('script.png', bbox_extra_artists=(lgd,), bbox_inches='tight')
In principle, #Matt Pitkin's answer shows the right approach. However, rather than set_figheight one would use set_size_inches. The calculation also needs to include the figure margins, which can be obtained from the fig.subplotpars.
Additionally to the height, we can also set the width of the figure, such that the legend is included.
import matplotlib.pyplot as plt
import numpy as np
t = np.linspace(0,10); c=20
fig, ax = plt.subplots()
for c in range(0, 20):
ax.plot(t, t*c/2, label='func {}'.format(c))
bbox = (1.01,1)
ax.legend(bbox_to_anchor=bbox, loc=2, borderaxespad=0.)
fig.canvas.draw()
legend_h = ax.get_legend().get_window_extent().height
ax_height = ax.get_window_extent().height
if ax_height < legend_h:
w,h = fig.get_size_inches()
h =legend_h/fig.dpi/(fig.subplotpars.top-fig.subplotpars.bottom)
fig.set_size_inches(w,h)
# set width as well
w,h = fig.get_size_inches()
r = ax.get_legend().get_window_extent().width/fig.dpi/w
fig.subplots_adjust(right=1-1.1*r)
plt.show()
The picture below is when running this as a script.
In Ipython or jupyter, the figure will automatically be cropped or expanded, because the png shown is automatically saved using the bbox_inches='tight' option. Therefore, the width adjustment is not necessary for a jupyter notebook.
I wish to produce a series of 2D histograms using pyplot.
I want to be able to specify the size and scale (or aspect ratio) of the generated image. In addition to this, I would like to remove the ticks and axes labels and borders.
This does not seem to be possible in the arguments to the plt.hist2d() method.
Rather than share my (rather complex) code, I post the pyplot demo script. If what I want is possible with this code, then it will be possible with mine.
import matplotlib.pyplot as plt
import numpy as np
x = np.random.randn(1000)
y = np.random.randn(1000) + 5
# normal distribution center at x=0 and y=5
plt.hist2d(x, y, bins=40)
plt.show()
Thanks for your help in advance.
Specifying the aspect alone will not help, you need the figure size in width or height in addition.
To get rid of the margins you can use subplots_adjust. And in order to turn the axes off you need axis("off").
import matplotlib.pyplot as plt
import numpy as np
x = np.random.randn(1000)
y = np.random.randn(1000) + 5
width=4 # inch
aspect=0.8 # height/width ratio
height = width*aspect
plt.figure(figsize=(width, height ))
plt.hist2d(x, y, bins=40)
plt.subplots_adjust(bottom=0, top=1, left=0, right=1)
plt.gca().axis("off")
plt.show()
The figsize should do what you want:
plt.figure(figsize=(20,10))
plt.hist2d(x, y, bins=40)
plt.show()
The following snippet shows how to quickly and easily
set the figure size (and implicitly the aspect ratio)
disable the axis bounding box and tick annotations
set the axis to fill the whole figure (removes borders)
save the resulting figure to an image file.
.
import matplotlib.pyplot as plt
import numpy as np
x = np.random.randn(1000)
y = np.random.randn(1000) + 5
plt.figure(figsize=[7, 2]) # set figure dimensions to weird but illustrative aspect ratio
plt.hist2d(x, y, bins=40)
plt.box(False) # disable axis box
plt.xticks([]) # no x axis ticks
plt.yticks([]) # no y axis ticks
plt.subplots_adjust(left=0, right=1, top=1, bottom=0) # remove borders
plt.savefig('output.png')
plt.show()
In python matplotlib, there are two convention used to draw plots:
1.
plt.figure(1,figsize=(400,8))
2.
fig,ax = plt.subplots()
fig.set_size_inches(400,8)
Both have different ways of doing the same thing. eg defining axis label.
Which one is better to use? What is the advantage of one over the other?
Or what is the "Good Practice" for plotting a graph using matplotlib?
Although #tacaswell already gave a brief comment on the key difference. I will add more to this question only from my own experience with matplotlib.
plt.figure just creates a Figure (but with no Axes in it), this means you have to specify the ax to place your data (lines, scatter points, images). Minimum code should look like this:
import numpy as np
import matplotlib.pyplot as plt
# create a figure
fig = plt.figure(figsize=(7.2, 7.2))
# generate ax1
ax1 = fig.add_axes([0.1, 0.1, 0.5, 0.5])
# generate ax2, make it red to distinguish
ax2 = fig.add_axes([0.6, 0.6, 0.3, 0.3], fc='red')
# add data
x = np.linspace(0, 2*np.pi, 20)
y = np.sin(x)
ax1.plot(x, y)
ax2.scatter(x, y)
In the case of plt.subplots(nrows=, ncols=), you will get Figure and an array of Axes(AxesSubplot). It is mostly used for generating many subplots at the same time. Some example code:
def display_axes(axes):
for i, ax in enumerate(axes.ravel()):
ax.text(0.5, 0.5, s='ax{}'.format(i+1), transform=ax.transAxes)
# create figures and (2x2) axes array
fig, axes = plt.subplots(2, 2, figsize=(7.2, 7.2))
# four (2*2=4) axes
ax1, ax2, ax3, ax4 = axes.ravel()
# for illustration purpose
display_axes(axes)
Summary:
plt.figure() is usually used when you want more customization to you axes, such as positions, sizes, colors and etc. You can see artist tutorial for more details. (I personally prefer this for individual plot).
plt.subplots() is recommended for generating multiple subplots in grids. You can also achieve higher flexibility using 'gridspec' and 'subplots', see details here.
This might sound trivial, but I am unable find a solution in PYTHON. No problem in ROOT or MATLAB.
So, I have a 3x3 array, and I would like each element in the array to represent the height (frequency) of a bin. I should have a histogram with 9 bins. Here's an example of what I have been trying.
import numpy as np
import matplotlib.pyplot as plt
H = np.array([[21,33,6],[25,20,2],[80,40,0]])
hist, bin = np.histogramdd(H, bins=3)
center = 0.5*(bin[:-1] + bin[1:])
plt.bar(center, hist)
plt.show()
I've tried histogram2D, I just can't find any to get this to work with PYTHON. Thanks in advance for any help on this.
If im not mistaken shouldnt this just be:
H=H.reshape(-1)
plt.bar(np.arange(H.shape[0]),H)
You can also do a 3D histogram:
extent = [0,2,0,2]
plt.imshow(H, extent=extent, interpolation='nearest')
plt.colorbar()
plt.show()
3D Bar histogram:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
for z,height in enumerate(H):
cs = [c] * len(xs)
cs[0] = 'c'
ax.bar(np.arange(3), height, zs=z, zdir='y', color=cs, alpha=0.8)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plt.show()
The above should work, I dont have my laptop with me at the moment. More example can be found here. A great example for 3D bars can be found here.