Adding image to a plot -matplotlib PYTHON - python

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)

Related

How to preserve axis aspect ratio with tight_layout

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()

Matplotlib: Add a custom colorbar that runs from full transparent to full color (remove artifacts)

I am trying to add a custom colorbar to my matplotlib figure, that runs from full transparent (white) to full color (mediumpurple).
I have come far, but still a few issues. The way I make this, creates lines between each patch, which are visible. This creates artifacts when I try to make the colorbar look fluent.
fig, ax = plt.subplots(figsize=(10, 10))
max_val = 4
transparency_ticks = 500
color = mpl.colors.to_rgba(color)
cmap = mpl.colors.ListedColormap([(*color[:3], (1+a)/transparency_ticks) for a in range(transparency_ticks)])
norm = mpl.colors.Normalize(vmin=0, vmax=max_val)
cax = fig.add_axes([0.8, 0.17, 0.05, 0.5])
mpl.colorbar.ColorbarBase(cax, cmap=cmap, norm=norm, orientation='vertical')
This is the image for transparency_ticks = 500. So you can see the lines between each patch.
This is the image for transparency_ticks = 5000. You don't see the lines anymore since they have blended with the rest, but these lines make the colorbar look a lot darker.
Instead of levels onRGBA, use HSV with various saturation:
fig, ax = plt.subplots(figsize=(10, 10))
max_val = 4
transparency_ticks = 50
colors = [mpl.colors.hsv_to_rgb((0.83, a/transparency_ticks, 1))
for a in range(transparency_ticks)]
cmap = mpl.colors.ListedColormap(colors)
norm = mpl.colors.Normalize(vmin=0, vmax=max_val)
cax = fig.add_axes([0.8, 0.17, 0.05, 0.5])
mpl.colorbar.ColorbarBase(cax, cmap=cmap, norm=norm, orientation='vertical')

How to make matplotlib.pyplot subplots that overlap?

I am learning how to use subplots. For example:
import numpy
import matplotlib.pyplot as plt
plt.figure(1)
plt.subplot(221)
plt.subplot(222)
plt.subplot(223)
plt.show()
plt.close(1)
I am getting 3 subplots in figure1
Now I want to make a large subplot with the other subplots within the first one. I tried:
plt.figure(1)
plt.subplot(111)
plt.subplot(222)
plt.subplot(223)
But the first subplot disappears.
My question: is it possible to overlap subplots?
thank you
If you want a total control of the subplots size and position, use Matplotlib add_axes method instead.
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(6, 4))
ax1 = fig.add_axes([0.1, 0.1, 0.85, 0.85])
ax2 = fig.add_axes([0.4, 0.6, 0.45, 0.3])
ax3 = fig.add_axes([0.6, 0.2, 0.2, 0.65])
ax1.text(0.01, 0.95, "ax1", size=12)
ax2.text(0.05, 0.8, "ax2", size=12)
ax3.text(0.05, 0.9, "ax3", size=12)
plt.show()
You can use mpl_toolkits.axes_grid1.inset_locator.inset_axes to create an inset axes on an existing figure.
I added a print statement at the end which shows a list of two axes.
import matplotlib.pyplot as plt
import mpl_toolkits.axes_grid1.inset_locator as mpl_il
plt.plot()
ax2 = mpl_il.inset_axes(plt.gca(), width='60%', height='40%', loc=6)
ax2.plot()
print(plt.gcf().get_axes())
plt.show()
It's not possible to use plt.subplots() to create overlapping subplots. Also, plt.subplot2grid will not work.
However, you can create them using the figure.add_subplot() method.
import matplotlib.pyplot as plt
fig = plt.figure(1)
fig.add_subplot(111)
fig.add_subplot(222)
fig.add_subplot(223)
plt.show()

changes axis of scatter plot with slider matplotlib python

I have a very large data set and want the user to be able to slide along the axis to view sections of the data. I'm trying to leverage off of the slider example but I'm unsure of how to update the graph. Hoping someone can explain some of the behinds the scenes with this.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.widgets import Slider, Button, RadioButtons
fig = plt.figure()
ax = fig.add_subplot(111)
fig.subplots_adjust(left=0.25, bottom=0.25)
min0 = 0
max0 = 10
x = np.arange(10)
y = np.arange(10)
im1 = plt.scatter(x,y, s=3, c=u'b', edgecolor='None',alpha=.75)
#most examples here return something iterable
plt.ylim([0,10])#initial limits
axcolor = 'lightgoldenrodyellow'
axmin = fig.add_axes([0.25, 0.1, 0.65, 0.03], axisbg=axcolor)
axmax = fig.add_axes([0.25, 0.15, 0.65, 0.03], axisbg=axcolor)
smin = Slider(axmin, 'Min', 0, 10, valinit=min0)
smax = Slider(axmax, 'Max', 0, 10, valinit=max0)
def update(val):
plt.ylim([smin.val,smax.val])
ax.canvas.draw()#unsure on this
smin.on_changed(update)
smax.on_changed(update)
plt.show()
The graph updates itself when you set new limits. You just don't see this because you update wrong subplot. Just select right subplot to update:
def update(val):
plt.subplot(111)
plt.ylim([smin.val,smax.val])
(this work for me)
or maybe even:
def update(val):
plt.ylim([smin.val,smax.val])
plt.subplot(111)
smin.on_changed(update)
smax.on_changed(update)
if you don`t do anything with it elsewhere
UPD: also in matplotlib examples you can find fig.canvas.draw_idle()

matplotlib fig size with colorbar

I'm trying to produce two figure. The second one is equal to the first one, with the only exception that it has superimposed an image with the corresponding colorbar. I need this in a presentation for a correct overlay. The code I'm using is the following
import matplotlib as mpl
# first figure
fig = mpl.pylab.figure(figsize=(10, 7))
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])
ax.plot(x,y)
ax.set_xlabel(r'x')
ax.set_ylabel(r'y')
ax.set_xlim([0,1])
ax.set_ylim([0,1])
mpl.pylab.savefig('one.pdf',bbox_inches='tight')
# second figure
fig = mpl.pylab.figure(figsize=(10, 7))
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])
ax.plot(x,y)
ax.set_xlabel(r'x')
ax.set_ylabel(r'y')
ax.set_xlim([0,1])
ax.set_ylim([0,1])
im = ax.imshow(image,aspect='auto',origin='lower',extent=(0,1,0.5,1))
cb = fig.colorbar(im, orientation='vertical')
cb.set_label(r'p$_e$ [Pa]', fontsize = 18)
mpl.pylab.savefig('two.pdf',bbox_inches='tight')
The problem is that I would like that the canvas (I think this is the correct name, i.e. the space occupied by the axis and label) to be exactly the same for the two figures, whereas the second one is shrink because of the colorbar. How can I correctly determine the size for the figures?
Check out this post
You can also check out this example
I would recommend either plotting both plots on the same figure, making a grid, or doing a separate colorbar as in this example
import matplotlib as mpl
# first plot
plt.subplot(131)
...
# second plot
plt.subplot(132)
...
#colorbar
plt.subplot(133)
...

Categories

Resources