I have created a plot that contains two plots within the same axis similar to this:
https://matplotlib.org/1.5.1/examples/pylab_examples/ganged_plots.html
fig = plt.figure()
ax1 = fig.add_axes([0.1, 0.5, 0.8, 0.4],
xticklabels=[], ylim=(-1.2, 1.2))
ax2 = fig.add_axes([0.1, 0.1, 0.8, 0.4],
ylim=(-1.2, 1.2))
x = np.linspace(0, 10)
ax1.plot(np.sin(x))
ax2.plot(np.cos(x));
Is there a way I can place transect lines that pass through both plots if I have the specific x coordinate for each line?
IIUC, you can do something like this using list comprehension on a list of your axes:
[i.axvline(20, color='r') for i in [ax1,ax2]]
Output:
Related
I have a plot with both a colorbar and a legend. I want to place the legend outside of the plot to the right of the colorbar. To accomplish this, I use bbox_to_anchor argument, but this causes the legend to get cut off:
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import norm
_, ax = plt.subplots()
extent = np.r_[0, 1, 0, 1]
space = np.linspace(0, 1)
probs = np.array([[norm.cdf(x + y) for x in space] for y in space])
colormap = ax.imshow(probs, aspect="auto", origin="lower", extent=extent, alpha=0.5)
colorbar = plt.colorbar(colormap, ax=ax)
colorbar.set_label(f"Probability")
ax.scatter(
[0.2, 0.4, 0.6], [0.8, 0.6, 0.4], color="r", label="Labeled Points",
)
plt.legend(loc="center left", bbox_to_anchor=(1.3, 0.5))
plt.title
plt.show()
Plot with legend cut off
To fix the legend, I insert a call to plt.tight_layout() before plt.show(), but this causes the aspect ratio to get distorted:
Plot with distorted aspect ratio
How can I show the entire legend and preserve the aspect ratio of the axes?
You can manage the ratio between axis height and width with matplotlib.axes.Axes.set_aspect. Since you want them to be equal:
ax.set_aspect(1)
Then you can use matplotlib.pyplot.tight_layout to fit the legend within the figure.
If you want to adjust margins too, you can use matplotlib.pyplot.subplots_adjust.
Complete Code
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import norm
_, ax = plt.subplots()
extent = np.r_[0, 1, 0, 1]
space = np.linspace(0, 1)
probs = np.array([[norm.cdf(x + y) for x in space] for y in space])
colormap = ax.imshow(probs, aspect="auto", origin="lower", extent=extent, alpha=0.5)
colorbar = plt.colorbar(colormap, ax=ax)
colorbar.set_label(f"Probability")
ax.scatter([0.2, 0.4, 0.6], [0.8, 0.6, 0.4], color="r", label="Labeled Points",)
plt.legend(loc="center left", bbox_to_anchor=(1.3, 0.5))
ax.set_aspect(1)
plt.tight_layout()
plt.subplots_adjust(left = 0.1)
plt.show()
How can I create one plot for this loop?
I want to create some subplots according to i values taken from the loop. Do I need to create a new For/Loop which goes to each subplot? How can I do it?. This is my code:
fig, axes = plt.subplots(nrows=4, ncols=3)
fig.subplots_adjust(hspace=0.5)
fig.suptitle('Main plots')
for i in range(1,13):
month = [i]
DF_sub = DF[DF['months'].isin(month)]
out = pd.cut(DF_sub['new'], bins=[0, 0.25, 0.5, 0.75, 1], include_lowest=True)
out_norm = out.value_counts(sort=False, normalize=True)
ax = out_norm.plot.bar(rot=0, color="b", figsize=(6,4))
plt.title('Subplot -' + str(i))
Up to now, I just get the last one, but I am missing the previos i-s values from the loop
You need to pass the ax parameter to plot.bar to specify on which of your axes, returned from plt.subplots, the bar chart should be plotted, i.e.:
fig, axes = plt.subplots(nrows=4, ncols=3)
fig.subplots_adjust(hspace=0.5)
fig.suptitle('Main plots')
for i in range(1,13):
month = [i]
ax = axes[i - 1]
DF_sub = DF[DF['months'].isin(month)]
out = pd.cut(DF_sub['new'], bins=[0, 0.25, 0.5, 0.75, 1], include_lowest=True)
out_norm = out.value_counts(sort=False, normalize=True)
out_norm.plot.bar(rot=0, color="b", figsize=(6,4), ax=ax)
plt.title('Subplot -' + str(i))
If you don't pass the ax parameter, the bar chart will automatically be plotted on the currently active axis, which is the one most recently created unless set otherwise.
The following script generates a scatter plot with annotated data points. I'd like remove circle markers from the plot and just show the labels.
fig, ax = Plot.subplots()
ax.scatter(Y0_mean, Y1_mean)
for i, txt in enumerate(features.playerCountry.unique()):
country_name = countries_code[countries_code.CountryCode == txt]
['ctr'].values[0].lower()
ax.annotate(country_name, (Y0_mean[i], Y1_mean[i]), xytext=(Y0_mean[i],
Y1_mean[i]), size=5)
ax.legend(fontsize=8)
fig.savefig(figPath + 'LocationAwareMeanFeatures_ctr'+str(lr), dpi=300)
There are 2 options. 1) don't call ax.scatter. This does mean you have to set the axes limits yourself in order to see the points.
y=[2.56422, 3.77284,3.52623,3.51468,3.02199]
x=[0.15, 0.3, 0.45, 0.6, 0.75]
n=[58,651,393,203,123]
fig, ax = plt.subplots()
# ax.scatter(x, y)
for i, txt in enumerate(n):
ax.annotate(txt, (x[i],y[i]))
ax.set_ylim(2.5,4)
plt.show()
or option 2) Call ax.scatter but remove the LineCollections that are added by doing:
y=[2.56422, 3.77284,3.52623,3.51468,3.02199]
x=[0.15, 0.3, 0.45, 0.6, 0.75]
n=[58,651,393,203,123]
fig, ax = plt.subplots()
points = ax.scatter(x, y)
for i, txt in enumerate(n):
ax.annotate(txt, (x[i],y[i]))
points.remove()
plt.show()
Both methods give the same result (provided you set the same axis limits in option 1 as you get in option 2):
I have tried the following to produce a regular polygon:
import matplotlib.pyplot as plt
import matplotlib.patches as patches
fig2 = plt.figure()
ax2 = fig2.add_subplot(111, aspect='equal')
ax2.add_patch(
patches.RegularPolygon(
(0.5, 0.5),
3,
0.2,
fill=False # remove background
)
)
fig2.savefig('reg-polygon.png', dpi=90, bbox_inches='tight')
plt.show()
While this produces a triangle, I haven't found any way to produce a trapezoid and and a parallelogram.
Are there any commands to do this? Or can I transform the regular polygon into one of the other shapes?
You would need to use a matplotlib.patches.Polygon and define the corners yourself.
import matplotlib.pyplot as plt
import matplotlib.patches as patches
fig = plt.figure()
ax = fig.add_subplot(111, aspect='equal')
# Parallelogram
x = [0.3,0.6,.7,.4]
y = [0.4,0.4,0.6,0.6]
ax.add_patch(patches.Polygon(xy=list(zip(x,y)), fill=False))
# Trapez
x = [0.3,0.6,.5,.4]
y = [0.7,0.7,0.9,0.9]
ax.add_patch(patches.Polygon(xy=list(zip(x,y)), fill=False))
plt.show()
For filled patches with size greater than 1 x 1
fig = plt.figure()
ax = fig.add_subplot(111, aspect='equal')
ax.set_xlim(0, 3)
ax.set_ylim(0, 3)
x = [0, 1.16, 2.74, 2, 0]
y = [0, 2.8, 2.8, 0, 0]
ax.add_patch(patches.Polygon(xy=list(zip(x,y)), fill=True))
x = [0.3,0.6,.5,.4]
y = [0.7,0.7,0.9,0.9]
ax.add_patch(patches.Polygon(xy=list(zip(x,y)), fill=True, color='magenta'))
One simple way to do it is creating a list of lists as the end points of the polygon( parallelogram/trapezoid) and plotting(or rather tracing) them.
import matplotlib.pyplot as plt
import matplotlib.patches as patches
fig2 = plt.figure()
ax2 = fig2.add_subplot(111, aspect='equal')
points = [[0.2, 0.4], [0.4, 0.8], [0.8, 0.8], [0.6, 0.4], [0.2,0.4]] #the points to trace the edges.
polygon= plt.Polygon(points, fill=None, edgecolor='r')
ax2.add_patch(polygon)
fig2.savefig('reg-polygon.png', dpi=90, bbox_inches='tight')
plt.show()
Also, note that you should use Polygon instead of RegularPolygon.
I am trying to insert a .png image to the right side of the plot and following the code mentioned here:
Combine picture and plot with Python Matplotlib
Here is what I have tried:
import numpy as np
from matplotlib.colors import LinearSegmentedColormap
import matplotlib.pyplot as plt
import matplotlib as mpl
import matplotlib.cbook as cbook
from matplotlib._png import read_png
from matplotlib.offsetbox import OffsetImage
cmap = mpl.cm.hot
norm = mpl.colors.Normalize(vmin=-1 * outlier, vmax=outlier)
cmap.set_over('green')
cmap.set_under('green')
cmap.set_bad('green')
plt.xlim(0,35)
plt.ylim(0,35)
fig, ax = plt.subplots()
ax.set_aspect('equal')
cb_ax=fig.add_axes([0.85, 0.1, 0.03, 0.8])
img = ax.imshow(np.ma.masked_values(data, outlier), cmap=cmap, norm=norm, interpolation='none',vmax=outlier)
cb = mpl.colorbar.ColorbarBase(cb_ax, cmap=cmap, norm=norm, extend='both')
##axim = plt.subplot2grid(shape, loc, rowspan=1)
## phlo tree
image_file = cbook.get_sample_data('mytree.png',asfileobj=False)
image = plt.imread(image_file)
phyl_ax=fig.add_axes([0.10,0.1, 0.03, 0.8])
phyl_ax.imshow(image,interpolation='nearest')
Th heat map would be on the left side and the image of a tree will be inserted on the right side. With the above code here is what I get...
There is something being added to the right side but obviously it isn't the way it should look like.
At first I thought I was setting the dimensions of phyl_ax too small but when I try to increase it, even the previous "something" is also not being added.
Could someone point at where I am going wrong with it?
You are calling both subplots, which, by default, gives you a single axes, and also adding axes via add_axes. You should do one or the other, e.g.
...
fig = plt.figure()
ht_ax = fig.add_axes([0.1, 0.1, 0.3, 0.8])
cb_ax = fig.add_axes([0.45, 0.3, 0.02, 0.4])
phyl_ax = fig.add_axes([0.6, 0.1, 0.3, 0.8])
...
--or--
...
fig, ax = plt.subplots(1,2)
fig.subplots_adjust(left=0.15)
ht_ax = ax[0]
phyl_ax = ax[1]
cb_ax=fig.add_axes([0.05, 0.3, 0.02, 0.4])
...
You can use subplots_adjust and set_aspect to adjust the layout. You can also use colorbar.make_axes to get an appropriately sized colorbar axes. Here I also used grid_spec to get the plots to be a size ratio I liked
gs = gridspec.GridSpec(1, 2, width_ratios=[3, 2])
ht_ax = plt.subplot(gs[0])
phyl_ax = plt.subplot(gs[1])
cb_ax, kw = mpl.colorbar.make_axes(ht_ax, shrink=0.55)
...
cb = mpl.colorbar.ColorbarBase(ax=cb_ax, cmap=cmap, norm=norm, extend='both', **kw)